Bump version to 5.0-14
[LibreOffice.git] / dbaccess / source / ui / relationdesign / RelationController.cxx
blob063fe310989a31921f70813f76bde74d87925596
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <map>
24 #include "dbu_reghelper.hxx"
25 #include "uiservices.hxx"
26 #include <sfx2/sfxsids.hrc>
27 #include "dbu_rel.hrc"
28 #include <vcl/svapp.hxx>
29 #include "browserids.hxx"
30 #include <comphelper/types.hxx>
31 #include "dbustrings.hrc"
32 #include <connectivity/dbtools.hxx>
33 #include <com/sun/star/frame/FrameSearchFlag.hpp>
34 #include <comphelper/extract.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <com/sun/star/container/XChild.hpp>
37 #include <com/sun/star/container/XNameContainer.hpp>
38 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
39 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
40 #include <com/sun/star/sdbcx/KeyType.hpp>
41 #include <com/sun/star/sdbcx/XDrop.hpp>
42 #include <com/sun/star/sdbcx/XAlterTable.hpp>
43 #include <com/sun/star/sdbcx/XAppend.hpp>
44 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
45 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
46 #include <com/sun/star/sdb/SQLContext.hpp>
47 #include <com/sun/star/sdbc/SQLWarning.hpp>
48 #include <com/sun/star/sdbc/ColumnValue.hpp>
49 #include <com/sun/star/sdbc/XRow.hpp>
50 #include <connectivity/dbexception.hxx>
51 #include <connectivity/dbmetadata.hxx>
52 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
53 #include <comphelper/streamsection.hxx>
54 #include <comphelper/seqstream.hxx>
55 #include <com/sun/star/io/XActiveDataSource.hpp>
56 #include <com/sun/star/io/XActiveDataSink.hpp>
57 #include "sqlmessage.hxx"
58 #include "RelationController.hxx"
59 #include <vcl/layout.hxx>
60 #include "TableWindowData.hxx"
61 #include "UITools.hxx"
62 #include "RTableConnectionData.hxx"
63 #include "RelationTableView.hxx"
64 #include "RelationDesignView.hxx"
65 #include <tools/debug.hxx>
66 #include <tools/diagnose_ex.h>
67 #include <vcl/waitobj.hxx>
68 #include <osl/thread.hxx>
69 #include <osl/mutex.hxx>
71 #define MAX_THREADS 10
73 extern "C" void SAL_CALL createRegistryInfo_ORelationControl()
75 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::ORelationController > aAutoRegistration;
78 using namespace ::com::sun::star::uno;
79 using namespace ::com::sun::star::io;
80 using namespace ::com::sun::star::beans;
81 using namespace ::com::sun::star::frame;
82 using namespace ::com::sun::star::lang;
83 using namespace ::com::sun::star::container;
84 using namespace ::com::sun::star::sdbcx;
85 using namespace ::com::sun::star::sdbc;
86 using namespace ::com::sun::star::sdb;
87 using namespace ::com::sun::star::ui::dialogs;
88 using namespace ::com::sun::star::util;
89 using namespace ::dbtools;
90 using namespace ::dbaui;
91 using namespace ::comphelper;
92 using namespace ::osl;
94 OUString SAL_CALL ORelationController::getImplementationName() throw( RuntimeException, std::exception )
96 return getImplementationName_Static();
99 OUString ORelationController::getImplementationName_Static() throw( RuntimeException )
101 return OUString("org.openoffice.comp.dbu.ORelationDesign");
104 Sequence< OUString> ORelationController::getSupportedServiceNames_Static() throw( RuntimeException )
106 Sequence< OUString> aSupported(1);
107 aSupported[0] = "com.sun.star.sdb.RelationDesign";
108 return aSupported;
111 Sequence< OUString> SAL_CALL ORelationController::getSupportedServiceNames() throw(RuntimeException, std::exception)
113 return getSupportedServiceNames_Static();
116 Reference< XInterface > SAL_CALL ORelationController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
118 return *(new ORelationController(comphelper::getComponentContext(_rxFactory)));
121 ORelationController::ORelationController(const Reference< XComponentContext >& _rM)
122 : OJoinController(_rM)
123 ,m_nThreadEvent(0)
124 ,m_bRelationsPossible(true)
126 InvalidateAll();
129 ORelationController::~ORelationController()
133 FeatureState ORelationController::GetState(sal_uInt16 _nId) const
135 FeatureState aReturn;
136 aReturn.bEnabled = m_bRelationsPossible;
137 switch (_nId)
139 case SID_RELATION_ADD_RELATION:
140 aReturn.bEnabled = !m_vTableData.empty() && isConnected() && isEditable();
141 aReturn.bChecked = false;
142 break;
143 case ID_BROWSER_SAVEDOC:
144 aReturn.bEnabled = haveDataSource() && impl_isModified();
145 break;
146 default:
147 aReturn = OJoinController::GetState(_nId);
148 break;
150 return aReturn;
153 void ORelationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
155 switch(_nId)
157 case ID_BROWSER_SAVEDOC:
159 OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
160 if(!::dbaui::checkDataSourceAvailable(::comphelper::getString(getDataSource()->getPropertyValue(PROPERTY_NAME)), getORB()))
162 OUString aMessage(ModuleRes(STR_DATASOURCE_DELETED));
163 ScopedVclPtr<OSQLWarningBox>::Create( getView(), aMessage )->Execute();
165 else
167 // now we save the layout information
168 // create the output stream
171 if ( haveDataSource() && getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) )
173 ::comphelper::NamedValueCollection aWindowsData;
174 saveTableWindows( aWindowsData );
175 getDataSource()->setPropertyValue( PROPERTY_LAYOUTINFORMATION, makeAny( aWindowsData.getPropertyValues() ) );
176 setModified(sal_False);
179 catch ( const Exception& )
181 DBG_UNHANDLED_EXCEPTION();
185 break;
186 case SID_RELATION_ADD_RELATION:
187 static_cast<ORelationTableView*>(static_cast<ORelationDesignView*>( getView() )->getTableView())->AddNewRelation();
188 break;
189 default:
190 OJoinController::Execute(_nId,aArgs);
191 return;
193 InvalidateFeature(_nId);
196 void ORelationController::impl_initialize()
198 OJoinController::impl_initialize();
200 if( !getSdbMetaData().supportsRelations() )
201 {// check if this database supports relations
203 setEditable(false);
204 m_bRelationsPossible = false;
206 OUString sTitle(ModuleRes(STR_RELATIONDESIGN));
207 sTitle = sTitle.copy(3);
208 ScopedVclPtrInstance< OSQLMessageBox > aDlg(nullptr,sTitle,ModuleRes(STR_RELATIONDESIGN_NOT_AVAILABLE));
209 aDlg->Execute();
211 disconnect();
212 throw SQLException();
215 if(!m_bRelationsPossible)
216 InvalidateAll();
218 // we need a datasource
219 OSL_ENSURE(haveDataSource(),"ORelationController::initialize: need a datasource!");
221 Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
222 OSL_ENSURE(xSup.is(),"Connection isn't a XTablesSupplier!");
223 if(xSup.is())
224 m_xTables = xSup->getTables();
225 // load the layoutInformation
226 loadLayoutInformation();
229 loadData();
230 if ( !m_nThreadEvent )
231 Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished));
233 catch( const Exception& )
235 DBG_UNHANDLED_EXCEPTION();
240 OUString ORelationController::getPrivateTitle( ) const
242 OUString sName = getDataSourceName();
243 return ::dbaui::getStrippedDatabaseName(getDataSource(),sName);
246 bool ORelationController::Construct(vcl::Window* pParent)
248 setView( VclPtr<ORelationDesignView>::Create( pParent, *this, getORB() ) );
249 OJoinController::Construct(pParent);
250 return true;
253 short ORelationController::saveModified()
255 short nSaved = RET_YES;
256 if(haveDataSource() && isModified())
258 ScopedVclPtrInstance<MessageDialog> aQry(getView(), "DesignSaveModifiedDialog",
259 "dbaccess/ui/designsavemodifieddialog.ui");
260 nSaved = aQry->Execute();
261 if(nSaved == RET_YES)
262 Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
264 return nSaved;
267 void ORelationController::describeSupportedFeatures()
269 OJoinController::describeSupportedFeatures();
270 implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT );
273 namespace
275 class RelationLoader : public ::osl::Thread
277 typedef std::map<OUString, ::boost::shared_ptr<OTableWindowData>, ::comphelper::UStringMixLess> TTableDataHelper;
278 TTableDataHelper m_aTableData;
279 TTableConnectionData m_vTableConnectionData;
280 const Sequence< OUString> m_aTableList;
281 ORelationController* m_pParent;
282 const Reference< XDatabaseMetaData> m_xMetaData;
283 const Reference< XNameAccess > m_xTables;
284 const sal_Int32 m_nStartIndex;
285 const sal_Int32 m_nEndIndex;
287 public:
288 RelationLoader(ORelationController* _pParent
289 ,const Reference< XDatabaseMetaData>& _xMetaData
290 ,const Reference< XNameAccess >& _xTables
291 ,const Sequence< OUString>& _aTableList
292 ,const sal_Int32 _nStartIndex
293 ,const sal_Int32 _nEndIndex)
294 :m_aTableData(_xMetaData.is() && _xMetaData->supportsMixedCaseQuotedIdentifiers())
295 ,m_aTableList(_aTableList)
296 ,m_pParent(_pParent)
297 ,m_xMetaData(_xMetaData)
298 ,m_xTables(_xTables)
299 ,m_nStartIndex(_nStartIndex)
300 ,m_nEndIndex(_nEndIndex)
304 /// Working method which should be overridden.
305 virtual void SAL_CALL run() SAL_OVERRIDE;
306 virtual void SAL_CALL onTerminated() SAL_OVERRIDE;
307 protected:
308 virtual ~RelationLoader(){}
310 void loadTableData(const Any& _aTable);
313 void SAL_CALL RelationLoader::run()
315 osl_setThreadName("RelationLoader");
317 const OUString* pIter = m_aTableList.getConstArray() + m_nStartIndex;
318 for(sal_Int32 i = m_nStartIndex; i < m_nEndIndex;++i,++pIter)
320 OUString sCatalog,sSchema,sTable;
321 ::dbtools::qualifiedNameComponents(m_xMetaData,
322 *pIter,
323 sCatalog,
324 sSchema,
325 sTable,
326 ::dbtools::eInDataManipulation);
327 Any aCatalog;
328 if ( !sCatalog.isEmpty() )
329 aCatalog <<= sCatalog;
333 Reference< XResultSet > xResult = m_xMetaData->getImportedKeys(aCatalog, sSchema,sTable);
334 if ( xResult.is() && xResult->next() )
336 ::comphelper::disposeComponent(xResult);
337 loadTableData(m_xTables->getByName(*pIter));
340 catch( const Exception& )
342 DBG_UNHANDLED_EXCEPTION();
346 void SAL_CALL RelationLoader::onTerminated()
348 m_pParent->mergeData(m_vTableConnectionData);
349 delete this;
352 void RelationLoader::loadTableData(const Any& _aTable)
354 Reference<XPropertySet> xTableProp(_aTable,UNO_QUERY);
355 const OUString sSourceName = ::dbtools::composeTableName( m_xMetaData, xTableProp, ::dbtools::eInTableDefinitions, false, false, false );
356 TTableDataHelper::iterator aFind = m_aTableData.find(sSourceName);
357 if ( aFind == m_aTableData.end() )
359 aFind = m_aTableData.insert(TTableDataHelper::value_type(sSourceName,::boost::shared_ptr<OTableWindowData>(new OTableWindowData(xTableProp,sSourceName, sSourceName)))).first;
360 aFind->second->ShowAll(false);
362 TTableWindowData::value_type pReferencingTable = aFind->second;
363 Reference<XIndexAccess> xKeys = pReferencingTable->getKeys();
364 const Reference<XKeysSupplier> xKeySup(xTableProp,UNO_QUERY);
366 if ( !xKeys.is() && xKeySup.is() )
368 xKeys = xKeySup->getKeys();
371 if ( xKeys.is() )
373 Reference<XPropertySet> xKey;
374 const sal_Int32 nCount = xKeys->getCount();
375 for(sal_Int32 i = 0 ; i < nCount ; ++i)
377 xKeys->getByIndex(i) >>= xKey;
378 sal_Int32 nKeyType = 0;
379 xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
380 if ( KeyType::FOREIGN == nKeyType )
382 OUString sReferencedTable;
383 xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
385 // insert windows
386 TTableDataHelper::iterator aRefFind = m_aTableData.find(sReferencedTable);
387 if ( aRefFind == m_aTableData.end() )
389 if ( m_xTables->hasByName(sReferencedTable) )
391 Reference<XPropertySet> xReferencedTable(m_xTables->getByName(sReferencedTable),UNO_QUERY);
392 aRefFind = m_aTableData.insert(TTableDataHelper::value_type(sReferencedTable,::boost::shared_ptr<OTableWindowData>(new OTableWindowData(xReferencedTable,sReferencedTable, sReferencedTable)))).first;
393 aRefFind->second->ShowAll(false);
395 else
396 continue; // table name could not be found so we do not show this table releation
398 TTableWindowData::value_type pReferencedTable = aRefFind->second;
400 OUString sKeyName;
401 xKey->getPropertyValue(PROPERTY_NAME) >>= sKeyName;
402 // insert connection
403 ORelationTableConnectionData* pTabConnData = new ORelationTableConnectionData( pReferencingTable, pReferencedTable, sKeyName );
404 m_vTableConnectionData.push_back(TTableConnectionData::value_type(pTabConnData));
405 // insert columns
406 const Reference<XColumnsSupplier> xColsSup(xKey,UNO_QUERY);
407 OSL_ENSURE(xColsSup.is(),"Key is no XColumnsSupplier!");
408 const Reference<XNameAccess> xColumns = xColsSup->getColumns();
409 const Sequence< OUString> aNames = xColumns->getElementNames();
410 const OUString* pIter = aNames.getConstArray();
411 const OUString* pEnd = pIter + aNames.getLength();
412 OUString sColumnName,sRelatedName;
413 for(sal_uInt16 j=0;pIter != pEnd;++pIter,++j)
415 const Reference<XPropertySet> xPropSet(xColumns->getByName(*pIter),UNO_QUERY);
416 OSL_ENSURE(xPropSet.is(),"Invalid column found in KeyColumns!");
417 if ( xPropSet.is() )
419 xPropSet->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
420 xPropSet->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedName;
422 pTabConnData->SetConnLine( j, sColumnName, sRelatedName );
424 // Update/Del-Flags setzen
425 sal_Int32 nUpdateRule = 0;
426 sal_Int32 nDeleteRule = 0;
427 xKey->getPropertyValue(PROPERTY_UPDATERULE) >>= nUpdateRule;
428 xKey->getPropertyValue(PROPERTY_DELETERULE) >>= nDeleteRule;
430 pTabConnData->SetUpdateRules( nUpdateRule );
431 pTabConnData->SetDeleteRules( nDeleteRule );
433 // Kardinalitaet setzen
434 pTabConnData->SetCardinality();
441 void ORelationController::mergeData(const TTableConnectionData& _aConnectionData)
443 ::osl::MutexGuard aGuard( getMutex() );
445 ::std::copy( _aConnectionData.begin(), _aConnectionData.end(), ::std::back_inserter( m_vTableConnectionData ));
446 //const Reference< XDatabaseMetaData> xMetaData = getConnection()->getMetaData();
447 const bool bCase = true;//xMetaData.is() && xMetaData->supportsMixedCaseQuotedIdentifiers();
448 // here we are finished, so we can collect the table from connection data
449 TTableConnectionData::iterator aConnDataIter = m_vTableConnectionData.begin();
450 TTableConnectionData::iterator aConnDataEnd = m_vTableConnectionData.end();
451 for(;aConnDataIter != aConnDataEnd;++aConnDataIter)
453 if ( !existsTable((*aConnDataIter)->getReferencingTable()->GetComposedName(),bCase) )
455 m_vTableData.push_back((*aConnDataIter)->getReferencingTable());
457 if ( !existsTable((*aConnDataIter)->getReferencedTable()->GetComposedName(),bCase) )
459 m_vTableData.push_back((*aConnDataIter)->getReferencedTable());
462 if ( m_nThreadEvent )
464 --m_nThreadEvent;
465 if ( !m_nThreadEvent )
466 Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished));
470 IMPL_LINK_NOARG( ORelationController, OnThreadFinished )
472 ::SolarMutexGuard aSolarGuard;
473 ::osl::MutexGuard aGuard( getMutex() );
476 getView()->initialize(); // show the windows and fill with our information
477 getView()->Invalidate(INVALIDATE_NOERASE);
478 ClearUndoManager();
479 setModified(sal_False); // and we are not modified yet
481 if(m_vTableData.empty())
482 Execute(ID_BROWSER_ADDTABLE,Sequence<PropertyValue>());
484 catch( const Exception& )
486 DBG_UNHANDLED_EXCEPTION();
488 m_pWaitObject.reset();
489 return 0L;
492 void ORelationController::loadData()
494 m_pWaitObject.reset( new WaitObject(getView()) );
497 if ( !m_xTables.is() )
498 return;
499 DatabaseMetaData aMeta(getConnection());
500 // this may take some time
501 const Reference< XDatabaseMetaData> xMetaData = getConnection()->getMetaData();
502 const Sequence< OUString> aNames = m_xTables->getElementNames();
503 const sal_Int32 nCount = aNames.getLength();
504 if ( aMeta.supportsThreads() )
506 const sal_Int32 nMaxElements = (nCount / MAX_THREADS) +1;
507 sal_Int32 nStart = 0,nEnd = ::std::min(nMaxElements,nCount);
508 while(nStart != nEnd)
510 ++m_nThreadEvent;
511 RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,nStart,nEnd);
512 pThread->createSuspended();
513 pThread->setPriority(osl_Thread_PriorityBelowNormal);
514 pThread->resume();
515 nStart = nEnd;
516 nEnd += nMaxElements;
517 nEnd = ::std::min(nEnd,nCount);
520 else
522 RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,0,nCount);
523 pThread->run();
524 pThread->onTerminated();
527 catch(SQLException& e)
529 showError(SQLExceptionInfo(e));
531 catch(const Exception&)
533 DBG_UNHANDLED_EXCEPTION();
537 TTableWindowData::value_type ORelationController::existsTable(const OUString& _rComposedTableName,bool _bCase) const
539 ::comphelper::UStringMixEqual bCase(_bCase);
540 TTableWindowData::const_iterator aIter = m_vTableData.begin();
541 TTableWindowData::const_iterator aEnd = m_vTableData.end();
542 for(;aIter != aEnd;++aIter)
544 if(bCase((*aIter)->GetComposedName(),_rComposedTableName))
545 break;
547 return ( aIter != aEnd) ? *aIter : TTableWindowData::value_type();
550 void ORelationController::loadLayoutInformation()
554 OSL_ENSURE(haveDataSource(),"We need a datasource from our connection!");
555 if ( haveDataSource() )
557 if ( getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) )
559 Sequence<PropertyValue> aWindows;
560 getDataSource()->getPropertyValue(PROPERTY_LAYOUTINFORMATION) >>= aWindows;
561 loadTableWindows(aWindows);
565 catch(Exception&)
570 void ORelationController::reset()
572 loadLayoutInformation();
573 ODataView* pView = getView();
574 OSL_ENSURE(pView,"No current view!");
575 if(pView)
577 pView->initialize();
578 pView->Invalidate(INVALIDATE_NOERASE);
582 bool ORelationController::allowViews() const
584 return false;
587 bool ORelationController::allowQueries() const
589 return false;
592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */