Version 3.6.0.2, tag libreoffice-3.6.0.2
[LibreOffice.git] / dbaccess / source / ui / relationdesign / RelationController.cxx
bloba096d788c0c31d82b5931a7a6f638fbc5efc8c78
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"));
117 return aSupported;
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)
133 ,m_nThreadEvent(0)
134 ,m_bRelationsPossible(sal_True)
136 DBG_CTOR(ORelationController,NULL);
137 InvalidateAll();
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;
149 switch (_nId)
151 case SID_RELATION_ADD_RELATION:
152 aReturn.bEnabled = !m_vTableData.empty() && isConnected() && isEditable();
153 aReturn.bChecked = false;
154 break;
155 case ID_BROWSER_SAVEDOC:
156 aReturn.bEnabled = haveDataSource() && impl_isModified();
157 break;
158 default:
159 aReturn = OJoinController::GetState(_nId);
160 break;
162 return aReturn;
164 // -----------------------------------------------------------------------------
165 void ORelationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
167 switch(_nId)
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();
177 else
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();
197 break;
198 case SID_RELATION_ADD_RELATION:
199 static_cast<ORelationTableView*>(static_cast<ORelationDesignView*>( getView() )->getTableView())->AddNewRelation();
200 break;
201 default:
202 OJoinController::Execute(_nId,aArgs);
203 return;
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));
219 sTitle.Erase(0,3);
220 OSQLMessageBox aDlg(NULL,sTitle,ModuleRes(STR_RELATIONDESIGN_NOT_AVAILABLE));
221 aDlg.Execute();
223 disconnect();
224 throw SQLException();
227 if(!m_bRelationsPossible)
228 InvalidateAll();
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!");
235 if(xSup.is())
236 m_xTables = xSup->getTables();
237 // load the layoutInformation
238 loadLayoutInformation();
241 loadData();
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);
262 return sal_True;
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>());
275 return nSaved;
277 // -----------------------------------------------------------------------------
278 void ORelationController::describeSupportedFeatures()
280 OJoinController::describeSupportedFeatures();
281 implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT );
283 namespace
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;
297 public:
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)
306 ,m_pParent(_pParent)
307 ,m_xMetaData(_xMetaData)
308 ,m_xTables(_xTables)
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();
317 protected:
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,
330 *pIter,
331 sCatalog,
332 sSchema,
333 sTable,
334 ::dbtools::eInDataManipulation);
335 Any aCatalog;
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);
357 delete this;
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();
379 if ( xKeys.is() )
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 //////////////////////////////////////////////////////////////////////
393 // insert windows
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);
403 else
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 //////////////////////////////////////////////////////////////////////
411 // insert connection
412 ORelationTableConnectionData* pTabConnData = new ORelationTableConnectionData( pReferencingTable, pReferencedTable, sKeyName );
413 m_vTableConnectionData.push_back(TTableConnectionData::value_type(pTabConnData));
414 //////////////////////////////////////////////////////////////////////
415 // insert columns
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!");
427 if ( xPropSet.is() )
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 )
476 --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);
490 ClearUndoManager();
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();
501 return 0L;
503 // -----------------------------------------------------------------------------
504 void ORelationController::loadData()
506 m_pWaitObject.reset( new WaitObject(getView()) );
509 if ( !m_xTables.is() )
510 return;
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)
522 ++m_nThreadEvent;
523 RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,nStart,nEnd);
524 pThread->createSuspended();
525 pThread->setPriority(osl_Thread_PriorityBelowNormal);
526 pThread->resume();
527 nStart = nEnd;
528 nEnd += nMaxElements;
529 nEnd = ::std::min(nEnd,nCount);
532 else
534 RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,0,nCount);
535 pThread->run();
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))
557 break;
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);
577 catch(Exception&)
581 // -----------------------------------------------------------------------------
582 void ORelationController::reset()
584 loadLayoutInformation();
585 ODataView* pView = getView();
586 OSL_ENSURE(pView,"No current view!");
587 if(pView)
589 pView->initialize();
590 pView->Invalidate(INVALIDATE_NOERASE);
594 // -----------------------------------------------------------------------------
595 bool ORelationController::allowViews() const
597 return false;
600 // -----------------------------------------------------------------------------
601 bool ORelationController::allowQueries() const
603 return false;
606 // -----------------------------------------------------------------------------
609 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */