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