xref: /trunk/main/extensions/source/abpilot/fieldmappingimpl.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 #include "fieldmappingimpl.hxx"
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
35 #include <com/sun/star/awt/XWindow.hpp>
36 #include <com/sun/star/sdb/CommandType.hpp>
37 #include <tools/debug.hxx>
38 #ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
39 #include <toolkit/unohlp.hxx>
40 #endif
41 #include <vcl/stdtext.hxx>
42 #include <com/sun/star/util/AliasProgrammaticPair.hpp>
43 #ifndef EXTENSIONS_ABPRESID_HRC
44 #include "abpresid.hrc"
45 #endif
46 #include "componentmodule.hxx"
47 #include <unotools/confignode.hxx>
48 
49 //.........................................................................
50 namespace abp
51 {
52 //.........................................................................
53 
54     using namespace ::utl;
55     using namespace ::com::sun::star::uno;
56     using namespace ::com::sun::star::awt;
57     using namespace ::com::sun::star::util;
58     using namespace ::com::sun::star::lang;
59     using namespace ::com::sun::star::beans;
60     using namespace ::com::sun::star::sdb;
61     using namespace ::com::sun::star::ui::dialogs;
62 
63     //---------------------------------------------------------------------
64     static const ::rtl::OUString& lcl_getDriverSettingsNodeName()
65     {
66         static const ::rtl::OUString s_sDriverSettingsNodeName =
67             ::rtl::OUString::createFromAscii( "/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.MozabDriver" );
68         return s_sDriverSettingsNodeName;
69     }
70 
71     //---------------------------------------------------------------------
72     static const ::rtl::OUString& lcl_getAddressBookNodeName()
73     {
74         static const ::rtl::OUString s_sAddressBookNodeName =
75             ::rtl::OUString::createFromAscii( "/org.openoffice.Office.DataAccess/AddressBook" );
76         return s_sAddressBookNodeName;
77     }
78 
79     //.....................................................................
80     namespace fieldmapping
81     {
82     //.....................................................................
83 
84         //-----------------------------------------------------------------
85         sal_Bool invokeDialog( const Reference< XMultiServiceFactory >& _rxORB, class Window* _pParent,
86             const Reference< XPropertySet >& _rxDataSource, AddressSettings& _rSettings ) SAL_THROW ( ( ) )
87         {
88             _rSettings.aFieldMapping.clear();
89 
90             DBG_ASSERT( _rxORB.is(), "fieldmapping::invokeDialog: invalid service factory!" );
91             DBG_ASSERT( _rxDataSource.is(), "fieldmapping::invokeDialog: invalid data source!" );
92             if ( !_rxORB.is() || !_rxDataSource.is() )
93                 return sal_False;
94 
95             try
96             {
97                 // ........................................................
98                 // the parameters for creating the dialog
99                 Sequence< Any > aArguments(5);
100                 Any* pArguments = aArguments.getArray();
101 
102                 // the parent window
103                 Reference< XWindow > xDialogParent = VCLUnoHelper::GetInterface( _pParent );
104                 *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii( "ParentWindow" ), -1, makeAny( xDialogParent ), PropertyState_DIRECT_VALUE);
105 
106                 // the data source to use
107                 *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii( "DataSource" ), -1, makeAny( _rxDataSource ), PropertyState_DIRECT_VALUE);
108                 *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii( "DataSourceName" ), -1, makeAny( (sal_Bool)_rSettings.bRegisterDataSource ? _rSettings.sRegisteredDataSourceName : _rSettings.sDataSourceName ), PropertyState_DIRECT_VALUE);
109 
110                 // the table to use
111                 *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii( "Command" ), -1, makeAny( _rSettings.sSelectedTable ), PropertyState_DIRECT_VALUE);
112 
113                 // the title
114                 ::rtl::OUString sTitle = String( ModuleRes( RID_STR_FIELDDIALOGTITLE ) );
115                 *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii( "Title" ), -1, makeAny( sTitle ), PropertyState_DIRECT_VALUE);
116 
117                 // ........................................................
118                 // create an instance of the dialog service
119                 static ::rtl::OUString s_sAdressBookFieldAssignmentServiceName = ::rtl::OUString::createFromAscii( "com.sun.star.ui.AddressBookSourceDialog" );
120                 Reference< XExecutableDialog > xDialog(
121                     _rxORB->createInstanceWithArguments( s_sAdressBookFieldAssignmentServiceName, aArguments ),
122                     UNO_QUERY
123                 );
124                 if ( !xDialog.is( ) )
125                 {
126                     ShowServiceNotAvailableError( _pParent, s_sAdressBookFieldAssignmentServiceName, sal_True );
127                     return sal_False;
128                 }
129 
130                 // execute the dialog
131                 if ( xDialog->execute() )
132                 {
133                     // retrieve the field mapping as set by he user
134                     Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY );
135 
136                     Sequence< AliasProgrammaticPair > aMapping;
137 #ifdef DBG_UTIL
138                     sal_Bool bSuccess =
139 #endif
140                     xDialogProps->getPropertyValue( ::rtl::OUString::createFromAscii( "FieldMapping" ) ) >>= aMapping;
141                     DBG_ASSERT( bSuccess, "fieldmapping::invokeDialog: invalid property type for FieldMapping!" );
142 
143                     // and copy it into the map
144                     const AliasProgrammaticPair* pMapping = aMapping.getConstArray();
145                     const AliasProgrammaticPair* pMappingEnd = pMapping + aMapping.getLength();
146                     for (;pMapping != pMappingEnd; ++pMapping)
147                         _rSettings.aFieldMapping[ pMapping->ProgrammaticName ] = pMapping->Alias;
148 
149                     return sal_True;
150                 }
151 
152             }
153             catch(const Exception&)
154             {
155                 DBG_ERROR("fieldmapping::invokeDialog: caught an exception while executing the dialog!");
156             }
157             return sal_False;
158         }
159 
160         //-----------------------------------------------------------------
161         void defaultMapping(  const Reference< XMultiServiceFactory >& _rxORB, MapString2String& _rFieldAssignment ) SAL_THROW ( ( ) )
162         {
163             _rFieldAssignment.clear();
164 
165             try
166             {
167                 // what we have:
168                 // a) For the address data source, we need a mapping from programmatic names (1) to real column names
169                 // b) The SDBC driver has a fixed set of columns, which, when returned, are named according to
170                 //    some configuration entries. E.g., the driver displays the field which it knows contains
171                 //    the first name as "First Name" - the latter string is stored in the config.
172                 //    For this, the driver uses programmatic names, too, but they differ from the programmatic names the
173                 //    template documents have.
174                 // So what we need first is a mapping from programmatic names (1) to programmatic names (2)
175                 const sal_Char* pMappingProgrammatics[] =
176                 {
177                     "FirstName",            "FirstName",
178                     "LastName",             "LastName",
179                     "Street",               "HomeAddress",
180                     "Zip",                  "HomeZipCode",
181                     "City",                 "HomeCity",
182                     "State",                "HomeState",
183                     "Country",              "HomeCountry",
184                     "PhonePriv",            "HomePhone",
185                     "PhoneComp",            "WorkPhone",
186                     "PhoneCell",            "CellularNumber",
187                     "Pager",                "PagerNumber",
188                     "Fax",                  "FaxNumber",
189                     "EMail",                "PrimaryEmail",
190                     "URL",                  "WebPage1",
191                     "Note",                 "Notes",
192                     "Altfield1",            "Custom1",
193                     "Altfield2",            "Custom2",
194                     "Altfield3",            "Custom3",
195                     "Altfield4",            "Custom4",
196                     "Title",                "JobTitle",
197                     "Company",              "Company",
198                     "Department",           "Department"
199                 };
200                     // (this list is not complete: both lists of programmatic names are larger in real,
201                     // but this list above is the intersection)
202 
203 
204                 // access the configuration information which the driver uses for determining it's column names
205                 ::rtl::OUString sDriverAliasesNodeName = lcl_getDriverSettingsNodeName();
206                 sDriverAliasesNodeName += ::rtl::OUString::createFromAscii( "/ColumnAliases" );
207 
208                 // create a config node for this
209                 OConfigurationTreeRoot aDriverFieldAliasing = OConfigurationTreeRoot::createWithServiceFactory(
210                     _rxORB, sDriverAliasesNodeName, -1, OConfigurationTreeRoot::CM_READONLY);
211 
212                 // loop through all programmatic pairs
213                 DBG_ASSERT( 0 == ( sizeof( pMappingProgrammatics ) / sizeof( pMappingProgrammatics[ 0 ] ) ) % 2,
214                     "fieldmapping::defaultMapping: invalid programmatic map!" );
215                 // number of pairs
216                 sal_Int32 nIntersectedProgrammatics = sizeof( pMappingProgrammatics ) / sizeof( pMappingProgrammatics[ 0 ] ) / 2;
217 
218                 const sal_Char** pProgrammatic = pMappingProgrammatics;
219                 ::rtl::OUString sAddressProgrammatic;
220                 ::rtl::OUString sDriverProgrammatic;
221                 ::rtl::OUString sDriverUI;
222                 for (   sal_Int32 i=0;
223                         i < nIntersectedProgrammatics;
224                         ++i
225                     )
226                 {
227                     sAddressProgrammatic = ::rtl::OUString::createFromAscii( *pProgrammatic++ );
228                     sDriverProgrammatic = ::rtl::OUString::createFromAscii( *pProgrammatic++ );
229 
230                     if ( aDriverFieldAliasing.hasByName( sDriverProgrammatic ) )
231                     {
232                         aDriverFieldAliasing.getNodeValue( sDriverProgrammatic ) >>= sDriverUI;
233                         if ( 0 == sDriverUI.getLength() )
234                         {
235                             DBG_ERROR( "fieldmapping::defaultMapping: invalid driver UI column name!");
236                         }
237                         else
238                             _rFieldAssignment[ sAddressProgrammatic ] = sDriverUI;
239                     }
240                     else
241                     {
242                         DBG_ERROR( "fieldmapping::defaultMapping: invalid driver programmatic name!" );
243                     }
244                 }
245             }
246             catch( const Exception& )
247             {
248                 DBG_ERROR("fieldmapping::defaultMapping: code is assumed to throw no exceptions!");
249                     // the config nodes we're using herein should not do this ....
250             }
251         }
252 
253         //-----------------------------------------------------------------
254         void writeTemplateAddressFieldMapping( const Reference< XMultiServiceFactory >& _rxORB, const MapString2String& _rFieldAssignment ) SAL_THROW ( ( ) )
255         {
256             // want to have a non-const map for easier handling
257             MapString2String aFieldAssignment( _rFieldAssignment );
258 
259             // access the configuration information which the driver uses for determining it's column names
260             const ::rtl::OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
261 
262             // create a config node for this
263             OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithServiceFactory(
264                 _rxORB, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
265 
266             OConfigurationNode aFields = aAddressBookSettings.openNode( ::rtl::OUString::createFromAscii( "Fields" ) );
267 
268             // loop through all existent fields
269             Sequence< ::rtl::OUString > aExistentFields = aFields.getNodeNames();
270             const ::rtl::OUString* pExistentFields = aExistentFields.getConstArray();
271             const ::rtl::OUString* pExistentFieldsEnd = pExistentFields + aExistentFields.getLength();
272 
273             const ::rtl::OUString sProgrammaticNodeName = ::rtl::OUString::createFromAscii( "ProgrammaticFieldName" );
274             const ::rtl::OUString sAssignedNodeName = ::rtl::OUString::createFromAscii( "AssignedFieldName" );
275 
276             for ( ; pExistentFields != pExistentFieldsEnd; ++pExistentFields )
277             {
278 #ifdef DBG_UTIL
279                 ::rtl::OUString sRedundantProgrammaticName;
280                 aFields.openNode( *pExistentFields ).getNodeValue( sProgrammaticNodeName ) >>= sRedundantProgrammaticName;
281 #endif
282                 DBG_ASSERT( sRedundantProgrammaticName == *pExistentFields,
283                     "fieldmapping::writeTemplateAddressFieldMapping: inconsistent config data!" );
284                     // there should be a redundancy in the config data .... if this asserts, there isn't anymore!
285 
286                 // do we have a new alias for the programmatic?
287                 MapString2StringIterator aPos = aFieldAssignment.find( *pExistentFields );
288                 if ( aFieldAssignment.end() != aPos )
289                 {   // yes
290                     // -> set a new value
291                     OConfigurationNode aExistentField = aFields.openNode( *pExistentFields );
292                     aExistentField.setNodeValue( sAssignedNodeName, makeAny( aPos->second ) );
293                     // and remove the mapping entry
294                     aFieldAssignment.erase( *pExistentFields );
295                 }
296                 else
297                 {   // no
298                     // -> remove it
299                     aFields.removeNode( *pExistentFields );
300                 }
301             }
302 
303             // now everything remaining in aFieldAssignment marks a mapping entry which was not present
304             // in the config before
305             for (   ConstMapString2StringIterator aNewMapping = aFieldAssignment.begin();
306                     aNewMapping != aFieldAssignment.end();
307                     ++aNewMapping
308                 )
309             {
310                 DBG_ASSERT( !aFields.hasByName( aNewMapping->first ),
311                     "fieldmapping::writeTemplateAddressFieldMapping: inconsistence!" );
312                     // in case the config node for the fields already has the node named <aNewMapping->first>,
313                     // the entry should have been removed from aNewMapping (in the above loop)
314                 OConfigurationNode aNewField =  aFields.createNode( aNewMapping->first );
315                 aNewField.setNodeValue( sProgrammaticNodeName, makeAny( aNewMapping->first ) );
316                 aNewField.setNodeValue( sAssignedNodeName, makeAny( aNewMapping->second ) );
317             }
318 
319             // commit the changes done
320             aAddressBookSettings.commit();
321         }
322 
323     //.....................................................................
324     }   // namespace fieldmapping
325     //.....................................................................
326 
327     //.....................................................................
328     namespace addressconfig
329     {
330     //.....................................................................
331 
332         //-----------------------------------------------------------------
333         void writeTemplateAddressSource( const Reference< XMultiServiceFactory >& _rxORB,
334             const ::rtl::OUString& _rDataSourceName, const ::rtl::OUString& _rTableName ) SAL_THROW ( ( ) )
335         {
336             // access the configuration information which the driver uses for determining it's column names
337             const ::rtl::OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
338 
339             // create a config node for this
340             OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithServiceFactory(
341                 _rxORB, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
342 
343             aAddressBookSettings.setNodeValue( ::rtl::OUString::createFromAscii( "DataSourceName" ), makeAny( _rDataSourceName ) );
344             aAddressBookSettings.setNodeValue( ::rtl::OUString::createFromAscii( "Command" ), makeAny( _rTableName ) );
345             aAddressBookSettings.setNodeValue( ::rtl::OUString::createFromAscii( "CommandType" ), makeAny( (sal_Int32)CommandType::TABLE ) );
346 
347             // commit the changes done
348             aAddressBookSettings.commit();
349         }
350 
351         //-----------------------------------------------------------------
352         void markPilotSuccess( const Reference< XMultiServiceFactory >& _rxORB ) SAL_THROW ( ( ) )
353         {
354             // access the configuration information which the driver uses for determining it's column names
355             const ::rtl::OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
356 
357             // create a config node for this
358             OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithServiceFactory(
359                 _rxORB, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
360 
361             // set the flag
362             aAddressBookSettings.setNodeValue( ::rtl::OUString::createFromAscii( "AutoPilotCompleted" ), makeAny( (sal_Bool)sal_True ) );
363 
364             // commit the changes done
365             aAddressBookSettings.commit();
366         }
367 
368     //.....................................................................
369     }   // namespace addressconfig
370     //.....................................................................
371 
372 //.........................................................................
373 }   // namespace abp
374 //.........................................................................
375 
376