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