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