1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
65 class FieldLinkRow
: public TabPage
68 VclPtr
<ComboBox
> m_pDetailColumn
;
69 VclPtr
<ComboBox
> m_pMasterColumn
;
71 Link
<FieldLinkRow
&,void> m_aLinkChangeHandler
;
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
; }
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
);
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()
116 void FieldLinkRow::dispose()
118 m_pDetailColumn
.clear();
119 m_pMasterColumn
.clear();
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
)
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");
178 get(m_pSuggest
, "suggestButton");
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 );
200 FormLinkDialog::~FormLinkDialog( )
205 void FormLinkDialog::dispose( )
207 m_pExplanation
.clear();
208 m_pDetailLabel
.clear();
209 m_pMasterLabel
.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() )
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
)
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
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
)
383 m_pOK
->Enable( bEnable
);
387 OUString
FormLinkDialog::getFormDataSourceType( const Reference
< XPropertySet
>& _rxForm
)
395 sal_Int32 nCommandType
= CommandType::COMMAND
;
398 _rxForm
->getPropertyValue( PROPERTY_COMMANDTYPE
) >>= nCommandType
;
399 _rxForm
->getPropertyValue( PROPERTY_COMMAND
) >>= sCommand
;
401 if ( ( nCommandType
== CommandType::TABLE
)
402 || ( nCommandType
== CommandType::QUERY
)
406 catch( const Exception
& )
408 OSL_FAIL( "FormLinkDialog::getFormDataSourceType: caught an exception!" );
414 void FormLinkDialog::getFormFields( const Reference
< XPropertySet
>& _rxForm
, Sequence
< OUString
>& /* [out] */ _rNames
) const
416 _rNames
.realloc( 0 );
418 ::dbtools::SQLExceptionInfo aErrorInfo
;
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(
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
);
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() )
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
;
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!" );
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();
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
)
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() )
555 const sal_Int32 columnCount
= xKeyColumns
->getCount();
556 _rLeftFields
.resize( columnCount
);
557 _rRightFields
.resize( columnCount
);
558 for ( sal_Int32 column
= 0; column
< columnCount
; ++column
)
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() )
595 // only show the button when both forms are based on the same data source
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
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
&)
620 // only enable the button if there is a "canonic" table underlying both forms
621 Reference
< XPropertySet
> xDetailTable
, xMasterTable
;
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();
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
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 )
672 IMPL_LINK_NOARG( FormLinkDialog
, OnInitialize
, void*, void )
674 initializeColumnLabels();
675 initializeFieldLists();
683 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */