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