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 <strings.hrc>
25 #include "formstrings.hxx"
26 #include <sal/log.hxx>
27 #include <comphelper/diagnose_ex.hxx>
29 #include <vcl/svapp.hxx>
30 #include <connectivity/dbtools.hxx>
31 #include <connectivity/dbexception.hxx>
32 #include <comphelper/sequence.hxx>
34 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
35 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
36 #include <com/sun/star/sdbcx/KeyType.hpp>
37 #include <com/sun/star/container/XNameAccess.hpp>
38 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
39 #include <com/sun/star/sdbc/XRowSet.hpp>
40 #include <com/sun/star/sdb/CommandType.hpp>
41 #include <com/sun/star/sdb/SQLContext.hpp>
42 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
48 using namespace ::com::sun::star::uno
;
49 using namespace ::com::sun::star::sdb
;
50 using namespace ::com::sun::star::sdbc
;
51 using namespace ::com::sun::star::sdbcx
;
52 using namespace ::com::sun::star::beans
;
53 using namespace ::com::sun::star::container
;
61 std::unique_ptr
<weld::ComboBox
> m_xDetailColumn
;
62 std::unique_ptr
<weld::ComboBox
> m_xMasterColumn
;
64 Link
<FieldLinkRow
&,void> m_aLinkChangeHandler
;
67 FieldLinkRow(std::unique_ptr
<weld::ComboBox
> xDetailColumn
,
68 std::unique_ptr
<weld::ComboBox
> xMasterColumn
);
71 void SetLinkChangeHandler( const Link
<FieldLinkRow
&,void>& _rHdl
) { m_aLinkChangeHandler
= _rHdl
; }
78 /** retrieves the selected field name for either the master or the detail field
79 @return <TRUE/> if and only a valid field is selected
81 bool GetFieldName( LinkParticipant _eWhich
, OUString
& /* [out] */ _rName
) const;
82 void SetFieldName( LinkParticipant _eWhich
, const OUString
& _rName
);
84 void fillList( LinkParticipant _eWhich
, const Sequence
< OUString
>& _rFieldNames
);
88 m_xDetailColumn
->show();
89 m_xMasterColumn
->show();
93 DECL_LINK( OnFieldNameChanged
, weld::ComboBox
&, void );
97 FieldLinkRow::FieldLinkRow(std::unique_ptr
<weld::ComboBox
> xDetailColumn
,
98 std::unique_ptr
<weld::ComboBox
> xMasterColumn
)
99 : m_xDetailColumn(std::move(xDetailColumn
))
100 , m_xMasterColumn(std::move(xMasterColumn
))
102 m_xDetailColumn
->connect_changed( LINK( this, FieldLinkRow
, OnFieldNameChanged
) );
103 m_xMasterColumn
->connect_changed( LINK( this, FieldLinkRow
, OnFieldNameChanged
) );
106 void FieldLinkRow::fillList( LinkParticipant _eWhich
, const Sequence
< OUString
>& _rFieldNames
)
108 weld::ComboBox
* pBox
= ( _eWhich
== eDetailField
) ? m_xDetailColumn
.get() : m_xMasterColumn
.get();
110 const OUString
* pFieldName
= _rFieldNames
.getConstArray();
111 const OUString
* pFieldNameEnd
= pFieldName
+ _rFieldNames
.getLength();
112 for ( ; pFieldName
!= pFieldNameEnd
; ++pFieldName
)
113 pBox
->append_text( *pFieldName
);
116 bool FieldLinkRow::GetFieldName( LinkParticipant _eWhich
, OUString
& /* [out] */ _rName
) const
118 const weld::ComboBox
* pBox
= ( _eWhich
== eDetailField
) ? m_xDetailColumn
.get() : m_xMasterColumn
.get();
119 _rName
= pBox
->get_active_text();
120 return !_rName
.isEmpty();
123 void FieldLinkRow::SetFieldName( LinkParticipant _eWhich
, const OUString
& _rName
)
125 weld::ComboBox
* pBox
= ( _eWhich
== eDetailField
) ? m_xDetailColumn
.get() : m_xMasterColumn
.get();
126 pBox
->set_entry_text( _rName
);
129 IMPL_LINK_NOARG( FieldLinkRow
, OnFieldNameChanged
, weld::ComboBox
&, void )
131 m_aLinkChangeHandler
.Call( *this );
136 FormLinkDialog::FormLinkDialog(weld::Window
* _pParent
, const Reference
< XPropertySet
>& _rxDetailForm
,
137 const Reference
< XPropertySet
>& _rxMasterForm
, const Reference
< XComponentContext
>& _rxContext
,
138 const OUString
& _sExplanation
,
139 OUString _sDetailLabel
,
140 OUString _sMasterLabel
)
141 : GenericDialogController(_pParent
, u
"modules/spropctrlr/ui/formlinksdialog.ui"_ustr
, u
"FormLinks"_ustr
)
142 , m_xContext ( _rxContext
)
143 , m_xDetailForm( _rxDetailForm
)
144 , m_xMasterForm( _rxMasterForm
)
145 , m_sDetailLabel(std::move(_sDetailLabel
))
146 , m_sMasterLabel(std::move(_sMasterLabel
))
147 , m_xExplanation(m_xBuilder
->weld_label(u
"explanationLabel"_ustr
))
148 , m_xDetailLabel(m_xBuilder
->weld_label(u
"detailLabel"_ustr
))
149 , m_xMasterLabel(m_xBuilder
->weld_label(u
"masterLabel"_ustr
))
150 , m_xRow1(std::make_unique
<FieldLinkRow
>(m_xBuilder
->weld_combo_box(u
"detailCombobox1"_ustr
),
151 m_xBuilder
->weld_combo_box(u
"masterCombobox1"_ustr
)))
152 , m_xRow2(std::make_unique
<FieldLinkRow
>(m_xBuilder
->weld_combo_box(u
"detailCombobox2"_ustr
),
153 m_xBuilder
->weld_combo_box(u
"masterCombobox2"_ustr
)))
154 , m_xRow3(std::make_unique
<FieldLinkRow
>(m_xBuilder
->weld_combo_box(u
"detailCombobox3"_ustr
),
155 m_xBuilder
->weld_combo_box(u
"masterCombobox3"_ustr
)))
156 , m_xRow4(std::make_unique
<FieldLinkRow
>(m_xBuilder
->weld_combo_box(u
"detailCombobox4"_ustr
),
157 m_xBuilder
->weld_combo_box(u
"masterCombobox4"_ustr
)))
158 , m_xOK(m_xBuilder
->weld_button(u
"ok"_ustr
))
159 , m_xSuggest(m_xBuilder
->weld_button(u
"suggestButton"_ustr
))
165 m_xDialog
->set_size_request(600, -1);
167 if ( !_sExplanation
.isEmpty() )
168 m_xExplanation
->set_label(_sExplanation
);
170 m_xSuggest
->connect_clicked(LINK(this, FormLinkDialog
, OnSuggest
));
171 m_xRow1
->SetLinkChangeHandler( LINK( this, FormLinkDialog
, OnFieldChanged
) );
172 m_xRow2
->SetLinkChangeHandler( LINK( this, FormLinkDialog
, OnFieldChanged
) );
173 m_xRow3
->SetLinkChangeHandler( LINK( this, FormLinkDialog
, OnFieldChanged
) );
174 m_xRow4
->SetLinkChangeHandler( LINK( this, FormLinkDialog
, OnFieldChanged
) );
176 Application::PostUserEvent(LINK(this, FormLinkDialog
, OnInitialize
));
181 FormLinkDialog::~FormLinkDialog()
185 void FormLinkDialog::commitLinkPairs()
187 // collect the field lists from the rows
188 std::vector
< OUString
> aDetailFields
; aDetailFields
.reserve( 4 );
189 std::vector
< OUString
> aMasterFields
; aMasterFields
.reserve( 4 );
191 const FieldLinkRow
* aRows
[] = {
192 m_xRow1
.get(), m_xRow2
.get(), m_xRow3
.get(), m_xRow4
.get()
195 for (const FieldLinkRow
* aRow
: aRows
)
197 OUString sDetailField
, sMasterField
;
198 aRow
->GetFieldName( FieldLinkRow::eDetailField
, sDetailField
);
199 aRow
->GetFieldName( FieldLinkRow::eMasterField
, sMasterField
);
200 if ( sDetailField
.isEmpty() && sMasterField
.isEmpty() )
203 aDetailFields
.push_back( sDetailField
);
204 aMasterFields
.push_back( sMasterField
);
207 // and set as property values
210 if ( m_xDetailForm
.is() )
212 m_xDetailForm
->setPropertyValue( PROPERTY_DETAILFIELDS
, Any( Sequence
< OUString
>( aDetailFields
.data(), aDetailFields
.size() ) ) );
213 m_xDetailForm
->setPropertyValue( PROPERTY_MASTERFIELDS
, Any( Sequence
< OUString
>( aMasterFields
.data(), aMasterFields
.size() ) ) );
216 catch( const Exception
& )
218 TOOLS_WARN_EXCEPTION("extensions.propctrlr",
219 "caught an exception while setting the properties!");
223 short FormLinkDialog::run()
225 short nResult
= GenericDialogController::run();
227 if ( RET_OK
== nResult
)
233 void FormLinkDialog::initializeFieldLists()
235 Sequence
< OUString
> sDetailFields
;
236 getFormFields( m_xDetailForm
, sDetailFields
);
238 Sequence
< OUString
> sMasterFields
;
239 getFormFields( m_xMasterForm
, sMasterFields
);
241 FieldLinkRow
* aRows
[] = {
242 m_xRow1
.get(), m_xRow2
.get(), m_xRow3
.get(), m_xRow4
.get()
244 for (FieldLinkRow
* aRow
: aRows
)
246 aRow
->fillList( FieldLinkRow::eDetailField
, sDetailFields
);
247 aRow
->fillList( FieldLinkRow::eMasterField
, sMasterFields
);
253 void FormLinkDialog::initializeColumnLabels()
255 // label for the detail form
256 OUString sDetailType
= getFormDataSourceType( m_xDetailForm
);
257 if ( sDetailType
.isEmpty() )
259 if ( m_sDetailLabel
.isEmpty() )
261 m_sDetailLabel
= PcrRes(STR_DETAIL_FORM
);
263 sDetailType
= m_sDetailLabel
;
265 m_xDetailLabel
->set_label( sDetailType
);
267 // label for the master form
268 OUString sMasterType
= getFormDataSourceType( m_xMasterForm
);
269 if ( sMasterType
.isEmpty() )
271 if ( m_sMasterLabel
.isEmpty() )
273 m_sMasterLabel
= PcrRes(STR_MASTER_FORM
);
275 sMasterType
= m_sMasterLabel
;
277 m_xMasterLabel
->set_label( sMasterType
);
280 void FormLinkDialog::initializeFieldRowsFrom( std::vector
< OUString
>& _rDetailFields
, std::vector
< OUString
>& _rMasterFields
)
282 // our UI does allow 4 fields max
283 _rDetailFields
.resize( 4 );
284 _rMasterFields
.resize( 4 );
286 FieldLinkRow
* aRows
[] = {
287 m_xRow1
.get(), m_xRow2
.get(), m_xRow3
.get(), m_xRow4
.get()
289 for ( sal_Int32 i
= 0; i
< 4; ++i
)
291 aRows
[ i
]->SetFieldName( FieldLinkRow::eDetailField
, _rDetailFields
[i
] );
292 aRows
[ i
]->SetFieldName( FieldLinkRow::eMasterField
, _rMasterFields
[i
] );
297 void FormLinkDialog::initializeLinks()
301 Sequence
< OUString
> aDetailFields
;
302 Sequence
< OUString
> aMasterFields
;
304 if ( m_xDetailForm
.is() )
306 m_xDetailForm
->getPropertyValue( PROPERTY_DETAILFIELDS
) >>= aDetailFields
;
307 m_xDetailForm
->getPropertyValue( PROPERTY_MASTERFIELDS
) >>= aMasterFields
;
310 std::vector
< OUString
> aDetailFields1
;
311 comphelper::sequenceToContainer(aDetailFields1
, aDetailFields
);
312 std::vector
< OUString
> aMasterFields1
;
313 comphelper::sequenceToContainer(aMasterFields1
, aMasterFields
);
314 initializeFieldRowsFrom( aDetailFields1
, aMasterFields1
);
316 catch( const Exception
& )
318 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::initializeLinks" );
323 void FormLinkDialog::updateOkButton()
325 // in all rows, there must be either two valid selections, or none at all
326 // If there is at least one row with exactly one valid selection, then the
327 // OKButton needs to be disabled
330 const FieldLinkRow
* aRows
[] = {
331 m_xRow1
.get(), m_xRow2
.get(), m_xRow3
.get(), m_xRow4
.get()
334 for ( sal_Int32 i
= 0; ( i
< 4 ) && bEnable
; ++i
)
336 OUString sNotInterestedInRightNow
;
337 if ( aRows
[ i
]->GetFieldName( FieldLinkRow::eDetailField
, sNotInterestedInRightNow
)
338 != aRows
[ i
]->GetFieldName( FieldLinkRow::eMasterField
, sNotInterestedInRightNow
)
343 m_xOK
->set_sensitive(bEnable
);
346 OUString
FormLinkDialog::getFormDataSourceType( const Reference
< XPropertySet
>& _rxForm
)
354 sal_Int32 nCommandType
= CommandType::COMMAND
;
357 _rxForm
->getPropertyValue( PROPERTY_COMMANDTYPE
) >>= nCommandType
;
358 _rxForm
->getPropertyValue( PROPERTY_COMMAND
) >>= sCommand
;
360 if ( ( nCommandType
== CommandType::TABLE
)
361 || ( nCommandType
== CommandType::QUERY
)
365 catch( const Exception
& )
367 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getFormDataSourceType" );
372 void FormLinkDialog::getFormFields( const Reference
< XPropertySet
>& _rxForm
, Sequence
< OUString
>& /* [out] */ _rNames
) const
374 _rNames
.realloc( 0 );
376 ::dbtools::SQLExceptionInfo aErrorInfo
;
380 weld::WaitObject
aWaitCursor(m_xDialog
.get());
382 OSL_ENSURE( _rxForm
.is(), "FormLinkDialog::getFormFields: invalid form!" );
384 sal_Int32 nCommandType
= CommandType::COMMAND
;
386 _rxForm
->getPropertyValue( PROPERTY_COMMANDTYPE
) >>= nCommandType
;
387 _rxForm
->getPropertyValue( PROPERTY_COMMAND
) >>= sCommand
;
389 Reference
< XConnection
> xConnection
;
390 ensureFormConnection( _rxForm
, xConnection
);
392 _rNames
= ::dbtools::getFieldNamesByCommandDescriptor(
399 catch (const SQLContext
& e
) { aErrorInfo
= e
; }
400 catch (const SQLWarning
& e
) { aErrorInfo
= e
; }
401 catch (const SQLException
& e
) { aErrorInfo
= e
; }
402 catch( const Exception
& )
404 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getFormFields: caught a non-SQL exception!" );
407 if ( !aErrorInfo
.isValid() )
410 OUString sErrorMessage
;
412 sErrorMessage
= PcrRes(STR_ERROR_RETRIEVING_COLUMNS
);
413 sErrorMessage
= sErrorMessage
.replaceFirst("#", sCommand
);
416 SQLContext
aContext(sErrorMessage
, {}, {}, 0, aErrorInfo
.get(), {});
417 ::dbtools::showError(aContext
, m_xDialog
->GetXWindow(), m_xContext
);
420 void FormLinkDialog::ensureFormConnection( const Reference
< XPropertySet
>& _rxFormProps
, Reference
< XConnection
>& /* [out] */ _rxConnection
) const
422 OSL_PRECOND( _rxFormProps
.is(), "FormLinkDialog::ensureFormConnection: invalid form!" );
423 if ( !_rxFormProps
.is() )
425 if ( _rxFormProps
->getPropertySetInfo()->hasPropertyByName(PROPERTY_ACTIVE_CONNECTION
) )
426 _rxConnection
.set(_rxFormProps
->getPropertyValue(PROPERTY_ACTIVE_CONNECTION
),UNO_QUERY
);
428 if ( !_rxConnection
.is() )
429 _rxConnection
= ::dbtools::connectRowset( Reference
< XRowSet
>( _rxFormProps
, UNO_QUERY
), m_xContext
, nullptr );
433 void FormLinkDialog::getConnectionMetaData( const Reference
< XPropertySet
>& _rxFormProps
, Reference
< XDatabaseMetaData
>& /* [out] */ _rxMeta
)
435 if ( _rxFormProps
.is() )
437 Reference
< XConnection
> xConnection
;
438 if ( !::dbtools::isEmbeddedInDatabase( _rxFormProps
, xConnection
) )
439 _rxFormProps
->getPropertyValue( PROPERTY_ACTIVE_CONNECTION
) >>= xConnection
;
440 if ( xConnection
.is() )
441 _rxMeta
= xConnection
->getMetaData();
446 Reference
< XPropertySet
> FormLinkDialog::getCanonicUnderlyingTable( const Reference
< XPropertySet
>& _rxFormProps
) const
448 Reference
< XPropertySet
> xTable
;
451 Reference
< XTablesSupplier
> xTablesInForm( ::dbtools::getCurrentSettingsComposer( _rxFormProps
, m_xContext
, nullptr ), UNO_QUERY
);
452 Reference
< XNameAccess
> xTables
;
453 if ( xTablesInForm
.is() )
454 xTables
= xTablesInForm
->getTables();
455 Sequence
< OUString
> aTableNames
;
457 aTableNames
= xTables
->getElementNames();
459 if ( aTableNames
.getLength() == 1 )
461 xTables
->getByName( aTableNames
[ 0 ] ) >>= xTable
;
462 OSL_ENSURE( xTable
.is(), "FormLinkDialog::getCanonicUnderlyingTable: invalid table!" );
465 catch( const Exception
& )
467 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getCanonicUnderlyingTable" );
473 bool FormLinkDialog::getExistingRelation( const Reference
< XPropertySet
>& _rxLHS
, const Reference
< XPropertySet
>& /*_rxRHS*/,
474 // TODO: fix the usage of _rxRHS. This is issue #i81956#.
475 std::vector
< OUString
>& _rLeftFields
, std::vector
< OUString
>& _rRightFields
)
479 Reference
< XKeysSupplier
> xSuppKeys( _rxLHS
, UNO_QUERY
);
480 Reference
< XIndexAccess
> xKeys
;
481 if ( xSuppKeys
.is() )
482 xKeys
= xSuppKeys
->getKeys();
486 Reference
< XPropertySet
> xKey
;
487 Reference
< XColumnsSupplier
> xKeyColSupp( xKey
, UNO_QUERY
);
488 Reference
< XIndexAccess
> xKeyColumns
;
489 Reference
< XPropertySet
> xKeyColumn
;
490 OUString sColumnName
, sRelatedColumnName
;
492 const sal_Int32 keyCount
= xKeys
->getCount();
493 for ( sal_Int32 key
= 0; key
< keyCount
; ++key
)
495 xKeys
->getByIndex( key
) >>= xKey
;
496 sal_Int32 nKeyType
= 0;
497 xKey
->getPropertyValue(u
"Type"_ustr
) >>= nKeyType
;
498 if ( nKeyType
!= KeyType::FOREIGN
)
502 xKeyColSupp
.set(xKey
, css::uno::UNO_QUERY
);
503 if ( xKeyColSupp
.is() )
504 xKeyColumns
.set(xKeyColSupp
->getColumns(), css::uno::UNO_QUERY
);
505 OSL_ENSURE( xKeyColumns
.is(), "FormLinkDialog::getExistingRelation: could not obtain the columns for the key!" );
507 if ( !xKeyColumns
.is() )
510 const sal_Int32 columnCount
= xKeyColumns
->getCount();
511 _rLeftFields
.resize( columnCount
);
512 _rRightFields
.resize( columnCount
);
513 for ( sal_Int32 column
= 0; column
< columnCount
; ++column
)
516 xKeyColumns
->getByIndex( column
) >>= xKeyColumn
;
517 OSL_ENSURE( xKeyColumn
.is(), "FormLinkDialog::getExistingRelation: invalid key column!" );
518 if ( xKeyColumn
.is() )
520 xKeyColumn
->getPropertyValue( PROPERTY_NAME
) >>= sColumnName
;
521 xKeyColumn
->getPropertyValue(u
"RelatedColumn"_ustr
) >>= sRelatedColumnName
;
523 _rLeftFields
[ column
] = sColumnName
;
524 _rRightFields
[ column
] = sRelatedColumnName
;
530 catch( const Exception
& )
532 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getExistingRelation" );
535 return ( !_rLeftFields
.empty() ) && ( !_rLeftFields
[ 0 ].isEmpty() );
539 void FormLinkDialog::initializeSuggest()
541 if ( !m_xDetailForm
.is() || !m_xMasterForm
.is() )
546 // only show the button when both forms are based on the same data source
547 OUString sMasterDS
, sDetailDS
;
548 m_xMasterForm
->getPropertyValue( PROPERTY_DATASOURCE
) >>= sMasterDS
;
549 m_xDetailForm
->getPropertyValue( PROPERTY_DATASOURCE
) >>= sDetailDS
;
550 bool bEnable
= ( sMasterDS
== sDetailDS
);
552 // only show the button when the connection supports relations
555 Reference
< XDatabaseMetaData
> xMeta
;
556 getConnectionMetaData( m_xDetailForm
, xMeta
);
557 OSL_ENSURE( xMeta
.is(), "FormLinkDialog::initializeSuggest: unable to retrieve the meta data for the connection!" );
560 bEnable
= xMeta
.is() && xMeta
->supportsIntegrityEnhancementFacility();
562 catch(const Exception
&)
568 // only enable the button if there is a "canonic" table underlying both forms
569 Reference
< XPropertySet
> xDetailTable
, xMasterTable
;
572 xDetailTable
= getCanonicUnderlyingTable( m_xDetailForm
);
573 xMasterTable
= getCanonicUnderlyingTable( m_xMasterForm
);
574 bEnable
= xDetailTable
.is() && xMasterTable
.is();
577 // only enable the button if there is a relation between both tables
578 m_aRelationDetailColumns
.clear();
579 m_aRelationMasterColumns
.clear();
582 bEnable
= getExistingRelation( xDetailTable
, xMasterTable
, m_aRelationDetailColumns
, m_aRelationMasterColumns
);
583 SAL_WARN_IF( m_aRelationMasterColumns
.size() != m_aRelationDetailColumns
.size(),
584 "extensions.propctrlr",
585 "FormLinkDialog::initializeSuggest: nonsense!" );
586 if ( m_aRelationMasterColumns
.empty() )
587 { // okay, there is no relation "pointing" (via a foreign key) from the detail table to the master table
588 // but perhaps the other way round (would make less sense, but who knows ...)
589 bEnable
= getExistingRelation( xMasterTable
, xDetailTable
, m_aRelationMasterColumns
, m_aRelationDetailColumns
);
593 // only enable the button if the relation contains at most 4 field pairs
596 bEnable
= ( m_aRelationMasterColumns
.size() <= 4 );
599 m_xSuggest
->set_sensitive(bEnable
);
601 catch( const Exception
& )
603 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::initializeSuggest" );
607 IMPL_LINK_NOARG( FormLinkDialog
, OnSuggest
, weld::Button
&, void )
609 initializeFieldRowsFrom( m_aRelationDetailColumns
, m_aRelationMasterColumns
);
612 IMPL_LINK_NOARG( FormLinkDialog
, OnFieldChanged
, FieldLinkRow
&, void )
617 IMPL_LINK_NOARG( FormLinkDialog
, OnInitialize
, void*, void )
619 initializeColumnLabels();
620 initializeFieldLists();
628 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */