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_svtools.hxx"
26
27 #include <stdio.h>
28 #include <svtools/addresstemplate.hxx>
29 #include "addresstemplate.hrc"
30 #include <svtools/svtools.hrc>
31 #include <svtools/helpid.hrc>
32 #include <svtools/svtdata.hxx>
33 #include <tools/debug.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/stl_types.hxx>
36 #include <vcl/stdtext.hxx>
37 #include <vcl/waitobj.hxx>
38 #include <vcl/msgbox.hxx>
39 #include <toolkit/helper/vclunohelper.hxx>
40 #include <comphelper/extract.hxx>
41 #include <comphelper/interaction.hxx>
42 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
43 #include <com/sun/star/awt/XWindow.hpp>
44 #include <com/sun/star/beans/PropertyValue.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/sdb/XCompletedConnection.hpp>
47 #include <com/sun/star/sdb/SQLContext.hpp>
48 #include <com/sun/star/sdbc/SQLWarning.hpp>
49 #include <com/sun/star/sdbc/XConnection.hpp>
50 #include <com/sun/star/task/XInteractionHandler.hpp>
51 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
52 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
53 #include <com/sun/star/sdb/CommandType.hpp>
54 #include <svtools/localresaccess.hxx>
55 #include "svl/filenotation.hxx"
56 #include <tools/urlobj.hxx>
57 #include <algorithm>
58
59 // .......................................................................
60 namespace svt
61 {
62 // .......................................................................
63
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::lang;
66 using namespace ::com::sun::star::container;
67 using namespace ::com::sun::star::ui::dialogs;
68 using namespace ::com::sun::star::util;
69 using namespace ::com::sun::star::beans;
70 using namespace ::com::sun::star::sdb;
71 using namespace ::com::sun::star::sdbc;
72 using namespace ::com::sun::star::sdbcx;
73 using namespace ::com::sun::star::task;
74 using namespace ::comphelper;
75 using namespace ::utl;
76
77 DECLARE_STL_VECTOR( String, StringArray );
78 DECLARE_STL_STDKEY_SET( ::rtl::OUString, StringBag );
79 DECLARE_STL_USTRINGACCESS_MAP( ::rtl::OUString, MapString2String );
80
81 namespace
82 {
lcl_getSelectedDataSource(const ComboBox & _dataSourceCombo)83 String lcl_getSelectedDataSource( const ComboBox& _dataSourceCombo )
84 {
85 String selectedDataSource = _dataSourceCombo.GetText();
86 if ( _dataSourceCombo.GetEntryPos( selectedDataSource ) == LISTBOX_ENTRY_NOTFOUND )
87 {
88 // none of the pre-selected entries -> assume a path to a database document
89 OFileNotation aFileNotation( selectedDataSource, OFileNotation::N_SYSTEM );
90 selectedDataSource = aFileNotation.get( OFileNotation::N_URL );
91 }
92 return selectedDataSource;
93 }
94 }
95
96 // ===================================================================
97 // = IAssigmentData
98 // ===================================================================
99 class IAssigmentData
100 {
101 public:
102 virtual ~IAssigmentData();
103
104 /// the data source to use for the address book
105 virtual ::rtl::OUString getDatasourceName() const = 0;
106
107 /// the command to use for the address book
108 virtual ::rtl::OUString getCommand() const = 0;
109
110 /** the command type to use for the address book
111 @return
112 a <type scope="com.sun.star.sdb">CommandType</type> value
113 */
114 virtual sal_Int32 getCommandType() const = 0;
115
116 /// checks whether or not there is an assignment for a given logical field
117 virtual sal_Bool hasFieldAssignment(const ::rtl::OUString& _rLogicalName) = 0;
118 /// retrieves the assignment for a given logical field
119 virtual ::rtl::OUString getFieldAssignment(const ::rtl::OUString& _rLogicalName) = 0;
120
121 /// set the assignment for a given logical field
122 virtual void setFieldAssignment(const ::rtl::OUString& _rLogicalName, const ::rtl::OUString& _rAssignment) = 0;
123 /// clear the assignment for a given logical field
124 virtual void clearFieldAssignment(const ::rtl::OUString& _rLogicalName) = 0;
125
126 virtual void setDatasourceName(const ::rtl::OUString& _rName) = 0;
127 virtual void setCommand(const ::rtl::OUString& _rCommand) = 0;
128 };
129
130 // -------------------------------------------------------------------
~IAssigmentData()131 IAssigmentData::~IAssigmentData()
132 {
133 }
134
135 // ===================================================================
136 // = AssigmentTransientData
137 // ===================================================================
138 class AssigmentTransientData : public IAssigmentData
139 {
140 protected:
141 Reference< XDataSource > m_xDataSource;
142 ::rtl::OUString m_sDSName;
143 ::rtl::OUString m_sTableName;
144 MapString2String m_aAliases;
145
146 public:
147 AssigmentTransientData(
148 const Reference< XDataSource >& _rxDataSource,
149 const ::rtl::OUString& _rDataSourceName,
150 const ::rtl::OUString& _rTableName,
151 const Sequence< AliasProgrammaticPair >& _rFields
152 );
153
154 // IAssigmentData overridables
155 virtual ::rtl::OUString getDatasourceName() const;
156 virtual ::rtl::OUString getCommand() const;
157 virtual sal_Int32 getCommandType() const;
158
159 virtual sal_Bool hasFieldAssignment(const ::rtl::OUString& _rLogicalName);
160 virtual ::rtl::OUString getFieldAssignment(const ::rtl::OUString& _rLogicalName);
161 virtual void setFieldAssignment(const ::rtl::OUString& _rLogicalName, const ::rtl::OUString& _rAssignment);
162 virtual void clearFieldAssignment(const ::rtl::OUString& _rLogicalName);
163
164 virtual void setDatasourceName(const ::rtl::OUString& _rName);
165 virtual void setCommand(const ::rtl::OUString& _rCommand);
166 };
167
168 // -------------------------------------------------------------------
AssigmentTransientData(const Reference<XDataSource> & _rxDataSource,const::rtl::OUString & _rDataSourceName,const::rtl::OUString & _rTableName,const Sequence<AliasProgrammaticPair> & _rFields)169 AssigmentTransientData::AssigmentTransientData( const Reference< XDataSource >& _rxDataSource,
170 const ::rtl::OUString& _rDataSourceName, const ::rtl::OUString& _rTableName,
171 const Sequence< AliasProgrammaticPair >& _rFields )
172 :m_xDataSource( _rxDataSource )
173 ,m_sDSName( _rDataSourceName )
174 ,m_sTableName( _rTableName )
175 {
176 // fill our aliaes structure
177 // first collect all known programmatic names
178 StringBag aKnownNames;
179
180 String sLogicalFieldNames( SvtResId( STR_LOCAGICAL_FIELD_NAMES ) );
181 sal_Int32 nTokenCount = sLogicalFieldNames.GetTokenCount(';');
182 for (sal_Int32 i = 0; i<nTokenCount; ++i)
183 aKnownNames.insert(sLogicalFieldNames.GetToken((sal_uInt16)i, ';'));
184
185 // loop throuzh the given names
186 const AliasProgrammaticPair* pFields = _rFields.getConstArray();
187 for (;pFields != pFields; ++pFields)
188 {
189 StringBagIterator aKnownPos = aKnownNames.find( pFields->ProgrammaticName );
190 if ( aKnownNames.end() != aKnownPos )
191 {
192 m_aAliases[ pFields->ProgrammaticName ] = pFields->Alias;
193 }
194 else
195 {
196 DBG_ERROR ( ( ::rtl::OString("AssigmentTransientData::AssigmentTransientData: unknown programmatic name (")
197 += ::rtl::OString(pFields->ProgrammaticName.getStr(), pFields->ProgrammaticName.getLength(), RTL_TEXTENCODING_ASCII_US)
198 += ::rtl::OString(")!")
199 ).getStr()
200 );
201 }
202 }
203 }
204
205 // -------------------------------------------------------------------
getDatasourceName() const206 ::rtl::OUString AssigmentTransientData::getDatasourceName() const
207 {
208 return m_sDSName;
209 }
210
211 // -------------------------------------------------------------------
getCommand() const212 ::rtl::OUString AssigmentTransientData::getCommand() const
213 {
214 return m_sTableName;
215 }
216
217 // -------------------------------------------------------------------
getCommandType() const218 sal_Int32 AssigmentTransientData::getCommandType() const
219 {
220 return CommandType::TABLE;
221 }
222
223 // -------------------------------------------------------------------
hasFieldAssignment(const::rtl::OUString & _rLogicalName)224 sal_Bool AssigmentTransientData::hasFieldAssignment(const ::rtl::OUString& _rLogicalName)
225 {
226 ConstMapString2StringIterator aPos = m_aAliases.find( _rLogicalName );
227 return ( m_aAliases.end() != aPos )
228 && ( aPos->second.getLength() );
229 }
230
231 // -------------------------------------------------------------------
getFieldAssignment(const::rtl::OUString & _rLogicalName)232 ::rtl::OUString AssigmentTransientData::getFieldAssignment(const ::rtl::OUString& _rLogicalName)
233 {
234 ::rtl::OUString sReturn;
235 ConstMapString2StringIterator aPos = m_aAliases.find( _rLogicalName );
236 if ( m_aAliases.end() != aPos )
237 sReturn = aPos->second;
238
239 return sReturn;
240 }
241
242 // -------------------------------------------------------------------
setFieldAssignment(const::rtl::OUString & _rLogicalName,const::rtl::OUString & _rAssignment)243 void AssigmentTransientData::setFieldAssignment(const ::rtl::OUString& _rLogicalName, const ::rtl::OUString& _rAssignment)
244 {
245 m_aAliases[ _rLogicalName ] = _rAssignment;
246 }
247
248 // -------------------------------------------------------------------
clearFieldAssignment(const::rtl::OUString & _rLogicalName)249 void AssigmentTransientData::clearFieldAssignment(const ::rtl::OUString& _rLogicalName)
250 {
251 MapString2StringIterator aPos = m_aAliases.find( _rLogicalName );
252 if ( m_aAliases.end() != aPos )
253 m_aAliases.erase( aPos );
254 }
255
256 // -------------------------------------------------------------------
setDatasourceName(const::rtl::OUString &)257 void AssigmentTransientData::setDatasourceName(const ::rtl::OUString&)
258 {
259 DBG_ERROR( "AssigmentTransientData::setDatasourceName: cannot be implemented for transient data!" );
260 }
261
262 // -------------------------------------------------------------------
setCommand(const::rtl::OUString &)263 void AssigmentTransientData::setCommand(const ::rtl::OUString&)
264 {
265 DBG_ERROR( "AssigmentTransientData::setCommand: cannot be implemented for transient data!" );
266 }
267
268 // ===================================================================
269 // = AssignmentPersistentData
270 // ===================================================================
271 class AssignmentPersistentData
272 :public ::utl::ConfigItem
273 ,public IAssigmentData
274 {
275 protected:
276 StringBag m_aStoredFields;
277
278 protected:
279 ::com::sun::star::uno::Any
280 getProperty(const ::rtl::OUString& _rLocalName) const;
281 ::com::sun::star::uno::Any
282 getProperty(const sal_Char* _pLocalName) const;
283
284 ::rtl::OUString getStringProperty(const sal_Char* _pLocalName) const;
285 sal_Int32 getInt32Property(const sal_Char* _pLocalName) const;
286
287 ::rtl::OUString getStringProperty(const ::rtl::OUString& _rLocalName) const;
288
289 void setStringProperty(const sal_Char* _pLocalName, const ::rtl::OUString& _rValue);
290
291 public:
292 AssignmentPersistentData();
293 ~AssignmentPersistentData();
294
295 // IAssigmentData overridables
296 virtual ::rtl::OUString getDatasourceName() const;
297 virtual ::rtl::OUString getCommand() const;
298 virtual sal_Int32 getCommandType() const;
299
300 virtual sal_Bool hasFieldAssignment(const ::rtl::OUString& _rLogicalName);
301 virtual ::rtl::OUString getFieldAssignment(const ::rtl::OUString& _rLogicalName);
302 virtual void setFieldAssignment(const ::rtl::OUString& _rLogicalName, const ::rtl::OUString& _rAssignment);
303 virtual void clearFieldAssignment(const ::rtl::OUString& _rLogicalName);
304
305 virtual void setDatasourceName(const ::rtl::OUString& _rName);
306 virtual void setCommand(const ::rtl::OUString& _rCommand);
307
308 virtual void Notify( const com::sun::star::uno::Sequence<rtl::OUString>& aPropertyNames);
309 virtual void Commit();
310 };
311
312
Notify(const com::sun::star::uno::Sequence<rtl::OUString> &)313 void AssignmentPersistentData::Notify( const com::sun::star::uno::Sequence<rtl::OUString>& )
314 {
315 }
316
Commit()317 void AssignmentPersistentData::Commit()
318 {
319 }
320
321 // -------------------------------------------------------------------
AssignmentPersistentData()322 AssignmentPersistentData::AssignmentPersistentData()
323 :ConfigItem( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Office.DataAccess/AddressBook" )))
324 {
325 Sequence< ::rtl::OUString > aStoredNames = GetNodeNames(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Fields")));
326 const ::rtl::OUString* pStoredNames = aStoredNames.getConstArray();
327 for (sal_Int32 i=0; i<aStoredNames.getLength(); ++i, ++pStoredNames)
328 m_aStoredFields.insert(*pStoredNames);
329 }
330
331 // -------------------------------------------------------------------
~AssignmentPersistentData()332 AssignmentPersistentData::~AssignmentPersistentData()
333 {
334 }
335
336 // -------------------------------------------------------------------
hasFieldAssignment(const::rtl::OUString & _rLogicalName)337 sal_Bool AssignmentPersistentData::hasFieldAssignment(const ::rtl::OUString& _rLogicalName)
338 {
339 return (m_aStoredFields.end() != m_aStoredFields.find(_rLogicalName));
340 }
341
342 // -------------------------------------------------------------------
getFieldAssignment(const::rtl::OUString & _rLogicalName)343 ::rtl::OUString AssignmentPersistentData::getFieldAssignment(const ::rtl::OUString& _rLogicalName)
344 {
345 ::rtl::OUString sAssignment;
346 if (hasFieldAssignment(_rLogicalName))
347 {
348 ::rtl::OUString sFieldPath(RTL_CONSTASCII_USTRINGPARAM("Fields/"));
349 sFieldPath += _rLogicalName;
350 sFieldPath += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/AssignedFieldName"));
351 sAssignment = getStringProperty(sFieldPath);
352 }
353 return sAssignment;
354 }
355
356 // -------------------------------------------------------------------
getProperty(const sal_Char * _pLocalName) const357 Any AssignmentPersistentData::getProperty(const sal_Char* _pLocalName) const
358 {
359 return getProperty(::rtl::OUString::createFromAscii(_pLocalName));
360 }
361
362 // -------------------------------------------------------------------
getProperty(const::rtl::OUString & _rLocalName) const363 Any AssignmentPersistentData::getProperty(const ::rtl::OUString& _rLocalName) const
364 {
365 Sequence< ::rtl::OUString > aProperties(&_rLocalName, 1);
366 Sequence< Any > aValues = const_cast<AssignmentPersistentData*>(this)->GetProperties(aProperties);
367 DBG_ASSERT(aValues.getLength() == 1, "AssignmentPersistentData::getProperty: invalid sequence length!");
368 return aValues[0];
369 }
370
371 // -------------------------------------------------------------------
getStringProperty(const::rtl::OUString & _rLocalName) const372 ::rtl::OUString AssignmentPersistentData::getStringProperty(const ::rtl::OUString& _rLocalName) const
373 {
374 ::rtl::OUString sReturn;
375 getProperty( _rLocalName ) >>= sReturn;
376 return sReturn;
377 }
378
379 // -------------------------------------------------------------------
getStringProperty(const sal_Char * _pLocalName) const380 ::rtl::OUString AssignmentPersistentData::getStringProperty(const sal_Char* _pLocalName) const
381 {
382 ::rtl::OUString sReturn;
383 getProperty( _pLocalName ) >>= sReturn;
384 return sReturn;
385 }
386
387 // -------------------------------------------------------------------
getInt32Property(const sal_Char * _pLocalName) const388 sal_Int32 AssignmentPersistentData::getInt32Property(const sal_Char* _pLocalName) const
389 {
390 sal_Int32 nReturn = 0;
391 getProperty( _pLocalName ) >>= nReturn;
392 return nReturn;
393 }
394
395 // -------------------------------------------------------------------
setStringProperty(const sal_Char * _pLocalName,const::rtl::OUString & _rValue)396 void AssignmentPersistentData::setStringProperty(const sal_Char* _pLocalName, const ::rtl::OUString& _rValue)
397 {
398 Sequence< ::rtl::OUString > aNames(1);
399 Sequence< Any > aValues(1);
400 aNames[0] = ::rtl::OUString::createFromAscii(_pLocalName);
401 aValues[0] <<= _rValue;
402 PutProperties(aNames, aValues);
403 }
404
405 // -------------------------------------------------------------------
setFieldAssignment(const::rtl::OUString & _rLogicalName,const::rtl::OUString & _rAssignment)406 void AssignmentPersistentData::setFieldAssignment(const ::rtl::OUString& _rLogicalName, const ::rtl::OUString& _rAssignment)
407 {
408 if (!_rAssignment.getLength())
409 {
410 if (hasFieldAssignment(_rLogicalName))
411 // the assignment exists but it should be reset
412 clearFieldAssignment(_rLogicalName);
413 return;
414 }
415
416 // Fields
417 ::rtl::OUString sDescriptionNodePath(RTL_CONSTASCII_USTRINGPARAM("Fields"));
418
419 // Fields/<field>
420 ::rtl::OUString sFieldElementNodePath(sDescriptionNodePath);
421 sFieldElementNodePath += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));
422 sFieldElementNodePath += _rLogicalName;
423
424 Sequence< PropertyValue > aNewFieldDescription(2);
425 // Fields/<field>/ProgrammaticFieldName
426 aNewFieldDescription[0].Name = sFieldElementNodePath;
427 aNewFieldDescription[0].Name += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/ProgrammaticFieldName"));
428 aNewFieldDescription[0].Value <<= _rLogicalName;
429 // Fields/<field>/AssignedFieldName
430 aNewFieldDescription[1].Name = sFieldElementNodePath;
431 aNewFieldDescription[1].Name += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/AssignedFieldName"));
432 aNewFieldDescription[1].Value <<= _rAssignment;
433
434 // just set the new value
435 #ifdef DBG_UTIL
436 sal_Bool bSuccess =
437 #endif
438 SetSetProperties(sDescriptionNodePath, aNewFieldDescription);
439 DBG_ASSERT(bSuccess, "AssignmentPersistentData::setFieldAssignment: could not commit the changes a field!");
440 }
441
442 // -------------------------------------------------------------------
clearFieldAssignment(const::rtl::OUString & _rLogicalName)443 void AssignmentPersistentData::clearFieldAssignment(const ::rtl::OUString& _rLogicalName)
444 {
445 if (!hasFieldAssignment(_rLogicalName))
446 // nothing to do
447 return;
448
449 ::rtl::OUString sDescriptionNodePath(RTL_CONSTASCII_USTRINGPARAM("Fields"));
450 Sequence< ::rtl::OUString > aNames(&_rLogicalName, 1);
451 ClearNodeElements(sDescriptionNodePath, aNames);
452 }
453
454 // -------------------------------------------------------------------
getDatasourceName() const455 ::rtl::OUString AssignmentPersistentData::getDatasourceName() const
456 {
457 return getStringProperty( "DataSourceName" );
458 }
459
460 // -------------------------------------------------------------------
getCommand() const461 ::rtl::OUString AssignmentPersistentData::getCommand() const
462 {
463 return getStringProperty( "Command" );
464 }
465
466 // -------------------------------------------------------------------
setDatasourceName(const::rtl::OUString & _rName)467 void AssignmentPersistentData::setDatasourceName(const ::rtl::OUString& _rName)
468 {
469 setStringProperty( "DataSourceName", _rName );
470 }
471
472 // -------------------------------------------------------------------
setCommand(const::rtl::OUString & _rCommand)473 void AssignmentPersistentData::setCommand(const ::rtl::OUString& _rCommand)
474 {
475 setStringProperty( "Command", _rCommand );
476 }
477
478 // -------------------------------------------------------------------
getCommandType() const479 sal_Int32 AssignmentPersistentData::getCommandType() const
480 {
481 return getInt32Property( "CommandType" );
482 }
483
484 // ===================================================================
485 // = AddressBookSourceDialogData
486 // ===================================================================
487 struct AddressBookSourceDialogData
488 {
489 FixedText* pFieldLabels[FIELD_PAIRS_VISIBLE * 2];
490 ListBox* pFields[FIELD_PAIRS_VISIBLE * 2];
491
492 /// when working transient, we need the data source
493 Reference< XDataSource >
494 m_xTransientDataSource;
495 /// current scroll pos in the field list
496 sal_Int32 nFieldScrollPos;
497 /// the index within m_pFields of the last visible list box. This is redundant, it could be extracted from other members
498 sal_Int32 nLastVisibleListIndex;
499 /// indicates that we've an odd field number. This member is for efficiency only, it's redundant.
500 sal_Bool bOddFieldNumber : 1;
501 /// indicates that we're working with the real persistent configuration
502 sal_Bool bWorkingPersistent : 1;
503
504 /// the strings to use as labels for the field selection listboxes
505 StringArray aFieldLabels;
506 // the current field assignment
507 StringArray aFieldAssignments;
508 /// the logical field names
509 StringArray aLogicalFieldNames;
510
511 IAssigmentData* pConfigData;
512
513 // ................................................................
AddressBookSourceDialogDatasvt::AddressBookSourceDialogData514 AddressBookSourceDialogData( )
515 :nFieldScrollPos(0)
516 ,nLastVisibleListIndex(0)
517 ,bOddFieldNumber(sal_False)
518 ,bWorkingPersistent( sal_True )
519 ,pConfigData( new AssignmentPersistentData )
520 {
521 }
522
523 // ................................................................
AddressBookSourceDialogDatasvt::AddressBookSourceDialogData524 AddressBookSourceDialogData( const Reference< XDataSource >& _rxTransientDS, const ::rtl::OUString& _rDataSourceName,
525 const ::rtl::OUString& _rTableName, const Sequence< AliasProgrammaticPair >& _rFields )
526 :m_xTransientDataSource( _rxTransientDS )
527 ,nFieldScrollPos(0)
528 ,nLastVisibleListIndex(0)
529 ,bOddFieldNumber(sal_False)
530 ,bWorkingPersistent( sal_False )
531 ,pConfigData( new AssigmentTransientData( m_xTransientDataSource, _rDataSourceName, _rTableName, _rFields ) )
532 {
533 }
534
~AddressBookSourceDialogDatasvt::AddressBookSourceDialogData535 ~AddressBookSourceDialogData()
536 {
537 delete pConfigData;
538 }
539
540 };
541
542 // ===================================================================
543 // = AddressBookSourceDialog
544 // ===================================================================
545 #define INIT_FIELDS() \
546 ModalDialog(_pParent, SvtResId( DLG_ADDRESSBOOKSOURCE ))\
547 ,m_aDatasourceFrame (this, SvtResId(FL_DATASOURCEFRAME))\
548 ,m_aDatasourceLabel (this, SvtResId(FT_DATASOURCE))\
549 ,m_aDatasource (this, SvtResId(CB_DATASOURCE))\
550 ,m_aAdministrateDatasources (this, SvtResId(PB_ADMINISTATE_DATASOURCES))\
551 ,m_aTableLabel (this, SvtResId(FT_TABLE))\
552 ,m_aTable (this, SvtResId(CB_TABLE))\
553 ,m_aFieldsTitle (this, SvtResId(FT_FIELDS))\
554 ,m_aFieldsFrame (this, SvtResId(CT_BORDER))\
555 ,m_aFieldScroller (&m_aFieldsFrame, SvtResId(SB_FIELDSCROLLER))\
556 ,m_aOK (this, SvtResId(PB_OK))\
557 ,m_aCancel (this, SvtResId(PB_CANCEL))\
558 ,m_aHelp (this, SvtResId(PB_HELP))\
559 ,m_sNoFieldSelection(SvtResId(STR_NO_FIELD_SELECTION))\
560 ,m_xORB(_rxORB)
561
562 // -------------------------------------------------------------------
AddressBookSourceDialog(Window * _pParent,const Reference<XMultiServiceFactory> & _rxORB)563 AddressBookSourceDialog::AddressBookSourceDialog(Window* _pParent,
564 const Reference< XMultiServiceFactory >& _rxORB )
565 :INIT_FIELDS()
566 ,m_pImpl( new AddressBookSourceDialogData )
567 {
568 implConstruct();
569 }
570
571 // -------------------------------------------------------------------
AddressBookSourceDialog(Window * _pParent,const Reference<XMultiServiceFactory> & _rxORB,const Reference<XDataSource> & _rxTransientDS,const::rtl::OUString & _rDataSourceName,const::rtl::OUString & _rTable,const Sequence<AliasProgrammaticPair> & _rMapping)572 AddressBookSourceDialog::AddressBookSourceDialog( Window* _pParent, const Reference< XMultiServiceFactory >& _rxORB,
573 const Reference< XDataSource >& _rxTransientDS, const ::rtl::OUString& _rDataSourceName,
574 const ::rtl::OUString& _rTable, const Sequence< AliasProgrammaticPair >& _rMapping )
575 :INIT_FIELDS()
576 ,m_pImpl( new AddressBookSourceDialogData( _rxTransientDS, _rDataSourceName, _rTable, _rMapping ) )
577 {
578 implConstruct();
579 }
580
581 // -------------------------------------------------------------------
implConstruct()582 void AddressBookSourceDialog::implConstruct()
583 {
584 for (sal_Int32 row=0; row<FIELD_PAIRS_VISIBLE; ++row)
585 {
586 for (sal_Int32 column=0; column<2; ++column)
587 {
588 // the label
589 m_pImpl->pFieldLabels[row * 2 + column] = new FixedText(&m_aFieldsFrame, SvtResId((sal_uInt16)(FT_FIELD_BASE + row * 2 + column)));
590 // the listbox
591 m_pImpl->pFields[row * 2 + column] = new ListBox(&m_aFieldsFrame, SvtResId((sal_uInt16)(LB_FIELD_BASE + row * 2 + column)));
592 m_pImpl->pFields[row * 2 + column]->SetDropDownLineCount(15);
593 m_pImpl->pFields[row * 2 + column]->SetSelectHdl(LINK(this, AddressBookSourceDialog, OnFieldSelect));
594
595 m_pImpl->pFields[row * 2 + column]->SetHelpId(HID_ADDRTEMPL_FIELD_ASSIGNMENT);
596 }
597 }
598
599 m_aFieldsFrame.SetStyle((m_aFieldsFrame.GetStyle() | WB_TABSTOP | WB_DIALOGCONTROL) & ~WB_NODIALOGCONTROL);
600
601 // correct the z-order
602 m_aFieldScroller.SetZOrder(m_pImpl->pFields[FIELD_CONTROLS_VISIBLE - 1], WINDOW_ZORDER_BEHIND);
603 m_aOK.SetZOrder(&m_aFieldsFrame, WINDOW_ZORDER_BEHIND);
604 m_aCancel.SetZOrder(&m_aOK, WINDOW_ZORDER_BEHIND);
605
606 initializeDatasources();
607
608 // for the moment, we have a hard coded list of all known fields.
609 // A better solution would be to store all known field translations in the configuration, which could be
610 // extensible by the user in an arbitrary way.
611 // But for the moment we need a quick solution ...
612 // (the main thing would be to store the translations to use here in the user interface, besides that, the code
613 // should be adjustable with a rather small effort.)
614
615 // initialize the strings for the field labels
616 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_FIRSTNAME )) );
617 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_LASTNAME )) );
618 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_COMPANY)) );
619 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_DEPARTMENT )) );
620 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_STREET )) );
621 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_ZIPCODE )) );
622 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_CITY )) );
623 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_STATE)) );
624 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_COUNTRY )) );
625 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_HOMETEL )) );
626 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_WORKTEL )) );
627 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_OFFICETEL)) );
628 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_MOBILE)) );
629 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_TELOTHER)) );
630 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_PAGER)) );
631 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_FAX )) );
632 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_EMAIL )) );
633 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_URL )) );
634 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_TITLE )) );
635 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_POSITION )) );
636 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_INITIALS )) );
637 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_ADDRFORM )) );
638 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_SALUTATION )) );
639 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_ID)) );
640 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_CALENDAR)) );
641 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_INVITE)) );
642 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_NOTE)) );
643 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_USER1)) );
644 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_USER2)) );
645 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_USER3)) );
646 m_pImpl->aFieldLabels.push_back( String(SvtResId( STR_FIELD_USER4)) );
647
648 // force a even number of known fields
649 m_pImpl->bOddFieldNumber = (m_pImpl->aFieldLabels.size() % 2) != 0;
650 if (m_pImpl->bOddFieldNumber)
651 m_pImpl->aFieldLabels.push_back( String() );
652
653 // limit the scrollbar range accordingly
654 sal_Int32 nOverallFieldPairs = m_pImpl->aFieldLabels.size() / 2;
655 m_aFieldScroller.SetRange( Range(0, nOverallFieldPairs - FIELD_PAIRS_VISIBLE) );
656 m_aFieldScroller.SetLineSize(1);
657 m_aFieldScroller.SetPageSize(FIELD_PAIRS_VISIBLE);
658
659 // reset the current field assignments
660 m_pImpl->aFieldAssignments.resize(m_pImpl->aFieldLabels.size());
661 // (empty strings mean "no assignment")
662
663 // some knittings
664 m_aFieldScroller.SetScrollHdl(LINK(this, AddressBookSourceDialog, OnFieldScroll));
665 m_aAdministrateDatasources.SetClickHdl(LINK(this, AddressBookSourceDialog, OnAdministrateDatasources));
666 m_aDatasource.EnableAutocomplete(sal_True);
667 m_aTable.EnableAutocomplete(sal_True);
668 m_aTable.SetGetFocusHdl(LINK(this, AddressBookSourceDialog, OnComboGetFocus));
669 m_aDatasource.SetGetFocusHdl(LINK(this, AddressBookSourceDialog, OnComboGetFocus));
670 m_aTable.SetLoseFocusHdl(LINK(this, AddressBookSourceDialog, OnComboLoseFocus));
671 m_aDatasource.SetLoseFocusHdl(LINK(this, AddressBookSourceDialog, OnComboLoseFocus));
672 m_aTable.SetSelectHdl(LINK(this, AddressBookSourceDialog, OnComboSelect));
673 m_aDatasource.SetSelectHdl(LINK(this, AddressBookSourceDialog, OnComboSelect));
674 m_aOK.SetClickHdl(LINK(this, AddressBookSourceDialog, OnOkClicked));
675
676 m_aDatasource.SetDropDownLineCount(15);
677
678 // initialize the field controls
679 resetFields();
680 m_aFieldScroller.SetThumbPos(0);
681 m_pImpl->nFieldScrollPos = -1;
682 implScrollFields(0, sal_False, sal_False);
683
684 // the logical names
685 String sLogicalFieldNames(SvtResId(STR_LOCAGICAL_FIELD_NAMES));
686 sal_Int32 nAdjustedTokenCount = sLogicalFieldNames.GetTokenCount(';') + (m_pImpl->bOddFieldNumber ? 1 : 0);
687 DBG_ASSERT(nAdjustedTokenCount == (sal_Int32)m_pImpl->aFieldLabels.size(),
688 "AddressBookSourceDialog::AddressBookSourceDialog: inconsistence between logical and UI field names!");
689 m_pImpl->aLogicalFieldNames.reserve(nAdjustedTokenCount);
690 for (sal_Int32 i = 0; i<nAdjustedTokenCount; ++i)
691 m_pImpl->aLogicalFieldNames.push_back(sLogicalFieldNames.GetToken((sal_uInt16)i, ';'));
692
693 PostUserEvent(LINK(this, AddressBookSourceDialog, OnDelayedInitialize));
694 // so the dialog will at least show up before we do the loading of the
695 // configuration data and the (maybe time consuming) analysis of the data source/table to select
696
697 FreeResource();
698
699 if ( !m_pImpl->bWorkingPersistent )
700 {
701 StyleSettings aSystemStyle = GetSettings().GetStyleSettings();
702 const Color& rNewColor = aSystemStyle.GetDialogColor();
703
704 m_aDatasource.SetReadOnly( sal_True );
705 m_aDatasource.SetBackground( Wallpaper( rNewColor ) );
706 m_aDatasource.SetControlBackground( rNewColor );
707
708 m_aTable.SetReadOnly( sal_True );
709 m_aTable.SetBackground( Wallpaper( rNewColor ) );
710 m_aTable.SetControlBackground( rNewColor );
711
712 m_aAdministrateDatasources.Hide( );
713 }
714 }
715
716 // -------------------------------------------------------------------
getFieldMapping(Sequence<AliasProgrammaticPair> & _rMapping) const717 void AddressBookSourceDialog::getFieldMapping(Sequence< AliasProgrammaticPair >& _rMapping) const
718 {
719 _rMapping.realloc( m_pImpl->aLogicalFieldNames.size() );
720 AliasProgrammaticPair* pPair = _rMapping.getArray();
721
722 ::rtl::OUString sCurrent;
723 for ( ConstStringArrayIterator aProgrammatic = m_pImpl->aLogicalFieldNames.begin();
724 aProgrammatic != m_pImpl->aLogicalFieldNames.end();
725 ++aProgrammatic
726 )
727 {
728 sCurrent = *aProgrammatic;
729 if ( m_pImpl->pConfigData->hasFieldAssignment( sCurrent ) )
730 {
731 // the user gave us an assignment for this field
732 pPair->ProgrammaticName = *aProgrammatic;
733 pPair->Alias = m_pImpl->pConfigData->getFieldAssignment( *aProgrammatic );
734 ++pPair;
735 }
736 }
737
738 _rMapping.realloc( pPair - _rMapping.getArray() );
739 }
740
741 // -------------------------------------------------------------------
loadConfiguration()742 void AddressBookSourceDialog::loadConfiguration()
743 {
744 ::rtl::OUString sName = m_pImpl->pConfigData->getDatasourceName();
745 INetURLObject aURL( sName );
746 if( aURL.GetProtocol() != INET_PROT_NOT_VALID )
747 {
748 OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
749 sName = aFileNotation.get(OFileNotation::N_SYSTEM);
750 }
751
752 m_aDatasource.SetText(sName);
753 m_aTable.SetText(m_pImpl->pConfigData->getCommand());
754 // we ignore the CommandType: only tables are supported
755
756 // the logical names for the fields
757 DBG_ASSERT(m_pImpl->aLogicalFieldNames.size() == m_pImpl->aFieldAssignments.size(),
758 "AddressBookSourceDialog::loadConfiguration: inconsistence between field names and field assignments!");
759
760 ConstStringArrayIterator aLogical = m_pImpl->aLogicalFieldNames.begin();
761 StringArrayIterator aAssignment = m_pImpl->aFieldAssignments.begin();
762 for ( ;
763 aLogical < m_pImpl->aLogicalFieldNames.end();
764 ++aLogical, ++aAssignment
765 )
766 *aAssignment = m_pImpl->pConfigData->getFieldAssignment(*aLogical);
767 }
768
769 // -------------------------------------------------------------------
~AddressBookSourceDialog()770 AddressBookSourceDialog::~AddressBookSourceDialog()
771 {
772 sal_Int32 i;
773 for (i=0; i<FIELD_CONTROLS_VISIBLE; ++i)
774 {
775 delete m_pImpl->pFieldLabels[i];
776 delete m_pImpl->pFields[i];
777 }
778
779 delete m_pImpl;
780 }
781
782 // -------------------------------------------------------------------
initializeDatasources()783 void AddressBookSourceDialog::initializeDatasources()
784 {
785 if (!m_xDatabaseContext.is())
786 {
787 DBG_ASSERT(m_xORB.is(), "AddressBookSourceDialog::initializeDatasources: no service factory!");
788 if (!m_xORB.is())
789 return;
790
791 const String sContextServiceName = String::CreateFromAscii("com.sun.star.sdb.DatabaseContext");
792 try
793 {
794 m_xDatabaseContext = Reference< XNameAccess >(m_xORB->createInstance(sContextServiceName), UNO_QUERY);
795 }
796 catch(Exception&) { }
797 if (!m_xDatabaseContext.is())
798 {
799 ShowServiceNotAvailableError( this, sContextServiceName, sal_False);
800 return;
801 }
802 }
803 m_aDatasource.Clear();
804
805 // fill the datasources listbox
806 Sequence< ::rtl::OUString > aDatasourceNames;
807 try
808 {
809 aDatasourceNames = m_xDatabaseContext->getElementNames();
810 }
811 catch(Exception&)
812 {
813 DBG_ERROR("AddressBookSourceDialog::initializeDatasources: caught an exception while asking for the data source names!");
814 }
815 const ::rtl::OUString* pDatasourceNames = aDatasourceNames.getConstArray();
816 const ::rtl::OUString* pEnd = pDatasourceNames + aDatasourceNames.getLength();
817 for (; pDatasourceNames < pEnd; ++pDatasourceNames)
818 m_aDatasource.InsertEntry(*pDatasourceNames);
819 }
820
821 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnFieldScroll,ScrollBar *,_pScrollBar)822 IMPL_LINK(AddressBookSourceDialog, OnFieldScroll, ScrollBar*, _pScrollBar)
823 {
824 implScrollFields( _pScrollBar->GetThumbPos(), sal_True, sal_True );
825 return 0L;
826 }
827
828 // -------------------------------------------------------------------
resetTables()829 void AddressBookSourceDialog::resetTables()
830 {
831 if (!m_xDatabaseContext.is())
832 return;
833
834 WaitObject aWaitCursor(this);
835
836 // no matter what we do here, we handled the currently selected data source (no matter if successfull or not)
837 m_aDatasource.SaveValue();
838
839 // create an interaction handler (may be needed for connecting)
840 const String sInteractionHandlerServiceName = String::CreateFromAscii("com.sun.star.task.InteractionHandler");
841 Reference< XInteractionHandler > xHandler;
842 try
843 {
844 xHandler = Reference< XInteractionHandler >(m_xORB->createInstance(sInteractionHandlerServiceName), UNO_QUERY);
845 }
846 catch(Exception&) { }
847 if (!xHandler.is())
848 {
849 ShowServiceNotAvailableError(this, sInteractionHandlerServiceName, sal_True);
850 return;
851 }
852
853 // the currently selected table
854 ::rtl::OUString sOldTable = m_aTable.GetText();
855
856 m_aTable.Clear();
857
858 m_xCurrentDatasourceTables= NULL;
859
860 // get the tables of the connection
861 Sequence< ::rtl::OUString > aTableNames;
862 Any aException;
863 try
864 {
865 Reference< XCompletedConnection > xDS;
866 if ( m_pImpl->bWorkingPersistent )
867 {
868 String sSelectedDS = lcl_getSelectedDataSource( m_aDatasource );
869
870 // get the data source the user has chosen and let it build a connection
871 INetURLObject aURL( sSelectedDS );
872 if ( aURL.GetProtocol() != INET_PROT_NOT_VALID || m_xDatabaseContext->hasByName(sSelectedDS) )
873 m_xDatabaseContext->getByName( sSelectedDS ) >>= xDS;
874 }
875 else
876 {
877 xDS = xDS.query( m_pImpl->m_xTransientDataSource );
878 }
879
880 // build the connection
881 Reference< XConnection > xConn;
882 if (xDS.is())
883 xConn = xDS->connectWithCompletion(xHandler);
884
885 // get the table names
886 Reference< XTablesSupplier > xSupplTables(xConn, UNO_QUERY);
887 if (xSupplTables.is())
888 {
889 m_xCurrentDatasourceTables = Reference< XNameAccess >(xSupplTables->getTables(), UNO_QUERY);
890 if (m_xCurrentDatasourceTables.is())
891 aTableNames = m_xCurrentDatasourceTables->getElementNames();
892 }
893 }
894 catch(SQLContext& e) { aException <<= e; }
895 catch(SQLWarning& e) { aException <<= e; }
896 catch(SQLException& e) { aException <<= e; }
897 catch(Exception&)
898 {
899 DBG_ERROR("AddressBookSourceDialog::resetTables: could not retrieve the table!");
900 }
901
902 if (aException.hasValue())
903 {
904 Reference< XInteractionRequest > xRequest = new OInteractionRequest(aException);
905 try
906 {
907 xHandler->handle(xRequest);
908 }
909 catch(Exception&) { }
910 return;
911 }
912
913 sal_Bool bKnowOldTable = sal_False;
914 // fill the table list
915 const ::rtl::OUString* pTableNames = aTableNames.getConstArray();
916 const ::rtl::OUString* pEnd = pTableNames + aTableNames.getLength();
917 for (;pTableNames != pEnd; ++pTableNames)
918 {
919 m_aTable.InsertEntry(*pTableNames);
920 if (0 == pTableNames->compareTo(sOldTable))
921 bKnowOldTable = sal_True;
922 }
923
924 // set the old table, if the new data source knows a table with this name, too. Else reset the tables edit field.
925 if (!bKnowOldTable)
926 sOldTable = ::rtl::OUString();
927 m_aTable.SetText(sOldTable);
928
929 resetFields();
930 }
931
932 // -------------------------------------------------------------------
resetFields()933 void AddressBookSourceDialog::resetFields()
934 {
935 WaitObject aWaitCursor(this);
936
937 // no matter what we do here, we handled the currently selected table (no matter if successfull or not)
938 m_aDatasource.SaveValue();
939
940 String sSelectedTable = m_aTable.GetText();
941 Sequence< ::rtl::OUString > aColumnNames;
942 try
943 {
944 if (m_xCurrentDatasourceTables.is())
945 {
946 // get the table and the columns
947 Reference< XColumnsSupplier > xSuppTableCols;
948 if (m_xCurrentDatasourceTables->hasByName(sSelectedTable))
949 ::cppu::extractInterface(xSuppTableCols, m_xCurrentDatasourceTables->getByName(sSelectedTable));
950 Reference< XNameAccess > xColumns;
951 if (xSuppTableCols.is())
952 xColumns = xSuppTableCols->getColumns();
953 if (xColumns.is())
954 aColumnNames = xColumns->getElementNames();
955 }
956 }
957 catch(Exception&)
958 {
959 DBG_ERROR("AddressBookSourceDialog::resetFields: could not retrieve the table columns!");
960 }
961
962
963 const ::rtl::OUString* pColumnNames = aColumnNames.getConstArray();
964 const ::rtl::OUString* pEnd = pColumnNames + aColumnNames.getLength();
965
966 // for quicker access
967 ::std::set< String > aColumnNameSet;
968 for (pColumnNames = aColumnNames.getConstArray(); pColumnNames != pEnd; ++pColumnNames)
969 aColumnNameSet.insert(*pColumnNames);
970
971 std::vector<String>::iterator aInitialSelection = m_pImpl->aFieldAssignments.begin() + m_pImpl->nFieldScrollPos;
972
973 ListBox** pListbox = m_pImpl->pFields;
974 String sSaveSelection;
975 for (sal_Int32 i=0; i<FIELD_CONTROLS_VISIBLE; ++i, ++pListbox, ++aInitialSelection)
976 {
977 sSaveSelection = (*pListbox)->GetSelectEntry();
978
979 (*pListbox)->Clear();
980
981 // the one entry for "no selection"
982 (*pListbox)->InsertEntry(m_sNoFieldSelection, 0);
983 // as it's entry data, set the index of the list box in our array
984 (*pListbox)->SetEntryData(0, reinterpret_cast<void*>(i));
985
986 // the field names
987 for (pColumnNames = aColumnNames.getConstArray(); pColumnNames != pEnd; ++pColumnNames)
988 (*pListbox)->InsertEntry(*pColumnNames);
989
990 if (aInitialSelection->Len() && (aColumnNameSet.end() != aColumnNameSet.find(*aInitialSelection)))
991 // we can select the entry as specified in our field assignment array
992 (*pListbox)->SelectEntry(*aInitialSelection);
993 else
994 // try to restore the selection
995 if (aColumnNameSet.end() != aColumnNameSet.find(sSaveSelection))
996 // the old selection is a valid column name
997 (*pListbox)->SelectEntry(sSaveSelection);
998 else
999 // select the <none> entry
1000 (*pListbox)->SelectEntryPos(0);
1001 }
1002
1003 // adjust m_pImpl->aFieldAssignments
1004 for ( StringArrayIterator aAdjust = m_pImpl->aFieldAssignments.begin();
1005 aAdjust != m_pImpl->aFieldAssignments.end();
1006 ++aAdjust
1007 )
1008 if (aAdjust->Len())
1009 if (aColumnNameSet.end() == aColumnNameSet.find(*aAdjust))
1010 aAdjust->Erase();
1011 }
1012
1013 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnFieldSelect,ListBox *,_pListbox)1014 IMPL_LINK(AddressBookSourceDialog, OnFieldSelect, ListBox*, _pListbox)
1015 {
1016 // the index of the affected list box in our array
1017 sal_IntPtr nListBoxIndex = reinterpret_cast<sal_IntPtr>(_pListbox->GetEntryData(0));
1018 DBG_ASSERT(nListBoxIndex >= 0 && nListBoxIndex < FIELD_CONTROLS_VISIBLE,
1019 "AddressBookSourceDialog::OnFieldScroll: invalid list box entry!");
1020
1021 // update the array where we remember the field selections
1022 if (0 == _pListbox->GetSelectEntryPos())
1023 // it's the "no field selection" entry
1024 m_pImpl->aFieldAssignments[m_pImpl->nFieldScrollPos * 2 + nListBoxIndex] = String();
1025 else
1026 // it's a regular field entry
1027 m_pImpl->aFieldAssignments[m_pImpl->nFieldScrollPos * 2 + nListBoxIndex] = _pListbox->GetSelectEntry();
1028
1029 return 0L;
1030 }
1031
1032 // -------------------------------------------------------------------
implScrollFields(sal_Int32 _nPos,sal_Bool _bAdjustFocus,sal_Bool _bAdjustScrollbar)1033 void AddressBookSourceDialog::implScrollFields(sal_Int32 _nPos, sal_Bool _bAdjustFocus, sal_Bool _bAdjustScrollbar)
1034 {
1035 if (_nPos == m_pImpl->nFieldScrollPos)
1036 // nothing to do
1037 return;
1038
1039 // loop through our field control rows and do some adjustments
1040 // for the new texts
1041 FixedText** pLeftLabelControl = m_pImpl->pFieldLabels;
1042 FixedText** pRightLabelControl = pLeftLabelControl + 1;
1043 ConstStringArrayIterator pLeftColumnLabel = m_pImpl->aFieldLabels.begin() + 2 * _nPos;
1044 ConstStringArrayIterator pRightColumnLabel = pLeftColumnLabel + 1;
1045
1046 // for the focus movement and the selection scroll
1047 ListBox** pLeftListControl = m_pImpl->pFields;
1048 ListBox** pRightListControl = pLeftListControl + 1;
1049
1050 // for the focus movement
1051 sal_Int32 nOldFocusRow = -1;
1052 sal_Int32 nOldFocusColumn = 0;
1053
1054 // for the selection scroll
1055 ConstStringArrayIterator pLeftAssignment = m_pImpl->aFieldAssignments.begin() + 2 * _nPos;
1056 ConstStringArrayIterator pRightAssignment = pLeftAssignment + 1;
1057
1058 m_pImpl->nLastVisibleListIndex = -1;
1059 // loop
1060 for (sal_Int32 i=0; i<FIELD_PAIRS_VISIBLE; ++i)
1061 {
1062 if ((*pLeftListControl)->HasChildPathFocus())
1063 {
1064 nOldFocusRow = i;
1065 nOldFocusColumn = 0;
1066 }
1067 else if ((*pRightListControl)->HasChildPathFocus())
1068 {
1069 nOldFocusRow = i;
1070 nOldFocusColumn = 1;
1071 }
1072
1073 // the new texts of the label controls
1074 (*pLeftLabelControl)->SetText(*pLeftColumnLabel);
1075 (*pRightLabelControl)->SetText(*pRightColumnLabel);
1076
1077 // we may have to hide the controls in the right column, if we have no label text for it
1078 // (which means we have an odd number of fields, though we forced our internal arrays to
1079 // be even-sized for easier handling)
1080 // (If sometimes we support an arbitrary number of field assignments, we would have to care for
1081 // an invisible left hand side column, too. But right now, the left hand side controls are always
1082 // visible)
1083 sal_Bool bHideRightColumn = (0 == pRightColumnLabel->Len());
1084 (*pRightLabelControl)->Show(!bHideRightColumn);
1085 (*pRightListControl)->Show(!bHideRightColumn);
1086 // the new selections of the listboxes
1087 implSelectField(*pLeftListControl, *pLeftAssignment);
1088 implSelectField(*pRightListControl, *pRightAssignment);
1089
1090 // the index of the last visible list box
1091 ++m_pImpl->nLastVisibleListIndex; // the left hand side box is always visible
1092 if (!bHideRightColumn)
1093 ++m_pImpl->nLastVisibleListIndex;
1094
1095 // increment ...
1096 if ( i < FIELD_PAIRS_VISIBLE - 1 )
1097 { // (not in the very last round, here the +=2 could result in an invalid
1098 // iterator position, which causes an abort in a non-product version
1099 pLeftLabelControl += 2;
1100 pRightLabelControl += 2;
1101 pLeftColumnLabel += 2;
1102 pRightColumnLabel += 2;
1103
1104 pLeftListControl += 2;
1105 pRightListControl += 2;
1106 pLeftAssignment += 2;
1107 pRightAssignment += 2;
1108 }
1109 }
1110
1111 if (_bAdjustFocus && (nOldFocusRow >= 0))
1112 { // we have to adjust the focus and one of the list boxes has the focus
1113 sal_Int32 nDelta = m_pImpl->nFieldScrollPos - _nPos;
1114 // the new row for the focus
1115 sal_Int32 nNewFocusRow = nOldFocusRow + nDelta;
1116 // normalize
1117 nNewFocusRow = std::min(nNewFocusRow, (sal_Int32)(FIELD_PAIRS_VISIBLE - 1), ::std::less< sal_Int32 >());
1118 nNewFocusRow = std::max(nNewFocusRow, (sal_Int32)0, ::std::less< sal_Int32 >());
1119 // set the new focus (in the same column)
1120 m_pImpl->pFields[nNewFocusRow * 2 + nOldFocusColumn]->GrabFocus();
1121 }
1122
1123 m_pImpl->nFieldScrollPos = _nPos;
1124
1125 if (_bAdjustScrollbar)
1126 m_aFieldScroller.SetThumbPos(m_pImpl->nFieldScrollPos);
1127 }
1128
1129 // -------------------------------------------------------------------
implSelectField(ListBox * _pBox,const String & _rText)1130 void AddressBookSourceDialog::implSelectField(ListBox* _pBox, const String& _rText)
1131 {
1132 if (_rText.Len())
1133 // a valid field name
1134 _pBox->SelectEntry(_rText);
1135 else
1136 // no selection for this item
1137 _pBox->SelectEntryPos(0);
1138 }
1139
1140 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnDelayedInitialize,void *,EMPTYARG)1141 IMPL_LINK(AddressBookSourceDialog, OnDelayedInitialize, void*, EMPTYARG)
1142 {
1143 // load the initial data from the configuration
1144 loadConfiguration();
1145 resetTables();
1146 // will reset the tables/fields implicitly
1147
1148 if ( !m_pImpl->bWorkingPersistent )
1149 if ( m_pImpl->pFields[0] )
1150 m_pImpl->pFields[0]->GrabFocus();
1151
1152 return 0L;
1153 }
1154
1155 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnComboSelect,ComboBox *,_pBox)1156 IMPL_LINK(AddressBookSourceDialog, OnComboSelect, ComboBox*, _pBox)
1157 {
1158 if (_pBox == &m_aDatasource)
1159 resetTables();
1160 else
1161 resetFields();
1162 return 0;
1163 }
1164
1165 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnComboGetFocus,ComboBox *,_pBox)1166 IMPL_LINK(AddressBookSourceDialog, OnComboGetFocus, ComboBox*, _pBox)
1167 {
1168 _pBox->SaveValue();
1169 return 0L;
1170 }
1171
1172 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnComboLoseFocus,ComboBox *,_pBox)1173 IMPL_LINK(AddressBookSourceDialog, OnComboLoseFocus, ComboBox*, _pBox)
1174 {
1175 if (_pBox->GetSavedValue() != _pBox->GetText())
1176 {
1177 if (_pBox == &m_aDatasource)
1178 resetTables();
1179 else
1180 resetFields();
1181 }
1182 return 0L;
1183 }
1184
1185 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnOkClicked,Button *,EMPTYARG)1186 IMPL_LINK(AddressBookSourceDialog, OnOkClicked, Button*, EMPTYARG)
1187 {
1188 String sSelectedDS = lcl_getSelectedDataSource( m_aDatasource );
1189 if ( m_pImpl->bWorkingPersistent )
1190 {
1191 m_pImpl->pConfigData->setDatasourceName(sSelectedDS);
1192 m_pImpl->pConfigData->setCommand(m_aTable.GetText());
1193 }
1194
1195 // set the field assignments
1196 ConstStringArrayIterator aLogical = m_pImpl->aLogicalFieldNames.begin();
1197 ConstStringArrayIterator aAssignment = m_pImpl->aFieldAssignments.begin();
1198 for ( ;
1199 aLogical < m_pImpl->aLogicalFieldNames.end();
1200 ++aLogical, ++aAssignment
1201 )
1202 m_pImpl->pConfigData->setFieldAssignment(*aLogical, *aAssignment);
1203
1204
1205 EndDialog(RET_OK);
1206 return 0L;
1207 }
1208
1209 // -------------------------------------------------------------------
IMPL_LINK(AddressBookSourceDialog,OnAdministrateDatasources,void *,EMPTYARG)1210 IMPL_LINK(AddressBookSourceDialog, OnAdministrateDatasources, void*, EMPTYARG)
1211 {
1212 // collect some initial arguments for the dialog
1213 Sequence< Any > aArgs(1);
1214 aArgs[0] <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParentWindow")), 0, makeAny(VCLUnoHelper::GetInterface(this)), PropertyState_DIRECT_VALUE);
1215
1216 // create the dialog object
1217 const String sDialogServiceName = String::CreateFromAscii("com.sun.star.ui.dialogs.AddressBookSourcePilot");
1218 Reference< XExecutableDialog > xAdminDialog;
1219 try
1220 {
1221 xAdminDialog = Reference< XExecutableDialog >(m_xORB->createInstanceWithArguments(sDialogServiceName, aArgs), UNO_QUERY);
1222 }
1223 catch(Exception&) { }
1224 if (!xAdminDialog.is())
1225 {
1226 ShowServiceNotAvailableError(this, sDialogServiceName, sal_True);
1227 return 1L;
1228 }
1229
1230 // excute the dialog
1231 try
1232 {
1233 if ( xAdminDialog->execute() == RET_OK )
1234 {
1235 Reference<XPropertySet> xProp(xAdminDialog,UNO_QUERY);
1236 if ( xProp.is() )
1237 {
1238 ::rtl::OUString sName;
1239 xProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DataSourceName"))) >>= sName;
1240
1241 INetURLObject aURL( sName );
1242 if( aURL.GetProtocol() != INET_PROT_NOT_VALID )
1243 {
1244 OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
1245 sName = aFileNotation.get(OFileNotation::N_SYSTEM);
1246 }
1247 m_aDatasource.InsertEntry(sName);
1248 delete m_pImpl->pConfigData;
1249 m_pImpl->pConfigData = new AssignmentPersistentData();
1250 loadConfiguration();
1251 resetTables();
1252 // will reset the fields implicitly
1253 }
1254 }
1255 }
1256 catch(Exception&)
1257 {
1258 DBG_ERROR("AddressBookSourceDialog::OnAdministrateDatasources: an error occured while executing the administration dialog!");
1259 }
1260
1261 // re-fill the data source list
1262 // try to preserve the current selection
1263
1264 // initializeDatasources();
1265
1266 return 0L;
1267 }
1268
1269 // -------------------------------------------------------------------
PreNotify(NotifyEvent & _rNEvt)1270 long AddressBookSourceDialog::PreNotify( NotifyEvent& _rNEvt )
1271 {
1272 switch (_rNEvt.GetType())
1273 {
1274 case EVENT_KEYINPUT:
1275 {
1276 const KeyEvent* pKeyEvent = _rNEvt.GetKeyEvent();
1277 sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
1278 sal_Bool bShift = pKeyEvent->GetKeyCode().IsShift();
1279 sal_Bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
1280 sal_Bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
1281
1282 if (KEY_TAB == nCode)
1283 { // somebody pressed the tab key
1284 if (!bAlt && !bCtrl && !bShift)
1285 { // it's really the only the key (no modifiers)
1286 if (m_pImpl->pFields[m_pImpl->nLastVisibleListIndex]->HasChildPathFocus())
1287 // the last of our visible list boxes has the focus
1288 if (m_pImpl->nFieldScrollPos < m_aFieldScroller.GetRangeMax())
1289 { // we can still scroll down
1290 sal_Int32 nNextFocusList = m_pImpl->nLastVisibleListIndex + 1 - 2;
1291 // -> scroll down
1292 implScrollFields(m_pImpl->nFieldScrollPos + 1, sal_False, sal_True);
1293 // give the left control in the "next" line the focus
1294 m_pImpl->pFields[nNextFocusList]->GrabFocus();
1295 // return saying "have handled this"
1296 return 1;
1297 }
1298 }
1299 else if (!bAlt && !bCtrl && bShift)
1300 { // it's shift-tab
1301 if (m_pImpl->pFields[0]->HasChildPathFocus())
1302 // our first list box has the focus
1303 if (m_pImpl->nFieldScrollPos > 0)
1304 { // we can still scroll up
1305 // -> scroll up
1306 implScrollFields(m_pImpl->nFieldScrollPos - 1, sal_False, sal_True);
1307 // give the right control in the "prebious" line the focus
1308 m_pImpl->pFields[0 - 1 + 2]->GrabFocus();
1309 // return saying "have handled this"
1310 return 1;
1311 }
1312 }
1313 }
1314 }
1315 break;
1316 }
1317 return ModalDialog::PreNotify(_rNEvt);
1318 }
1319
1320 // .......................................................................
1321 } // namespace svt
1322 // .......................................................................
1323
1324