LibreOffice Module dbaccess (master) 1
QueryTableView.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <QueryTableView.hxx>
23#include <osl/diagnose.h>
24#include <helpids.h>
25#include "QTableWindow.hxx"
26#include "QTableConnection.hxx"
28#include <QueryDesignView.hxx>
31#include <browserids.hxx>
32#include <com/sun/star/sdbc/XConnection.hpp>
33#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
34#include <com/sun/star/accessibility/AccessibleEventId.hpp>
35#include <JAccess.hxx>
36#include <com/sun/star/sdbcx/KeyType.hpp>
37#include <com/sun/star/container/XIndexAccess.hpp>
38#include <com/sun/star/beans/XPropertySet.hpp>
41#include "querydlg.hxx"
42#include <core_resource.hxx>
43#include <strings.hrc>
44#include <strings.hxx>
45
46using namespace dbaui;
47using namespace ::com::sun::star::uno;
48using namespace ::com::sun::star::sdbc;
49using namespace ::com::sun::star::sdbcx;
50using namespace ::com::sun::star::beans;
51using namespace ::com::sun::star::container;
52using namespace ::com::sun::star::accessibility;
53
54namespace
55{
62 void addUndoAction( OQueryTableView const * _pView,
63 std::unique_ptr<OQueryTabConnUndoAction> _pUndoAction,
64 OQueryTableConnection* _pConnection,
65 bool _bOwner = false)
66 {
67 _pUndoAction->SetOwnership(_bOwner);
68 _pUndoAction->SetConnection(_pConnection);
69 _pView->getDesignView()->getController().addUndoActionAndInvalidate(std::move(_pUndoAction));
70 }
77 bool openJoinDialog(OQueryTableView* _pView,const TTableConnectionData::value_type& _pConnectionData,bool _bSelectableTables)
78 {
79 OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pConnectionData.get());
80
81 DlgQryJoin aDlg(_pView,_pConnectionData,&_pView->GetTabWinMap(),_pView->getDesignView()->getController().getConnection(),_bSelectableTables);
82 bool bOk = aDlg.run() == RET_OK;
83 if( bOk )
84 {
85 pData->SetJoinType(aDlg.GetJoinType());
86 _pView->getDesignView()->getController().setModified(true);
87 }
88
89 return bOk;
90 }
96 void connectionModified(OQueryTableView* _pView,
97 OTableConnection* _pConnection,
98 bool _bAddUndo)
99 {
100 OSL_ENSURE(_pConnection,"Invalid connection!");
101 _pConnection->UpdateLineList();
102
103 // add an undo action
104 if ( _bAddUndo )
105 addUndoAction( _pView,
106 std::make_unique<OQueryAddTabConnUndoAction>(_pView),
107 static_cast< OQueryTableConnection*>(_pConnection));
108 // redraw
109 _pConnection->RecalcLines();
110 // force an invalidation of the bounding rectangle
111 _pConnection->InvalidateConnection();
112
113 _pView->Invalidate(InvalidateFlags::NoChildren);
114 }
115 void addConnections(OQueryTableView* _pView,
116 const OQueryTableWindow& _rSource,
117 const OQueryTableWindow& _rDest,
118 const Reference<XNameAccess>& _rxSourceForeignKeyColumns)
119 {
120 if ( _rSource.GetData()->isQuery() || _rDest.GetData()->isQuery() )
121 // nothing to do if one of both denotes a query
122 return;
123
124 // we found a table in our view where we can insert some connections
125 // the key columns have a property called RelatedColumn
126 // build OQueryTableConnectionData
127 auto xNewConnData = std::make_shared<OQueryTableConnectionData>( _rSource.GetData(), _rDest.GetData() );
128
129 OUString sRelatedColumn;
130
131 // iterate through all foreignkey columns to create the connections
132 const Sequence<OUString> aKeyCols = _rxSourceForeignKeyColumns->getElementNames();
133 for(const OUString& rElement : aKeyCols)
134 {
136 if ( !( _rxSourceForeignKeyColumns->getByName(rElement) >>= xColumn ) )
137 {
138 OSL_FAIL( "addConnections: invalid foreign key column!" );
139 continue;
140 }
141
142 xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn;
143
144 {
145 sal_Int32 nFindIndex = ::comphelper::findValue(_rSource.GetOriginalColumns()->getElementNames(),rElement);
146 if(nFindIndex != -1)
147 xNewConnData->SetFieldIndex(JTCS_FROM,nFindIndex+1);
148 else
149 OSL_FAIL("Column not found!");
150 }
151 // get the position inside the table
152 Reference<XNameAccess> xRefColumns = _rDest.GetOriginalColumns();
153 if(xRefColumns.is())
154 {
155 sal_Int32 nFindIndex = ::comphelper::findValue(xRefColumns->getElementNames(),sRelatedColumn);
156 if(nFindIndex != -1)
157 xNewConnData->SetFieldIndex(JTCS_TO,nFindIndex+1);
158 else
159 OSL_FAIL("Column not found!");
160 }
161 xNewConnData->AppendConnLine(rElement,sRelatedColumn);
162
163 // now add the Conn itself
164 ScopedVclPtrInstance< OQueryTableConnection > aNewConn(_pView, xNewConnData);
165 // referring to the local variable is not important, as NotifyQueryTabConn creates a new copy
166 // to add me (if not existent)
167 _pView->NotifyTabConnection(*aNewConn, false);
168 // don't create an Undo-Action for the new connection : the connection is
169 // covered by the Undo-Action for the tabwin, as the "Undo the insert" will
170 // automatically remove all connections adjacent to the win.
171 // (Because of this automatism we would have an ownership ambiguity for
172 // the connection data if we would insert the conn-Undo-Action)
173 }
174 }
175}
176
177OQueryTableView::OQueryTableView( vcl::Window* pParent,OQueryDesignView* pView)
178 : OJoinTableView( pParent,pView)
179{
181}
182
183sal_Int32 OQueryTableView::CountTableAlias(const OUString& rName, sal_Int32& rMax)
184{
185 sal_Int32 nRet = 0;
186
187 OTableWindowMap::const_iterator aIter = GetTabWinMap().find(rName);
188 while(aIter != GetTabWinMap().end())
189 {
190 OUString aNewName = rName + "_" + OUString::number(++nRet);
191 aIter = GetTabWinMap().find(aNewName);
192 }
193
194 rMax = nRet;
195
196 return nRet;
197}
198
200{
201 TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData();
202 OSL_ENSURE((getTableConnections().empty()) && (GetTabWinMap().empty()),
203 "before calling OQueryTableView::ReSync() please call ClearAll !");
204
205 // I need a collection of all window names that cannot be created so that I do not initialize connections for them.
206 std::vector<OUString> arrInvalidTables;
207
208 TTableWindowData::const_reverse_iterator aIter = rTabWinDataList.rbegin();
209 // Create the window and add it
210
211 for(;aIter != rTabWinDataList.rend();++aIter)
212 {
213 OQueryTableWindowData* pData = static_cast<OQueryTableWindowData*>(aIter->get());
214 VclPtr<OTableWindow> pTabWin = createWindow(*aIter);
215
216 // I don't use ShowTabWin as this adds the window data to the list of documents.
217 // This would be bad as I am getting them from there.
218 // Instead, I do it step by step
219 if (!pTabWin->Init())
220 {
221 // The initialisation has gone wrong, this TabWin is not available, so
222 // I must clean up the data and the document
223 pTabWin->clearListBox();
224 pTabWin.disposeAndClear();
225 arrInvalidTables.push_back(pData->GetAliasName());
226
227 rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), *aIter), rTabWinDataList.end());
228 continue;
229 }
230
231 GetTabWinMap()[pData->GetAliasName()] = pTabWin; // add at the beginning as I am going backwards through the DataList
232 // Use the default if there is no position or size
233 if (!pData->HasPosition() && !pData->HasSize())
235
236 pTabWin->Show();
237 }
238
239 // Add the connections
240 TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData();
241 TTableConnectionData::const_reverse_iterator aConIter = rTabConnDataList.rbegin();
242
243 for(;aConIter != rTabConnDataList.rend();++aConIter)
244 {
245 OQueryTableConnectionData* pTabConnData = static_cast<OQueryTableConnectionData*>(aConIter->get());
246
247 // do both tables for the connection exist ?
248 OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetWinName();
249 bool bInvalid = std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
250 strTabExistenceTest = pTabConnData->getReferencedTable()->GetWinName();
251 bInvalid = bInvalid && std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
252
253 if (bInvalid)
254 {
255 // no -> bad luck, no connection
256 rTabConnDataList.erase( std::remove(rTabConnDataList.begin(), rTabConnDataList.end(), *aConIter), rTabConnDataList.end());
257 continue;
258 }
259
260 // adds a new connection to join view and notifies our accessible and invalidates the controller
262 }
263}
264
266{
268
269 SetUpdateMode(true);
270 m_pView->getController().setModified(true);
271}
272
273VclPtr<OTableWindow> OQueryTableView::createWindow(const TTableWindowData::value_type& _pData)
274{
275 return VclPtr<OQueryTableWindow>::Create(this,_pData);
276}
277
278void OQueryTableView::NotifyTabConnection(const OQueryTableConnection& rNewConn, bool _bCreateUndoAction)
279{
280 // let's first check if I have the connection already
281 OQueryTableConnection* pTabConn = nullptr;
282 const auto& rConnections = getTableConnections();
283 auto aEnd = rConnections.end();
284 auto aIter = std::find( rConnections.begin(),
285 aEnd,
286 VclPtr<OTableConnection>(const_cast<OTableConnection*>(static_cast<const OTableConnection*>(&rNewConn)))
287 );
288 if(aIter == aEnd)
289 {
290 for (auto const& connection : rConnections)
291 {
292 if(*static_cast<OQueryTableConnection*>(connection.get()) == rNewConn)
293 {
294 pTabConn = static_cast<OQueryTableConnection*>(connection.get());
295 break;
296 }
297 }
298 }
299 else
300 pTabConn = static_cast<OQueryTableConnection*>((*aIter).get());
301
302 // no -> insert
303 if (pTabConn == nullptr)
304 {
305 // the new data ...
306 auto pNewData = std::static_pointer_cast<OQueryTableConnectionData>(rNewConn.GetData()->NewInstance());
307 pNewData->CopyFrom(*rNewConn.GetData());
308 VclPtrInstance<OQueryTableConnection> pNewConn(this, pNewData);
309 GetConnection(pNewConn);
310
311 connectionModified(this,pNewConn,_bCreateUndoAction);
312 }
313}
314
315std::shared_ptr<OTableWindowData> OQueryTableView::CreateImpl(const OUString& _rComposedName
316 ,const OUString& _sTableName
317 ,const OUString& _rWinName)
318{
319 return std::make_shared<OQueryTableWindowData>( _rComposedName, _sTableName,_rWinName );
320}
321
322void OQueryTableView::AddTabWin(const OUString& _rTableName, const OUString& _rAliasName, bool bNewTable)
323{
324 // this method has been inherited from the base class, linking back to the parent and which constructs
325 // an Alias and which passes on to my other AddTabWin
326
327 // pity _rTableName is fully qualified, OQueryDesignView expects a string which only
328 // contains schema and tables but no catalog.
329 Reference< XConnection> xConnection = m_pView->getController().getConnection();
330 if(!xConnection.is())
331 return;
332 try
333 {
334 Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
335 OUString sCatalog, sSchema, sTable;
336 ::dbtools::qualifiedNameComponents(xMetaData,
337 _rTableName,
338 sCatalog,
339 sSchema,
340 sTable,
341 ::dbtools::EComposeRule::InDataManipulation);
342 OUString sRealName(sSchema);
343 if (!sRealName.isEmpty())
344 sRealName += ".";
345 sRealName += sTable;
346
347 AddTabWin(_rTableName, sRealName, _rAliasName, bNewTable);
348 }
349 catch(SQLException&)
350 {
351 OSL_FAIL("qualifiedNameComponents");
352 }
353}
354
355// find the table which has a foreign key with this referencedTable name
356static Reference<XPropertySet> getKeyReferencedTo(const Reference<XIndexAccess>& _rxKeys,std::u16string_view _rReferencedTable)
357{
358 if(!_rxKeys.is())
360
361 // search the one and only primary key
362 const sal_Int32 nCount = _rxKeys->getCount();
363 for(sal_Int32 i=0;i<nCount ;++i)
364 {
365 Reference<XPropertySet> xKey(_rxKeys->getByIndex(i),UNO_QUERY);
366 if(xKey.is())
367 {
368 sal_Int32 nKeyType = 0;
369 xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
370 if(KeyType::FOREIGN == nKeyType)
371 {
372 OUString sReferencedTable;
373 xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
374 // TODO check case
375 if(sReferencedTable == _rReferencedTable)
376 return xKey;
377 }
378 }
379 }
381}
382
383void OQueryTableView::AddTabWin(const OUString& _rComposedName, const OUString& _rTableName, const OUString& strAlias, bool bNewTable)
384{
385 OSL_ENSURE(!_rTableName.isEmpty() || !strAlias.isEmpty(), "OQueryTableView::AddTabWin : no tables or aliases !");
386 // If the table is not set, then it is a dummy window, but at least the alias must be set
387
388 // build a new data structure
389 // first check if this already has its data
390 bool bAppend = bNewTable;
391 TTableWindowData::value_type pNewTabWinData;
393 bool bFoundElem = false;
394 for (auto const& elem : rWindowData)
395 {
396 pNewTabWinData = elem;
397 if (pNewTabWinData && pNewTabWinData->GetWinName() == strAlias && pNewTabWinData->GetComposedName() == _rComposedName && pNewTabWinData->GetTableName() == _rTableName)
398 {
399 bFoundElem = true;
400 break;
401 }
402 }
403 if ( !bAppend )
404 bAppend = !bFoundElem;
405 if ( bAppend )
406 pNewTabWinData = createTableWindowData(_rComposedName, _rTableName, strAlias);
407 // I do not need to add TabWinData to the DocShell list, ShowTabWin does that.
408
409 // Create a new window
410 VclPtr<OQueryTableWindow> pNewTabWin = static_cast<OQueryTableWindow*>(createWindow(pNewTabWinData).get());
411 // No need to initialize, as that happens in ShowTabWin
412
413 // New UndoAction
414 std::unique_ptr<OQueryTabWinShowUndoAct> pUndoAction(new OQueryTabWinShowUndoAct(this));
415 pUndoAction->SetTabWin(pNewTabWin); // Window
416 bool bSuccess = ShowTabWin(pNewTabWin, pUndoAction.get(), bAppend);
417 if(!bSuccess)
418 {
419 // reset table window
420 pUndoAction->SetTabWin(nullptr);
421 pUndoAction->SetOwnership(false);
422 return;
423 }
424
425 // Show the relations between the individual tables
426 OTableWindowMap& rTabWins = GetTabWinMap();
427 if(bNewTable && !rTabWins.empty() && !_rTableName.isEmpty())
428 {
429 modified();
430 if ( m_pAccessible )
431 m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
432 Any(),
433 Any(pNewTabWin->GetAccessible())
434 );
435
436 do {
437
438 if ( pNewTabWin->GetData()->isQuery() )
439 break;
440
441 try
442 {
443 // find relations between the table and the tables already inserted
444 Reference< XIndexAccess> xKeyIndex = pNewTabWin->GetData()->getKeys();
445 if ( !xKeyIndex.is() )
446 break;
447
448 Reference<XNameAccess> xFKeyColumns;
449 OUString aReferencedTable;
450 Reference<XColumnsSupplier> xColumnsSupplier;
451
452 const sal_Int32 nKeyCount = xKeyIndex->getCount();
453 for ( sal_Int32 i=0; i<nKeyCount ; ++i )
454 {
455 Reference< XPropertySet > xProp( xKeyIndex->getByIndex(i), UNO_QUERY_THROW );
456 xColumnsSupplier.set( xProp, UNO_QUERY_THROW );
457 xFKeyColumns.set( xColumnsSupplier->getColumns(), UNO_SET_THROW );
458
459 sal_Int32 nKeyType = 0;
460 xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
461
462 switch ( nKeyType )
463 {
464 case KeyType::FOREIGN:
465 { // our new table has a foreign key
466 // so look if the referenced table is already in our list
467 xProp->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= aReferencedTable;
468 OSL_ENSURE(!aReferencedTable.isEmpty(),"Foreign key without referencedTableName");
469
470 OTableWindowMap::const_iterator aIter = rTabWins.find(aReferencedTable);
471 OTableWindowMap::const_iterator aEnd = rTabWins.end();
472 if(aIter == aEnd)
473 {
474 for(aIter = rTabWins.begin();aIter != aEnd;++aIter)
475 {
476 OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(aIter->second.get());
477 OSL_ENSURE( pTabWinTmp,"TableWindow is null!" );
478 if ( pTabWinTmp != pNewTabWin && pTabWinTmp->GetComposedName() == aReferencedTable )
479 break;
480 }
481 }
482 if ( aIter != aEnd && pNewTabWin.get() != aIter->second.get() )
483 addConnections( this, *pNewTabWin, *static_cast<OQueryTableWindow*>(aIter->second.get()), xFKeyColumns );
484 }
485 break;
486
487 case KeyType::PRIMARY:
488 {
489 // we have a primary key so look in our list if there exists a key which this is referred to
490 for (auto const& tabWin : rTabWins)
491 {
492 OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(tabWin.second.get());
493 if ( pTabWinTmp == pNewTabWin )
494 continue;
495
496 if ( pTabWinTmp->GetData()->isQuery() )
497 continue;
498
499 OSL_ENSURE(pTabWinTmp,"TableWindow is null!");
500 Reference< XPropertySet > xFKKey = getKeyReferencedTo( pTabWinTmp->GetData()->getKeys(), pNewTabWin->GetComposedName() );
501 if ( !xFKKey.is() )
502 continue;
503
504 Reference<XColumnsSupplier> xFKColumnsSupplier( xFKKey, UNO_QUERY_THROW );
505 Reference< XNameAccess > xTColumns( xFKColumnsSupplier->getColumns(), UNO_SET_THROW );
506 addConnections( this, *pTabWinTmp, *pNewTabWin, xTColumns );
507 }
508 }
509 break;
510 }
511 }
512 }
513 catch( const Exception& )
514 {
515 DBG_UNHANDLED_EXCEPTION("dbaccess");
516 }
517
518 } while ( false );
519 }
520
521 // My parent needs to be informed about the delete
522 m_pView->getController().addUndoActionAndInvalidate( std::move(pUndoAction) );
523}
524
526{
527 OQueryTableWindow* pSourceWin = static_cast< OQueryTableWindow*>(jxdSource.pListBox->GetTabWin());
528 OQueryTableWindow* pDestWin = static_cast< OQueryTableWindow*>(jxdDest.pListBox->GetTabWin());
529
530 OUString aSourceFieldName, aDestFieldName;
531 weld::TreeView& rSourceTreeView = jxdSource.pListBox->get_widget();
532 aSourceFieldName = rSourceTreeView.get_text(jxdSource.nEntry);
533 weld::TreeView& rDestTreeView = jxdDest.pListBox->get_widget();
534 aDestFieldName = rDestTreeView.get_text(jxdDest.nEntry);
535
536 OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true);
537 if ( !pConn )
538 {
539 // new data object
540 auto xNewConnectionData = std::make_shared<OQueryTableConnectionData>(pSourceWin->GetData(), pDestWin->GetData());
541
542 sal_uInt32 nSourceFieldIndex, nDestFieldIndex;
543
544 // Get name/position of both affected fields ...
545 // Source
546 nSourceFieldIndex = jxdSource.nEntry;
547 // Dest
548 nDestFieldIndex = jxdDest.nEntry;
549
550 // ... and set them
551 xNewConnectionData->SetFieldIndex(JTCS_FROM, nSourceFieldIndex);
552 xNewConnectionData->SetFieldIndex(JTCS_TO, nDestFieldIndex);
553
554 xNewConnectionData->AppendConnLine( aSourceFieldName,aDestFieldName );
555
556 ScopedVclPtrInstance< OQueryTableConnection > aNewConnection(this, xNewConnectionData);
557 NotifyTabConnection(*aNewConnection);
558 // As usual with NotifyTabConnection, using a local variable is fine because a copy is made
559 }
560 else
561 {
562 // the connection could point on the other side
563 if(pConn->GetSourceWin() == pDestWin)
564 {
565 OUString aTmp(aSourceFieldName);
566 aSourceFieldName = aDestFieldName;
567 aDestFieldName = aTmp;
568 }
569
570 pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName );
571
572 connectionModified(this,pConn,false);
573 }
574}
575
577{
578 if (openJoinDialog(this, rConnection->GetData(), false))
579 {
580 connectionModified(this, rConnection, false);
581 SelectConn(rConnection);
582 }
583}
584
586{
587 TTableConnectionData::value_type pData = std::make_shared<OQueryTableConnectionData>();
588 if( !openJoinDialog(this,pData,true) )
589 return;
590
592 OQueryTableWindow* pSourceWin = static_cast< OQueryTableWindow*>(rMap[pData->getReferencingTable()->GetWinName()].get());
593 OQueryTableWindow* pDestWin = static_cast< OQueryTableWindow*>(rMap[pData->getReferencedTable()->GetWinName()].get());
594 // first we have to look if the this connection already exists
595 OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true);
596 bool bNew = true;
597 if ( pConn )
598 {
599 pConn->GetData()->CopyFrom( *pData );
600 bNew = false;
601 }
602 else
603 {
604 // create a new connection and append it
606 GetConnection(pQConn);
607 pConn = pQConn;
608 }
609 connectionModified(this,pConn,bNew);
610 if ( !bNew && pConn == GetSelectedConn() ) // our connection was selected before so we have to reselect it
611 SelectConn( pConn );
612}
613
615{
616 VclPtr<OQueryTableConnection> xConnection(static_cast<OQueryTableConnection*>(rConnection.get()));
617
618 // we don't want that our connection will be deleted, we put it in the undo manager
619 bool bRet = OJoinTableView::RemoveConnection(rConnection, false);
620
621 // add undo action
622 addUndoAction(this,
623 std::make_unique<OQueryDelTabConnUndoAction>(this),
624 xConnection.get(),
625 true);
626
627 return bRet;
628}
629
631{
632 OSL_ENSURE(!rAliasName.isEmpty(), "OQueryTableView::FindTable : the AliasName should not be empty !");
633 // (it is harmless but does not make sense and indicates that there is probably an error in the caller)
634 OTableWindowMap::const_iterator aIter = GetTabWinMap().find(rAliasName);
635 if(aIter != GetTabWinMap().end())
636 return static_cast<OQueryTableWindow*>(aIter->second.get());
637 return nullptr;
638}
639
640bool OQueryTableView::FindTableFromField(const OUString& rFieldName, OTableFieldDescRef const & rInfo, sal_uInt16& rCnt)
641{
642 rCnt = 0;
643 for (auto const& tabWin : GetTabWinMap())
644 {
645 if(static_cast<OQueryTableWindow*>(tabWin.second.get())->ExistsField(rFieldName, rInfo))
646 ++rCnt;
647 }
648 // TODO JNA : what should we rCnt > 1?
649
650 return rCnt == 1;
651}
652
654{
655
656 for (auto const& tabWin : GetTabWinMap())
657 {
658 if ( tabWin.second == &rTabWin )
659 {
660 return true;
661 }
662 }
663
664 return false;
665}
666
668{
669 OSL_ENSURE(pTabWin != nullptr, "OQueryTableView::RemoveTabWin : Window should not be NULL !");
670
671 if(!(pTabWin && ContainsTabWin(*pTabWin))) // #i122589# check if registered before deleting
672 return;
673
674 // I need my parent so it can be informed about the deletion
675 OQueryDesignView* pParent = static_cast<OQueryDesignView*>(getDesignView());
676
677 SfxUndoManager& rUndoMgr = m_pView->getController().GetUndoManager();
678 rUndoMgr.EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE) , OUString(), 0, ViewShellId(-1));
679
680 // add the Undo-Action
681 std::unique_ptr<OQueryTabWinDelUndoAct> pUndoAction(new OQueryTabWinDelUndoAct(this));
682 pUndoAction->SetTabWin(static_cast< OQueryTableWindow*>(pTabWin));
683
684 // and hide the window
685 HideTabWin(static_cast< OQueryTableWindow*>(pTabWin), pUndoAction.get());
686
687 // Undo Actions and delete the fields in SelectionBrowseBox
688 pParent->TableDeleted( static_cast< OQueryTableWindowData*>(pTabWin->GetData().get())->GetAliasName() );
689
690 m_pView->getController().addUndoActionAndInvalidate( std::move(pUndoAction) );
691 rUndoMgr.LeaveListAction();
692
693 modified();
694 if ( m_pAccessible )
695 m_pAccessible->notifyAccessibleEvent( AccessibleEventId::CHILD,
696 Any(pTabWin->GetAccessible()),
697 Any()
698 );
699}
700
702{
703
704 Invalidate(InvalidateFlags::NoChildren);
706}
707
709{
710 // add to me and the document
711
712 addConnection( pConn );
713}
714
716{
717 // Pay attention to the selection
718 // remove from me and the document
719 VclPtr<OTableConnection> xConn(rConn.get());
720 RemoveConnection(xConn, false);
721}
722
724{
725 OTableWindowMap& rTabWins = GetTabWinMap();
726
727 // Window
728 // save the position in its data
730 // (I need to go via the parent, as only the parent knows the position of the scrollbars)
731 // and then out of the TabWins list and hide
732 OTableWindowMap::const_iterator aIter = std::find_if(rTabWins.begin(), rTabWins.end(),
733 [&pTabWin](const OTableWindowMap::value_type& rEntry) { return rEntry.second == pTabWin; });
734 if (aIter != rTabWins.end())
735 rTabWins.erase( aIter );
736
737 pTabWin->Hide(); // do not destroy it, as it is still in the undo list!!
738
739 // the TabWin data must also be passed out of my responsibility
740 TTableWindowData& rTabWinDataList = m_pView->getController().getTableWindowData();
741 rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), pTabWin->GetData()), rTabWinDataList.end());
742 // The data should not be destroyed as TabWin itself - which is still alive - needs them
743 // Either it goes back into my responsibility, (via ShowTabWin), then I add the data back,
744 // or the Undo-Action, which currently has full responsibility for the window
745 // and its data, gets destroyed and destroys both the window and its data
746
747 if (m_pLastFocusTabWin == pTabWin)
748 m_pLastFocusTabWin = nullptr;
749
750 // collect connections belonging to the window and pass to UndoAction
751 sal_Int16 nCnt = 0;
752 const auto& rTabConList = getTableConnections();
753 auto aIter2 = rTabConList.begin();
754 for(;aIter2 != rTabConList.end();)// the end may change
755 {
756 VclPtr<OTableConnection> xTmpEntry = *aIter2;
757 OQueryTableConnection* pTmpEntry = static_cast<OQueryTableConnection*>(xTmpEntry.get());
758 OSL_ENSURE(pTmpEntry,"OQueryTableConnection is null!");
759 if( pTmpEntry->GetAliasName(JTCS_FROM) == pTabWin->GetAliasName() ||
760 pTmpEntry->GetAliasName(JTCS_TO) == pTabWin->GetAliasName() )
761 {
762 // add to undo list
763 pUndoAction->InsertConnection(xTmpEntry);
764
765 // call base class because we append an undo action
766 // but this time we are in an undo action list
767 OJoinTableView::RemoveConnection(xTmpEntry, false);
768 aIter2 = rTabConList.begin();
769 ++nCnt;
770 }
771 else
772 ++aIter2;
773 }
774
775 if (nCnt)
777
778 m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE);
779
780 // inform the UndoAction that the window and connections belong to it
781 pUndoAction->SetOwnership(true);
782
783 // by doing so, we have modified the document
784 m_pView->getController().setModified( true );
785 m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
786}
787
788bool OQueryTableView::ShowTabWin( OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction, bool _bAppend )
789{
790
791 bool bSuccess = false;
792
793 if (pTabWin)
794 {
795 if (pTabWin->Init())
796 {
797 TTableWindowData::value_type pData = pTabWin->GetData();
798 OSL_ENSURE(pData != nullptr, "OQueryTableView::ShowTabWin : TabWin has no data !");
799 // If there is a position and size defined, we use them
800 if (pData->HasPosition() && pData->HasSize())
801 {
802 Size aSize(CalcZoom(pData->GetSize().Width()),CalcZoom(pData->GetSize().Height()));
803 pTabWin->SetPosSizePixel(pData->GetPosition(), aSize);
804 }
805 else
806 // else set a default position
808
809 // Show the window and add to the list
810 OUString sName = static_cast< OQueryTableWindowData*>(pData.get())->GetAliasName();
811 OSL_ENSURE(GetTabWinMap().find(sName) == GetTabWinMap().end(),"Alias name already in list!");
812 GetTabWinMap().emplace(sName,pTabWin);
813
814 pTabWin->Show();
815
816 pTabWin->PaintImmediately();
817 // We must call Update() in order to show the connections in the window correctly. This sounds strange,
818 // but the Listbox has an internal Member which is initialized when the Listbox is first shown (after the Listbox
819 // is filled in Init). This Member will eventually be needed for
820 // GetEntryPos, and then in turn by the Connection, when its starting point to the window must be determined.
821
822 // the Connections
823 auto rTableCon = pUndoAction->GetTabConnList();
824 for(const auto& conn : rTableCon)
825 addConnection(conn); // add all connections from the undo action
826
827 rTableCon.clear();
828
829 // and add the window's data to the list (of the document)
830 if(_bAppend)
831 m_pView->getController().getTableWindowData().push_back(pTabWin->GetData());
832
833 m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE);
834
835 // and inform the UndoAction that the window belongs to me
836 pUndoAction->SetOwnership(false);
837
838 bSuccess = true;
839 }
840 else
841 {
842 // Initialisation failed
843 // (for example when the Connection to the database is not available at the moment)
844 pTabWin->clearListBox();
845 pTabWin->disposeOnce();
846 }
847 }
848
849 // show that I have changed the document
850 if(!m_pView->getController().isReadOnly())
851 m_pView->getController().setModified( true );
852
853 m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
854
855 return bSuccess;
856}
857
859{
860 OSL_ENSURE(getDesignView() != nullptr, "OQueryTableView::InsertField : has no Parent !");
861 static_cast<OQueryDesignView*>(getDesignView())->InsertField(rInfo);
862}
863
865{
866 for(const auto& conn : getTableConnections())
867 {
868 OQueryTableConnection* pTemp = static_cast<OQueryTableConnection*>(conn.get());
869 if (pTemp->IsVisited() &&
870 (pFrom == static_cast< OQueryTableWindow*>(pTemp->GetSourceWin()) || pFrom == static_cast< OQueryTableWindow*>(pTemp->GetDestWin())))
871 return true;
872 }
873
874 return false;
875}
876
878{
879 OUString sError(DBA_RES(STR_STATEMENT_WITHOUT_RESULT_SET));
880 ::dbtools::throwSQLException( sError, ::dbtools::StandardSQLState::GENERAL_ERROR, nullptr );
881}
882
883bool OQueryTableView::suppressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const
884{
885 OQueryTableConnectionData* pQueryData = static_cast<OQueryTableConnectionData*>(_pData.get());
886 return pQueryData && (pQueryData->GetJoinType() == CROSS_JOIN);
887}
888
889/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sSchema
OptionalString sCatalog
OptionalString sName
static Reference< XPropertySet > getKeyReferencedTo(const Reference< XIndexAccess > &_rxKeys, std::u16string_view _rReferencedTable)
#define ID_BROWSER_ADDTABLE
Definition: browserids.hxx:53
size_t LeaveListAction()
virtual void EnterListAction(const OUString &rComment, const OUString &rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId)
void disposeAndClear()
reference_type * get() const
static VclPtr< reference_type > Create(Arg &&... arg)
TTableWindowData & getTableWindowData()
void SaveTabWinUIConfig(OTableWindow const *pWin)
OJoinController & getController() const
rtl::Reference< OJoinDesignViewAccess > m_pAccessible
const std::vector< VclPtr< OTableConnection > > & getTableConnections() const
gives a read only access to the connection vector
virtual bool RemoveConnection(VclPtr< OTableConnection > &rConnection, bool bDelete)
RemoveConnection allows to remove connections from join table view.
VclPtr< OTableWindow > m_pLastFocusTabWin
TTableWindowData::value_type createTableWindowData(const OUString &_rComposedName, const OUString &_sTableName, const OUString &_rWinName)
virtual void EnsureVisible(const OTableWindow *_pWin)
std::map< OUString, VclPtr< OTableWindow > > OTableWindowMap
virtual void ClearAll()
Hard deletion.
void SelectConn(OTableConnection *pConn)
OJoinDesignView * getDesignView() const
VclPtr< OJoinDesignView > m_pView
VclPtr< OTableConnection > & GetSelectedConn()
void SetDefaultTabWinPosSize(OTableWindow *pTabWin)
OTableConnection * GetTabConn(const OTableWindow *pLhs, const OTableWindow *pRhs, bool _bSuppressCrossOrNaturalJoin=false) const
void addConnection(OTableConnection *_pConnection, bool _bAddData=true)
allows to add new connections to join table view
OTableWindowMap & GetTabWinMap()
void TableDeleted(const OUString &rAliasName)
void InsertConnection(OTableConnection *pConnection)
std::vector< VclPtr< OTableConnection > > & GetTabConnList()
OUString const & GetAliasName(EConnectionSide nWhich) const
virtual void onNoColumns_throw() override
called when init fails at the tablewindowdata because the m_xTable object could not provide columns,...
virtual void ReSync() override
rebuild everything (TabWins, Connections) (PRECONDITION: ClearAll was called previously)
virtual bool RemoveConnection(VclPtr< OTableConnection > &rConn, bool bDelete) override
RemoveConnection allows to remove connections from join table view.
bool FindTableFromField(const OUString &rFieldName, OTableFieldDescRef const &rInfo, sal_uInt16 &rCnt)
void GetConnection(OQueryTableConnection *pConn)
Inserting a Connection the structure.
bool ShowTabWin(OQueryTableWindow *pTabWin, OQueryTabWinUndoAct *pUndoAction, bool _bAppend)
void NotifyTabConnection(const OQueryTableConnection &rNewConn, bool _bCreateUndoAction=true)
announce new Connection and insert it, if not existing yet
bool ExistsAVisitedConn(const OQueryTableWindow *pFrom) const
virtual std::shared_ptr< OTableWindowData > CreateImpl(const OUString &_rComposedName, const OUString &_sTableName, const OUString &_rWinName) override
virtual bool suppressCrossNaturalJoin(const TTableConnectionData::value_type &_pData) const override
OQueryTableWindow * FindTable(const OUString &rAliasName)
search TabWin
virtual void EnsureVisible(const OTableWindow *_pWin) override
ensure visibility of TabWins (+ and invalidate connections)
virtual void ConnDoubleClicked(VclPtr< OTableConnection > &rConnection) override
bool ContainsTabWin(const OTableWindow &rTabWin)
base class overwritten: create and delete windows (not really delete, as it becomes an UndoAction)
void HideTabWin(OQueryTableWindow *pTabWin, OQueryTabWinUndoAct *pUndoAction)
virtual VclPtr< OTableWindow > createWindow(const TTableWindowData::value_type &_pData) override
factory method to create table windows
void createNewConnection()
opens the join dialog and allows to create a new join connection
void InsertField(const OTableFieldDescRef &rInfo)
insert field (simply passed to parents)
virtual void AddTabWin(const OUString &_rTableName, const OUString &_rAliasName, bool bNewTable=false) override
virtual void RemoveTabWin(OTableWindow *pTabWin) override
virtual void ClearAll() override
delete everything hard (TabWins, Connections), without any notifications
sal_Int32 CountTableAlias(const OUString &rName, sal_Int32 &rMax)
how many tables with a certain alias do I already have?
virtual void AddConnection(const OJoinExchangeData &jxdSource, const OJoinExchangeData &jxdDest) override
base class overwritten: create and delete Connections
void DropConnection(VclPtr< OQueryTableConnection > const &rConn)
Removing a Connection from the structure.
OUString const & GetAliasName() const
virtual bool Init() override
bool ExistsField(const OUString &strFieldName, OTableFieldDescRef const &rInfo)
OUString const & GetAliasName() const
void addUndoActionAndInvalidate(std::unique_ptr< SfxUndoAction > pAction)
addUndoActionAndInvalidate adds an undo action to the undoManager, additionally invalidates the UNDO ...
const TTableWindowData::value_type & getReferencingTable() const
const TTableWindowData::value_type & getReferencedTable() const
const TTableConnectionData::value_type & GetData() const
OTableWindow * GetDestWin() const
OTableWindow * GetSourceWin() const
css::uno::Reference< css::container::XNameAccess > GetOriginalColumns() const
const TTableWindowData::value_type & GetData() const
void clearListBox()
clears the listbox inside.
void SetPosSizePixel(const Point &rNewPos, const Size &rNewSize) override
OUString const & GetComposedName() const
void SetUpdateMode(bool bUpdate)
void PaintImmediately()
tools::Long CalcZoom(tools::Long n) const
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
css::uno::Reference< css::accessibility::XAccessible > GetAccessible(bool bCreate=true)
void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
void SetHelpId(const OUString &)
virtual OUString get_text(int row, int col=-1) const=0
#define DBA_RES(id)
int nCount
#define DBG_UNHANDLED_EXCEPTION(...)
Reference< XColumn > xColumn
constexpr OUStringLiteral HID_CTL_QRYDGNTAB
Definition: helpids.h:33
std::unique_ptr< sal_Int32[]> pData
@ Exception
OSQLColumns::const_iterator find(const OSQLColumns::const_iterator &first, const OSQLColumns::const_iterator &last, std::u16string_view _rVal, const ::comphelper::UStringMixEqual &_rCase)
std::vector< std::shared_ptr< OTableConnectionData > > TTableConnectionData
@ JTCS_TO
Definition: QEnumTypes.hxx:44
@ JTCS_FROM
Definition: QEnumTypes.hxx:43
std::vector< std::shared_ptr< OTableWindowData > > TTableWindowData
@ CROSS_JOIN
Definition: QEnumTypes.hxx:58
int i
end
constexpr OUStringLiteral PROPERTY_RELATEDCOLUMN(u"RelatedColumn")
constexpr OUStringLiteral PROPERTY_TYPE(u"Type")
constexpr OUStringLiteral PROPERTY_REFERENCEDTABLE(u"ReferencedTable")
VclPtr< OTableWindowListBox > pListBox
RET_OK