Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "fieldmappingimpl.hxx"
21 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
22 : #include <com/sun/star/beans/PropertyValue.hpp>
23 : #include <com/sun/star/beans/XPropertySet.hpp>
24 : #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
25 : #include <com/sun/star/ui/AddressBookSourceDialog.hpp>
26 : #include <com/sun/star/awt/XWindow.hpp>
27 : #include <com/sun/star/sdb/CommandType.hpp>
28 : #include <tools/debug.hxx>
29 : #include <toolkit/helper/vclunohelper.hxx>
30 : #include <vcl/stdtext.hxx>
31 : #include <com/sun/star/util/AliasProgrammaticPair.hpp>
32 : #include "abpresid.hrc"
33 : #include "componentmodule.hxx"
34 : #include <unotools/confignode.hxx>
35 : #include "sal/macros.h"
36 :
37 :
38 : namespace abp
39 : {
40 :
41 :
42 : using namespace ::utl;
43 : using namespace ::com::sun::star::uno;
44 : using namespace ::com::sun::star::awt;
45 : using namespace ::com::sun::star::util;
46 : using namespace ::com::sun::star::lang;
47 : using namespace ::com::sun::star::beans;
48 : using namespace ::com::sun::star::sdb;
49 : using namespace ::com::sun::star::ui;
50 : using namespace ::com::sun::star::ui::dialogs;
51 :
52 :
53 : static const char sDriverSettingsNodeName[] = "/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.MozabDriver";
54 : static const char sAddressBookNodeName[] = "/org.openoffice.Office.DataAccess/AddressBook";
55 :
56 :
57 : namespace fieldmapping
58 : {
59 :
60 :
61 :
62 0 : bool invokeDialog( const Reference< XComponentContext >& _rxORB, class vcl::Window* _pParent,
63 : const Reference< XPropertySet >& _rxDataSource, AddressSettings& _rSettings )
64 : {
65 0 : _rSettings.aFieldMapping.clear();
66 :
67 : DBG_ASSERT( _rxORB.is(), "fieldmapping::invokeDialog: invalid service factory!" );
68 : DBG_ASSERT( _rxDataSource.is(), "fieldmapping::invokeDialog: invalid data source!" );
69 0 : if ( !_rxORB.is() || !_rxDataSource.is() )
70 0 : return false;
71 :
72 : try
73 : {
74 :
75 : // create an instance of the dialog service
76 0 : Reference< XWindow > xDialogParent = VCLUnoHelper::GetInterface( _pParent );
77 0 : OUString sTitle(ModuleRes(RID_STR_FIELDDIALOGTITLE).toString());
78 : Reference< XExecutableDialog > xDialog = AddressBookSourceDialog::createWithDataSource(_rxORB,
79 : // the parent window
80 : xDialogParent,
81 : _rxDataSource,
82 : _rSettings.bRegisterDataSource ? _rSettings.sRegisteredDataSourceName : _rSettings.sDataSourceName,
83 : // the table to use
84 : _rSettings.sSelectedTable,
85 0 : sTitle);
86 :
87 : // execute the dialog
88 0 : if ( xDialog->execute() )
89 : {
90 : // retrieve the field mapping as set by he user
91 0 : Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY );
92 :
93 0 : Sequence< AliasProgrammaticPair > aMapping;
94 : #ifdef DBG_UTIL
95 : bool bSuccess =
96 : #endif
97 0 : xDialogProps->getPropertyValue("FieldMapping") >>= aMapping;
98 : DBG_ASSERT( bSuccess, "fieldmapping::invokeDialog: invalid property type for FieldMapping!" );
99 :
100 : // and copy it into the map
101 0 : const AliasProgrammaticPair* pMapping = aMapping.getConstArray();
102 0 : const AliasProgrammaticPair* pMappingEnd = pMapping + aMapping.getLength();
103 0 : for (;pMapping != pMappingEnd; ++pMapping)
104 0 : _rSettings.aFieldMapping[ pMapping->ProgrammaticName ] = pMapping->Alias;
105 :
106 0 : return true;
107 0 : }
108 :
109 : }
110 0 : catch(const Exception&)
111 : {
112 : OSL_FAIL("fieldmapping::invokeDialog: caught an exception while executing the dialog!");
113 : }
114 0 : return false;
115 : }
116 :
117 :
118 0 : void defaultMapping( const Reference< XComponentContext >& _rxContext, MapString2String& _rFieldAssignment )
119 : {
120 0 : _rFieldAssignment.clear();
121 :
122 : try
123 : {
124 : // what we have:
125 : // a) For the address data source, we need a mapping from programmatic names (1) to real column names
126 : // b) The SDBC driver has a fixed set of columns, which, when returned, are named according to
127 : // some configuration entries. E.g., the driver displays the field which it knows contains
128 : // the first name as "First Name" - the latter string is stored in the config.
129 : // For this, the driver uses programmatic names, too, but they differ from the programmatic names the
130 : // template documents have.
131 : // So what we need first is a mapping from programmatic names (1) to programmatic names (2)
132 : const sal_Char* pMappingProgrammatics[] =
133 : {
134 : "FirstName", "FirstName",
135 : "LastName", "LastName",
136 : "Street", "HomeAddress",
137 : "Zip", "HomeZipCode",
138 : "City", "HomeCity",
139 : "State", "HomeState",
140 : "Country", "HomeCountry",
141 : "PhonePriv", "HomePhone",
142 : "PhoneComp", "WorkPhone",
143 : "PhoneCell", "CellularNumber",
144 : "Pager", "PagerNumber",
145 : "Fax", "FaxNumber",
146 : "EMail", "PrimaryEmail",
147 : "URL", "WebPage1",
148 : "Note", "Notes",
149 : "Altfield1", "Custom1",
150 : "Altfield2", "Custom2",
151 : "Altfield3", "Custom3",
152 : "Altfield4", "Custom4",
153 : "Title", "JobTitle",
154 : "Company", "Company",
155 : "Department", "Department"
156 0 : };
157 : // (this list is not complete: both lists of programmatic names are larger in real,
158 : // but this list above is the intersection)
159 :
160 :
161 : // access the configuration information which the driver uses for determining it's column names
162 0 : OUString sDriverAliasesNodeName = sDriverSettingsNodeName;
163 0 : sDriverAliasesNodeName += OUString( "/ColumnAliases" );
164 :
165 : // create a config node for this
166 : OConfigurationTreeRoot aDriverFieldAliasing = OConfigurationTreeRoot::createWithComponentContext(
167 0 : _rxContext, sDriverAliasesNodeName, -1, OConfigurationTreeRoot::CM_READONLY);
168 :
169 : // loop through all programmatic pairs
170 : DBG_ASSERT( 0 == SAL_N_ELEMENTS( pMappingProgrammatics ) % 2,
171 : "fieldmapping::defaultMapping: invalid programmatic map!" );
172 : // number of pairs
173 0 : sal_Int32 nIntersectedProgrammatics = SAL_N_ELEMENTS( pMappingProgrammatics ) / 2;
174 :
175 0 : const sal_Char** pProgrammatic = pMappingProgrammatics;
176 0 : OUString sAddressProgrammatic;
177 0 : OUString sDriverProgrammatic;
178 0 : OUString sDriverUI;
179 0 : for ( sal_Int32 i=0;
180 : i < nIntersectedProgrammatics;
181 : ++i
182 : )
183 : {
184 0 : sAddressProgrammatic = OUString::createFromAscii( *pProgrammatic++ );
185 0 : sDriverProgrammatic = OUString::createFromAscii( *pProgrammatic++ );
186 :
187 0 : if ( aDriverFieldAliasing.hasByName( sDriverProgrammatic ) )
188 : {
189 0 : aDriverFieldAliasing.getNodeValue( sDriverProgrammatic ) >>= sDriverUI;
190 0 : if ( 0 == sDriverUI.getLength() )
191 : {
192 : OSL_FAIL( "fieldmapping::defaultMapping: invalid driver UI column name!");
193 : }
194 : else
195 0 : _rFieldAssignment[ sAddressProgrammatic ] = sDriverUI;
196 : }
197 : else
198 : {
199 : OSL_FAIL( "fieldmapping::defaultMapping: invalid driver programmatic name!" );
200 : }
201 0 : }
202 : }
203 0 : catch( const Exception& )
204 : {
205 : OSL_FAIL("fieldmapping::defaultMapping: code is assumed to throw no exceptions!");
206 : // the config nodes we're using herein should not do this ....
207 : }
208 0 : }
209 :
210 :
211 0 : void writeTemplateAddressFieldMapping( const Reference< XComponentContext >& _rxContext, const MapString2String& _rFieldAssignment )
212 : {
213 : // want to have a non-const map for easier handling
214 0 : MapString2String aFieldAssignment( _rFieldAssignment );
215 :
216 : // access the configuration information which the driver uses for determining it's column names
217 :
218 : // create a config node for this
219 : OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext(
220 0 : _rxContext, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
221 :
222 0 : OConfigurationNode aFields = aAddressBookSettings.openNode( OUString( "Fields" ) );
223 :
224 : // loop through all existent fields
225 0 : Sequence< OUString > aExistentFields = aFields.getNodeNames();
226 0 : const OUString* pExistentFields = aExistentFields.getConstArray();
227 0 : const OUString* pExistentFieldsEnd = pExistentFields + aExistentFields.getLength();
228 :
229 0 : const OUString sProgrammaticNodeName( "ProgrammaticFieldName" );
230 0 : const OUString sAssignedNodeName( "AssignedFieldName" );
231 :
232 0 : for ( ; pExistentFields != pExistentFieldsEnd; ++pExistentFields )
233 : {
234 : #ifdef DBG_UTIL
235 : OUString sRedundantProgrammaticName;
236 : aFields.openNode( *pExistentFields ).getNodeValue( sProgrammaticNodeName ) >>= sRedundantProgrammaticName;
237 : #endif
238 : DBG_ASSERT( sRedundantProgrammaticName == *pExistentFields,
239 : "fieldmapping::writeTemplateAddressFieldMapping: inconsistent config data!" );
240 : // there should be a redundancy in the config data .... if this asserts, there isn't anymore!
241 :
242 : // do we have a new alias for the programmatic?
243 0 : MapString2String::iterator aPos = aFieldAssignment.find( *pExistentFields );
244 0 : if ( aFieldAssignment.end() != aPos )
245 : { // yes
246 : // -> set a new value
247 0 : OConfigurationNode aExistentField = aFields.openNode( *pExistentFields );
248 0 : aExistentField.setNodeValue( sAssignedNodeName, makeAny( aPos->second ) );
249 : // and remove the mapping entry
250 0 : aFieldAssignment.erase( *pExistentFields );
251 : }
252 : else
253 : { // no
254 : // -> remove it
255 0 : aFields.removeNode( *pExistentFields );
256 : }
257 : }
258 :
259 : // now everything remaining in aFieldAssignment marks a mapping entry which was not present
260 : // in the config before
261 0 : for ( MapString2String::const_iterator aNewMapping = aFieldAssignment.begin();
262 0 : aNewMapping != aFieldAssignment.end();
263 : ++aNewMapping
264 : )
265 : {
266 : DBG_ASSERT( !aFields.hasByName( aNewMapping->first ),
267 : "fieldmapping::writeTemplateAddressFieldMapping: inconsistence!" );
268 : // in case the config node for the fields already has the node named <aNewMapping->first>,
269 : // the entry should have been removed from aNewMapping (in the above loop)
270 0 : OConfigurationNode aNewField = aFields.createNode( aNewMapping->first );
271 0 : aNewField.setNodeValue( sProgrammaticNodeName, makeAny( aNewMapping->first ) );
272 0 : aNewField.setNodeValue( sAssignedNodeName, makeAny( aNewMapping->second ) );
273 0 : }
274 :
275 : // commit the changes done
276 0 : aAddressBookSettings.commit();
277 0 : }
278 :
279 :
280 : } // namespace fieldmapping
281 :
282 :
283 :
284 : namespace addressconfig
285 : {
286 :
287 :
288 :
289 0 : void writeTemplateAddressSource( const Reference< XComponentContext >& _rxContext,
290 : const OUString& _rDataSourceName, const OUString& _rTableName )
291 : {
292 : // access the configuration information which the driver uses for determining it's column names
293 :
294 : // create a config node for this
295 : OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext(
296 0 : _rxContext, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
297 :
298 0 : aAddressBookSettings.setNodeValue( OUString( "DataSourceName" ), makeAny( _rDataSourceName ) );
299 0 : aAddressBookSettings.setNodeValue( OUString( "Command" ), makeAny( _rTableName ) );
300 0 : aAddressBookSettings.setNodeValue( OUString( "CommandType" ), makeAny( (sal_Int32)CommandType::TABLE ) );
301 :
302 : // commit the changes done
303 0 : aAddressBookSettings.commit();
304 0 : }
305 :
306 :
307 0 : void markPilotSuccess( const Reference< XComponentContext >& _rxContext )
308 : {
309 : // access the configuration information which the driver uses for determining it's column names
310 :
311 : // create a config node for this
312 : OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext(
313 0 : _rxContext, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
314 :
315 : // set the flag
316 0 : aAddressBookSettings.setNodeValue( OUString( "AutoPilotCompleted" ), makeAny( true ) );
317 :
318 : // commit the changes done
319 0 : aAddressBookSettings.commit();
320 0 : }
321 :
322 :
323 : } // namespace addressconfig
324 :
325 :
326 :
327 : } // namespace abp
328 :
329 :
330 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|