xref: /AOO41X/main/svtools/source/dialogs/addresstemplate.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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     {
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
206     ::rtl::OUString AssigmentTransientData::getDatasourceName() const
207     {
208         return m_sDSName;
209     }
210 
211     // -------------------------------------------------------------------
212     ::rtl::OUString AssigmentTransientData::getCommand() const
213     {
214         return m_sTableName;
215     }
216 
217     // -------------------------------------------------------------------
218     sal_Int32 AssigmentTransientData::getCommandType() const
219     {
220         return CommandType::TABLE;
221     }
222 
223     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
243     void AssigmentTransientData::setFieldAssignment(const ::rtl::OUString& _rLogicalName, const ::rtl::OUString& _rAssignment)
244     {
245         m_aAliases[ _rLogicalName ] = _rAssignment;
246     }
247 
248     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
257     void AssigmentTransientData::setDatasourceName(const ::rtl::OUString&)
258     {
259         DBG_ERROR( "AssigmentTransientData::setDatasourceName: cannot be implemented for transient data!" );
260     }
261 
262     // -------------------------------------------------------------------
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 
313 void AssignmentPersistentData::Notify( const com::sun::star::uno::Sequence<rtl::OUString>& )
314 {
315 }
316 
317 void AssignmentPersistentData::Commit()
318 {
319 }
320 
321     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
332     AssignmentPersistentData::~AssignmentPersistentData()
333     {
334     }
335 
336     // -------------------------------------------------------------------
337     sal_Bool AssignmentPersistentData::hasFieldAssignment(const ::rtl::OUString& _rLogicalName)
338     {
339         return (m_aStoredFields.end() != m_aStoredFields.find(_rLogicalName));
340     }
341 
342     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
357     Any AssignmentPersistentData::getProperty(const sal_Char* _pLocalName) const
358     {
359         return getProperty(::rtl::OUString::createFromAscii(_pLocalName));
360     }
361 
362     // -------------------------------------------------------------------
363     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     // -------------------------------------------------------------------
372     ::rtl::OUString AssignmentPersistentData::getStringProperty(const ::rtl::OUString& _rLocalName) const
373     {
374         ::rtl::OUString sReturn;
375         getProperty( _rLocalName ) >>= sReturn;
376         return sReturn;
377     }
378 
379     // -------------------------------------------------------------------
380     ::rtl::OUString AssignmentPersistentData::getStringProperty(const sal_Char* _pLocalName) const
381     {
382         ::rtl::OUString sReturn;
383         getProperty( _pLocalName ) >>= sReturn;
384         return sReturn;
385     }
386 
387     // -------------------------------------------------------------------
388     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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
455     ::rtl::OUString AssignmentPersistentData::getDatasourceName() const
456     {
457         return getStringProperty( "DataSourceName" );
458     }
459 
460     // -------------------------------------------------------------------
461     ::rtl::OUString AssignmentPersistentData::getCommand() const
462     {
463         return getStringProperty( "Command" );
464     }
465 
466     // -------------------------------------------------------------------
467     void AssignmentPersistentData::setDatasourceName(const ::rtl::OUString& _rName)
468     {
469         setStringProperty( "DataSourceName", _rName );
470     }
471 
472     // -------------------------------------------------------------------
473     void AssignmentPersistentData::setCommand(const ::rtl::OUString& _rCommand)
474     {
475         setStringProperty( "Command", _rCommand );
476     }
477 
478     // -------------------------------------------------------------------
479     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         // ................................................................
514         AddressBookSourceDialogData( )
515             :nFieldScrollPos(0)
516             ,nLastVisibleListIndex(0)
517             ,bOddFieldNumber(sal_False)
518             ,bWorkingPersistent( sal_True )
519             ,pConfigData( new AssignmentPersistentData )
520         {
521         }
522 
523         // ................................................................
524         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 
535         ~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     // -------------------------------------------------------------------
563     AddressBookSourceDialog::AddressBookSourceDialog(Window* _pParent,
564             const Reference< XMultiServiceFactory >& _rxORB )
565         :INIT_FIELDS()
566         ,m_pImpl( new AddressBookSourceDialogData )
567     {
568         implConstruct();
569     }
570 
571     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
717     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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
822     IMPL_LINK(AddressBookSourceDialog, OnFieldScroll, ScrollBar*, _pScrollBar)
823     {
824         implScrollFields( _pScrollBar->GetThumbPos(), sal_True, sal_True );
825         return 0L;
826     }
827 
828     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
1166     IMPL_LINK(AddressBookSourceDialog, OnComboGetFocus, ComboBox*, _pBox)
1167     {
1168         _pBox->SaveValue();
1169         return 0L;
1170     }
1171 
1172     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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     // -------------------------------------------------------------------
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