1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <QueryTableView.hxx>
21 #include <TableFieldDescription.hxx>
22 #include <comphelper/diagnose_ex.hxx>
23 #include <osl/diagnose.h>
25 #include "QTableWindow.hxx"
26 #include "QTableConnection.hxx"
27 #include "QTableConnectionData.hxx"
28 #include <QueryDesignView.hxx>
29 #include "QueryAddTabConnUndoAction.hxx"
30 #include "QueryTabWinShowUndoAct.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>
39 #include <connectivity/dbtools.hxx>
40 #include <comphelper/sequence.hxx>
41 #include "querydlg.hxx"
42 #include <core_resource.hxx>
43 #include <strings.hrc>
44 #include <strings.hxx>
46 using namespace dbaui
;
47 using namespace ::com::sun::star::uno
;
48 using namespace ::com::sun::star::sdbc
;
49 using namespace ::com::sun::star::sdbcx
;
50 using namespace ::com::sun::star::beans
;
51 using namespace ::com::sun::star::container
;
52 using namespace ::com::sun::star::accessibility
;
56 /** appends a new TabAdd Undo action at controller
57 @param _pView the view which we use
58 @param _pUndoAction the undo action which should be added
59 @param _pConnection the connection for which the undo action should be appended
60 @param _bOwner is the undo action the owner
62 void addUndoAction( OQueryTableView
const * _pView
,
63 std::unique_ptr
<OQueryTabConnUndoAction
> _pUndoAction
,
64 OQueryTableConnection
* _pConnection
,
67 _pUndoAction
->SetOwnership(_bOwner
);
68 _pUndoAction
->SetConnection(_pConnection
);
69 _pView
->getDesignView()->getController().addUndoActionAndInvalidate(std::move(_pUndoAction
));
71 /** openJoinDialog opens the join dialog with this connection data
72 @param _pView the view which we use
73 @param _pConnectionData the connection data
75 @return true when OK was pressed otherwise false
77 bool openJoinDialog(OQueryTableView
* _pView
,const TTableConnectionData::value_type
& _pConnectionData
,bool _bSelectableTables
)
79 OQueryTableConnectionData
* pData
= static_cast< OQueryTableConnectionData
*>(_pConnectionData
.get());
81 DlgQryJoin
aDlg(_pView
,_pConnectionData
,&_pView
->GetTabWinMap(),_pView
->getDesignView()->getController().getConnection(),_bSelectableTables
);
82 bool bOk
= aDlg
.run() == RET_OK
;
85 pData
->SetJoinType(aDlg
.GetJoinType());
86 _pView
->getDesignView()->getController().setModified(true);
91 /** connectionModified adds an undo action for the modified connection and forces a redraw
92 @param _pView the view which we use
93 @param _pConnection the connection which was modified
94 @param _bAddUndo true when an undo action should be appended
96 void connectionModified(OQueryTableView
* _pView
,
97 OTableConnection
* _pConnection
,
100 OSL_ENSURE(_pConnection
,"Invalid connection!");
101 _pConnection
->UpdateLineList();
103 // add an undo action
105 addUndoAction( _pView
,
106 std::make_unique
<OQueryAddTabConnUndoAction
>(_pView
),
107 static_cast< OQueryTableConnection
*>(_pConnection
));
109 _pConnection
->RecalcLines();
110 // force an invalidation of the bounding rectangle
111 _pConnection
->InvalidateConnection();
113 _pView
->Invalidate(InvalidateFlags::NoChildren
);
115 void addConnections(OQueryTableView
* _pView
,
116 const OQueryTableWindow
& _rSource
,
117 const OQueryTableWindow
& _rDest
,
118 const Reference
<XNameAccess
>& _rxSourceForeignKeyColumns
)
120 if ( _rSource
.GetData()->isQuery() || _rDest
.GetData()->isQuery() )
121 // nothing to do if one of both denotes a query
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() );
129 OUString sRelatedColumn
;
131 // iterate through all foreignkey columns to create the connections
132 const Sequence
<OUString
> aKeyCols
= _rxSourceForeignKeyColumns
->getElementNames();
133 for(const OUString
& rElement
: aKeyCols
)
135 Reference
<XPropertySet
> xColumn
;
136 if ( !( _rxSourceForeignKeyColumns
->getByName(rElement
) >>= xColumn
) )
138 OSL_FAIL( "addConnections: invalid foreign key column!" );
142 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
145 sal_Int32 nFindIndex
= ::comphelper::findValue(_rSource
.GetOriginalColumns()->getElementNames(),rElement
);
147 xNewConnData
->SetFieldIndex(JTCS_FROM
,nFindIndex
+1);
149 OSL_FAIL("Column not found!");
151 // get the position inside the table
152 Reference
<XNameAccess
> xRefColumns
= _rDest
.GetOriginalColumns();
155 sal_Int32 nFindIndex
= ::comphelper::findValue(xRefColumns
->getElementNames(),sRelatedColumn
);
157 xNewConnData
->SetFieldIndex(JTCS_TO
,nFindIndex
+1);
159 OSL_FAIL("Column not found!");
161 xNewConnData
->AppendConnLine(rElement
,sRelatedColumn
);
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)
177 OQueryTableView::OQueryTableView( vcl::Window
* pParent
,OQueryDesignView
* pView
)
178 : OJoinTableView( pParent
,pView
)
180 SetHelpId(HID_CTL_QRYDGNTAB
);
183 sal_Int32
OQueryTableView::CountTableAlias(const OUString
& rName
, sal_Int32
& rMax
)
187 OTableWindowMap::const_iterator aIter
= GetTabWinMap().find(rName
);
188 while(aIter
!= GetTabWinMap().end())
190 OUString aNewName
= rName
+ "_" + OUString::number(++nRet
);
191 aIter
= GetTabWinMap().find(aNewName
);
199 void OQueryTableView::ReSync()
201 TTableWindowData
& rTabWinDataList
= m_pView
->getController().getTableWindowData();
202 OSL_ENSURE((getTableConnections().empty()) && (GetTabWinMap().empty()),
203 "before calling OQueryTableView::ReSync() please call ClearAll !");
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
;
208 TTableWindowData::const_reverse_iterator aIter
= rTabWinDataList
.rbegin();
209 // Create the window and add it
211 for(;aIter
!= rTabWinDataList
.rend();++aIter
)
213 OQueryTableWindowData
* pData
= static_cast<OQueryTableWindowData
*>(aIter
->get());
214 VclPtr
<OTableWindow
> pTabWin
= createWindow(*aIter
);
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())
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());
227 rTabWinDataList
.erase( std::remove(rTabWinDataList
.begin(), rTabWinDataList
.end(), *aIter
), rTabWinDataList
.end());
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())
234 SetDefaultTabWinPosSize(pTabWin
);
239 // Add the connections
240 TTableConnectionData
& rTabConnDataList
= m_pView
->getController().getTableConnectionData();
241 TTableConnectionData::const_reverse_iterator aConIter
= rTabConnDataList
.rbegin();
243 for(;aConIter
!= rTabConnDataList
.rend();++aConIter
)
245 OQueryTableConnectionData
* pTabConnData
= static_cast<OQueryTableConnectionData
*>(aConIter
->get());
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();
255 // no -> bad luck, no connection
256 rTabConnDataList
.erase( std::remove(rTabConnDataList
.begin(), rTabConnDataList
.end(), *aConIter
), rTabConnDataList
.end());
260 // adds a new connection to join view and notifies our accessible and invalidates the controller
261 addConnection(VclPtr
<OQueryTableConnection
>::Create(this, *aConIter
));
265 void OQueryTableView::ClearAll()
267 OJoinTableView::ClearAll();
270 m_pView
->getController().setModified(true);
273 VclPtr
<OTableWindow
> OQueryTableView::createWindow(const TTableWindowData::value_type
& _pData
)
275 return VclPtr
<OQueryTableWindow
>::Create(this,_pData
);
278 void OQueryTableView::NotifyTabConnection(const OQueryTableConnection
& rNewConn
, bool _bCreateUndoAction
)
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(),
286 VclPtr
<OTableConnection
>(const_cast<OTableConnection
*>(static_cast<const OTableConnection
*>(&rNewConn
)))
290 for (auto const& connection
: rConnections
)
292 if(*static_cast<OQueryTableConnection
*>(connection
.get()) == rNewConn
)
294 pTabConn
= static_cast<OQueryTableConnection
*>(connection
.get());
300 pTabConn
= static_cast<OQueryTableConnection
*>((*aIter
).get());
303 if (pTabConn
== nullptr)
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
);
311 connectionModified(this,pNewConn
,_bCreateUndoAction
);
315 std::shared_ptr
<OTableWindowData
> OQueryTableView::CreateImpl(const OUString
& _rComposedName
316 ,const OUString
& _sTableName
317 ,const OUString
& _rWinName
)
319 return std::make_shared
<OQueryTableWindowData
>( _rComposedName
, _sTableName
,_rWinName
);
322 void OQueryTableView::AddTabWin(const OUString
& _rTableName
, const OUString
& _rAliasName
, bool bNewTable
)
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
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())
334 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
335 OUString sCatalog
, sSchema
, sTable
;
336 ::dbtools::qualifiedNameComponents(xMetaData
,
341 ::dbtools::EComposeRule::InDataManipulation
);
342 OUString
sRealName(sSchema
);
343 if (!sRealName
.isEmpty())
347 AddTabWin(_rTableName
, sRealName
, _rAliasName
, bNewTable
);
351 OSL_FAIL("qualifiedNameComponents");
355 // find the table which has a foreign key with this referencedTable name
356 static Reference
<XPropertySet
> getKeyReferencedTo(const Reference
<XIndexAccess
>& _rxKeys
,std::u16string_view _rReferencedTable
)
359 return Reference
<XPropertySet
>();
361 // search the one and only primary key
362 const sal_Int32 nCount
= _rxKeys
->getCount();
363 for(sal_Int32 i
=0;i
<nCount
;++i
)
365 Reference
<XPropertySet
> xKey(_rxKeys
->getByIndex(i
),UNO_QUERY
);
368 sal_Int32 nKeyType
= 0;
369 xKey
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
370 if(KeyType::FOREIGN
== nKeyType
)
372 OUString sReferencedTable
;
373 xKey
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= sReferencedTable
;
375 if(sReferencedTable
== _rReferencedTable
)
380 return Reference
<XPropertySet
>();
383 void OQueryTableView::AddTabWin(const OUString
& _rComposedName
, const OUString
& _rTableName
, const OUString
& strAlias
, bool bNewTable
)
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
388 // build a new data structure
389 // first check if this already has its data
390 bool bAppend
= bNewTable
;
391 TTableWindowData::value_type pNewTabWinData
;
392 TTableWindowData
& rWindowData
= getDesignView()->getController().getTableWindowData();
393 bool bFoundElem
= false;
394 for (auto const& elem
: rWindowData
)
396 pNewTabWinData
= elem
;
397 if (pNewTabWinData
&& pNewTabWinData
->GetWinName() == strAlias
&& pNewTabWinData
->GetComposedName() == _rComposedName
&& pNewTabWinData
->GetTableName() == _rTableName
)
404 bAppend
= !bFoundElem
;
406 pNewTabWinData
= createTableWindowData(_rComposedName
, _rTableName
, strAlias
);
407 // I do not need to add TabWinData to the DocShell list, ShowTabWin does that.
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
414 std::unique_ptr
<OQueryTabWinShowUndoAct
> pUndoAction(new OQueryTabWinShowUndoAct(this));
415 pUndoAction
->SetTabWin(pNewTabWin
); // Window
416 bool bSuccess
= ShowTabWin(pNewTabWin
, pUndoAction
.get(), bAppend
);
419 // reset table window
420 pUndoAction
->SetTabWin(nullptr);
421 pUndoAction
->SetOwnership(false);
425 // Show the relations between the individual tables
426 OTableWindowMap
& rTabWins
= GetTabWinMap();
427 if(bNewTable
&& !rTabWins
.empty() && !_rTableName
.isEmpty())
431 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
433 Any(pNewTabWin
->GetAccessible())
438 if ( pNewTabWin
->GetData()->isQuery() )
443 // find relations between the table and the tables already inserted
444 Reference
< XIndexAccess
> xKeyIndex
= pNewTabWin
->GetData()->getKeys();
445 if ( !xKeyIndex
.is() )
448 Reference
<XNameAccess
> xFKeyColumns
;
449 OUString aReferencedTable
;
450 Reference
<XColumnsSupplier
> xColumnsSupplier
;
452 const sal_Int32 nKeyCount
= xKeyIndex
->getCount();
453 for ( sal_Int32 i
=0; i
<nKeyCount
; ++i
)
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
);
459 sal_Int32 nKeyType
= 0;
460 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
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");
470 OTableWindowMap::const_iterator aIter
= rTabWins
.find(aReferencedTable
);
471 OTableWindowMap::const_iterator aEnd
= rTabWins
.end();
474 for(aIter
= rTabWins
.begin();aIter
!= aEnd
;++aIter
)
476 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(aIter
->second
.get());
477 OSL_ENSURE( pTabWinTmp
,"TableWindow is null!" );
478 if ( pTabWinTmp
!= pNewTabWin
&& pTabWinTmp
->GetComposedName() == aReferencedTable
)
482 if ( aIter
!= aEnd
&& pNewTabWin
.get() != aIter
->second
.get() )
483 addConnections( this, *pNewTabWin
, *static_cast<OQueryTableWindow
*>(aIter
->second
.get()), xFKeyColumns
);
487 case KeyType::PRIMARY
:
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
)
492 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(tabWin
.second
.get());
493 if ( pTabWinTmp
== pNewTabWin
)
496 if ( pTabWinTmp
->GetData()->isQuery() )
499 OSL_ENSURE(pTabWinTmp
,"TableWindow is null!");
500 Reference
< XPropertySet
> xFKKey
= getKeyReferencedTo( pTabWinTmp
->GetData()->getKeys(), pNewTabWin
->GetComposedName() );
504 Reference
<XColumnsSupplier
> xFKColumnsSupplier( xFKKey
, UNO_QUERY_THROW
);
505 Reference
< XNameAccess
> xTColumns( xFKColumnsSupplier
->getColumns(), UNO_SET_THROW
);
506 addConnections( this, *pTabWinTmp
, *pNewTabWin
, xTColumns
);
513 catch( const Exception
& )
515 DBG_UNHANDLED_EXCEPTION("dbaccess");
521 // My parent needs to be informed about the delete
522 m_pView
->getController().addUndoActionAndInvalidate( std::move(pUndoAction
) );
525 void OQueryTableView::AddConnection(const OJoinExchangeData
& jxdSource
, const OJoinExchangeData
& jxdDest
)
527 OQueryTableWindow
* pSourceWin
= static_cast< OQueryTableWindow
*>(jxdSource
.pListBox
->GetTabWin());
528 OQueryTableWindow
* pDestWin
= static_cast< OQueryTableWindow
*>(jxdDest
.pListBox
->GetTabWin());
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
);
536 OTableConnection
* pConn
= GetTabConn(pSourceWin
,pDestWin
,true);
540 auto xNewConnectionData
= std::make_shared
<OQueryTableConnectionData
>(pSourceWin
->GetData(), pDestWin
->GetData());
542 sal_uInt32 nSourceFieldIndex
, nDestFieldIndex
;
544 // Get name/position of both affected fields ...
546 nSourceFieldIndex
= jxdSource
.nEntry
;
548 nDestFieldIndex
= jxdDest
.nEntry
;
551 xNewConnectionData
->SetFieldIndex(JTCS_FROM
, nSourceFieldIndex
);
552 xNewConnectionData
->SetFieldIndex(JTCS_TO
, nDestFieldIndex
);
554 xNewConnectionData
->AppendConnLine( aSourceFieldName
,aDestFieldName
);
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
562 // the connection could point on the other side
563 if(pConn
->GetSourceWin() == pDestWin
)
565 OUString
aTmp(aSourceFieldName
);
566 aSourceFieldName
= aDestFieldName
;
567 aDestFieldName
= aTmp
;
570 pConn
->GetData()->AppendConnLine( aSourceFieldName
,aDestFieldName
);
572 connectionModified(this,pConn
,false);
576 void OQueryTableView::ConnDoubleClicked(VclPtr
<OTableConnection
>& rConnection
)
578 if (openJoinDialog(this, rConnection
->GetData(), false))
580 connectionModified(this, rConnection
, false);
581 SelectConn(rConnection
);
585 void OQueryTableView::createNewConnection()
587 TTableConnectionData::value_type pData
= std::make_shared
<OQueryTableConnectionData
>();
588 if( !openJoinDialog(this,pData
,true) )
591 OTableWindowMap
& rMap
= GetTabWinMap();
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);
599 pConn
->GetData()->CopyFrom( *pData
);
604 // create a new connection and append it
605 VclPtrInstance
<OQueryTableConnection
> pQConn(this, pData
);
606 GetConnection(pQConn
);
609 connectionModified(this,pConn
,bNew
);
610 if ( !bNew
&& pConn
== GetSelectedConn() ) // our connection was selected before so we have to reselect it
614 bool OQueryTableView::RemoveConnection(VclPtr
<OTableConnection
>& rConnection
, bool /*_bDelete*/)
616 VclPtr
<OQueryTableConnection
> xConnection(static_cast<OQueryTableConnection
*>(rConnection
.get()));
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);
623 std::make_unique
<OQueryDelTabConnUndoAction
>(this),
630 OQueryTableWindow
* OQueryTableView::FindTable(const OUString
& rAliasName
)
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());
640 bool OQueryTableView::FindTableFromField(const OUString
& rFieldName
, OTableFieldDescRef
const & rInfo
, sal_uInt16
& rCnt
)
643 for (auto const& tabWin
: GetTabWinMap())
645 if(static_cast<OQueryTableWindow
*>(tabWin
.second
.get())->ExistsField(rFieldName
, rInfo
))
648 // TODO JNA : what should we rCnt > 1?
653 bool OQueryTableView::ContainsTabWin(const OTableWindow
& rTabWin
)
656 for (auto const& tabWin
: GetTabWinMap())
658 if ( tabWin
.second
== &rTabWin
)
667 void OQueryTableView::RemoveTabWin(OTableWindow
* pTabWin
)
669 OSL_ENSURE(pTabWin
!= nullptr, "OQueryTableView::RemoveTabWin : Window should not be NULL !");
671 if(!(pTabWin
&& ContainsTabWin(*pTabWin
))) // #i122589# check if registered before deleting
674 // I need my parent so it can be informed about the deletion
675 OQueryDesignView
* pParent
= static_cast<OQueryDesignView
*>(getDesignView());
677 SfxUndoManager
& rUndoMgr
= m_pView
->getController().GetUndoManager();
678 rUndoMgr
.EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE
) , OUString(), 0, ViewShellId(-1));
680 // add the Undo-Action
681 std::unique_ptr
<OQueryTabWinDelUndoAct
> pUndoAction(new OQueryTabWinDelUndoAct(this));
682 pUndoAction
->SetTabWin(static_cast< OQueryTableWindow
*>(pTabWin
));
684 // and hide the window
685 HideTabWin(static_cast< OQueryTableWindow
*>(pTabWin
), pUndoAction
.get());
687 // Undo Actions and delete the fields in SelectionBrowseBox
688 pParent
->TableDeleted( static_cast< OQueryTableWindowData
*>(pTabWin
->GetData().get())->GetAliasName() );
690 m_pView
->getController().addUndoActionAndInvalidate( std::move(pUndoAction
) );
691 rUndoMgr
.LeaveListAction();
695 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
696 Any(pTabWin
->GetAccessible()),
701 void OQueryTableView::EnsureVisible(const OTableWindow
* pWin
)
704 Invalidate(InvalidateFlags::NoChildren
);
705 OJoinTableView::EnsureVisible(pWin
);
708 void OQueryTableView::GetConnection(OQueryTableConnection
* pConn
)
710 // add to me and the document
712 addConnection( pConn
);
715 void OQueryTableView::DropConnection(VclPtr
<OQueryTableConnection
> const & rConn
)
717 // Pay attention to the selection
718 // remove from me and the document
719 VclPtr
<OTableConnection
> xConn(rConn
.get());
720 RemoveConnection(xConn
, false);
723 void OQueryTableView::HideTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
)
725 OTableWindowMap
& rTabWins
= GetTabWinMap();
728 // save the position in its data
729 getDesignView()->SaveTabWinUIConfig(pTabWin
);
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
);
737 pTabWin
->Hide(); // do not destroy it, as it is still in the undo list!!
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
747 if (m_pLastFocusTabWin
== pTabWin
)
748 m_pLastFocusTabWin
= nullptr;
750 // collect connections belonging to the window and pass to UndoAction
752 const auto& rTabConList
= getTableConnections();
753 auto aIter2
= rTabConList
.begin();
754 for(;aIter2
!= rTabConList
.end();)// the end may change
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() )
763 pUndoAction
->InsertConnection(xTmpEntry
);
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();
776 InvalidateConnections();
778 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
780 // inform the UndoAction that the window and connections belong to it
781 pUndoAction
->SetOwnership(true);
783 // by doing so, we have modified the document
784 m_pView
->getController().setModified( true );
785 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
788 bool OQueryTableView::ShowTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
, bool _bAppend
)
791 bool bSuccess
= false;
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())
802 Size
aSize(CalcZoom(pData
->GetSize().Width()),CalcZoom(pData
->GetSize().Height()));
803 pTabWin
->SetPosSizePixel(pData
->GetPosition(), aSize
);
806 // else set a default position
807 SetDefaultTabWinPosSize(pTabWin
);
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
);
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.
823 auto rTableCon
= pUndoAction
->GetTabConnList();
824 for(const auto& conn
: rTableCon
)
825 addConnection(conn
); // add all connections from the undo action
829 // and add the window's data to the list (of the document)
831 m_pView
->getController().getTableWindowData().push_back(pTabWin
->GetData());
833 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
835 // and inform the UndoAction that the window belongs to me
836 pUndoAction
->SetOwnership(false);
842 // Initialisation failed
843 // (for example when the Connection to the database is not available at the moment)
844 pTabWin
->clearListBox();
845 pTabWin
->disposeOnce();
849 // show that I have changed the document
850 if(!m_pView
->getController().isReadOnly())
851 m_pView
->getController().setModified( true );
853 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
858 void OQueryTableView::InsertField(const OTableFieldDescRef
& rInfo
)
860 OSL_ENSURE(getDesignView() != nullptr, "OQueryTableView::InsertField : has no Parent !");
861 static_cast<OQueryDesignView
*>(getDesignView())->InsertField(rInfo
);
864 bool OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow
* pFrom
) const
866 for(const auto& conn
: getTableConnections())
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())))
877 void OQueryTableView::onNoColumns_throw()
879 OUString
sError(DBA_RES(STR_STATEMENT_WITHOUT_RESULT_SET
));
880 ::dbtools::throwSQLException( sError
, ::dbtools::StandardSQLState::GENERAL_ERROR
, nullptr );
883 bool OQueryTableView::suppressCrossNaturalJoin(const TTableConnectionData::value_type
& _pData
) const
885 OQueryTableConnectionData
* pQueryData
= static_cast<OQueryTableConnectionData
*>(_pData
.get());
886 return pQueryData
&& (pQueryData
->GetJoinType() == CROSS_JOIN
);
889 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */