calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / dbaccess / source / ui / relationdesign / RelationController.cxx
blob2c642cd765c91466d86326ff05588dc725079db3
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 <strings.hrc>
25 #include <strings.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/weld.hxx>
28 #include <browserids.hxx>
29 #include <comphelper/types.hxx>
30 #include <core_resource.hxx>
31 #include <connectivity/dbtools.hxx>
32 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
33 #include <com/sun/star/sdbcx/KeyType.hpp>
34 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
35 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
36 #include <com/sun/star/sdbc/SQLException.hpp>
37 #include <com/sun/star/sdbc/XRow.hpp>
38 #include <connectivity/dbexception.hxx>
39 #include <connectivity/dbmetadata.hxx>
40 #include <sqlmessage.hxx>
41 #include <RelationController.hxx>
42 #include <TableWindowData.hxx>
43 #include <UITools.hxx>
44 #include <RTableConnectionData.hxx>
45 #include <RelationTableView.hxx>
46 #include <RelationDesignView.hxx>
47 #include <comphelper/diagnose_ex.hxx>
48 #include <osl/thread.hxx>
49 #include <osl/mutex.hxx>
51 #define MAX_THREADS 10
53 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
54 org_openoffice_comp_dbu_ORelationDesign_get_implementation(
55 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
57 return cppu::acquire(new ::dbaui::ORelationController(context));
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::io;
62 using namespace ::com::sun::star::beans;
63 using namespace ::com::sun::star::frame;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::container;
66 using namespace ::com::sun::star::sdbcx;
67 using namespace ::com::sun::star::sdbc;
68 using namespace ::com::sun::star::sdb;
69 using namespace ::com::sun::star::ui::dialogs;
70 using namespace ::com::sun::star::util;
71 using namespace ::dbtools;
72 using namespace ::dbaui;
73 using namespace ::comphelper;
74 using namespace ::osl;
76 OUString SAL_CALL ORelationController::getImplementationName()
78 return "org.openoffice.comp.dbu.ORelationDesign";
81 Sequence< OUString> SAL_CALL ORelationController::getSupportedServiceNames()
83 return { "com.sun.star.sdb.RelationDesign" };
86 ORelationController::ORelationController(const Reference< XComponentContext >& _rM)
87 : OJoinController(_rM)
88 ,m_nThreadEvent(0)
89 ,m_bRelationsPossible(true)
91 InvalidateAll();
94 ORelationController::~ORelationController()
98 FeatureState ORelationController::GetState(sal_uInt16 _nId) const
100 FeatureState aReturn;
101 aReturn.bEnabled = m_bRelationsPossible;
102 switch (_nId)
104 case SID_RELATION_ADD_RELATION:
105 aReturn.bEnabled = !m_vTableData.empty() && isConnected() && isEditable();
106 aReturn.bChecked = false;
107 break;
108 case ID_BROWSER_SAVEDOC:
109 aReturn.bEnabled = haveDataSource() && impl_isModified();
110 break;
111 default:
112 aReturn = OJoinController::GetState(_nId);
113 break;
115 return aReturn;
118 void ORelationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
120 switch(_nId)
122 case ID_BROWSER_SAVEDOC:
124 OSL_ENSURE(isEditable(),"Slot ID_BROWSER_SAVEDOC should not be enabled!");
125 if(!::dbaui::checkDataSourceAvailable(::comphelper::getString(getDataSource()->getPropertyValue(PROPERTY_NAME)), getORB()))
127 OUString aMessage(DBA_RES(STR_DATASOURCE_DELETED));
128 OSQLWarningBox aWarning(getFrameWeld(), aMessage);
129 aWarning.run();
131 else
133 // now we save the layout information
134 // create the output stream
137 if ( haveDataSource() && getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) )
139 ::comphelper::NamedValueCollection aWindowsData;
140 saveTableWindows( aWindowsData );
141 getDataSource()->setPropertyValue( PROPERTY_LAYOUTINFORMATION, Any( aWindowsData.getPropertyValues() ) );
142 setModified(false);
145 catch ( const Exception& )
147 DBG_UNHANDLED_EXCEPTION("dbaccess");
151 break;
152 case SID_RELATION_ADD_RELATION:
153 static_cast<ORelationTableView*>(static_cast<ORelationDesignView*>( getView() )->getTableView())->AddNewRelation();
154 break;
155 default:
156 OJoinController::Execute(_nId,aArgs);
157 return;
159 InvalidateFeature(_nId);
162 void ORelationController::impl_initialize()
164 OJoinController::impl_initialize();
166 if( !getSdbMetaData().supportsRelations() )
167 {// check if this database supports relations
169 setEditable(false);
170 m_bRelationsPossible = false;
172 OUString sTitle(DBA_RES(STR_RELATIONDESIGN));
173 sTitle = sTitle.copy(3);
174 OSQLMessageBox aDlg(getFrameWeld(), sTitle, DBA_RES(STR_RELATIONDESIGN_NOT_AVAILABLE));
175 aDlg.run();
177 disconnect();
178 throw SQLException();
181 if(!m_bRelationsPossible)
182 InvalidateAll();
184 // we need a datasource
185 OSL_ENSURE(haveDataSource(),"ORelationController::initialize: need a datasource!");
187 Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY);
188 OSL_ENSURE(xSup.is(),"Connection isn't a XTablesSupplier!");
189 if(xSup.is())
190 m_xTables = xSup->getTables();
191 // load the layoutInformation
192 loadLayoutInformation();
195 loadData();
196 if ( !m_nThreadEvent )
197 Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished));
199 catch( const Exception& )
201 DBG_UNHANDLED_EXCEPTION("dbaccess");
206 OUString ORelationController::getPrivateTitle( ) const
208 OUString sName = getDataSourceName();
209 return ::dbaui::getStrippedDatabaseName(getDataSource(),sName);
212 bool ORelationController::Construct(vcl::Window* pParent)
214 setView( VclPtr<ORelationDesignView>::Create( pParent, *this, getORB() ) );
215 OJoinController::Construct(pParent);
216 return true;
219 short ORelationController::saveModified()
221 short nSaved = RET_YES;
222 if(haveDataSource() && isModified())
224 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/designsavemodifieddialog.ui"));
225 std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DesignSaveModifiedDialog"));
226 nSaved = xQuery->run();
227 if(nSaved == RET_YES)
228 Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
230 return nSaved;
233 void ORelationController::describeSupportedFeatures()
235 OJoinController::describeSupportedFeatures();
236 implDescribeSupportedFeature( ".uno:DBAddRelation", SID_RELATION_ADD_RELATION, CommandGroup::EDIT );
239 namespace
241 class RelationLoader : public ::osl::Thread
243 typedef std::map<OUString, std::shared_ptr<OTableWindowData>, ::comphelper::UStringMixLess> TTableDataHelper;
244 TTableDataHelper m_aTableData;
245 TTableConnectionData m_vTableConnectionData;
246 const Sequence< OUString> m_aTableList;
247 ORelationController* m_pParent;
248 const Reference< XDatabaseMetaData> m_xMetaData;
249 const Reference< XNameAccess > m_xTables;
250 const sal_Int32 m_nStartIndex;
251 const sal_Int32 m_nEndIndex;
253 public:
254 RelationLoader(ORelationController* _pParent
255 ,const Reference< XDatabaseMetaData>& _xMetaData
256 ,const Reference< XNameAccess >& _xTables
257 ,const Sequence< OUString>& _aTableList
258 ,const sal_Int32 _nStartIndex
259 ,const sal_Int32 _nEndIndex)
260 :m_aTableData(_xMetaData.is() && _xMetaData->supportsMixedCaseQuotedIdentifiers())
261 ,m_aTableList(_aTableList)
262 ,m_pParent(_pParent)
263 ,m_xMetaData(_xMetaData)
264 ,m_xTables(_xTables)
265 ,m_nStartIndex(_nStartIndex)
266 ,m_nEndIndex(_nEndIndex)
270 /// Working method which should be overridden.
271 virtual void SAL_CALL run() override;
272 virtual void SAL_CALL onTerminated() override;
273 protected:
274 virtual ~RelationLoader() override {}
276 void loadTableData(const Any& _aTable);
279 void SAL_CALL RelationLoader::run()
281 osl_setThreadName("RelationLoader");
283 for(sal_Int32 i = m_nStartIndex; i < m_nEndIndex; ++i)
285 OUString sCatalog,sSchema,sTable;
286 ::dbtools::qualifiedNameComponents(m_xMetaData,
287 m_aTableList[i],
288 sCatalog,
289 sSchema,
290 sTable,
291 ::dbtools::EComposeRule::InDataManipulation);
292 Any aCatalog;
293 if ( !sCatalog.isEmpty() )
294 aCatalog <<= sCatalog;
298 Reference< XResultSet > xResult = m_xMetaData->getImportedKeys(aCatalog, sSchema,sTable);
299 if ( xResult.is() && xResult->next() )
301 ::comphelper::disposeComponent(xResult);
302 loadTableData(m_xTables->getByName(m_aTableList[i]));
305 catch( const Exception& )
307 DBG_UNHANDLED_EXCEPTION("dbaccess");
311 void SAL_CALL RelationLoader::onTerminated()
313 m_pParent->mergeData(m_vTableConnectionData);
314 delete this;
317 void RelationLoader::loadTableData(const Any& _aTable)
319 Reference<XPropertySet> xTableProp(_aTable,UNO_QUERY);
320 const OUString sSourceName = ::dbtools::composeTableName( m_xMetaData, xTableProp, ::dbtools::EComposeRule::InTableDefinitions, false );
321 TTableDataHelper::const_iterator aFind = m_aTableData.find(sSourceName);
322 if ( aFind == m_aTableData.end() )
324 aFind = m_aTableData.emplace(sSourceName,std::make_shared<OTableWindowData>(xTableProp,sSourceName, sSourceName, OUString())).first;
325 aFind->second->ShowAll(false);
327 TTableWindowData::value_type pReferencingTable = aFind->second;
328 Reference<XIndexAccess> xKeys = pReferencingTable->getKeys();
329 const Reference<XKeysSupplier> xKeySup(xTableProp,UNO_QUERY);
331 if ( !xKeys.is() && xKeySup.is() )
333 xKeys = xKeySup->getKeys();
336 if ( !xKeys.is() )
337 return;
339 Reference<XPropertySet> xKey;
340 const sal_Int32 nCount = xKeys->getCount();
341 for(sal_Int32 i = 0 ; i < nCount ; ++i)
343 xKeys->getByIndex(i) >>= xKey;
344 sal_Int32 nKeyType = 0;
345 xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
346 if ( KeyType::FOREIGN == nKeyType )
348 OUString sReferencedTable;
349 xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
351 // insert windows
352 TTableDataHelper::const_iterator aRefFind = m_aTableData.find(sReferencedTable);
353 if ( aRefFind == m_aTableData.end() )
355 if ( m_xTables->hasByName(sReferencedTable) )
357 Reference<XPropertySet> xReferencedTable(m_xTables->getByName(sReferencedTable),UNO_QUERY);
358 aRefFind = m_aTableData.emplace(sReferencedTable,std::make_shared<OTableWindowData>(xReferencedTable,sReferencedTable, sReferencedTable, OUString())).first;
359 aRefFind->second->ShowAll(false);
361 else
362 continue; // table name could not be found so we do not show this table relation
364 TTableWindowData::value_type pReferencedTable = aRefFind->second;
366 OUString sKeyName;
367 xKey->getPropertyValue(PROPERTY_NAME) >>= sKeyName;
368 // insert connection
369 auto xTabConnData = std::make_shared<ORelationTableConnectionData>( pReferencingTable, pReferencedTable, sKeyName );
370 m_vTableConnectionData.push_back(xTabConnData);
371 // insert columns
372 const Reference<XColumnsSupplier> xColsSup(xKey,UNO_QUERY);
373 OSL_ENSURE(xColsSup.is(),"Key is no XColumnsSupplier!");
374 const Reference<XNameAccess> xColumns = xColsSup->getColumns();
375 const Sequence< OUString> aNames = xColumns->getElementNames();
376 OUString sColumnName,sRelatedName;
377 for(sal_Int32 j=0;j<aNames.getLength();++j)
379 const Reference<XPropertySet> xPropSet(xColumns->getByName(aNames[j]),UNO_QUERY);
380 OSL_ENSURE(xPropSet.is(),"Invalid column found in KeyColumns!");
381 if ( xPropSet.is() )
383 xPropSet->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
384 xPropSet->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedName;
386 xTabConnData->SetConnLine( j, sColumnName, sRelatedName );
388 // set update/del flags
389 sal_Int32 nUpdateRule = 0;
390 sal_Int32 nDeleteRule = 0;
391 xKey->getPropertyValue(PROPERTY_UPDATERULE) >>= nUpdateRule;
392 xKey->getPropertyValue(PROPERTY_DELETERULE) >>= nDeleteRule;
394 xTabConnData->SetUpdateRules( nUpdateRule );
395 xTabConnData->SetDeleteRules( nDeleteRule );
397 // set cardinality
398 xTabConnData->SetCardinality();
404 void ORelationController::mergeData(const TTableConnectionData& _aConnectionData)
406 ::osl::MutexGuard aGuard( getMutex() );
408 m_vTableConnectionData.insert( m_vTableConnectionData.end(), _aConnectionData.begin(), _aConnectionData.end() );
409 // here we are finished, so we can collect the table from connection data
410 for (auto const& elem : m_vTableConnectionData)
412 if ( !existsTable(elem->getReferencingTable()->GetComposedName()) )
414 m_vTableData.push_back(elem->getReferencingTable());
416 if ( !existsTable(elem->getReferencedTable()->GetComposedName()) )
418 m_vTableData.push_back(elem->getReferencedTable());
421 if ( m_nThreadEvent )
423 --m_nThreadEvent;
424 if ( !m_nThreadEvent )
425 Application::PostUserEvent(LINK(this, ORelationController, OnThreadFinished));
429 IMPL_LINK_NOARG( ORelationController, OnThreadFinished, void*, void )
431 ::SolarMutexGuard aSolarGuard;
432 ::osl::MutexGuard aGuard( getMutex() );
435 getView()->initialize(); // show the windows and fill with our information
436 getView()->Invalidate(InvalidateFlags::NoErase);
437 ClearUndoManager();
438 setModified(false); // and we are not modified yet
440 if(m_vTableData.empty())
441 Execute(ID_BROWSER_ADDTABLE,Sequence<PropertyValue>());
443 catch( const Exception& )
445 DBG_UNHANDLED_EXCEPTION("dbaccess");
447 m_xWaitObject.reset();
450 void ORelationController::loadData()
452 m_xWaitObject.reset(new weld::WaitObject(getFrameWeld()));
455 if ( !m_xTables.is() )
456 return;
457 DatabaseMetaData aMeta(getConnection());
458 // this may take some time
459 const Reference< XDatabaseMetaData> xMetaData = getConnection()->getMetaData();
460 const Sequence< OUString> aNames = m_xTables->getElementNames();
461 const sal_Int32 nCount = aNames.getLength();
462 if ( aMeta.supportsThreads() )
464 const sal_Int32 nMaxElements = (nCount / MAX_THREADS) +1;
465 sal_Int32 nStart = 0,nEnd = std::min(nMaxElements,nCount);
466 while(nStart != nEnd)
468 ++m_nThreadEvent;
469 RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,nStart,nEnd);
470 pThread->createSuspended();
471 pThread->setPriority(osl_Thread_PriorityBelowNormal);
472 pThread->resume();
473 nStart = nEnd;
474 nEnd += nMaxElements;
475 nEnd = std::min(nEnd,nCount);
478 else
480 RelationLoader* pThread = new RelationLoader(this,xMetaData,m_xTables,aNames,0,nCount);
481 pThread->run();
482 pThread->onTerminated();
485 catch(SQLException& e)
487 showError(SQLExceptionInfo(e));
489 catch(const Exception&)
491 DBG_UNHANDLED_EXCEPTION("dbaccess");
495 TTableWindowData::value_type ORelationController::existsTable(std::u16string_view _rComposedTableName) const
497 ::comphelper::UStringMixEqual bCase(true);
498 for (auto const& elem : m_vTableData)
500 if(bCase(elem->GetComposedName(),_rComposedTableName))
501 return elem;
503 return TTableWindowData::value_type();
506 void ORelationController::loadLayoutInformation()
510 OSL_ENSURE(haveDataSource(),"We need a datasource from our connection!");
511 if ( haveDataSource() )
513 if ( getDataSource()->getPropertySetInfo()->hasPropertyByName(PROPERTY_LAYOUTINFORMATION) )
515 Sequence<PropertyValue> aWindows;
516 getDataSource()->getPropertyValue(PROPERTY_LAYOUTINFORMATION) >>= aWindows;
517 loadTableWindows(aWindows);
521 catch(Exception&)
526 void ORelationController::reset()
528 loadLayoutInformation();
529 ODataView* pView = getView();
530 OSL_ENSURE(pView,"No current view!");
531 if(pView)
533 pView->initialize();
534 pView->Invalidate(InvalidateFlags::NoErase);
538 bool ORelationController::allowViews() const
540 return false;
543 bool ORelationController::allowQueries() const
545 return false;
548 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */