Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / extensions / source / propctrlr / formlinkdialog.cxx
blob601e4585b1d819ab377ad087c30269433f674ea3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "formlinkdialog.hxx"
23 #include "modulepcr.hxx"
24 #include "formresid.hrc"
25 #include "formstrings.hxx"
26 #include <sal/log.hxx>
27 #include <vcl/combobox.hxx>
28 #include <vcl/msgbox.hxx>
29 #include <vcl/waitobj.hxx>
30 #include <vcl/tabpage.hxx>
31 #include <vcl/layout.hxx>
32 #include <vcl/builderfactory.hxx>
33 #include <connectivity/dbtools.hxx>
34 #include <connectivity/dbexception.hxx>
35 #include <toolkit/helper/vclunohelper.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <comphelper/sequence.hxx>
39 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
40 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
41 #include <com/sun/star/sdbcx/KeyType.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
44 #include <com/sun/star/sdbc/XRowSet.hpp>
45 #include <com/sun/star/sdb/CommandType.hpp>
46 #include <com/sun/star/sdb/SQLContext.hpp>
49 namespace pcr
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::lang;
55 using namespace ::com::sun::star::form;
56 using namespace ::com::sun::star::sdb;
57 using namespace ::com::sun::star::sdbc;
58 using namespace ::com::sun::star::sdbcx;
59 using namespace ::com::sun::star::beans;
60 using namespace ::com::sun::star::container;
63 //= FieldLinkRow
65 class FieldLinkRow : public TabPage
67 private:
68 VclPtr<ComboBox> m_pDetailColumn;
69 VclPtr<ComboBox> m_pMasterColumn;
71 Link<FieldLinkRow&,void> m_aLinkChangeHandler;
73 public:
74 explicit FieldLinkRow( vcl::Window* _pParent );
75 virtual ~FieldLinkRow() override;
76 virtual void dispose() override;
78 void SetLinkChangeHandler( const Link<FieldLinkRow&,void>& _rHdl ) { m_aLinkChangeHandler = _rHdl; }
80 enum LinkParticipant
82 eDetailField,
83 eMasterField
85 /** retrieves the selected field name for either the master or the detail field
86 @return <TRUE/> if and only a valid field is selected
88 bool GetFieldName( LinkParticipant _eWhich, OUString& /* [out] */ _rName ) const;
89 void SetFieldName( LinkParticipant _eWhich, const OUString& _rName );
91 void fillList( LinkParticipant _eWhich, const Sequence< OUString >& _rFieldNames );
93 private:
94 DECL_LINK( OnFieldNameChanged, Edit&, void );
98 FieldLinkRow::FieldLinkRow( vcl::Window* _pParent )
99 :TabPage( _pParent, "FieldLinkRow", "modules/spropctrlr/ui/fieldlinkrow.ui" )
101 get(m_pDetailColumn, "detailCombobox");
102 get(m_pMasterColumn, "masterCombobox");
104 m_pDetailColumn->SetDropDownLineCount( 10 );
105 m_pMasterColumn->SetDropDownLineCount( 10 );
107 m_pDetailColumn->SetModifyHdl( LINK( this, FieldLinkRow, OnFieldNameChanged ) );
108 m_pMasterColumn->SetModifyHdl( LINK( this, FieldLinkRow, OnFieldNameChanged ) );
111 FieldLinkRow::~FieldLinkRow()
113 disposeOnce();
116 void FieldLinkRow::dispose()
118 m_pDetailColumn.clear();
119 m_pMasterColumn.clear();
120 TabPage::dispose();
123 void FieldLinkRow::fillList( LinkParticipant _eWhich, const Sequence< OUString >& _rFieldNames )
125 ComboBox* pBox = ( _eWhich == eDetailField ) ? m_pDetailColumn.get() : m_pMasterColumn.get();
127 const OUString* pFieldName = _rFieldNames.getConstArray();
128 const OUString* pFieldNameEnd = pFieldName + _rFieldNames.getLength();
129 for ( ; pFieldName != pFieldNameEnd; ++pFieldName )
130 pBox->InsertEntry( *pFieldName );
134 bool FieldLinkRow::GetFieldName( LinkParticipant _eWhich, OUString& /* [out] */ _rName ) const
136 const ComboBox* pBox = ( _eWhich == eDetailField ) ? m_pDetailColumn : m_pMasterColumn;
137 _rName = pBox->GetText();
138 return !_rName.isEmpty();
142 void FieldLinkRow::SetFieldName( LinkParticipant _eWhich, const OUString& _rName )
144 ComboBox* pBox = ( _eWhich == eDetailField ) ? m_pDetailColumn.get() : m_pMasterColumn.get();
145 pBox->SetText( _rName );
149 IMPL_LINK_NOARG( FieldLinkRow, OnFieldNameChanged, Edit&, void )
151 m_aLinkChangeHandler.Call( *this );
154 VCL_BUILDER_FACTORY(FieldLinkRow)
156 //= FormLinkDialog
158 FormLinkDialog::FormLinkDialog( vcl::Window* _pParent, const Reference< XPropertySet >& _rxDetailForm,
159 const Reference< XPropertySet >& _rxMasterForm, const Reference< XComponentContext >& _rxContext,
160 const OUString& _sExplanation,
161 const OUString& _sDetailLabel,
162 const OUString& _sMasterLabel)
163 :ModalDialog( _pParent, "FormLinks", "modules/spropctrlr/ui/formlinksdialog.ui" )
164 ,m_aRow1 ( VclPtr<FieldLinkRow>::Create( get<VclVBox>("box") ) )
165 ,m_aRow2 ( VclPtr<FieldLinkRow>::Create( get<VclVBox>("box") ) )
166 ,m_aRow3 ( VclPtr<FieldLinkRow>::Create( get<VclVBox>("box") ) )
167 ,m_aRow4 ( VclPtr<FieldLinkRow>::Create( get<VclVBox>("box") ) )
168 ,m_xContext ( _rxContext )
169 ,m_xDetailForm( _rxDetailForm )
170 ,m_xMasterForm( _rxMasterForm )
171 ,m_sDetailLabel(_sDetailLabel)
172 ,m_sMasterLabel(_sMasterLabel)
174 get(m_pExplanation, "explanationLabel");
175 get(m_pDetailLabel, "detailLabel");
176 get(m_pMasterLabel, "masterLabel");
177 get(m_pOK, "ok");
178 get(m_pSuggest, "suggestButton");
179 m_aRow1->Show();
180 m_aRow2->Show();
181 m_aRow3->Show();
182 m_aRow4->Show();
183 set_width_request(600);
185 if ( !_sExplanation.isEmpty() )
186 m_pExplanation->SetText(_sExplanation);
188 m_pSuggest->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 ) );
194 PostUserEvent( LINK( this, FormLinkDialog, OnInitialize ), nullptr, true );
196 updateOkButton();
200 FormLinkDialog::~FormLinkDialog( )
202 disposeOnce();
205 void FormLinkDialog::dispose( )
207 m_pExplanation.clear();
208 m_pDetailLabel.clear();
209 m_pMasterLabel.clear();
210 m_pOK.clear();
211 m_pSuggest.clear();
213 m_aRow1.disposeAndClear();
214 m_aRow2.disposeAndClear();
215 m_aRow3.disposeAndClear();
216 m_aRow4.disposeAndClear();
218 ModalDialog::dispose();
221 void FormLinkDialog::commitLinkPairs()
223 // collect the field lists from the rows
224 std::vector< OUString > aDetailFields; aDetailFields.reserve( 4 );
225 std::vector< OUString > aMasterFields; aMasterFields.reserve( 4 );
227 const FieldLinkRow* aRows[] = {
228 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get()
231 for (const FieldLinkRow* aRow : aRows)
233 OUString sDetailField, sMasterField;
234 aRow->GetFieldName( FieldLinkRow::eDetailField, sDetailField );
235 aRow->GetFieldName( FieldLinkRow::eMasterField, sMasterField );
236 if ( sDetailField.isEmpty() && sMasterField.isEmpty() )
237 continue;
239 aDetailFields.push_back( sDetailField );
240 aMasterFields.push_back( sMasterField );
243 // and set as property values
246 Reference< XPropertySet > xDetailFormProps( m_xDetailForm, UNO_QUERY );
247 if ( xDetailFormProps.is() )
249 xDetailFormProps->setPropertyValue( PROPERTY_DETAILFIELDS, makeAny( Sequence< OUString >( aDetailFields.data(), aDetailFields.size() ) ) );
250 xDetailFormProps->setPropertyValue( PROPERTY_MASTERFIELDS, makeAny( Sequence< OUString >( aMasterFields.data(), aMasterFields.size() ) ) );
253 catch( const Exception& )
255 OSL_FAIL( "FormLinkDialog::commitLinkPairs: caught an exception while setting the properties!" );
260 short FormLinkDialog::Execute()
262 short nResult = ModalDialog::Execute();
264 if ( RET_OK == nResult )
265 commitLinkPairs();
267 return nResult;
271 void FormLinkDialog::initializeFieldLists()
273 Sequence< OUString > sDetailFields;
274 getFormFields( m_xDetailForm, sDetailFields );
276 Sequence< OUString > sMasterFields;
277 getFormFields( m_xMasterForm, sMasterFields );
279 FieldLinkRow* aRows[] = {
280 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get()
282 for (FieldLinkRow* aRow : aRows)
284 aRow->fillList( FieldLinkRow::eDetailField, sDetailFields );
285 aRow->fillList( FieldLinkRow::eMasterField, sMasterFields );
291 void FormLinkDialog::initializeColumnLabels()
293 // label for the detail form
294 OUString sDetailType = getFormDataSourceType( m_xDetailForm );
295 if ( sDetailType.isEmpty() )
297 if ( m_sDetailLabel.isEmpty() )
299 m_sDetailLabel = PcrRes(STR_DETAIL_FORM);
301 sDetailType = m_sDetailLabel;
303 m_pDetailLabel->SetText( sDetailType );
305 // label for the master form
306 OUString sMasterType = getFormDataSourceType( m_xMasterForm );
307 if ( sMasterType.isEmpty() )
309 if ( m_sMasterLabel.isEmpty() )
311 m_sMasterLabel = PcrRes(STR_MASTER_FORM);
313 sMasterType = m_sMasterLabel;
315 m_pMasterLabel->SetText( sMasterType );
319 void FormLinkDialog::initializeFieldRowsFrom( std::vector< OUString >& _rDetailFields, std::vector< OUString >& _rMasterFields )
321 // our UI does allow 4 fields max
322 _rDetailFields.resize( 4 );
323 _rMasterFields.resize( 4 );
325 FieldLinkRow* aRows[] = {
326 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get()
328 for ( sal_Int32 i = 0; i < 4; ++i )
330 aRows[ i ]->SetFieldName( FieldLinkRow::eDetailField, _rDetailFields[i] );
331 aRows[ i ]->SetFieldName( FieldLinkRow::eMasterField, _rMasterFields[i] );
336 void FormLinkDialog::initializeLinks()
340 Sequence< OUString > aDetailFields;
341 Sequence< OUString > aMasterFields;
343 Reference< XPropertySet > xDetailFormProps( m_xDetailForm, UNO_QUERY );
344 if ( xDetailFormProps.is() )
346 xDetailFormProps->getPropertyValue( PROPERTY_DETAILFIELDS ) >>= aDetailFields;
347 xDetailFormProps->getPropertyValue( PROPERTY_MASTERFIELDS ) >>= aMasterFields;
350 std::vector< OUString > aDetailFields1;
351 comphelper::sequenceToContainer(aDetailFields1, aDetailFields);
352 std::vector< OUString > aMasterFields1;
353 comphelper::sequenceToContainer(aMasterFields1, aMasterFields);
354 initializeFieldRowsFrom( aDetailFields1, aMasterFields1 );
356 catch( const Exception& )
358 OSL_FAIL( "FormLinkDialog::initializeLinks: caught an exception!" );
363 void FormLinkDialog::updateOkButton()
365 // in all rows, there must be either two valid selections, or none at all
366 // If there is at least one row with exactly one valid selection, then the
367 // OKButton needs to be disabled
368 bool bEnable = true;
370 const FieldLinkRow* aRows[] = {
371 m_aRow1.get(), m_aRow2.get(), m_aRow3.get(), m_aRow4.get()
374 for ( sal_Int32 i = 0; ( i < 4 ) && bEnable; ++i )
376 OUString sNotInterestedInRightNow;
377 if ( aRows[ i ]->GetFieldName( FieldLinkRow::eDetailField, sNotInterestedInRightNow )
378 != aRows[ i ]->GetFieldName( FieldLinkRow::eMasterField, sNotInterestedInRightNow )
380 bEnable = false;
383 m_pOK->Enable( bEnable );
387 OUString FormLinkDialog::getFormDataSourceType( const Reference< XPropertySet >& _rxForm )
389 OUString sReturn;
390 if ( !_rxForm.is() )
391 return sReturn;
395 sal_Int32 nCommandType = CommandType::COMMAND;
396 OUString sCommand;
398 _rxForm->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType;
399 _rxForm->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand;
401 if ( ( nCommandType == CommandType::TABLE )
402 || ( nCommandType == CommandType::QUERY )
404 sReturn = sCommand;
406 catch( const Exception& )
408 OSL_FAIL( "FormLinkDialog::getFormDataSourceType: caught an exception!" );
410 return sReturn;
414 void FormLinkDialog::getFormFields( const Reference< XPropertySet >& _rxForm, Sequence< OUString >& /* [out] */ _rNames ) const
416 _rNames.realloc( 0 );
418 ::dbtools::SQLExceptionInfo aErrorInfo;
419 OUString sCommand;
422 WaitObject aWaitCursor( const_cast< FormLinkDialog* >( this ) );
424 OSL_ENSURE( _rxForm.is(), "FormLinkDialog::getFormFields: invalid form!" );
426 sal_Int32 nCommandType = CommandType::COMMAND;
428 _rxForm->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType;
429 _rxForm->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand;
431 Reference< XConnection > xConnection;
432 ensureFormConnection( _rxForm, xConnection );
434 _rNames = ::dbtools::getFieldNamesByCommandDescriptor(
435 xConnection,
436 nCommandType,
437 sCommand,
438 &aErrorInfo
441 catch (const SQLContext& e) { aErrorInfo = e; }
442 catch (const SQLWarning& e) { aErrorInfo = e; }
443 catch (const SQLException& e ) { aErrorInfo = e; }
444 catch( const Exception& )
446 OSL_FAIL( "FormLinkDialog::getFormFields: caught a non-SQL exception!" );
449 if ( aErrorInfo.isValid() )
451 OUString sErrorMessage;
453 sErrorMessage = PcrRes(STR_ERROR_RETRIEVING_COLUMNS);
454 sErrorMessage = sErrorMessage.replaceFirst("#", sCommand);
457 SQLContext aContext;
458 aContext.Message = sErrorMessage;
459 aContext.NextException = aErrorInfo.get();
460 ::dbtools::showError( aContext, VCLUnoHelper::GetInterface( const_cast< FormLinkDialog* >( this ) ), m_xContext );
465 void FormLinkDialog::ensureFormConnection( const Reference< XPropertySet >& _rxFormProps, Reference< XConnection >& /* [out] */ _rxConnection ) const
467 OSL_PRECOND( _rxFormProps.is(), "FormLinkDialog::ensureFormConnection: invalid form!" );
468 if ( !_rxFormProps.is() )
469 return;
470 if ( _rxFormProps->getPropertySetInfo()->hasPropertyByName(PROPERTY_ACTIVE_CONNECTION) )
471 _rxConnection.set(_rxFormProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
473 if ( !_rxConnection.is() )
474 _rxConnection = ::dbtools::connectRowset( Reference< XRowSet >( _rxFormProps, UNO_QUERY ), m_xContext, true );
478 void FormLinkDialog::getConnectionMetaData( const Reference< XPropertySet >& _rxFormProps, Reference< XDatabaseMetaData >& /* [out] */ _rxMeta )
480 if ( _rxFormProps.is() )
482 Reference< XConnection > xConnection;
483 if ( !::dbtools::isEmbeddedInDatabase( _rxFormProps, xConnection ) )
484 _rxFormProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
485 if ( xConnection.is() )
486 _rxMeta = xConnection->getMetaData();
491 Reference< XPropertySet > FormLinkDialog::getCanonicUnderlyingTable( const Reference< XPropertySet >& _rxFormProps ) const
493 Reference< XPropertySet > xTable;
496 Reference< XTablesSupplier > xTablesInForm( ::dbtools::getCurrentSettingsComposer( _rxFormProps, m_xContext ), UNO_QUERY );
497 Reference< XNameAccess > xTables;
498 if ( xTablesInForm.is() )
499 xTables = xTablesInForm->getTables();
500 Sequence< OUString > aTableNames;
501 if ( xTables.is() )
502 aTableNames = xTables->getElementNames();
504 if ( aTableNames.getLength() == 1 )
506 xTables->getByName( aTableNames[ 0 ] ) >>= xTable;
507 OSL_ENSURE( xTable.is(), "FormLinkDialog::getCanonicUnderlyingTable: invalid table!" );
510 catch( const Exception& )
512 OSL_FAIL( "FormLinkDialog::getCanonicUnderlyingTable: caught an exception!" );
514 return xTable;
518 bool FormLinkDialog::getExistingRelation( const Reference< XPropertySet >& _rxLHS, const Reference< XPropertySet >& /*_rxRHS*/,
519 // TODO: fix the usage of _rxRHS. This is issue #i81956#.
520 std::vector< OUString >& _rLeftFields, std::vector< OUString >& _rRightFields )
524 Reference< XKeysSupplier > xSuppKeys( _rxLHS, UNO_QUERY );
525 Reference< XIndexAccess > xKeys;
526 if ( xSuppKeys.is() )
527 xKeys = xSuppKeys->getKeys();
529 if ( xKeys.is() )
531 Reference< XPropertySet > xKey;
532 Reference< XColumnsSupplier > xKeyColSupp( xKey, UNO_QUERY );
533 Reference< XIndexAccess > xKeyColumns;
534 Reference< XPropertySet > xKeyColumn;
535 OUString sColumnName, sRelatedColumnName;
537 const sal_Int32 keyCount = xKeys->getCount();
538 for ( sal_Int32 key = 0; key < keyCount; ++key )
540 xKeys->getByIndex( key ) >>= xKey;
541 sal_Int32 nKeyType = 0;
542 xKey->getPropertyValue("Type") >>= nKeyType;
543 if ( nKeyType != KeyType::FOREIGN )
544 continue;
546 xKeyColumns.clear();
547 xKeyColSupp.set(xKey, css::uno::UNO_QUERY);
548 if ( xKeyColSupp.is() )
549 xKeyColumns.set(xKeyColSupp->getColumns(), css::uno::UNO_QUERY);
550 OSL_ENSURE( xKeyColumns.is(), "FormLinkDialog::getExistingRelation: could not obtain the columns for the key!" );
552 if ( !xKeyColumns.is() )
553 continue;
555 const sal_Int32 columnCount = xKeyColumns->getCount();
556 _rLeftFields.resize( columnCount );
557 _rRightFields.resize( columnCount );
558 for ( sal_Int32 column = 0; column < columnCount; ++column )
560 xKeyColumn.clear();
561 xKeyColumns->getByIndex( column ) >>= xKeyColumn;
562 OSL_ENSURE( xKeyColumn.is(), "FormLinkDialog::getExistingRelation: invalid key column!" );
563 if ( xKeyColumn.is() )
565 xKeyColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName;
566 xKeyColumn->getPropertyValue("RelatedColumn") >>= sRelatedColumnName;
568 _rLeftFields[ column ] = sColumnName;
569 _rRightFields[ column ] = sRelatedColumnName;
575 catch( const Exception& )
577 OSL_FAIL( "FormLinkDialog::getExistingRelation: caught an exception!" );
580 return ( !_rLeftFields.empty() ) && ( !_rLeftFields[ 0 ].isEmpty() );
584 void FormLinkDialog::initializeSuggest()
586 Reference< XPropertySet > xDetailFormProps( m_xDetailForm, UNO_QUERY );
587 Reference< XPropertySet > xMasterFormProps( m_xMasterForm, UNO_QUERY );
588 if ( !xDetailFormProps.is() || !xMasterFormProps.is() )
589 return;
593 bool bEnable = true;
595 // only show the button when both forms are based on the same data source
596 if ( bEnable )
598 OUString sMasterDS, sDetailDS;
599 xMasterFormProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sMasterDS;
600 xDetailFormProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sDetailDS;
601 bEnable = ( sMasterDS == sDetailDS );
604 // only show the button when the connection supports relations
605 if ( bEnable )
607 Reference< XDatabaseMetaData > xMeta;
608 getConnectionMetaData( xDetailFormProps, xMeta );
609 OSL_ENSURE( xMeta.is(), "FormLinkDialog::initializeSuggest: unable to retrieve the meta data for the connection!" );
612 bEnable = xMeta.is() && xMeta->supportsIntegrityEnhancementFacility();
614 catch(const Exception&)
616 bEnable = false;
620 // only enable the button if there is a "canonic" table underlying both forms
621 Reference< XPropertySet > xDetailTable, xMasterTable;
622 if ( bEnable )
624 xDetailTable = getCanonicUnderlyingTable( xDetailFormProps );
625 xMasterTable = getCanonicUnderlyingTable( xMasterFormProps );
626 bEnable = xDetailTable.is() && xMasterTable.is();
629 // only enable the button if there is a relation between both tables
630 m_aRelationDetailColumns.clear();
631 m_aRelationMasterColumns.clear();
632 if ( bEnable )
634 bEnable = getExistingRelation( xDetailTable, xMasterTable, m_aRelationDetailColumns, m_aRelationMasterColumns );
635 SAL_WARN_IF( m_aRelationMasterColumns.size() != m_aRelationDetailColumns.size(),
636 "extensions.propctrlr",
637 "FormLinkDialog::initializeSuggest: nonsense!" );
638 if ( m_aRelationMasterColumns.empty() )
639 { // okay, there is no relation "pointing" (via a foreign key) from the detail table to the master table
640 // but perhaps the other way round (would make less sense, but who knows ...)
641 bEnable = getExistingRelation( xMasterTable, xDetailTable, m_aRelationMasterColumns, m_aRelationDetailColumns );
645 // only enable the button if the relation contains at most 4 field pairs
646 if ( bEnable )
648 bEnable = ( m_aRelationMasterColumns.size() <= 4 );
651 m_pSuggest->Enable( bEnable );
653 catch( const Exception& )
655 OSL_FAIL( "FormLinkDialog::initializeSuggest: caught an exception!" );
660 IMPL_LINK_NOARG( FormLinkDialog, OnSuggest, Button*, void )
662 initializeFieldRowsFrom( m_aRelationDetailColumns, m_aRelationMasterColumns );
666 IMPL_LINK_NOARG( FormLinkDialog, OnFieldChanged, FieldLinkRow&, void )
668 updateOkButton();
672 IMPL_LINK_NOARG( FormLinkDialog, OnInitialize, void*, void )
674 initializeColumnLabels();
675 initializeFieldLists();
676 initializeLinks();
677 initializeSuggest();
680 } // namespace pcr
683 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */