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 0 : static const OUString& lcl_getDriverSettingsNodeName()
54 : {
55 0 : static const OUString s_sDriverSettingsNodeName( "/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.MozabDriver" );
56 0 : return s_sDriverSettingsNodeName;
57 : }
58 :
59 :
60 0 : static const OUString& lcl_getAddressBookNodeName()
61 : {
62 0 : static const OUString s_sAddressBookNodeName( "/org.openoffice.Office.DataAccess/AddressBook" );
63 0 : return s_sAddressBookNodeName;
64 : }
65 :
66 :
67 : namespace fieldmapping
68 : {
69 :
70 :
71 :
72 0 : bool invokeDialog( const Reference< XComponentContext >& _rxORB, class vcl::Window* _pParent,
73 : const Reference< XPropertySet >& _rxDataSource, AddressSettings& _rSettings )
74 : {
75 0 : _rSettings.aFieldMapping.clear();
76 :
77 : DBG_ASSERT( _rxORB.is(), "fieldmapping::invokeDialog: invalid service factory!" );
78 : DBG_ASSERT( _rxDataSource.is(), "fieldmapping::invokeDialog: invalid data source!" );
79 0 : if ( !_rxORB.is() || !_rxDataSource.is() )
80 0 : return false;
81 :
82 : try
83 : {
84 :
85 : // create an instance of the dialog service
86 0 : Reference< XWindow > xDialogParent = VCLUnoHelper::GetInterface( _pParent );
87 0 : OUString sTitle(ModuleRes(RID_STR_FIELDDIALOGTITLE).toString());
88 : Reference< XExecutableDialog > xDialog = AddressBookSourceDialog::createWithDataSource(_rxORB,
89 : // the parent window
90 : xDialogParent,
91 : _rxDataSource,
92 : _rSettings.bRegisterDataSource ? _rSettings.sRegisteredDataSourceName : _rSettings.sDataSourceName,
93 : // the table to use
94 : _rSettings.sSelectedTable,
95 0 : sTitle);
96 :
97 : // execute the dialog
98 0 : if ( xDialog->execute() )
99 : {
100 : // retrieve the field mapping as set by he user
101 0 : Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY );
102 :
103 0 : Sequence< AliasProgrammaticPair > aMapping;
104 : #ifdef DBG_UTIL
105 : bool bSuccess =
106 : #endif
107 0 : xDialogProps->getPropertyValue("FieldMapping") >>= aMapping;
108 : DBG_ASSERT( bSuccess, "fieldmapping::invokeDialog: invalid property type for FieldMapping!" );
109 :
110 : // and copy it into the map
111 0 : const AliasProgrammaticPair* pMapping = aMapping.getConstArray();
112 0 : const AliasProgrammaticPair* pMappingEnd = pMapping + aMapping.getLength();
113 0 : for (;pMapping != pMappingEnd; ++pMapping)
114 0 : _rSettings.aFieldMapping[ pMapping->ProgrammaticName ] = pMapping->Alias;
115 :
116 0 : return true;
117 0 : }
118 :
119 : }
120 0 : catch(const Exception&)
121 : {
122 : OSL_FAIL("fieldmapping::invokeDialog: caught an exception while executing the dialog!");
123 : }
124 0 : return false;
125 : }
126 :
127 :
128 0 : void defaultMapping( const Reference< XComponentContext >& _rxContext, MapString2String& _rFieldAssignment )
129 : {
130 0 : _rFieldAssignment.clear();
131 :
132 : try
133 : {
134 : // what we have:
135 : // a) For the address data source, we need a mapping from programmatic names (1) to real column names
136 : // b) The SDBC driver has a fixed set of columns, which, when returned, are named according to
137 : // some configuration entries. E.g., the driver displays the field which it knows contains
138 : // the first name as "First Name" - the latter string is stored in the config.
139 : // For this, the driver uses programmatic names, too, but they differ from the programmatic names the
140 : // template documents have.
141 : // So what we need first is a mapping from programmatic names (1) to programmatic names (2)
142 : const sal_Char* pMappingProgrammatics[] =
143 : {
144 : "FirstName", "FirstName",
145 : "LastName", "LastName",
146 : "Street", "HomeAddress",
147 : "Zip", "HomeZipCode",
148 : "City", "HomeCity",
149 : "State", "HomeState",
150 : "Country", "HomeCountry",
151 : "PhonePriv", "HomePhone",
152 : "PhoneComp", "WorkPhone",
153 : "PhoneCell", "CellularNumber",
154 : "Pager", "PagerNumber",
155 : "Fax", "FaxNumber",
156 : "EMail", "PrimaryEmail",
157 : "URL", "WebPage1",
158 : "Note", "Notes",
159 : "Altfield1", "Custom1",
160 : "Altfield2", "Custom2",
161 : "Altfield3", "Custom3",
162 : "Altfield4", "Custom4",
163 : "Title", "JobTitle",
164 : "Company", "Company",
165 : "Department", "Department"
166 0 : };
167 : // (this list is not complete: both lists of programmatic names are larger in real,
168 : // but this list above is the intersection)
169 :
170 :
171 : // access the configuration information which the driver uses for determining it's column names
172 0 : OUString sDriverAliasesNodeName = lcl_getDriverSettingsNodeName();
173 0 : sDriverAliasesNodeName += OUString( "/ColumnAliases" );
174 :
175 : // create a config node for this
176 : OConfigurationTreeRoot aDriverFieldAliasing = OConfigurationTreeRoot::createWithComponentContext(
177 0 : _rxContext, sDriverAliasesNodeName, -1, OConfigurationTreeRoot::CM_READONLY);
178 :
179 : // loop through all programmatic pairs
180 : DBG_ASSERT( 0 == SAL_N_ELEMENTS( pMappingProgrammatics ) % 2,
181 : "fieldmapping::defaultMapping: invalid programmatic map!" );
182 : // number of pairs
183 0 : sal_Int32 nIntersectedProgrammatics = SAL_N_ELEMENTS( pMappingProgrammatics ) / 2;
184 :
185 0 : const sal_Char** pProgrammatic = pMappingProgrammatics;
186 0 : OUString sAddressProgrammatic;
187 0 : OUString sDriverProgrammatic;
188 0 : OUString sDriverUI;
189 0 : for ( sal_Int32 i=0;
190 : i < nIntersectedProgrammatics;
191 : ++i
192 : )
193 : {
194 0 : sAddressProgrammatic = OUString::createFromAscii( *pProgrammatic++ );
195 0 : sDriverProgrammatic = OUString::createFromAscii( *pProgrammatic++ );
196 :
197 0 : if ( aDriverFieldAliasing.hasByName( sDriverProgrammatic ) )
198 : {
199 0 : aDriverFieldAliasing.getNodeValue( sDriverProgrammatic ) >>= sDriverUI;
200 0 : if ( 0 == sDriverUI.getLength() )
201 : {
202 : OSL_FAIL( "fieldmapping::defaultMapping: invalid driver UI column name!");
203 : }
204 : else
205 0 : _rFieldAssignment[ sAddressProgrammatic ] = sDriverUI;
206 : }
207 : else
208 : {
209 : OSL_FAIL( "fieldmapping::defaultMapping: invalid driver programmatic name!" );
210 : }
211 0 : }
212 : }
213 0 : catch( const Exception& )
214 : {
215 : OSL_FAIL("fieldmapping::defaultMapping: code is assumed to throw no exceptions!");
216 : // the config nodes we're using herein should not do this ....
217 : }
218 0 : }
219 :
220 :
221 0 : void writeTemplateAddressFieldMapping( const Reference< XComponentContext >& _rxContext, const MapString2String& _rFieldAssignment )
222 : {
223 : // want to have a non-const map for easier handling
224 0 : MapString2String aFieldAssignment( _rFieldAssignment );
225 :
226 : // access the configuration information which the driver uses for determining it's column names
227 0 : const OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
228 :
229 : // create a config node for this
230 : OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext(
231 0 : _rxContext, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
232 :
233 0 : OConfigurationNode aFields = aAddressBookSettings.openNode( OUString( "Fields" ) );
234 :
235 : // loop through all existent fields
236 0 : Sequence< OUString > aExistentFields = aFields.getNodeNames();
237 0 : const OUString* pExistentFields = aExistentFields.getConstArray();
238 0 : const OUString* pExistentFieldsEnd = pExistentFields + aExistentFields.getLength();
239 :
240 0 : const OUString sProgrammaticNodeName( "ProgrammaticFieldName" );
241 0 : const OUString sAssignedNodeName( "AssignedFieldName" );
242 :
243 0 : for ( ; pExistentFields != pExistentFieldsEnd; ++pExistentFields )
244 : {
245 : #ifdef DBG_UTIL
246 : OUString sRedundantProgrammaticName;
247 : aFields.openNode( *pExistentFields ).getNodeValue( sProgrammaticNodeName ) >>= sRedundantProgrammaticName;
248 : #endif
249 : DBG_ASSERT( sRedundantProgrammaticName == *pExistentFields,
250 : "fieldmapping::writeTemplateAddressFieldMapping: inconsistent config data!" );
251 : // there should be a redundancy in the config data .... if this asserts, there isn't anymore!
252 :
253 : // do we have a new alias for the programmatic?
254 0 : MapString2String::iterator aPos = aFieldAssignment.find( *pExistentFields );
255 0 : if ( aFieldAssignment.end() != aPos )
256 : { // yes
257 : // -> set a new value
258 0 : OConfigurationNode aExistentField = aFields.openNode( *pExistentFields );
259 0 : aExistentField.setNodeValue( sAssignedNodeName, makeAny( aPos->second ) );
260 : // and remove the mapping entry
261 0 : aFieldAssignment.erase( *pExistentFields );
262 : }
263 : else
264 : { // no
265 : // -> remove it
266 0 : aFields.removeNode( *pExistentFields );
267 : }
268 : }
269 :
270 : // now everything remaining in aFieldAssignment marks a mapping entry which was not present
271 : // in the config before
272 0 : for ( MapString2String::const_iterator aNewMapping = aFieldAssignment.begin();
273 0 : aNewMapping != aFieldAssignment.end();
274 : ++aNewMapping
275 : )
276 : {
277 : DBG_ASSERT( !aFields.hasByName( aNewMapping->first ),
278 : "fieldmapping::writeTemplateAddressFieldMapping: inconsistence!" );
279 : // in case the config node for the fields already has the node named <aNewMapping->first>,
280 : // the entry should have been removed from aNewMapping (in the above loop)
281 0 : OConfigurationNode aNewField = aFields.createNode( aNewMapping->first );
282 0 : aNewField.setNodeValue( sProgrammaticNodeName, makeAny( aNewMapping->first ) );
283 0 : aNewField.setNodeValue( sAssignedNodeName, makeAny( aNewMapping->second ) );
284 0 : }
285 :
286 : // commit the changes done
287 0 : aAddressBookSettings.commit();
288 0 : }
289 :
290 :
291 : } // namespace fieldmapping
292 :
293 :
294 :
295 : namespace addressconfig
296 : {
297 :
298 :
299 :
300 0 : void writeTemplateAddressSource( const Reference< XComponentContext >& _rxContext,
301 : const OUString& _rDataSourceName, const OUString& _rTableName )
302 : {
303 : // access the configuration information which the driver uses for determining it's column names
304 0 : const OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
305 :
306 : // create a config node for this
307 : OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext(
308 0 : _rxContext, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
309 :
310 0 : aAddressBookSettings.setNodeValue( OUString( "DataSourceName" ), makeAny( _rDataSourceName ) );
311 0 : aAddressBookSettings.setNodeValue( OUString( "Command" ), makeAny( _rTableName ) );
312 0 : aAddressBookSettings.setNodeValue( OUString( "CommandType" ), makeAny( (sal_Int32)CommandType::TABLE ) );
313 :
314 : // commit the changes done
315 0 : aAddressBookSettings.commit();
316 0 : }
317 :
318 :
319 0 : void markPilotSuccess( const Reference< XComponentContext >& _rxContext )
320 : {
321 : // access the configuration information which the driver uses for determining it's column names
322 0 : const OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
323 :
324 : // create a config node for this
325 : OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext(
326 0 : _rxContext, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
327 :
328 : // set the flag
329 0 : aAddressBookSettings.setNodeValue( OUString( "AutoPilotCompleted" ), makeAny( true ) );
330 :
331 : // commit the changes done
332 0 : aAddressBookSettings.commit();
333 0 : }
334 :
335 :
336 : } // namespace addressconfig
337 :
338 :
339 :
340 0 : } // namespace abp
341 :
342 :
343 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|