1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
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.
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).
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.
27 ************************************************************************/
29 #include "dbu_reghelper.hxx"
30 #include <sfx2/sfxsids.hrc>
31 #include "dbu_rel.hrc"
32 #include <vcl/svapp.hxx>
33 #include "browserids.hxx"
34 #include <comphelper/types.hxx>
35 #include "dbustrings.hrc"
36 #include <connectivity/dbtools.hxx>
37 #include <com/sun/star/frame/FrameSearchFlag.hpp>
38 #include <comphelper/extract.hxx>
39 #include <com/sun/star/container/XChild.hpp>
40 #include <com/sun/star/container/XNameContainer.hpp>
41 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
42 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
43 #include <com/sun/star/sdbcx/KeyType.hpp>
44 #include <com/sun/star/sdbcx/XDrop.hpp>
45 #include <com/sun/star/sdbcx/XAlterTable.hpp>
46 #include <com/sun/star/sdbcx/XAppend.hpp>
47 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
48 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
49 #include <com/sun/star/sdb/SQLContext.hpp>
50 #include <com/sun/star/sdbc/SQLWarning.hpp>
51 #include <com/sun/star/sdbc/ColumnValue.hpp>
52 #include <com/sun/star/sdbc/XRow.hpp>
53 #include <connectivity/dbexception.hxx>
54 #include <connectivity/dbmetadata.hxx>
55 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
56 #include <comphelper/streamsection.hxx>
57 #include <comphelper/basicio.hxx>
58 #include <comphelper/seqstream.hxx>
59 #include <com/sun/star/io/XActiveDataSource.hpp>
60 #include <com/sun/star/io/XActiveDataSink.hpp>
61 #include "sqlmessage.hxx"
62 #include "RelationController.hxx"
63 #include <vcl/msgbox.hxx>
64 #include "TableWindowData.hxx"
65 #include "UITools.hxx"
66 #include "RTableConnectionData.hxx"
67 #include "RelationTableView.hxx"
68 #include "RelationDesignView.hxx"
69 #include <tools/debug.hxx>
70 #include <tools/diagnose_ex.h>
71 #include <vcl/waitobj.hxx>
72 #include <osl/thread.hxx>
73 #include <osl/mutex.hxx>
76 #define MAX_THREADS 10
78 extern "C" void SAL_CALL
createRegistryInfo_ORelationControl()
80 static ::dbaui::OMultiInstanceAutoRegistration
< ::dbaui::ORelationController
> aAutoRegistration
;
84 using namespace ::com::sun::star::uno
;
85 using namespace ::com::sun::star::io
;
86 using namespace ::com::sun::star::beans
;
87 using namespace ::com::sun::star::frame
;
88 using namespace ::com::sun::star::util
;
89 using namespace ::com::sun::star::lang
;
90 using namespace ::com::sun::star::container
;
91 using namespace ::com::sun::star::sdbcx
;
92 using namespace ::com::sun::star::sdbc
;
93 using namespace ::com::sun::star::sdb
;
94 using namespace ::com::sun::star::ui::dialogs
;
95 using namespace ::com::sun::star::util
;
96 using namespace ::dbtools
;
97 using namespace ::dbaui
;
98 using namespace ::comphelper
;
99 using namespace ::osl
;
101 //------------------------------------------------------------------------------
102 ::rtl::OUString SAL_CALL
ORelationController::getImplementationName() throw( RuntimeException
)
104 return getImplementationName_Static();
107 //------------------------------------------------------------------------------
108 ::rtl::OUString
ORelationController::getImplementationName_Static() throw( RuntimeException
)
110 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.comp.dbu.ORelationDesign"));
112 //------------------------------------------------------------------------------
113 Sequence
< ::rtl::OUString
> ORelationController::getSupportedServiceNames_Static(void) throw( RuntimeException
)
115 Sequence
< ::rtl::OUString
> aSupported(1);
116 aSupported
.getArray()[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.RelationDesign"));
119 //-------------------------------------------------------------------------
120 Sequence
< ::rtl::OUString
> SAL_CALL
ORelationController::getSupportedServiceNames() throw(RuntimeException
)
122 return getSupportedServiceNames_Static();
124 // -------------------------------------------------------------------------
125 Reference
< XInterface
> SAL_CALL
ORelationController::Create(const Reference
<XMultiServiceFactory
>& _rxFactory
)
127 return *(new ORelationController(_rxFactory
));
129 DBG_NAME(ORelationController
);
130 // -----------------------------------------------------------------------------
131 ORelationController::ORelationController(const Reference
< XMultiServiceFactory
>& _rM
)
132 : OJoinController(_rM
)
134 ,m_bRelationsPossible(sal_True
)
136 DBG_CTOR(ORelationController
,NULL
);
139 // -----------------------------------------------------------------------------
140 ORelationController::~ORelationController()
142 DBG_DTOR(ORelationController
,NULL
);
144 // -----------------------------------------------------------------------------
145 FeatureState
ORelationController::GetState(sal_uInt16 _nId
) const
147 FeatureState aReturn
;
148 aReturn
.bEnabled
= m_bRelationsPossible
;
151 case SID_RELATION_ADD_RELATION
:
152 aReturn
.bEnabled
= !m_vTableData
.empty() && isConnected() && isEditable();
153 aReturn
.bChecked
= false;
155 case ID_BROWSER_SAVEDOC
:
156 aReturn
.bEnabled
= haveDataSource() && impl_isModified();
159 aReturn
= OJoinController::GetState(_nId
);
164 // -----------------------------------------------------------------------------
165 void ORelationController::Execute(sal_uInt16 _nId
, const Sequence
< PropertyValue
>& aArgs
)
169 case ID_BROWSER_SAVEDOC
:
171 OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
172 if(!::dbaui::checkDataSourceAvailable(::comphelper::getString(getDataSource()->getPropertyValue(PROPERTY_NAME
)),getORB()))
174 String
aMessage(ModuleRes(STR_DATASOURCE_DELETED
));
175 OSQLWarningBox( getView(), aMessage
).Execute();
179 // now we save the layout information
180 // create the output stream
183 if ( haveDataSource() && getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION
) )
185 ::comphelper::NamedValueCollection aWindowsData
;
186 saveTableWindows( aWindowsData
);
187 getDataSource()->setPropertyValue( PROPERTY_LAYOUTINFORMATION
, makeAny( aWindowsData
.getPropertyValues() ) );
188 setModified(sal_False
);
191 catch ( const Exception
& )
193 DBG_UNHANDLED_EXCEPTION();
198 case SID_RELATION_ADD_RELATION
:
199 static_cast<ORelationTableView
*>(static_cast<ORelationDesignView
*>( getView() )->getTableView())->AddNewRelation();
202 OJoinController::Execute(_nId
,aArgs
);
205 InvalidateFeature(_nId
);
207 // -----------------------------------------------------------------------------
208 void ORelationController::impl_initialize()
210 OJoinController::impl_initialize();
212 if( !getSdbMetaData().supportsRelations() )
213 {// check if this database supports relations
215 setEditable(sal_False
);
216 m_bRelationsPossible
= sal_False
;
218 String
sTitle(ModuleRes(STR_RELATIONDESIGN
));
220 OSQLMessageBox
aDlg(NULL
,sTitle
,ModuleRes(STR_RELATIONDESIGN_NOT_AVAILABLE
));
224 throw SQLException();
227 if(!m_bRelationsPossible
)
230 // we need a datasource
231 OSL_ENSURE(haveDataSource(),"ORelationController::initialize: need a datasource!");
233 Reference
<XTablesSupplier
> xSup(getConnection(),UNO_QUERY
);
234 OSL_ENSURE(xSup
.is(),"Connection isn't a XTablesSupplier!");
236 m_xTables
= xSup
->getTables();
237 // load the layoutInformation
238 loadLayoutInformation();
242 if ( !m_nThreadEvent
)
243 Application::PostUserEvent(LINK(this, ORelationController
, OnThreadFinished
));
245 catch( const Exception
& )
247 DBG_UNHANDLED_EXCEPTION();
251 // -----------------------------------------------------------------------------
252 ::rtl::OUString
ORelationController::getPrivateTitle( ) const
254 ::rtl::OUString sName
= getDataSourceName();
255 return ::dbaui::getStrippedDatabaseName(getDataSource(),sName
);
257 // -----------------------------------------------------------------------------
258 sal_Bool
ORelationController::Construct(Window
* pParent
)
260 setView( * new ORelationDesignView( pParent
, *this, getORB() ) );
261 OJoinController::Construct(pParent
);
264 // -----------------------------------------------------------------------------
265 short ORelationController::saveModified()
267 short nSaved
= RET_YES
;
268 if(haveDataSource() && isModified())
270 QueryBox
aQry(getView(), ModuleRes(RELATION_DESIGN_SAVEMODIFIED
));
271 nSaved
= aQry
.Execute();
272 if(nSaved
== RET_YES
)
273 Execute(ID_BROWSER_SAVEDOC
,Sequence
<PropertyValue
>());
277 // -----------------------------------------------------------------------------
278 void ORelationController::describeSupportedFeatures()
280 OJoinController::describeSupportedFeatures();
281 implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION
, CommandGroup::EDIT
);
285 class RelationLoader
: public ::osl::Thread
287 DECLARE_STL_MAP(::rtl::OUString
,::boost::shared_ptr
<OTableWindowData
>,::comphelper::UStringMixLess
,TTableDataHelper
);
288 TTableDataHelper m_aTableData
;
289 TTableConnectionData m_vTableConnectionData
;
290 const Sequence
< ::rtl::OUString
> m_aTableList
;
291 ORelationController
* m_pParent
;
292 const Reference
< XDatabaseMetaData
> m_xMetaData
;
293 const Reference
< XNameAccess
> m_xTables
;
294 const sal_Int32 m_nStartIndex
;
295 const sal_Int32 m_nEndIndex
;
298 RelationLoader(ORelationController
* _pParent
299 ,const Reference
< XDatabaseMetaData
>& _xMetaData
300 ,const Reference
< XNameAccess
>& _xTables
301 ,const Sequence
< ::rtl::OUString
>& _aTableList
302 ,const sal_Int32 _nStartIndex
303 ,const sal_Int32 _nEndIndex
)
304 :m_aTableData(_xMetaData
.is() && _xMetaData
->supportsMixedCaseQuotedIdentifiers())
305 ,m_aTableList(_aTableList
)
307 ,m_xMetaData(_xMetaData
)
309 ,m_nStartIndex(_nStartIndex
)
310 ,m_nEndIndex(_nEndIndex
)
314 /// Working method which should be overridden.
315 virtual void SAL_CALL
run();
316 virtual void SAL_CALL
onTerminated();
318 virtual ~RelationLoader(){}
320 void loadTableData(const Any
& _aTable
);
323 void SAL_CALL
RelationLoader::run()
325 const ::rtl::OUString
* pIter
= m_aTableList
.getConstArray() + m_nStartIndex
;
326 for(sal_Int32 i
= m_nStartIndex
; i
< m_nEndIndex
;++i
,++pIter
)
328 ::rtl::OUString sCatalog
,sSchema
,sTable
;
329 ::dbtools::qualifiedNameComponents(m_xMetaData
,
334 ::dbtools::eInDataManipulation
);
336 if ( !sCatalog
.isEmpty() )
337 aCatalog
<<= sCatalog
;
341 Reference
< XResultSet
> xResult
= m_xMetaData
->getImportedKeys(aCatalog
, sSchema
,sTable
);
342 if ( xResult
.is() && xResult
->next() )
344 ::comphelper::disposeComponent(xResult
);
345 loadTableData(m_xTables
->getByName(*pIter
));
348 catch( const Exception
& )
350 DBG_UNHANDLED_EXCEPTION();
354 void SAL_CALL
RelationLoader::onTerminated()
356 m_pParent
->mergeData(m_vTableConnectionData
);
360 void RelationLoader::loadTableData(const Any
& _aTable
)
362 Reference
<XPropertySet
> xTableProp(_aTable
,UNO_QUERY
);
363 const ::rtl::OUString sSourceName
= ::dbtools::composeTableName( m_xMetaData
, xTableProp
, ::dbtools::eInTableDefinitions
, false, false, false );
364 TTableDataHelper::iterator aFind
= m_aTableData
.find(sSourceName
);
365 if ( aFind
== m_aTableData
.end() )
367 aFind
= m_aTableData
.insert(TTableDataHelper::value_type(sSourceName
,::boost::shared_ptr
<OTableWindowData
>(new OTableWindowData(xTableProp
,sSourceName
, sSourceName
)))).first
;
368 aFind
->second
->ShowAll(sal_False
);
370 TTableWindowData::value_type pReferencingTable
= aFind
->second
;
371 Reference
<XIndexAccess
> xKeys
= pReferencingTable
->getKeys();
372 const Reference
<XKeysSupplier
> xKeySup(xTableProp
,UNO_QUERY
);
374 if ( !xKeys
.is() && xKeySup
.is() )
376 xKeys
= xKeySup
->getKeys();
381 Reference
<XPropertySet
> xKey
;
382 const sal_Int32 nCount
= xKeys
->getCount();
383 for(sal_Int32 i
= 0 ; i
< nCount
; ++i
)
385 xKeys
->getByIndex(i
) >>= xKey
;
386 sal_Int32 nKeyType
= 0;
387 xKey
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
388 if ( KeyType::FOREIGN
== nKeyType
)
390 ::rtl::OUString sReferencedTable
;
391 xKey
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= sReferencedTable
;
392 //////////////////////////////////////////////////////////////////////
394 TTableDataHelper::iterator aRefFind
= m_aTableData
.find(sReferencedTable
);
395 if ( aRefFind
== m_aTableData
.end() )
397 if ( m_xTables
->hasByName(sReferencedTable
) )
399 Reference
<XPropertySet
> xReferencedTable(m_xTables
->getByName(sReferencedTable
),UNO_QUERY
);
400 aRefFind
= m_aTableData
.insert(TTableDataHelper::value_type(sReferencedTable
,::boost::shared_ptr
<OTableWindowData
>(new OTableWindowData(xReferencedTable
,sReferencedTable
, sReferencedTable
)))).first
;
401 aRefFind
->second
->ShowAll(sal_False
);
404 continue; // table name could not be found so we do not show this table releation
406 TTableWindowData::value_type pReferencedTable
= aRefFind
->second
;
408 ::rtl::OUString sKeyName
;
409 xKey
->getPropertyValue(PROPERTY_NAME
) >>= sKeyName
;
410 //////////////////////////////////////////////////////////////////////
412 ORelationTableConnectionData
* pTabConnData
= new ORelationTableConnectionData( pReferencingTable
, pReferencedTable
, sKeyName
);
413 m_vTableConnectionData
.push_back(TTableConnectionData::value_type(pTabConnData
));
414 //////////////////////////////////////////////////////////////////////
416 const Reference
<XColumnsSupplier
> xColsSup(xKey
,UNO_QUERY
);
417 OSL_ENSURE(xColsSup
.is(),"Key is no XColumnsSupplier!");
418 const Reference
<XNameAccess
> xColumns
= xColsSup
->getColumns();
419 const Sequence
< ::rtl::OUString
> aNames
= xColumns
->getElementNames();
420 const ::rtl::OUString
* pIter
= aNames
.getConstArray();
421 const ::rtl::OUString
* pEnd
= pIter
+ aNames
.getLength();
422 ::rtl::OUString sColumnName
,sRelatedName
;
423 for(sal_uInt16 j
=0;pIter
!= pEnd
;++pIter
,++j
)
425 const Reference
<XPropertySet
> xPropSet(xColumns
->getByName(*pIter
),UNO_QUERY
);
426 OSL_ENSURE(xPropSet
.is(),"Invalid column found in KeyColumns!");
429 xPropSet
->getPropertyValue(PROPERTY_NAME
) >>= sColumnName
;
430 xPropSet
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedName
;
432 pTabConnData
->SetConnLine( j
, sColumnName
, sRelatedName
);
434 //////////////////////////////////////////////////////////////////////
435 // Update/Del-Flags setzen
436 sal_Int32 nUpdateRule
= 0;
437 sal_Int32 nDeleteRule
= 0;
438 xKey
->getPropertyValue(PROPERTY_UPDATERULE
) >>= nUpdateRule
;
439 xKey
->getPropertyValue(PROPERTY_DELETERULE
) >>= nDeleteRule
;
441 pTabConnData
->SetUpdateRules( nUpdateRule
);
442 pTabConnData
->SetDeleteRules( nDeleteRule
);
444 //////////////////////////////////////////////////////////////////////
445 // Kardinalitaet setzen
446 pTabConnData
->SetCardinality();
453 void ORelationController::mergeData(const TTableConnectionData
& _aConnectionData
)
455 ::osl::MutexGuard
aGuard( getMutex() );
457 ::std::copy( _aConnectionData
.begin(), _aConnectionData
.end(), ::std::back_inserter( m_vTableConnectionData
));
458 //const Reference< XDatabaseMetaData> xMetaData = getConnection()->getMetaData();
459 const sal_Bool bCase
= sal_True
;//xMetaData.is() && xMetaData->supportsMixedCaseQuotedIdentifiers();
460 // here we are finished, so we can collect the table from connection data
461 TTableConnectionData::iterator aConnDataIter
= m_vTableConnectionData
.begin();
462 TTableConnectionData::iterator aConnDataEnd
= m_vTableConnectionData
.end();
463 for(;aConnDataIter
!= aConnDataEnd
;++aConnDataIter
)
465 if ( !existsTable((*aConnDataIter
)->getReferencingTable()->GetComposedName(),bCase
) )
467 m_vTableData
.push_back((*aConnDataIter
)->getReferencingTable());
469 if ( !existsTable((*aConnDataIter
)->getReferencedTable()->GetComposedName(),bCase
) )
471 m_vTableData
.push_back((*aConnDataIter
)->getReferencedTable());
474 if ( m_nThreadEvent
)
477 if ( !m_nThreadEvent
)
478 Application::PostUserEvent(LINK(this, ORelationController
, OnThreadFinished
));
481 // -----------------------------------------------------------------------------
482 IMPL_LINK( ORelationController
, OnThreadFinished
, void*, /*NOTINTERESTEDIN*/ )
484 ::SolarMutexGuard aSolarGuard
;
485 ::osl::MutexGuard
aGuard( getMutex() );
488 getView()->initialize(); // show the windows and fill with our informations
489 getView()->Invalidate(INVALIDATE_NOERASE
);
491 setModified(sal_False
); // and we are not modified yet
493 if(m_vTableData
.empty())
494 Execute(ID_BROWSER_ADDTABLE
,Sequence
<PropertyValue
>());
496 catch( const Exception
& )
498 DBG_UNHANDLED_EXCEPTION();
500 m_pWaitObject
.reset();
503 // -----------------------------------------------------------------------------
504 void ORelationController::loadData()
506 m_pWaitObject
.reset( new WaitObject(getView()) );
509 if ( !m_xTables
.is() )
511 DatabaseMetaData
aMeta(getConnection());
512 // this may take some time
513 const Reference
< XDatabaseMetaData
> xMetaData
= getConnection()->getMetaData();
514 const Sequence
< ::rtl::OUString
> aNames
= m_xTables
->getElementNames();
515 const sal_Int32 nCount
= aNames
.getLength();
516 if ( aMeta
.supportsThreads() )
518 const sal_Int32 nMaxElements
= (nCount
/ MAX_THREADS
) +1;
519 sal_Int32 nStart
= 0,nEnd
= ::std::min(nMaxElements
,nCount
);
520 while(nStart
!= nEnd
)
523 RelationLoader
* pThread
= new RelationLoader(this,xMetaData
,m_xTables
,aNames
,nStart
,nEnd
);
524 pThread
->createSuspended();
525 pThread
->setPriority(osl_Thread_PriorityBelowNormal
);
528 nEnd
+= nMaxElements
;
529 nEnd
= ::std::min(nEnd
,nCount
);
534 RelationLoader
* pThread
= new RelationLoader(this,xMetaData
,m_xTables
,aNames
,0,nCount
);
536 pThread
->onTerminated();
539 catch(SQLException
& e
)
541 showError(SQLExceptionInfo(e
));
543 catch(const Exception
&)
545 DBG_UNHANDLED_EXCEPTION();
548 // -----------------------------------------------------------------------------
549 TTableWindowData::value_type
ORelationController::existsTable(const ::rtl::OUString
& _rComposedTableName
,sal_Bool _bCase
) const
551 ::comphelper::UStringMixEqual
bCase(_bCase
);
552 TTableWindowData::const_iterator aIter
= m_vTableData
.begin();
553 TTableWindowData::const_iterator aEnd
= m_vTableData
.end();
554 for(;aIter
!= aEnd
;++aIter
)
556 if(bCase((*aIter
)->GetComposedName(),_rComposedTableName
))
559 return ( aIter
!= aEnd
) ? *aIter
: TTableWindowData::value_type();
561 // -----------------------------------------------------------------------------
562 void ORelationController::loadLayoutInformation()
566 OSL_ENSURE(haveDataSource(),"We need a datasource from our connection!");
567 if ( haveDataSource() )
569 if ( getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION
) )
571 Sequence
<PropertyValue
> aWindows
;
572 getDataSource()->getPropertyValue(PROPERTY_LAYOUTINFORMATION
) >>= aWindows
;
573 loadTableWindows(aWindows
);
581 // -----------------------------------------------------------------------------
582 void ORelationController::reset()
584 loadLayoutInformation();
585 ODataView
* pView
= getView();
586 OSL_ENSURE(pView
,"No current view!");
590 pView
->Invalidate(INVALIDATE_NOERASE
);
594 // -----------------------------------------------------------------------------
595 bool ORelationController::allowViews() const
600 // -----------------------------------------------------------------------------
601 bool ORelationController::allowQueries() const
606 // -----------------------------------------------------------------------------
609 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */