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