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