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_extensions.hxx" 30 31 #include "formlinkdialog.hxx" 32 #include "formlinkdialog.hrc" 33 34 #ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_ 35 #include "modulepcr.hxx" 36 #endif 37 #ifndef _EXTENSIONS_FORMCTRLR_PROPRESID_HRC_ 38 #include "formresid.hrc" 39 #endif 40 #include "formstrings.hxx" 41 #include <vcl/combobox.hxx> 42 #include <vcl/msgbox.hxx> 43 #include <vcl/waitobj.hxx> 44 #include <svtools/localresaccess.hxx> 45 #include <connectivity/dbtools.hxx> 46 #include <connectivity/dbexception.hxx> 47 #include <toolkit/helper/vclunohelper.hxx> 48 49 /** === begin UNO includes === **/ 50 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> 51 #include <com/sun/star/sdbcx/XKeysSupplier.hpp> 52 #include <com/sun/star/sdbcx/KeyType.hpp> 53 #include <com/sun/star/container/XNameAccess.hpp> 54 #include <com/sun/star/sdbcx/XTablesSupplier.hpp> 55 #include <com/sun/star/sdbc/XRowSet.hpp> 56 #include <com/sun/star/sdb/CommandType.hpp> 57 #include <com/sun/star/sdb/SQLContext.hpp> 58 /** === end UNO includes === **/ 59 60 61 //............................................................................ 62 namespace pcr 63 { 64 //............................................................................ 65 66 using namespace ::com::sun::star::uno; 67 using namespace ::com::sun::star::lang; 68 using namespace ::com::sun::star::form; 69 using namespace ::com::sun::star::sdb; 70 using namespace ::com::sun::star::sdbc; 71 using namespace ::com::sun::star::sdbcx; 72 using namespace ::com::sun::star::beans; 73 using namespace ::com::sun::star::container; 74 75 //======================================================================== 76 //= FieldLinkRow 77 //======================================================================== 78 class FieldLinkRow : public Window 79 { 80 private: 81 ComboBox m_aDetailColumn; 82 FixedText m_aEqualSign; 83 ComboBox m_aMasterColumn; 84 85 Link m_aLinkChangeHandler; 86 87 public: 88 FieldLinkRow( Window* _pParent, const ResId& _rId ); 89 90 inline void SetLinkChangeHandler( const Link& _rHdl ) { m_aLinkChangeHandler = _rHdl; } 91 inline const Link& GetLinkChangeHandler( ) const { return m_aLinkChangeHandler; } 92 93 enum LinkParticipant 94 { 95 eDetailField, 96 eMasterField 97 }; 98 /** retrieves the selected field name for either the master or the detail field 99 @return <TRUE/> if and only a valid field is selected 100 */ 101 bool GetFieldName( LinkParticipant _eWhich, String& /* [out] */ _rName ) const; 102 void SetFieldName( LinkParticipant _eWhich, const String& _rName ); 103 104 void fillList( LinkParticipant _eWhich, const Sequence< ::rtl::OUString >& _rFieldNames ); 105 106 private: 107 DECL_LINK( OnFieldNameChanged, ComboBox* ); 108 }; 109 110 //------------------------------------------------------------------------ 111 FieldLinkRow::FieldLinkRow( Window* _pParent, const ResId& _rId ) 112 :Window( _pParent, _rId ) 113 ,m_aDetailColumn( this, ResId( 1, *_rId.GetResMgr() ) ) 114 ,m_aEqualSign ( this, ResId( 1, *_rId.GetResMgr() ) ) 115 ,m_aMasterColumn( this, ResId( 2, *_rId.GetResMgr() ) ) 116 { 117 FreeResource(); 118 119 m_aDetailColumn.SetDropDownLineCount( 10 ); 120 m_aMasterColumn.SetDropDownLineCount( 10 ); 121 122 m_aDetailColumn.SetModifyHdl( LINK( this, FieldLinkRow, OnFieldNameChanged ) ); 123 m_aMasterColumn.SetModifyHdl( LINK( this, FieldLinkRow, OnFieldNameChanged ) ); 124 } 125 126 //------------------------------------------------------------------------ 127 void FieldLinkRow::fillList( LinkParticipant _eWhich, const Sequence< ::rtl::OUString >& _rFieldNames ) 128 { 129 ComboBox* pBox = ( _eWhich == eDetailField ) ? &m_aDetailColumn : &m_aMasterColumn; 130 131 const ::rtl::OUString* pFieldName = _rFieldNames.getConstArray(); 132 const ::rtl::OUString* pFieldNameEnd = pFieldName + _rFieldNames.getLength(); 133 for ( ; pFieldName != pFieldNameEnd; ++pFieldName ) 134 pBox->InsertEntry( *pFieldName ); 135 } 136 137 //------------------------------------------------------------------------ 138 bool FieldLinkRow::GetFieldName( LinkParticipant _eWhich, String& /* [out] */ _rName ) const 139 { 140 const ComboBox* pBox = ( _eWhich == eDetailField ) ? &m_aDetailColumn : &m_aMasterColumn; 141 _rName = pBox->GetText(); 142 return _rName.Len() != 0; 143 } 144 145 //------------------------------------------------------------------------ 146 void FieldLinkRow::SetFieldName( LinkParticipant _eWhich, const String& _rName ) 147 { 148 ComboBox* pBox = ( _eWhich == eDetailField ) ? &m_aDetailColumn : &m_aMasterColumn; 149 pBox->SetText( _rName ); 150 } 151 152 //------------------------------------------------------------------------ 153 IMPL_LINK( FieldLinkRow, OnFieldNameChanged, ComboBox*, /*_pBox*/ ) 154 { 155 if ( m_aLinkChangeHandler.IsSet() ) 156 return m_aLinkChangeHandler.Call( this ); 157 158 return 0L; 159 } 160 161 //======================================================================== 162 //= FormLinkDialog 163 //======================================================================== 164 //------------------------------------------------------------------------ 165 FormLinkDialog::FormLinkDialog( Window* _pParent, const Reference< XPropertySet >& _rxDetailForm, 166 const Reference< XPropertySet >& _rxMasterForm, const Reference< XMultiServiceFactory >& _rxORB, 167 const ::rtl::OUString& _sExplanation, 168 const ::rtl::OUString& _sDetailLabel, 169 const ::rtl::OUString& _sMasterLabel) 170 :ModalDialog( _pParent, PcrRes( RID_DLG_FORMLINKS ) ) 171 ,m_aExplanation( this, PcrRes( FT_EXPLANATION ) ) 172 ,m_aDetailLabel( this, PcrRes( FT_DETAIL_LABEL ) ) 173 ,m_aMasterLabel( this, PcrRes( FT_MASTER_LABEL ) ) 174 ,m_aRow1 ( new FieldLinkRow( this, PcrRes( 1 ) ) ) 175 ,m_aRow2 ( new FieldLinkRow( this, PcrRes( 2 ) ) ) 176 ,m_aRow3 ( new FieldLinkRow( this, PcrRes( 3 ) ) ) 177 ,m_aRow4 ( new FieldLinkRow( this, PcrRes( 4 ) ) ) 178 ,m_aOK ( this, PcrRes( PB_OK ) ) 179 ,m_aCancel ( this, PcrRes( PB_CANCEL ) ) 180 ,m_aHelp ( this, PcrRes( PB_HELP ) ) 181 ,m_aSuggest ( this, PcrRes( PB_SUGGEST ) ) 182 ,m_xORB ( _rxORB ) 183 ,m_xDetailForm( _rxDetailForm ) 184 ,m_xMasterForm( _rxMasterForm ) 185 ,m_sDetailLabel(_sDetailLabel) 186 ,m_sMasterLabel(_sMasterLabel) 187 { 188 FreeResource(); 189 if ( _sExplanation.getLength() ) 190 m_aExplanation.SetText(_sExplanation); 191 192 m_aSuggest.SetClickHdl ( LINK( this, FormLinkDialog, OnSuggest ) ); 193 m_aRow1->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); 194 m_aRow2->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); 195 m_aRow3->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); 196 m_aRow4->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); 197 198 PostUserEvent( LINK( this, FormLinkDialog, OnInitialize ) ); 199 200 updateOkButton(); 201 } 202 203 //------------------------------------------------------------------------ 204 FormLinkDialog::~FormLinkDialog( ) 205 { 206 } 207 208 //------------------------------------------------------------------------ 209 void FormLinkDialog::commitLinkPairs() 210 { 211 // collect the field lists from the rows 212 ::std::vector< ::rtl::OUString > aDetailFields; aDetailFields.reserve( 4 ); 213 ::std::vector< ::rtl::OUString > aMasterFields; aMasterFields.reserve( 4 ); 214 215 const FieldLinkRow* aRows[] = { 216 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get() 217 }; 218 219 for ( sal_Int32 i = 0; i < 4; ++i ) 220 { 221 String sDetailField, sMasterField; 222 aRows[ i ]->GetFieldName( FieldLinkRow::eDetailField, sDetailField ); 223 aRows[ i ]->GetFieldName( FieldLinkRow::eMasterField, sMasterField ); 224 if ( !sDetailField.Len() && !sMasterField.Len() ) 225 continue; 226 227 aDetailFields.push_back( sDetailField ); 228 aMasterFields.push_back( sMasterField ); 229 } 230 231 // and set as property values 232 try 233 { 234 Reference< XPropertySet > xDetailFormProps( m_xDetailForm, UNO_QUERY ); 235 if ( xDetailFormProps.is() ) 236 { 237 ::rtl::OUString *pFields = aDetailFields.empty() ? 0 : &aDetailFields[0]; 238 xDetailFormProps->setPropertyValue( PROPERTY_DETAILFIELDS, makeAny( Sequence< ::rtl::OUString >( pFields, aDetailFields.size() ) ) ); 239 pFields = aMasterFields.empty() ? 0 : &aMasterFields[0]; 240 xDetailFormProps->setPropertyValue( PROPERTY_MASTERFIELDS, makeAny( Sequence< ::rtl::OUString >( pFields, aMasterFields.size() ) ) ); 241 } 242 } 243 catch( const Exception& ) 244 { 245 OSL_ENSURE( sal_False, "FormLinkDialog::commitLinkPairs: caught an exception while setting the properties!" ); 246 } 247 } 248 249 //------------------------------------------------------------------------ 250 short FormLinkDialog::Execute() 251 { 252 short nResult = ModalDialog::Execute(); 253 254 if ( RET_OK == nResult ) 255 commitLinkPairs(); 256 257 return nResult; 258 } 259 260 //------------------------------------------------------------------------ 261 void FormLinkDialog::initializeFieldLists() 262 { 263 Sequence< ::rtl::OUString > sDetailFields; 264 getFormFields( m_xDetailForm, sDetailFields ); 265 266 Sequence< ::rtl::OUString > sMasterFields; 267 getFormFields( m_xMasterForm, sMasterFields ); 268 269 FieldLinkRow* aRows[] = { 270 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get() 271 }; 272 for ( sal_Int32 i = 0; i < 4 ; ++i ) 273 { 274 aRows[i]->fillList( FieldLinkRow::eDetailField, sDetailFields ); 275 aRows[i]->fillList( FieldLinkRow::eMasterField, sMasterFields ); 276 } 277 278 } 279 280 //------------------------------------------------------------------------ 281 void FormLinkDialog::initializeColumnLabels() 282 { 283 // label for the detail form 284 String sDetailType = getFormDataSourceType( m_xDetailForm ); 285 if ( !sDetailType.Len() ) 286 { 287 if ( !m_sDetailLabel.getLength() ) 288 { 289 ::svt::OLocalResourceAccess aStringAccess( PcrRes( RID_DLG_FORMLINKS ), RSC_MODALDIALOG ); 290 m_sDetailLabel = String( PcrRes( STR_DETAIL_FORM ) ); 291 } 292 sDetailType = m_sDetailLabel; 293 } 294 m_aDetailLabel.SetText( sDetailType ); 295 296 // label for the master form 297 String sMasterType = getFormDataSourceType( m_xMasterForm ); 298 if ( !sMasterType.Len() ) 299 { 300 if ( !m_sMasterLabel.getLength() ) 301 { 302 ::svt::OLocalResourceAccess aStringAccess( PcrRes( RID_DLG_FORMLINKS ), RSC_MODALDIALOG ); 303 m_sMasterLabel = String( PcrRes( STR_MASTER_FORM ) ); 304 } 305 sMasterType = m_sMasterLabel; 306 } 307 m_aMasterLabel.SetText( sMasterType ); 308 } 309 310 //------------------------------------------------------------------------ 311 void FormLinkDialog::initializeFieldRowsFrom( Sequence< ::rtl::OUString >& _rDetailFields, Sequence< ::rtl::OUString >& _rMasterFields ) 312 { 313 // our UI does allow 4 fields max 314 _rDetailFields.realloc( 4 ); 315 _rMasterFields.realloc( 4 ); 316 317 const ::rtl::OUString* pDetailFields = _rDetailFields.getConstArray(); 318 const ::rtl::OUString* pMasterFields = _rMasterFields.getConstArray(); 319 320 FieldLinkRow* aRows[] = { 321 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get() 322 }; 323 for ( sal_Int32 i = 0; i < 4; ++i, ++pDetailFields, ++pMasterFields ) 324 { 325 aRows[ i ]->SetFieldName( FieldLinkRow::eDetailField, *pDetailFields ); 326 aRows[ i ]->SetFieldName( FieldLinkRow::eMasterField, *pMasterFields ); 327 } 328 } 329 330 //------------------------------------------------------------------------ 331 void FormLinkDialog::initializeLinks() 332 { 333 try 334 { 335 Sequence< ::rtl::OUString > aDetailFields; 336 Sequence< ::rtl::OUString > aMasterFields; 337 338 Reference< XPropertySet > xDetailFormProps( m_xDetailForm, UNO_QUERY ); 339 if ( xDetailFormProps.is() ) 340 { 341 xDetailFormProps->getPropertyValue( PROPERTY_DETAILFIELDS ) >>= aDetailFields; 342 xDetailFormProps->getPropertyValue( PROPERTY_MASTERFIELDS ) >>= aMasterFields; 343 } 344 345 initializeFieldRowsFrom( aDetailFields, aMasterFields ); 346 } 347 catch( const Exception& ) 348 { 349 OSL_ENSURE( sal_False, "FormLinkDialog::initializeLinks: caught an exception!" ); 350 } 351 } 352 353 //------------------------------------------------------------------------ 354 void FormLinkDialog::updateOkButton() 355 { 356 // in all rows, there must be either two valid selections, or none at all 357 // If there is at least one row with exactly one valid selection, then the 358 // OKButton needs to be disabled 359 sal_Bool bEnable = sal_True; 360 361 const FieldLinkRow* aRows[] = { 362 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get() 363 }; 364 365 for ( sal_Int32 i = 0; ( i < 4 ) && bEnable; ++i ) 366 { 367 String sNotInterestedInRightNow; 368 if ( aRows[ i ]->GetFieldName( FieldLinkRow::eDetailField, sNotInterestedInRightNow ) 369 != aRows[ i ]->GetFieldName( FieldLinkRow::eMasterField, sNotInterestedInRightNow ) 370 ) 371 bEnable = sal_False; 372 } 373 374 m_aOK.Enable( bEnable ); 375 } 376 377 //------------------------------------------------------------------------ 378 String FormLinkDialog::getFormDataSourceType( const Reference< XPropertySet >& _rxForm ) const SAL_THROW(()) 379 { 380 String sReturn; 381 Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY ); 382 if ( !xFormProps.is() ) 383 return sReturn; 384 385 try 386 { 387 sal_Int32 nCommandType = CommandType::COMMAND; 388 ::rtl::OUString sCommand; 389 390 xFormProps->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType; 391 xFormProps->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand; 392 393 if ( ( nCommandType == CommandType::TABLE ) 394 || ( nCommandType == CommandType::QUERY ) 395 ) 396 sReturn = sCommand; 397 } 398 catch( const Exception& ) 399 { 400 OSL_ENSURE( sal_False, "FormLinkDialog::getFormDataSourceType: caught an exception!" ); 401 } 402 return sReturn; 403 } 404 405 //------------------------------------------------------------------------ 406 void FormLinkDialog::getFormFields( const Reference< XPropertySet >& _rxForm, Sequence< ::rtl::OUString >& /* [out] */ _rNames ) const SAL_THROW(( )) 407 { 408 _rNames.realloc( 0 ); 409 410 ::dbtools::SQLExceptionInfo aErrorInfo; 411 ::rtl::OUString sCommand; 412 try 413 { 414 WaitObject aWaitCursor( const_cast< FormLinkDialog* >( this ) ); 415 416 Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY ); 417 OSL_ENSURE( xFormProps.is(), "FormLinkDialog::getFormFields: invalid form!" ); 418 419 sal_Int32 nCommandType = CommandType::COMMAND; 420 421 xFormProps->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType; 422 xFormProps->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand; 423 424 Reference< XConnection > xConnection; 425 ensureFormConnection( xFormProps, xConnection ); 426 427 _rNames = ::dbtools::getFieldNamesByCommandDescriptor( 428 xConnection, 429 nCommandType, 430 sCommand, 431 &aErrorInfo 432 ); 433 } 434 catch (const SQLContext& e) { aErrorInfo = e; } 435 catch (const SQLWarning& e) { aErrorInfo = e; } 436 catch (const SQLException& e ) { aErrorInfo = e; } 437 catch( const Exception& ) 438 { 439 OSL_ENSURE( sal_False, "FormLinkDialog::getFormFields: caught a non-SQL exception!" ); 440 } 441 442 if ( aErrorInfo.isValid() ) 443 { 444 String sErrorMessage; 445 { 446 ::svt::OLocalResourceAccess aStringAccess( PcrRes( RID_DLG_FORMLINKS ), RSC_MODALDIALOG ); 447 sErrorMessage = String( PcrRes( STR_ERROR_RETRIEVING_COLUMNS) ); 448 sErrorMessage.SearchAndReplace('#',sCommand); 449 } 450 451 SQLContext aContext; 452 aContext.Message = sErrorMessage; 453 aContext.NextException = aErrorInfo.get(); 454 ::dbtools::showError( aContext, VCLUnoHelper::GetInterface( const_cast< FormLinkDialog* >( this ) ), m_xORB ); 455 } 456 } 457 458 //------------------------------------------------------------------------ 459 void FormLinkDialog::ensureFormConnection( const Reference< XPropertySet >& _rxFormProps, Reference< XConnection >& /* [out] */ _rxConnection ) const SAL_THROW(( Exception )) 460 { 461 OSL_PRECOND( _rxFormProps.is(), "FormLinkDialog::ensureFormConnection: invalid form!" ); 462 if ( !_rxFormProps.is() ) 463 return; 464 if ( _rxFormProps->getPropertySetInfo()->hasPropertyByName(PROPERTY_ACTIVE_CONNECTION) ) 465 _rxConnection.set(_rxFormProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY); 466 467 if ( !_rxConnection.is() ) 468 _rxConnection = ::dbtools::connectRowset( Reference< XRowSet >( _rxFormProps, UNO_QUERY ), m_xORB, sal_True ); 469 } 470 471 //------------------------------------------------------------------------ 472 void FormLinkDialog::getConnectionMetaData( const Reference< XPropertySet >& _rxFormProps, Reference< XDatabaseMetaData >& /* [out] */ _rxMeta ) const SAL_THROW(( Exception )) 473 { 474 if ( _rxFormProps.is() ) 475 { 476 Reference< XConnection > xConnection; 477 if ( !::dbtools::isEmbeddedInDatabase( _rxFormProps, xConnection ) ) 478 _rxFormProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection; 479 if ( xConnection.is() ) 480 _rxMeta = xConnection->getMetaData(); 481 } 482 } 483 484 //------------------------------------------------------------------------ 485 Reference< XPropertySet > FormLinkDialog::getCanonicUnderlyingTable( const Reference< XPropertySet >& _rxFormProps ) const 486 { 487 Reference< XPropertySet > xTable; 488 try 489 { 490 Reference< XTablesSupplier > xTablesInForm( ::dbtools::getCurrentSettingsComposer( _rxFormProps, m_xORB ), UNO_QUERY ); 491 Reference< XNameAccess > xTables; 492 if ( xTablesInForm.is() ) 493 xTables = xTablesInForm->getTables(); 494 Sequence< ::rtl::OUString > aTableNames; 495 if ( xTables.is() ) 496 aTableNames = xTables->getElementNames(); 497 498 if ( aTableNames.getLength() == 1 ) 499 { 500 xTables->getByName( aTableNames[ 0 ] ) >>= xTable; 501 OSL_ENSURE( xTable.is(), "FormLinkDialog::getCanonicUnderlyingTable: invalid table!" ); 502 } 503 } 504 catch( const Exception& ) 505 { 506 OSL_ENSURE( sal_False, "FormLinkDialog::getCanonicUnderlyingTable: caught an exception!" ); 507 } 508 return xTable; 509 } 510 511 //------------------------------------------------------------------------ 512 sal_Bool FormLinkDialog::getExistingRelation( const Reference< XPropertySet >& _rxLHS, const Reference< XPropertySet >& /*_rxRHS*/, 513 // TODO: fix the usage of _rxRHS. This is issue #i81956#. 514 Sequence< ::rtl::OUString >& _rLeftFields, Sequence< ::rtl::OUString >& _rRightFields ) const 515 { 516 try 517 { 518 Reference< XKeysSupplier > xSuppKeys( _rxLHS, UNO_QUERY ); 519 Reference< XIndexAccess > xKeys; 520 if ( xSuppKeys.is() ) 521 xKeys = xSuppKeys->getKeys(); 522 523 if ( xKeys.is() ) 524 { 525 Reference< XPropertySet > xKey; 526 Reference< XColumnsSupplier > xKeyColSupp( xKey, UNO_QUERY ); 527 Reference< XIndexAccess > xKeyColumns; 528 Reference< XPropertySet > xKeyColumn; 529 ::rtl::OUString sColumnName, sRelatedColumnName; 530 531 const sal_Int32 keyCount = xKeys->getCount(); 532 for ( sal_Int32 key = 0; key < keyCount; ++key ) 533 { 534 xKeys->getByIndex( key ) >>= xKey; 535 sal_Int32 nKeyType = 0; 536 xKey->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Type" ) ) ) >>= nKeyType; 537 if ( nKeyType != KeyType::FOREIGN ) 538 continue; 539 540 xKeyColumns.clear(); 541 xKeyColSupp = xKeyColSupp.query( xKey ); 542 if ( xKeyColSupp.is() ) 543 xKeyColumns = xKeyColumns.query( xKeyColSupp->getColumns() ); 544 OSL_ENSURE( xKeyColumns.is(), "FormLinkDialog::getExistingRelation: could not obtain the columns for the key!" ); 545 546 if ( !xKeyColumns.is() ) 547 continue; 548 549 const sal_Int32 columnCount = xKeyColumns->getCount(); 550 _rLeftFields.realloc( columnCount ); 551 _rRightFields.realloc( columnCount ); 552 for ( sal_Int32 column = 0; column < columnCount; ++column ) 553 { 554 xKeyColumn.clear(); 555 xKeyColumns->getByIndex( column ) >>= xKeyColumn; 556 OSL_ENSURE( xKeyColumn.is(), "FormLinkDialog::getExistingRelation: invalid key column!" ); 557 if ( xKeyColumn.is() ) 558 { 559 xKeyColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName; 560 xKeyColumn->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RelatedColumn" ) ) ) >>= sRelatedColumnName; 561 562 _rLeftFields[ column ] = sColumnName; 563 _rRightFields[ column ] = sRelatedColumnName; 564 } 565 } 566 } 567 } 568 } 569 catch( const Exception& ) 570 { 571 OSL_ENSURE( sal_False, "FormLinkDialog::getExistingRelation: caught an exception!" ); 572 } 573 574 return ( _rLeftFields.getLength() > 0 ) && ( _rLeftFields[ 0 ].getLength() > 0 ); 575 } 576 577 //------------------------------------------------------------------------ 578 void FormLinkDialog::initializeSuggest() 579 { 580 Reference< XPropertySet > xDetailFormProps( m_xDetailForm, UNO_QUERY ); 581 Reference< XPropertySet > xMasterFormProps( m_xMasterForm, UNO_QUERY ); 582 if ( !xDetailFormProps.is() || !xMasterFormProps.is() ) 583 return; 584 585 try 586 { 587 sal_Bool bEnable = sal_True; 588 589 // only show the button when both forms are based on the same data source 590 if ( bEnable ) 591 { 592 ::rtl::OUString sMasterDS, sDetailDS; 593 xMasterFormProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sMasterDS; 594 xDetailFormProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sDetailDS; 595 bEnable = ( sMasterDS == sDetailDS ); 596 } 597 598 // only show the button when the connection supports relations 599 if ( bEnable ) 600 { 601 Reference< XDatabaseMetaData > xMeta; 602 getConnectionMetaData( xDetailFormProps, xMeta ); 603 OSL_ENSURE( xMeta.is(), "FormLinkDialog::initializeSuggest: unable to retrieve the meta data for the connection!" ); 604 try 605 { 606 bEnable = xMeta.is() && xMeta->supportsIntegrityEnhancementFacility(); 607 } 608 catch(const Exception&) 609 { 610 bEnable = sal_False; 611 } 612 } 613 614 // only enable the button if there is a "canonic" table underlying both forms 615 Reference< XPropertySet > xDetailTable, xMasterTable; 616 if ( bEnable ) 617 { 618 xDetailTable = getCanonicUnderlyingTable( xDetailFormProps ); 619 xMasterTable = getCanonicUnderlyingTable( xMasterFormProps ); 620 bEnable = xDetailTable.is() && xMasterTable.is(); 621 } 622 623 // only enable the button if there is a relation between both tables 624 m_aRelationDetailColumns.realloc( 0 ); 625 m_aRelationMasterColumns.realloc( 0 ); 626 if ( bEnable ) 627 { 628 bEnable = getExistingRelation( xDetailTable, xMasterTable, m_aRelationDetailColumns, m_aRelationMasterColumns ); 629 OSL_POSTCOND( m_aRelationMasterColumns.getLength() == m_aRelationDetailColumns.getLength(), "FormLinkDialog::initializeSuggest: nonsense!" ); 630 if ( m_aRelationMasterColumns.getLength() == 0 ) 631 { // okay, there is no relation "pointing" (via a foreign key) from the detail table to the master table 632 // but perhaps the other way round (would make less sense, but who knows ...) 633 bEnable = getExistingRelation( xMasterTable, xDetailTable, m_aRelationMasterColumns, m_aRelationDetailColumns ); 634 } 635 } 636 637 // only enable the button if the relation contains at most 4 field pairs 638 if ( bEnable ) 639 { 640 bEnable = ( m_aRelationMasterColumns.getLength() <= 4 ); 641 } 642 643 m_aSuggest.Enable( bEnable ); 644 } 645 catch( const Exception& ) 646 { 647 OSL_ENSURE( sal_False, "FormLinkDialog::initializeSuggest: caught an exception!" ); 648 } 649 } 650 651 //------------------------------------------------------------------------ 652 IMPL_LINK( FormLinkDialog, OnSuggest, void*, /*_pNotInterestedIn*/ ) 653 { 654 initializeFieldRowsFrom( m_aRelationDetailColumns, m_aRelationMasterColumns ); 655 return 0L; 656 } 657 658 //------------------------------------------------------------------------ 659 IMPL_LINK( FormLinkDialog, OnFieldChanged, FieldLinkRow*, /*_pRow*/ ) 660 { 661 updateOkButton(); 662 return 0L; 663 } 664 665 //------------------------------------------------------------------------ 666 IMPL_LINK( FormLinkDialog, OnInitialize, void*, /*_pNotInterestedIn*/ ) 667 { 668 initializeColumnLabels(); 669 initializeFieldLists(); 670 initializeLinks(); 671 initializeSuggest(); 672 return 0L; 673 } 674 //............................................................................ 675 } // namespace pcr 676 //............................................................................ 677