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