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