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