xref: /AOO41X/main/svtools/source/dialogs/addresstemplate.cxx (revision 441693ebd5224cbcf861f80a400de51a591b769d)
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 successfull 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