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