1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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
;
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
128 Reference
< XDataSource
> m_xDataSource
;
130 OUString m_sTableName
;
131 MapString2String m_aAliases
;
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
;
186 OSL_FAIL( ( OString("AssigmentTransientData::AssigmentTransientData: unknown programmatic name (")
187 += OString(pFields
->ProgrammaticName
.getStr(), pFields
->ProgrammaticName
.getLength(), RTL_TEXTENCODING_ASCII_US
)
196 OUString
AssigmentTransientData::getDatasourceName() const
202 OUString
AssigmentTransientData::getCommand() const
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
)
219 MapString2String::const_iterator aPos
= m_aAliases
.find( _rLogicalName
);
220 if ( m_aAliases
.end() != aPos
)
221 sReturn
= aPos
->second
;
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
252 StringBag m_aStoredFields
;
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
);
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
;
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
);
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!");
348 OUString
AssignmentPersistentData::getStringProperty(const OUString
& _rLocalName
) const
351 getProperty( _rLocalName
) >>= sReturn
;
356 OUString
AssignmentPersistentData::getStringProperty(const sal_Char
* _pLocalName
) const
359 getProperty( _pLocalName
) >>= 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
);
387 OUString
sDescriptionNodePath("Fields");
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
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
))
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( )
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
)
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()
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
))
517 , m_pImpl( new AddressBookSourceDialogData
)
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
))
529 , m_pImpl( new AddressBookSourceDialogData( _rxTransientDS
, _rDataSourceName
, _rTable
, _rMapping
) )
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
)
549 m_pImpl
->pFieldLabels
[row
* 2 + column
] = get
<FixedText
>(OString("label") + OString::number(row
* 2 + column
));
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")
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
645 m_pFieldScroller
->SetThumbPos(0);
646 m_pImpl
->nFieldScrollPos
= -1;
647 implScrollFields(0, false, false);
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();
686 for ( StringArray::const_iterator aProgrammatic
= m_pImpl
->aLogicalFieldNames
.begin();
687 aProgrammatic
!= m_pImpl
->aLogicalFieldNames
.end();
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
);
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();
726 aLogical
!= m_pImpl
->aLogicalFieldNames
.end();
727 ++aLogical
, ++aAssignment
729 *aAssignment
= m_pImpl
->pConfigData
->getFieldAssignment(*aLogical
);
733 AddressBookSourceDialog::~AddressBookSourceDialog()
738 void AddressBookSourceDialog::dispose()
741 m_pDatasource
.clear();
742 m_pAdministrateDatasources
.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!");
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);
769 m_pDatasource
->Clear();
771 // fill the datasources listbox
772 Sequence
< OUString
> aDatasourceNames
;
775 aDatasourceNames
= m_xDatabaseContext
->getElementNames();
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 );
795 void AddressBookSourceDialog::resetTables()
797 if (!m_xDatabaseContext
.is())
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
;
810 InteractionHandler::createWithParent(m_xORB
, 0),
813 catch(const Exception
&) { }
816 const OUString
sInteractionHandlerServiceName("com.sun.star.task.InteractionHandler");
817 ShowServiceNotAvailableError(this, sInteractionHandlerServiceName
, true);
821 // the currently selected table
822 OUString sOldTable
= m_pTable
->GetText();
826 m_xCurrentDatasourceTables
= NULL
;
828 // get the tables of the connection
829 Sequence
< OUString
> aTableNames
;
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
;
845 xDS
.set(m_pImpl
->m_xTransientDataSource
, css::uno::UNO_QUERY
);
848 // build the connection
849 Reference
< XConnection
> xConn
;
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
; }
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
&) { }
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.
895 m_pTable
->SetText(sOldTable
);
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
))
918 m_xCurrentDatasourceTables
->getByName(sSelectedTable
),
919 css::uno::UNO_QUERY
);
920 Reference
< XNameAccess
> xColumns
;
921 if (xSuppTableCols
.is())
922 xColumns
= xSuppTableCols
->getColumns();
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();
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
));
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
);
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
);
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();
978 if (!aAdjust
->isEmpty())
979 if (aColumnNameSet
.end() == aColumnNameSet
.find(*aAdjust
))
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();
996 // it's a regular field entry
997 m_pImpl
->aFieldAssignments
[m_pImpl
->nFieldScrollPos
* 2 + nListBoxIndex
] = _pListbox
->GetSelectEntry();
1003 void AddressBookSourceDialog::implScrollFields(sal_Int32 _nPos
, bool _bAdjustFocus
, bool _bAdjustScrollbar
)
1005 if (_nPos
== m_pImpl
->nFieldScrollPos
)
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;
1030 for (sal_Int32 i
=0; i
<FIELD_PAIRS_VISIBLE
; ++i
)
1032 if ((*pLeftListControl
)->HasChildPathFocus())
1035 nOldFocusColumn
= 0;
1037 else if ((*pRightListControl
)->HasChildPathFocus())
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
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
;
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
;
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
);
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();
1116 // will reset the tables/fields implicitly
1118 if ( !m_pImpl
->bWorkingPersistent
)
1119 if ( m_pImpl
->pFields
[0] )
1120 m_pImpl
->pFields
[0]->GrabFocus();
1126 IMPL_LINK(AddressBookSourceDialog
, OnComboSelect
, ComboBox
*, _pBox
)
1128 if (_pBox
== m_pDatasource
)
1137 AddressBookSourceDialog
, OnComboGetFocus
, ComboBox
*, _pBox
)
1144 IMPL_LINK(AddressBookSourceDialog
, OnComboLoseFocus
, ComboBox
*, _pBox
)
1146 if ( _pBox
->IsValueChangedFromSaved() )
1148 if (_pBox
== m_pDatasource
)
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();
1173 aLogical
!= m_pImpl
->aLogicalFieldNames
.end();
1174 ++aLogical
, ++aAssignment
1176 m_pImpl
->pConfigData
->setFieldAssignment(*aLogical
, *aAssignment
);
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);
1199 // execute the dialog
1202 if ( xAdminDialog
->execute() == RET_OK
)
1204 Reference
<XPropertySet
> xProp(xAdminDialog
,UNO_QUERY
);
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();
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();
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;
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"
1265 else if (!bAlt
&& !bCtrl
&& bShift
)
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
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"
1282 return ModalDialog::PreNotify(_rNEvt
);
1288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */