Linux x86 build fix
[LibreOffice.git] / svtools / source / dialogs / addresstemplate.cxx
blob88f079a38274d832eaa99b9810926067d3e66cd9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svtools/addresstemplate.hxx>
22 #include "addresstemplate.hrc"
23 #include <svtools/svtools.hrc>
24 #include <svtools/helpid.hrc>
25 #include <svtools/svtresid.hxx>
26 #include <tools/debug.hxx>
27 #include <comphelper/interaction.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <comphelper/string.hxx>
30 #include <vcl/stdtext.hxx>
31 #include <vcl/waitobj.hxx>
32 #include <vcl/msgbox.hxx>
33 #include <vcl/settings.hxx>
34 #include <toolkit/helper/vclunohelper.hxx>
35 #include <com/sun/star/ui/dialogs/AddressBookSourcePilot.hpp>
36 #include <com/sun/star/awt/XWindow.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/sdb/DatabaseContext.hpp>
40 #include <com/sun/star/sdb/XCompletedConnection.hpp>
41 #include <com/sun/star/sdb/SQLContext.hpp>
42 #include <com/sun/star/sdbc/SQLWarning.hpp>
43 #include <com/sun/star/sdbc/XConnection.hpp>
44 #include <com/sun/star/task/InteractionHandler.hpp>
45 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
46 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
47 #include <com/sun/star/sdb/CommandType.hpp>
48 #include <svtools/localresaccess.hxx>
49 #include <svl/filenotation.hxx>
50 #include <tools/urlobj.hxx>
51 #include <algorithm>
52 #include <map>
55 namespace svt
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::lang;
61 using namespace ::com::sun::star::container;
62 using namespace ::com::sun::star::ui::dialogs;
63 using namespace ::com::sun::star::util;
64 using namespace ::com::sun::star::beans;
65 using namespace ::com::sun::star::sdb;
66 using namespace ::com::sun::star::sdbc;
67 using namespace ::com::sun::star::sdbcx;
68 using namespace ::com::sun::star::task;
69 using namespace ::comphelper;
70 using namespace ::utl;
72 typedef std::vector<OUString> StringArray;
73 typedef std::set<OUString> StringBag;
74 typedef std::map<OUString, OUString> MapString2String;
76 namespace
78 OUString lcl_getSelectedDataSource( const ComboBox& _dataSourceCombo )
80 OUString selectedDataSource = _dataSourceCombo.GetText();
81 if ( _dataSourceCombo.GetEntryPos( selectedDataSource ) == LISTBOX_ENTRY_NOTFOUND )
83 // none of the pre-selected entries -> assume a path to a database document
84 OFileNotation aFileNotation( selectedDataSource, OFileNotation::N_SYSTEM );
85 selectedDataSource = aFileNotation.get( OFileNotation::N_URL );
87 return selectedDataSource;
92 // = IAssigmentData
94 class IAssigmentData
96 public:
97 virtual ~IAssigmentData();
99 /// the data source to use for the address book
100 virtual OUString getDatasourceName() const = 0;
102 /// the command to use for the address book
103 virtual OUString getCommand() const = 0;
105 /// checks whether or not there is an assignment for a given logical field
106 virtual bool hasFieldAssignment(const OUString& _rLogicalName) = 0;
107 /// retrieves the assignment for a given logical field
108 virtual OUString getFieldAssignment(const OUString& _rLogicalName) = 0;
110 /// set the assignment for a given logical field
111 virtual void setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment) = 0;
113 virtual void setDatasourceName(const OUString& _rName) = 0;
114 virtual void setCommand(const OUString& _rCommand) = 0;
118 IAssigmentData::~IAssigmentData()
123 // = AssigmentTransientData
125 class AssigmentTransientData : public IAssigmentData
127 protected:
128 Reference< XDataSource > m_xDataSource;
129 OUString m_sDSName;
130 OUString m_sTableName;
131 MapString2String m_aAliases;
133 public:
134 AssigmentTransientData(
135 const Reference< XDataSource >& _rxDataSource,
136 const OUString& _rDataSourceName,
137 const OUString& _rTableName,
138 const Sequence< AliasProgrammaticPair >& _rFields
141 // IAssigmentData overridables
142 virtual OUString getDatasourceName() const SAL_OVERRIDE;
143 virtual OUString getCommand() const SAL_OVERRIDE;
145 virtual bool hasFieldAssignment(const OUString& _rLogicalName) SAL_OVERRIDE;
146 virtual OUString getFieldAssignment(const OUString& _rLogicalName) SAL_OVERRIDE;
147 virtual void setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment) SAL_OVERRIDE;
149 virtual void setDatasourceName(const OUString& _rName) SAL_OVERRIDE;
150 virtual void setCommand(const OUString& _rCommand) SAL_OVERRIDE;
154 AssigmentTransientData::AssigmentTransientData( const Reference< XDataSource >& _rxDataSource,
155 const OUString& _rDataSourceName, const OUString& _rTableName,
156 const Sequence< AliasProgrammaticPair >& _rFields )
157 :m_xDataSource( _rxDataSource )
158 ,m_sDSName( _rDataSourceName )
159 ,m_sTableName( _rTableName )
161 // fill our aliases structure
162 // first collect all known programmatic names
163 StringBag aKnownNames;
165 OUString sLogicalFieldNames(SVT_RESSTR(STR_LOGICAL_FIELD_NAMES));
166 sal_Int32 nIndex = 0;
169 OUString aToken = sLogicalFieldNames.getToken(0, ';', nIndex);
170 aKnownNames.insert(aToken);
172 while ( nIndex >= 0);
174 // loop through the given names
175 const AliasProgrammaticPair* pFields = _rFields.getConstArray();
176 const AliasProgrammaticPair* pFieldsEnd = pFields + _rFields.getLength();
177 for (;pFields != pFieldsEnd; ++pFields)
179 StringBag::const_iterator aKnownPos = aKnownNames.find( pFields->ProgrammaticName );
180 if ( aKnownNames.end() != aKnownPos )
182 m_aAliases[ pFields->ProgrammaticName ] = pFields->Alias;
184 else
186 OSL_FAIL( ( OString("AssigmentTransientData::AssigmentTransientData: unknown programmatic name (")
187 += OString(pFields->ProgrammaticName.getStr(), pFields->ProgrammaticName.getLength(), RTL_TEXTENCODING_ASCII_US)
188 += OString(")!")
189 ).getStr()
196 OUString AssigmentTransientData::getDatasourceName() const
198 return m_sDSName;
202 OUString AssigmentTransientData::getCommand() const
204 return m_sTableName;
208 bool AssigmentTransientData::hasFieldAssignment(const OUString& _rLogicalName)
210 MapString2String::const_iterator aPos = m_aAliases.find( _rLogicalName );
211 return ( m_aAliases.end() != aPos )
212 && ( !aPos->second.isEmpty() );
216 OUString AssigmentTransientData::getFieldAssignment(const OUString& _rLogicalName)
218 OUString sReturn;
219 MapString2String::const_iterator aPos = m_aAliases.find( _rLogicalName );
220 if ( m_aAliases.end() != aPos )
221 sReturn = aPos->second;
223 return sReturn;
227 void AssigmentTransientData::setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment)
229 m_aAliases[ _rLogicalName ] = _rAssignment;
233 void AssigmentTransientData::setDatasourceName(const OUString&)
235 OSL_FAIL( "AssigmentTransientData::setDatasourceName: cannot be implemented for transient data!" );
239 void AssigmentTransientData::setCommand(const OUString&)
241 OSL_FAIL( "AssigmentTransientData::setCommand: cannot be implemented for transient data!" );
245 // = AssignmentPersistentData
247 class AssignmentPersistentData
248 :public ::utl::ConfigItem
249 ,public IAssigmentData
251 protected:
252 StringBag m_aStoredFields;
254 protected:
255 ::com::sun::star::uno::Any
256 getProperty(const OUString& _rLocalName) const;
257 ::com::sun::star::uno::Any
258 getProperty(const sal_Char* _pLocalName) const;
260 OUString getStringProperty(const sal_Char* _pLocalName) const;
262 OUString getStringProperty(const OUString& _rLocalName) const;
264 void setStringProperty(const sal_Char* _pLocalName, const OUString& _rValue);
266 public:
267 AssignmentPersistentData();
268 virtual ~AssignmentPersistentData();
270 // IAssigmentData overridables
271 virtual OUString getDatasourceName() const SAL_OVERRIDE;
272 virtual OUString getCommand() const SAL_OVERRIDE;
274 virtual bool hasFieldAssignment(const OUString& _rLogicalName) SAL_OVERRIDE;
275 virtual OUString getFieldAssignment(const OUString& _rLogicalName) SAL_OVERRIDE;
276 virtual void setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment) SAL_OVERRIDE;
278 virtual void setDatasourceName(const OUString& _rName) SAL_OVERRIDE;
279 virtual void setCommand(const OUString& _rCommand) SAL_OVERRIDE;
281 virtual void Notify( const com::sun::star::uno::Sequence<OUString>& aPropertyNames) SAL_OVERRIDE;
283 private:
284 virtual void ImplCommit() SAL_OVERRIDE;
285 void clearFieldAssignment(const OUString& _rLogicalName);
289 void AssignmentPersistentData::Notify( const com::sun::star::uno::Sequence<OUString>& )
293 void AssignmentPersistentData::ImplCommit()
298 AssignmentPersistentData::AssignmentPersistentData()
299 :ConfigItem( OUString( "Office.DataAccess/AddressBook" ))
301 Sequence< OUString > aStoredNames = GetNodeNames(OUString("Fields"));
302 const OUString* pStoredNames = aStoredNames.getConstArray();
303 for (sal_Int32 i=0; i<aStoredNames.getLength(); ++i, ++pStoredNames)
304 m_aStoredFields.insert(*pStoredNames);
308 AssignmentPersistentData::~AssignmentPersistentData()
313 bool AssignmentPersistentData::hasFieldAssignment(const OUString& _rLogicalName)
315 return (m_aStoredFields.end() != m_aStoredFields.find(_rLogicalName));
319 OUString AssignmentPersistentData::getFieldAssignment(const OUString& _rLogicalName)
321 OUString sAssignment;
322 if (hasFieldAssignment(_rLogicalName))
324 OUString sFieldPath("Fields/");
325 sFieldPath += _rLogicalName;
326 sFieldPath += "/AssignedFieldName";
327 sAssignment = getStringProperty(sFieldPath);
329 return sAssignment;
333 Any AssignmentPersistentData::getProperty(const sal_Char* _pLocalName) const
335 return getProperty(OUString::createFromAscii(_pLocalName));
339 Any AssignmentPersistentData::getProperty(const OUString& _rLocalName) const
341 Sequence< OUString > aProperties(&_rLocalName, 1);
342 Sequence< Any > aValues = const_cast<AssignmentPersistentData*>(this)->GetProperties(aProperties);
343 DBG_ASSERT(aValues.getLength() == 1, "AssignmentPersistentData::getProperty: invalid sequence length!");
344 return aValues[0];
348 OUString AssignmentPersistentData::getStringProperty(const OUString& _rLocalName) const
350 OUString sReturn;
351 getProperty( _rLocalName ) >>= sReturn;
352 return sReturn;
356 OUString AssignmentPersistentData::getStringProperty(const sal_Char* _pLocalName) const
358 OUString sReturn;
359 getProperty( _pLocalName ) >>= sReturn;
360 return sReturn;
364 void AssignmentPersistentData::setStringProperty(const sal_Char* _pLocalName, const OUString& _rValue)
366 Sequence< OUString > aNames(1);
367 Sequence< Any > aValues(1);
368 aNames[0] = OUString::createFromAscii(_pLocalName);
369 aValues[0] <<= _rValue;
370 PutProperties(aNames, aValues);
374 void AssignmentPersistentData::setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment)
376 if (_rAssignment.isEmpty())
378 if (hasFieldAssignment(_rLogicalName))
380 // the assignment exists but it should be reset
381 clearFieldAssignment(_rLogicalName);
383 return;
386 // Fields
387 OUString sDescriptionNodePath("Fields");
389 // Fields/<field>
390 OUString sFieldElementNodePath(sDescriptionNodePath);
391 sFieldElementNodePath += "/";
392 sFieldElementNodePath += _rLogicalName;
394 Sequence< PropertyValue > aNewFieldDescription(2);
395 // Fields/<field>/ProgrammaticFieldName
396 aNewFieldDescription[0].Name = sFieldElementNodePath + "/ProgrammaticFieldName";
397 aNewFieldDescription[0].Value <<= _rLogicalName;
398 // Fields/<field>/AssignedFieldName
399 aNewFieldDescription[1].Name = sFieldElementNodePath + "/AssignedFieldName";
400 aNewFieldDescription[1].Value <<= _rAssignment;
402 // just set the new value
403 #ifdef DBG_UTIL
404 bool bSuccess =
405 #endif
406 SetSetProperties(sDescriptionNodePath, aNewFieldDescription);
407 DBG_ASSERT(bSuccess, "AssignmentPersistentData::setFieldAssignment: could not commit the changes a field!");
411 void AssignmentPersistentData::clearFieldAssignment(const OUString& _rLogicalName)
413 if (!hasFieldAssignment(_rLogicalName))
414 // nothing to do
415 return;
417 OUString sDescriptionNodePath("Fields");
418 Sequence< OUString > aNames(&_rLogicalName, 1);
419 ClearNodeElements(sDescriptionNodePath, aNames);
423 OUString AssignmentPersistentData::getDatasourceName() const
425 return getStringProperty( "DataSourceName" );
429 OUString AssignmentPersistentData::getCommand() const
431 return getStringProperty( "Command" );
435 void AssignmentPersistentData::setDatasourceName(const OUString& _rName)
437 setStringProperty( "DataSourceName", _rName );
441 void AssignmentPersistentData::setCommand(const OUString& _rCommand)
443 setStringProperty( "Command", _rCommand );
447 // = AddressBookSourceDialogData
449 struct AddressBookSourceDialogData
451 VclPtr<FixedText> pFieldLabels[FIELD_PAIRS_VISIBLE * 2];
452 VclPtr<ListBox> pFields[FIELD_PAIRS_VISIBLE * 2];
454 /// when working transient, we need the data source
455 Reference< XDataSource >
456 m_xTransientDataSource;
457 /// current scroll pos in the field list
458 sal_Int32 nFieldScrollPos;
459 /// the index within m_pFields of the last visible list box. This is redundant, it could be extracted from other members
460 sal_Int32 nLastVisibleListIndex;
461 /// indicates that we've an odd field number. This member is for efficiency only, it's redundant.
462 bool bOddFieldNumber : 1;
463 /// indicates that we're working with the real persistent configuration
464 bool bWorkingPersistent : 1;
466 /// the strings to use as labels for the field selection listboxes
467 StringArray aFieldLabels;
468 // the current field assignment
469 StringArray aFieldAssignments;
470 /// the logical field names
471 StringArray aLogicalFieldNames;
473 IAssigmentData* pConfigData;
476 AddressBookSourceDialogData( )
477 :nFieldScrollPos(0)
478 ,nLastVisibleListIndex(0)
479 ,bOddFieldNumber(false)
480 ,bWorkingPersistent( true )
481 ,pConfigData( new AssignmentPersistentData )
483 memset(pFieldLabels, 0, sizeof(pFieldLabels));
484 memset(pFields, 0, sizeof(pFields));
487 AddressBookSourceDialogData( const Reference< XDataSource >& _rxTransientDS, const OUString& _rDataSourceName,
488 const OUString& _rTableName, const Sequence< AliasProgrammaticPair >& _rFields )
489 :m_xTransientDataSource( _rxTransientDS )
490 ,nFieldScrollPos(0)
491 ,nLastVisibleListIndex(0)
492 ,bOddFieldNumber(false)
493 ,bWorkingPersistent( false )
494 ,pConfigData( new AssigmentTransientData( m_xTransientDataSource, _rDataSourceName, _rTableName, _rFields ) )
496 memset(pFieldLabels, 0, sizeof(pFieldLabels));
497 memset(pFields, 0, sizeof(pFields));
500 ~AddressBookSourceDialogData()
502 delete pConfigData;
508 // = AddressBookSourceDialog
512 AddressBookSourceDialog::AddressBookSourceDialog(vcl::Window* _pParent,
513 const Reference< XComponentContext >& _rxORB )
514 : ModalDialog(_pParent, "AddressTemplateDialog", "svt/ui/addresstemplatedialog.ui")
515 , m_sNoFieldSelection(SVT_RESSTR(STR_NO_FIELD_SELECTION))
516 , m_xORB(_rxORB)
517 , m_pImpl( new AddressBookSourceDialogData )
519 implConstruct();
523 AddressBookSourceDialog::AddressBookSourceDialog( vcl::Window* _pParent, const Reference< XComponentContext >& _rxORB,
524 const Reference< XDataSource >& _rxTransientDS, const OUString& _rDataSourceName,
525 const OUString& _rTable, const Sequence< AliasProgrammaticPair >& _rMapping )
526 : ModalDialog(_pParent, "AddressTemplateDialog", "svt/ui/addresstemplatedialog.ui")
527 , m_sNoFieldSelection(SVT_RESSTR(STR_NO_FIELD_SELECTION))
528 , m_xORB(_rxORB)
529 , m_pImpl( new AddressBookSourceDialogData( _rxTransientDS, _rDataSourceName, _rTable, _rMapping ) )
531 implConstruct();
535 void AddressBookSourceDialog::implConstruct()
537 get(m_pDatasource, "datasource");
538 get(m_pAdministrateDatasources, "admin");
539 get(m_pTable, "datatable");
540 VclScrolledWindow *pScrollWindow = get<VclScrolledWindow>("scrollwindow");
541 pScrollWindow->setUserManagedScrolling(true);
542 m_pFieldScroller = &pScrollWindow->getVertScrollBar();
544 for (sal_Int32 row=0; row<FIELD_PAIRS_VISIBLE; ++row)
546 for (sal_Int32 column=0; column<2; ++column)
548 // the label
549 m_pImpl->pFieldLabels[row * 2 + column] = get<FixedText>(OString("label") + OString::number(row * 2 + column));
550 // the listbox
551 m_pImpl->pFields[row * 2 + column] = get<ListBox>(OString("box") + OString::number(row * 2 + column));
552 m_pImpl->pFields[row * 2 + column]->SetSelectHdl(LINK(this, AddressBookSourceDialog, OnFieldSelect));
557 initializeDatasources();
559 // for the moment, we have a hard coded list of all known fields.
560 // A better solution would be to store all known field translations in the configuration, which could be
561 // extensible by the user in an arbitrary way.
562 // But for the moment we need a quick solution ...
563 // (the main thing would be to store the translations to use here in the user interface, besides that, the code
564 // should be adjustable with a rather small effort.)
566 // initialize the strings for the field labels
567 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_FIRSTNAME ));
568 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_LASTNAME ));
569 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_COMPANY));
570 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_DEPARTMENT ));
571 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_STREET ));
572 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_ZIPCODE ));
573 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_CITY ));
574 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_STATE));
575 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_COUNTRY ));
576 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_HOMETEL ));
577 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_WORKTEL ));
578 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_OFFICETEL));
579 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_MOBILE));
580 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_TELOTHER));
581 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_PAGER));
582 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_FAX ));
583 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_EMAIL ));
584 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_URL ));
585 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_TITLE ));
586 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_POSITION ));
587 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_INITIALS ));
588 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_ADDRFORM ));
589 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_SALUTATION ));
590 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_ID));
591 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_CALENDAR));
592 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_INVITE));
593 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_NOTE));
594 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_USER1));
595 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_USER2));
596 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_USER3));
597 m_pImpl->aFieldLabels.push_back( SVT_RESSTR( STR_FIELD_USER4));
599 long nLabelWidth = 0;
600 long nListBoxWidth = m_pImpl->pFields[0]->approximate_char_width() * 20;
601 for (StringArray::const_iterator aI = m_pImpl->aFieldLabels.begin(), aEnd = m_pImpl->aFieldLabels.end(); aI != aEnd; ++aI)
603 nLabelWidth = std::max(nLabelWidth, FixedText::getTextDimensions(m_pImpl->pFieldLabels[0], *aI, 0x7FFFFFFF).Width());
605 for (sal_Int32 row=0; row<FIELD_PAIRS_VISIBLE; ++row)
607 for (sal_Int32 column=0; column<2; ++column)
609 m_pImpl->pFieldLabels[row * 2 + column]->set_width_request(nLabelWidth);
610 m_pImpl->pFields[row * 2 + column]->set_width_request(nListBoxWidth);
615 // force a even number of known fields
616 m_pImpl->bOddFieldNumber = (m_pImpl->aFieldLabels.size() % 2) != 0;
617 if (m_pImpl->bOddFieldNumber)
618 m_pImpl->aFieldLabels.push_back( OUString() );
620 // limit the scrollbar range accordingly
621 sal_Int32 nOverallFieldPairs = m_pImpl->aFieldLabels.size() / 2;
622 m_pFieldScroller->SetRange( Range(0, nOverallFieldPairs - FIELD_PAIRS_VISIBLE) );
623 m_pFieldScroller->SetLineSize(1);
624 m_pFieldScroller->SetPageSize(FIELD_PAIRS_VISIBLE);
626 // reset the current field assignments
627 m_pImpl->aFieldAssignments.resize(m_pImpl->aFieldLabels.size());
628 // (empty strings mean "no assignment")
630 // some knittings
631 m_pFieldScroller->SetScrollHdl(LINK(this, AddressBookSourceDialog, OnFieldScroll));
632 m_pAdministrateDatasources->SetClickHdl(LINK(this, AddressBookSourceDialog, OnAdministrateDatasources));
633 m_pDatasource->EnableAutocomplete(true);
634 m_pTable->EnableAutocomplete(true);
635 m_pTable->SetGetFocusHdl(LINK(this, AddressBookSourceDialog, OnComboGetFocus));
636 m_pDatasource->SetGetFocusHdl(LINK(this, AddressBookSourceDialog, OnComboGetFocus));
637 m_pTable->SetLoseFocusHdl(LINK(this, AddressBookSourceDialog, OnComboLoseFocus));
638 m_pDatasource->SetLoseFocusHdl(LINK(this, AddressBookSourceDialog, OnComboLoseFocus));
639 m_pTable->SetSelectHdl(LINK(this, AddressBookSourceDialog, OnComboSelect));
640 m_pDatasource->SetSelectHdl(LINK(this, AddressBookSourceDialog, OnComboSelect));
641 get<OKButton>("ok")->SetClickHdl(LINK(this, AddressBookSourceDialog, OnOkClicked));
643 // initialize the field controls
644 resetFields();
645 m_pFieldScroller->SetThumbPos(0);
646 m_pImpl->nFieldScrollPos = -1;
647 implScrollFields(0, false, false);
649 // the logical names
650 OUString sLogicalFieldNames(SVT_RESSTR(STR_LOGICAL_FIELD_NAMES));
651 sal_Int32 nAdjustedTokenCount = comphelper::string::getTokenCount(sLogicalFieldNames, ';') + (m_pImpl->bOddFieldNumber ? 1 : 0);
652 DBG_ASSERT(nAdjustedTokenCount == (sal_Int32)m_pImpl->aFieldLabels.size(),
653 "AddressBookSourceDialog::AddressBookSourceDialog: inconsistence between logical and UI field names!");
654 m_pImpl->aLogicalFieldNames.reserve(nAdjustedTokenCount);
655 for (sal_Int32 i = 0; i<nAdjustedTokenCount; ++i)
656 m_pImpl->aLogicalFieldNames.push_back(sLogicalFieldNames.getToken(i, ';'));
658 PostUserEvent(LINK(this, AddressBookSourceDialog, OnDelayedInitialize), NULL, true);
659 // so the dialog will at least show up before we do the loading of the
660 // configuration data and the (maybe time consuming) analysis of the data source/table to select
662 if ( !m_pImpl->bWorkingPersistent )
664 StyleSettings aSystemStyle = GetSettings().GetStyleSettings();
665 const ::Color& rNewColor = aSystemStyle.GetDialogColor();
667 m_pDatasource->SetReadOnly( true );
668 m_pDatasource->SetBackground( Wallpaper( rNewColor ) );
669 m_pDatasource->SetControlBackground( rNewColor );
671 m_pTable->SetReadOnly( true );
672 m_pTable->SetBackground( Wallpaper( rNewColor ) );
673 m_pTable->SetControlBackground( rNewColor );
675 m_pAdministrateDatasources->Hide( );
680 void AddressBookSourceDialog::getFieldMapping(Sequence< AliasProgrammaticPair >& _rMapping) const
682 _rMapping.realloc( m_pImpl->aLogicalFieldNames.size() );
683 AliasProgrammaticPair* pPair = _rMapping.getArray();
685 OUString sCurrent;
686 for ( StringArray::const_iterator aProgrammatic = m_pImpl->aLogicalFieldNames.begin();
687 aProgrammatic != m_pImpl->aLogicalFieldNames.end();
688 ++aProgrammatic
691 sCurrent = *aProgrammatic;
692 if ( m_pImpl->pConfigData->hasFieldAssignment( sCurrent ) )
694 // the user gave us an assignment for this field
695 pPair->ProgrammaticName = *aProgrammatic;
696 pPair->Alias = m_pImpl->pConfigData->getFieldAssignment( *aProgrammatic );
697 ++pPair;
701 _rMapping.realloc( pPair - _rMapping.getArray() );
705 void AddressBookSourceDialog::loadConfiguration()
707 OUString sName = m_pImpl->pConfigData->getDatasourceName();
708 INetURLObject aURL( sName );
709 if( aURL.GetProtocol() != INetProtocol::NotValid )
711 OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
712 sName = aFileNotation.get(OFileNotation::N_SYSTEM);
715 m_pDatasource->SetText(sName);
716 m_pTable->SetText(m_pImpl->pConfigData->getCommand());
717 // we ignore the CommandType: only tables are supported
719 // the logical names for the fields
720 // AddressBookSourceDialog::loadConfiguration: inconsistence between field names and field assignments!
721 assert(m_pImpl->aLogicalFieldNames.size() == m_pImpl->aFieldAssignments.size());
723 StringArray::const_iterator aLogical = m_pImpl->aLogicalFieldNames.begin();
724 StringArray::iterator aAssignment = m_pImpl->aFieldAssignments.begin();
725 for ( ;
726 aLogical != m_pImpl->aLogicalFieldNames.end();
727 ++aLogical, ++aAssignment
729 *aAssignment = m_pImpl->pConfigData->getFieldAssignment(*aLogical);
733 AddressBookSourceDialog::~AddressBookSourceDialog()
735 disposeOnce();
738 void AddressBookSourceDialog::dispose()
740 delete m_pImpl;
741 m_pDatasource.clear();
742 m_pAdministrateDatasources.clear();
743 m_pTable.clear();
744 m_pFieldScroller.clear();
745 ModalDialog::dispose();
749 void AddressBookSourceDialog::initializeDatasources()
751 if (!m_xDatabaseContext.is())
753 DBG_ASSERT(m_xORB.is(), "AddressBookSourceDialog::initializeDatasources: no service factory!");
754 if (!m_xORB.is())
755 return;
759 m_xDatabaseContext = DatabaseContext::create(m_xORB);
761 catch(const Exception&) { }
762 if (!m_xDatabaseContext.is())
764 const OUString sContextServiceName("com.sun.star.sdb.DatabaseContext");
765 ShowServiceNotAvailableError( this, sContextServiceName, false);
766 return;
769 m_pDatasource->Clear();
771 // fill the datasources listbox
772 Sequence< OUString > aDatasourceNames;
775 aDatasourceNames = m_xDatabaseContext->getElementNames();
777 catch(Exception&)
779 OSL_FAIL("AddressBookSourceDialog::initializeDatasources: caught an exception while asking for the data source names!");
781 const OUString* pDatasourceNames = aDatasourceNames.getConstArray();
782 const OUString* pEnd = pDatasourceNames + aDatasourceNames.getLength();
783 for (; pDatasourceNames < pEnd; ++pDatasourceNames)
784 m_pDatasource->InsertEntry(*pDatasourceNames);
788 IMPL_LINK(AddressBookSourceDialog, OnFieldScroll, ScrollBar*, _pScrollBar)
790 implScrollFields( _pScrollBar->GetThumbPos(), true, true );
791 return 0L;
795 void AddressBookSourceDialog::resetTables()
797 if (!m_xDatabaseContext.is())
798 return;
800 WaitObject aWaitCursor(this);
802 // no matter what we do here, we handled the currently selected data source (no matter if successful or not)
803 m_pDatasource->SaveValue();
805 // create an interaction handler (may be needed for connecting)
806 Reference< XInteractionHandler > xHandler;
809 xHandler.set(
810 InteractionHandler::createWithParent(m_xORB, 0),
811 UNO_QUERY_THROW );
813 catch(const Exception&) { }
814 if (!xHandler.is())
816 const OUString sInteractionHandlerServiceName("com.sun.star.task.InteractionHandler");
817 ShowServiceNotAvailableError(this, sInteractionHandlerServiceName, true);
818 return;
821 // the currently selected table
822 OUString sOldTable = m_pTable->GetText();
824 m_pTable->Clear();
826 m_xCurrentDatasourceTables= NULL;
828 // get the tables of the connection
829 Sequence< OUString > aTableNames;
830 Any aException;
833 Reference< XCompletedConnection > xDS;
834 if ( m_pImpl->bWorkingPersistent )
836 OUString sSelectedDS = lcl_getSelectedDataSource(*m_pDatasource);
838 // get the data source the user has chosen and let it build a connection
839 INetURLObject aURL( sSelectedDS );
840 if ( aURL.GetProtocol() != INetProtocol::NotValid || m_xDatabaseContext->hasByName(sSelectedDS) )
841 m_xDatabaseContext->getByName( sSelectedDS ) >>= xDS;
843 else
845 xDS.set(m_pImpl->m_xTransientDataSource, css::uno::UNO_QUERY);
848 // build the connection
849 Reference< XConnection > xConn;
850 if (xDS.is())
851 xConn = xDS->connectWithCompletion(xHandler);
853 // get the table names
854 Reference< XTablesSupplier > xSupplTables(xConn, UNO_QUERY);
855 if (xSupplTables.is())
857 m_xCurrentDatasourceTables = Reference< XNameAccess >(xSupplTables->getTables(), UNO_QUERY);
858 if (m_xCurrentDatasourceTables.is())
859 aTableNames = m_xCurrentDatasourceTables->getElementNames();
862 catch(const SQLContext& e) { aException <<= e; }
863 catch(const SQLWarning& e) { aException <<= e; }
864 catch(const SQLException& e) { aException <<= e; }
865 catch(Exception&)
867 OSL_FAIL("AddressBookSourceDialog::resetTables: could not retrieve the table!");
870 if (aException.hasValue())
872 Reference< XInteractionRequest > xRequest = new OInteractionRequest(aException);
875 xHandler->handle(xRequest);
877 catch(Exception&) { }
878 return;
881 bool bKnowOldTable = false;
882 // fill the table list
883 const OUString* pTableNames = aTableNames.getConstArray();
884 const OUString* pEnd = pTableNames + aTableNames.getLength();
885 for (;pTableNames != pEnd; ++pTableNames)
887 m_pTable->InsertEntry(*pTableNames);
888 if (0 == pTableNames->compareTo(sOldTable))
889 bKnowOldTable = true;
892 // set the old table, if the new data source knows a table with this name, too. Else reset the tables edit field.
893 if (!bKnowOldTable)
894 sOldTable.clear();
895 m_pTable->SetText(sOldTable);
897 resetFields();
901 void AddressBookSourceDialog::resetFields()
903 WaitObject aWaitCursor(this);
905 // no matter what we do here, we handled the currently selected table (no matter if successful or not)
906 m_pDatasource->SaveValue();
908 OUString sSelectedTable = m_pTable->GetText();
909 Sequence< OUString > aColumnNames;
912 if (m_xCurrentDatasourceTables.is())
914 // get the table and the columns
915 Reference< XColumnsSupplier > xSuppTableCols;
916 if (m_xCurrentDatasourceTables->hasByName(sSelectedTable))
917 xSuppTableCols.set(
918 m_xCurrentDatasourceTables->getByName(sSelectedTable),
919 css::uno::UNO_QUERY);
920 Reference< XNameAccess > xColumns;
921 if (xSuppTableCols.is())
922 xColumns = xSuppTableCols->getColumns();
923 if (xColumns.is())
924 aColumnNames = xColumns->getElementNames();
927 catch (const Exception&)
929 OSL_FAIL("AddressBookSourceDialog::resetFields: could not retrieve the table columns!");
933 const OUString* pColumnNames = aColumnNames.getConstArray();
934 const OUString* pEnd = pColumnNames + aColumnNames.getLength();
936 // for quicker access
937 ::std::set< OUString > aColumnNameSet;
938 for (pColumnNames = aColumnNames.getConstArray(); pColumnNames != pEnd; ++pColumnNames)
939 aColumnNameSet.insert(*pColumnNames);
941 std::vector<OUString>::iterator aInitialSelection = m_pImpl->aFieldAssignments.begin() + m_pImpl->nFieldScrollPos;
943 OUString sSaveSelection;
944 for (sal_Int32 i=0; i<FIELD_CONTROLS_VISIBLE; ++i, ++aInitialSelection)
946 VclPtr<ListBox>& pListbox = m_pImpl->pFields[i];
947 sSaveSelection = pListbox->GetSelectEntry();
949 pListbox->Clear();
951 // the one entry for "no selection"
952 pListbox->InsertEntry(m_sNoFieldSelection, 0);
953 // as it's entry data, set the index of the list box in our array
954 pListbox->SetEntryData(0, reinterpret_cast<void*>(i));
956 // the field names
957 for (pColumnNames = aColumnNames.getConstArray(); pColumnNames != pEnd; ++pColumnNames)
958 pListbox->InsertEntry(*pColumnNames);
960 if (!aInitialSelection->isEmpty() && (aColumnNameSet.end() != aColumnNameSet.find(*aInitialSelection)))
961 // we can select the entry as specified in our field assignment array
962 pListbox->SelectEntry(*aInitialSelection);
963 else
964 // try to restore the selection
965 if (aColumnNameSet.end() != aColumnNameSet.find(sSaveSelection))
966 // the old selection is a valid column name
967 pListbox->SelectEntry(sSaveSelection);
968 else
969 // select the <none> entry
970 pListbox->SelectEntryPos(0);
973 // adjust m_pImpl->aFieldAssignments
974 for ( StringArray::iterator aAdjust = m_pImpl->aFieldAssignments.begin();
975 aAdjust != m_pImpl->aFieldAssignments.end();
976 ++aAdjust
978 if (!aAdjust->isEmpty())
979 if (aColumnNameSet.end() == aColumnNameSet.find(*aAdjust))
980 aAdjust->clear();
984 IMPL_LINK(AddressBookSourceDialog, OnFieldSelect, ListBox*, _pListbox)
986 // the index of the affected list box in our array
987 sal_IntPtr nListBoxIndex = reinterpret_cast<sal_IntPtr>(_pListbox->GetEntryData(0));
988 DBG_ASSERT(nListBoxIndex >= 0 && nListBoxIndex < FIELD_CONTROLS_VISIBLE,
989 "AddressBookSourceDialog::OnFieldScroll: invalid list box entry!");
991 // update the array where we remember the field selections
992 if (0 == _pListbox->GetSelectEntryPos())
993 // it's the "no field selection" entry
994 m_pImpl->aFieldAssignments[m_pImpl->nFieldScrollPos * 2 + nListBoxIndex].clear();
995 else
996 // it's a regular field entry
997 m_pImpl->aFieldAssignments[m_pImpl->nFieldScrollPos * 2 + nListBoxIndex] = _pListbox->GetSelectEntry();
999 return 0L;
1003 void AddressBookSourceDialog::implScrollFields(sal_Int32 _nPos, bool _bAdjustFocus, bool _bAdjustScrollbar)
1005 if (_nPos == m_pImpl->nFieldScrollPos)
1006 // nothing to do
1007 return;
1009 // loop through our field control rows and do some adjustments
1010 // for the new texts
1011 VclPtr<FixedText>* pLeftLabelControl = m_pImpl->pFieldLabels;
1012 VclPtr<FixedText>* pRightLabelControl = pLeftLabelControl + 1;
1013 StringArray::const_iterator pLeftColumnLabel = m_pImpl->aFieldLabels.begin() + 2 * _nPos;
1014 StringArray::const_iterator pRightColumnLabel = pLeftColumnLabel + 1;
1016 // for the focus movement and the selection scroll
1017 VclPtr<ListBox>* pLeftListControl = m_pImpl->pFields;
1018 VclPtr<ListBox>* pRightListControl = pLeftListControl + 1;
1020 // for the focus movement
1021 sal_Int32 nOldFocusRow = -1;
1022 sal_Int32 nOldFocusColumn = 0;
1024 // for the selection scroll
1025 StringArray::const_iterator pLeftAssignment = m_pImpl->aFieldAssignments.begin() + 2 * _nPos;
1026 StringArray::const_iterator pRightAssignment = pLeftAssignment + 1;
1028 m_pImpl->nLastVisibleListIndex = -1;
1029 // loop
1030 for (sal_Int32 i=0; i<FIELD_PAIRS_VISIBLE; ++i)
1032 if ((*pLeftListControl)->HasChildPathFocus())
1034 nOldFocusRow = i;
1035 nOldFocusColumn = 0;
1037 else if ((*pRightListControl)->HasChildPathFocus())
1039 nOldFocusRow = i;
1040 nOldFocusColumn = 1;
1043 // the new texts of the label controls
1044 (*pLeftLabelControl)->SetText(*pLeftColumnLabel);
1045 (*pRightLabelControl)->SetText(*pRightColumnLabel);
1047 // we may have to hide the controls in the right column, if we have no label text for it
1048 // (which means we have an odd number of fields, though we forced our internal arrays to
1049 // be even-sized for easier handling)
1050 // (If sometimes we support an arbitrary number of field assignments, we would have to care for
1051 // an invisible left hand side column, too. But right now, the left hand side controls are always
1052 // visible)
1053 bool bHideRightColumn = pRightColumnLabel->isEmpty();
1054 (*pRightLabelControl)->Show(!bHideRightColumn);
1055 (*pRightListControl)->Show(!bHideRightColumn);
1056 // the new selections of the listboxes
1057 implSelectField(*pLeftListControl, *pLeftAssignment);
1058 implSelectField(*pRightListControl, *pRightAssignment);
1060 // the index of the last visible list box
1061 ++m_pImpl->nLastVisibleListIndex; // the left hand side box is always visible
1062 if (!bHideRightColumn)
1063 ++m_pImpl->nLastVisibleListIndex;
1065 // increment ...
1066 if ( i < FIELD_PAIRS_VISIBLE - 1 )
1067 { // (not in the very last round, here the +=2 could result in an invalid
1068 // iterator position, which causes an abort in a non-product version
1069 pLeftLabelControl += 2;
1070 pRightLabelControl += 2;
1071 pLeftColumnLabel += 2;
1072 pRightColumnLabel += 2;
1074 pLeftListControl += 2;
1075 pRightListControl += 2;
1076 pLeftAssignment += 2;
1077 pRightAssignment += 2;
1081 if (_bAdjustFocus && (nOldFocusRow >= 0))
1082 { // we have to adjust the focus and one of the list boxes has the focus
1083 sal_Int32 nDelta = m_pImpl->nFieldScrollPos - _nPos;
1084 // the new row for the focus
1085 sal_Int32 nNewFocusRow = nOldFocusRow + nDelta;
1086 // normalize
1087 nNewFocusRow = std::min(nNewFocusRow, (sal_Int32)(FIELD_PAIRS_VISIBLE - 1), ::std::less< sal_Int32 >());
1088 nNewFocusRow = std::max(nNewFocusRow, (sal_Int32)0, ::std::less< sal_Int32 >());
1089 // set the new focus (in the same column)
1090 m_pImpl->pFields[nNewFocusRow * 2 + nOldFocusColumn]->GrabFocus();
1093 m_pImpl->nFieldScrollPos = _nPos;
1095 if (_bAdjustScrollbar)
1096 m_pFieldScroller->SetThumbPos(m_pImpl->nFieldScrollPos);
1100 void AddressBookSourceDialog::implSelectField(ListBox* _pBox, const OUString& _rText)
1102 if (!_rText.isEmpty())
1103 // a valid field name
1104 _pBox->SelectEntry(_rText);
1105 else
1106 // no selection for this item
1107 _pBox->SelectEntryPos(0);
1111 IMPL_LINK_NOARG(AddressBookSourceDialog, OnDelayedInitialize)
1113 // load the initial data from the configuration
1114 loadConfiguration();
1115 resetTables();
1116 // will reset the tables/fields implicitly
1118 if ( !m_pImpl->bWorkingPersistent )
1119 if ( m_pImpl->pFields[0] )
1120 m_pImpl->pFields[0]->GrabFocus();
1122 return 0L;
1126 IMPL_LINK(AddressBookSourceDialog, OnComboSelect, ComboBox*, _pBox)
1128 if (_pBox == m_pDatasource)
1129 resetTables();
1130 else
1131 resetFields();
1132 return 0;
1136 IMPL_STATIC_LINK(
1137 AddressBookSourceDialog, OnComboGetFocus, ComboBox*, _pBox)
1139 _pBox->SaveValue();
1140 return 0L;
1144 IMPL_LINK(AddressBookSourceDialog, OnComboLoseFocus, ComboBox*, _pBox)
1146 if ( _pBox->IsValueChangedFromSaved() )
1148 if (_pBox == m_pDatasource)
1149 resetTables();
1150 else
1151 resetFields();
1153 return 0L;
1157 IMPL_LINK_NOARG(AddressBookSourceDialog, OnOkClicked)
1159 OUString sSelectedDS = lcl_getSelectedDataSource(*m_pDatasource);
1160 if ( m_pImpl->bWorkingPersistent )
1162 m_pImpl->pConfigData->setDatasourceName(sSelectedDS);
1163 m_pImpl->pConfigData->setCommand(m_pTable->GetText());
1166 // AddressBookSourceDialog::loadConfiguration: inconsistence between field names and field assignments!
1167 assert(m_pImpl->aLogicalFieldNames.size() == m_pImpl->aFieldAssignments.size());
1169 // set the field assignments
1170 StringArray::const_iterator aLogical = m_pImpl->aLogicalFieldNames.begin();
1171 StringArray::const_iterator aAssignment = m_pImpl->aFieldAssignments.begin();
1172 for ( ;
1173 aLogical != m_pImpl->aLogicalFieldNames.end();
1174 ++aLogical, ++aAssignment
1176 m_pImpl->pConfigData->setFieldAssignment(*aLogical, *aAssignment);
1179 EndDialog(RET_OK);
1180 return 0L;
1184 IMPL_LINK_NOARG(AddressBookSourceDialog, OnAdministrateDatasources)
1186 // create the dialog object
1187 Reference< XExecutableDialog > xAdminDialog;
1190 xAdminDialog = AddressBookSourcePilot::createWithParent( m_xORB, VCLUnoHelper::GetInterface(this) );
1192 catch(const Exception&) { }
1193 if (!xAdminDialog.is())
1195 ShowServiceNotAvailableError(this, OUString("com.sun.star.ui.dialogs.AddressBookSourcePilot"), true);
1196 return 1L;
1199 // execute the dialog
1202 if ( xAdminDialog->execute() == RET_OK )
1204 Reference<XPropertySet> xProp(xAdminDialog,UNO_QUERY);
1205 if ( xProp.is() )
1207 OUString sName;
1208 xProp->getPropertyValue("DataSourceName") >>= sName;
1210 INetURLObject aURL( sName );
1211 if( aURL.GetProtocol() != INetProtocol::NotValid )
1213 OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
1214 sName = aFileNotation.get(OFileNotation::N_SYSTEM);
1216 m_pDatasource->InsertEntry(sName);
1217 delete m_pImpl->pConfigData;
1218 m_pImpl->pConfigData = new AssignmentPersistentData();
1219 loadConfiguration();
1220 resetTables();
1221 // will reset the fields implicitly
1225 catch(const Exception&)
1227 OSL_FAIL("AddressBookSourceDialog::OnAdministrateDatasources: an error occurred while executing the administration dialog!");
1230 // re-fill the data source list
1231 // try to preserve the current selection
1233 // initializeDatasources();
1235 return 0L;
1238 bool AddressBookSourceDialog::PreNotify( NotifyEvent& _rNEvt )
1240 if (_rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
1242 const KeyEvent* pKeyEvent = _rNEvt.GetKeyEvent();
1243 sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
1244 bool bShift = pKeyEvent->GetKeyCode().IsShift();
1245 bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
1246 bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
1248 if (KEY_TAB == nCode)
1249 { // somebody pressed the tab key
1250 if (!bAlt && !bCtrl && !bShift)
1251 { // it's really the only the key (no modifiers)
1252 if (m_pImpl->pFields[m_pImpl->nLastVisibleListIndex]->HasChildPathFocus())
1253 // the last of our visible list boxes has the focus
1254 if (m_pImpl->nFieldScrollPos < m_pFieldScroller->GetRangeMax())
1255 { // we can still scroll down
1256 sal_Int32 nNextFocusList = m_pImpl->nLastVisibleListIndex + 1 - 2;
1257 // -> scroll down
1258 implScrollFields(m_pImpl->nFieldScrollPos + 1, false, true);
1259 // give the left control in the "next" line the focus
1260 m_pImpl->pFields[nNextFocusList]->GrabFocus();
1261 // return saying "have handled this"
1262 return true;
1265 else if (!bAlt && !bCtrl && bShift)
1266 { // it's shift-tab
1267 if (m_pImpl->pFields[0]->HasChildPathFocus())
1268 // our first list box has the focus
1269 if (m_pImpl->nFieldScrollPos > 0)
1270 { // we can still scroll up
1271 // -> scroll up
1272 implScrollFields(m_pImpl->nFieldScrollPos - 1, false, true);
1273 // give the right control in the "prebious" line the focus
1274 m_pImpl->pFields[0 - 1 + 2]->GrabFocus();
1275 // return saying "have handled this"
1276 return true;
1282 return ModalDialog::PreNotify(_rNEvt);
1285 } // namespace svt
1288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */