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 "TableFieldInfo.hxx"
22 #include "TableFieldDescription.hxx"
23 #include <tools/diagnose_ex.h>
24 #include <osl/diagnose.h>
25 #include "dbaccess_helpid.hrc"
26 #include "QTableWindow.hxx"
27 #include "QTableConnection.hxx"
28 #include "QTableConnectionData.hxx"
29 #include "QueryDesignView.hxx"
30 #include "querycontroller.hxx"
31 #include "QueryAddTabConnUndoAction.hxx"
32 #include "QueryTabWinShowUndoAct.hxx"
33 #include "browserids.hxx"
34 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
35 #include <com/sun/star/sdbc/XConnection.hpp>
36 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
37 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
38 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
39 #include "JAccess.hxx"
40 #include <com/sun/star/sdbcx/KeyType.hpp>
41 #include <com/sun/star/container/XIndexAccess.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include "dbustrings.hrc"
44 #include <connectivity/dbtools.hxx>
45 #include <comphelper/sequence.hxx>
46 #include "querydlg.hxx"
47 #include "JoinExchange.hxx"
48 #include <comphelper/extract.hxx>
49 #include "dbu_qry.hrc"
50 #include <vcl/msgbox.hxx>
51 #include "svtools/treelistentry.hxx"
53 using namespace dbaui
;
54 using namespace ::com::sun::star::uno
;
55 using namespace ::com::sun::star::sdbc
;
56 using namespace ::com::sun::star::sdbcx
;
57 using namespace ::com::sun::star::beans
;
58 using namespace ::com::sun::star::container
;
59 using namespace ::com::sun::star::accessibility
;
63 bool isColumnInKeyType(const Reference
<XIndexAccess
>& _rxKeys
,const OUString
& _rColumnName
,sal_Int32 _nKeyType
)
68 Reference
<XColumnsSupplier
> xColumnsSupplier
;
69 // search the one and only primary key
70 const sal_Int32 nCount
= _rxKeys
->getCount();
71 for(sal_Int32 i
=0;i
< nCount
;++i
)
73 Reference
<XPropertySet
> xProp(_rxKeys
->getByIndex(i
),UNO_QUERY
);
76 sal_Int32 nKeyType
= 0;
77 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
78 if(_nKeyType
== nKeyType
)
80 xColumnsSupplier
.set(xProp
,UNO_QUERY
);
81 if(xColumnsSupplier
.is())
83 Reference
<XNameAccess
> xColumns
= xColumnsSupplier
->getColumns();
84 if(xColumns
.is() && xColumns
->hasByName(_rColumnName
))
96 /** appends a new TabAdd Undo action at controller
97 @param _pView the view which we use
98 @param _pUndoAction the undo action which should be added
99 @param _pConnection the connection for which the undo action should be appended
100 @param _bOwner is the undo action the owner
102 void addUndoAction( OQueryTableView
* _pView
,
103 OQueryTabConnUndoAction
* _pUndoAction
,
104 OQueryTableConnection
* _pConnection
,
105 bool _bOwner
= false)
107 _pUndoAction
->SetOwnership(_bOwner
);
108 _pUndoAction
->SetConnection(_pConnection
);
109 _pView
->getDesignView()->getController().addUndoActionAndInvalidate(_pUndoAction
);
111 /** openJoinDialog opens the join dialog with this connection data
112 @param _pView the view which we use
113 @param _pConnectionData the connection data
115 @return true when OK was pressed otherwise false
117 bool openJoinDialog(OQueryTableView
* _pView
,const TTableConnectionData::value_type
& _pConnectionData
,bool _bSelectableTables
)
119 OQueryTableConnectionData
* pData
= static_cast< OQueryTableConnectionData
*>(_pConnectionData
.get());
121 ScopedVclPtrInstance
< DlgQryJoin
> aDlg(_pView
,_pConnectionData
,&_pView
->GetTabWinMap(),_pView
->getDesignView()->getController().getConnection(),_bSelectableTables
);
122 bool bOk
= aDlg
->Execute() == RET_OK
;
125 pData
->SetJoinType(aDlg
->GetJoinType());
126 _pView
->getDesignView()->getController().setModified(sal_True
);
131 /** connectionModified adds an undo action for the modified connection and forces an redraw
132 @param _pView the view which we use
133 @param _pConnection the connection which was modified
134 @param _bAddUndo true when an undo action should be appended
136 void connectionModified(OQueryTableView
* _pView
,
137 OTableConnection
* _pConnection
,
140 OSL_ENSURE(_pConnection
,"Invalid connection!");
141 _pConnection
->UpdateLineList();
143 // add an undo action
145 addUndoAction( _pView
,
146 new OQueryAddTabConnUndoAction(_pView
),
147 static_cast< OQueryTableConnection
*>(_pConnection
));
149 _pConnection
->RecalcLines();
150 // force an invalidation of the bounding rectangle
151 _pConnection
->InvalidateConnection();
153 _pView
->Invalidate(INVALIDATE_NOCHILDREN
);
155 void addConnections(OQueryTableView
* _pView
,
156 const OQueryTableWindow
& _rSource
,
157 const OQueryTableWindow
& _rDest
,
158 const Reference
<XNameAccess
>& _rxSourceForeignKeyColumns
)
160 if ( _rSource
.GetData()->isQuery() || _rDest
.GetData()->isQuery() )
161 // nothing to do if one of both denotes a query
164 // we found a table in our view where we can insert some connections
165 // the key columns have a property called RelatedColumn
166 // OQueryTableConnectionData aufbauen
167 OQueryTableConnectionData
* pNewConnData
= new OQueryTableConnectionData( _rSource
.GetData(), _rDest
.GetData() );
168 TTableConnectionData::value_type
aNewConnData(pNewConnData
);
170 Reference
<XIndexAccess
> xReferencedKeys( _rDest
.GetData()->getKeys());
171 OUString sRelatedColumn
;
173 // iterate through all foreignkey columns to create the connections
174 Sequence
< OUString
> aElements(_rxSourceForeignKeyColumns
->getElementNames());
175 const OUString
* pIter
= aElements
.getConstArray();
176 const OUString
* pEnd
= pIter
+ aElements
.getLength();
177 for(sal_Int32 i
=0;pIter
!= pEnd
;++pIter
,++i
)
179 Reference
<XPropertySet
> xColumn
;
180 if ( !( _rxSourceForeignKeyColumns
->getByName(*pIter
) >>= xColumn
) )
182 OSL_FAIL( "addConnections: invalid foreign key column!" );
186 pNewConnData
->SetFieldType(JTCS_FROM
,TAB_NORMAL_FIELD
);
188 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
189 pNewConnData
->SetFieldType(JTCS_TO
,isColumnInKeyType(xReferencedKeys
,sRelatedColumn
,KeyType::PRIMARY
) ? TAB_PRIMARY_FIELD
: TAB_NORMAL_FIELD
);
192 Sequence
< sal_Int16
> aFind(::comphelper::findValue(_rSource
.GetOriginalColumns()->getElementNames(),*pIter
,true));
193 if(aFind
.getLength())
194 pNewConnData
->SetFieldIndex(JTCS_FROM
,aFind
[0]+1);
196 OSL_FAIL("Column not found!");
198 // get the position inside the tabe
199 Reference
<XNameAccess
> xRefColumns
= _rDest
.GetOriginalColumns();
202 Sequence
< sal_Int16
> aFind(::comphelper::findValue(xRefColumns
->getElementNames(),sRelatedColumn
,true));
203 if(aFind
.getLength())
204 pNewConnData
->SetFieldIndex(JTCS_TO
,aFind
[0]+1);
206 OSL_FAIL("Column not found!");
208 pNewConnData
->AppendConnLine(*pIter
,sRelatedColumn
);
210 // now add the Conn itself
211 ScopedVclPtrInstance
< OQueryTableConnection
> aNewConn(_pView
, aNewConnData
);
212 // referring to the local variable is not important, as NotifyQueryTabConn creates a new copy
213 // to add me (if not existent)
214 _pView
->NotifyTabConnection(*aNewConn
.get(), false);
215 // don't create an Undo-Action for the new connection : the connection is
216 // covered by the Undo-Action for the tabwin, as the "Undo the insert" will
217 // automatically remove all connections adjacent to the win.
218 // (Because of this automatism we would have an ownerhsip ambiguity for
219 // the connection data if we would insert the conn-Undo-Action)
224 // class OQueryTableView
225 OQueryTableView::OQueryTableView( vcl::Window
* pParent
,OQueryDesignView
* pView
)
226 : OJoinTableView( pParent
,pView
)
228 SetHelpId(HID_CTL_QRYDGNTAB
);
231 sal_Int32
OQueryTableView::CountTableAlias(const OUString
& rName
, sal_Int32
& rMax
)
235 OTableWindowMap::iterator aIter
= GetTabWinMap().find(rName
);
236 while(aIter
!= GetTabWinMap().end())
238 OUString aNewName
= rName
+ "_" + OUString::number(++nRet
);
239 aIter
= GetTabWinMap().find(aNewName
);
247 void OQueryTableView::ReSync()
249 TTableWindowData
& rTabWinDataList
= m_pView
->getController().getTableWindowData();
250 OSL_ENSURE((getTableConnections().size()==0) && (GetTabWinMap().size()==0),
251 "before calling OQueryTableView::ReSync() please call ClearAll !");
253 // I need a collection of all window names that cannot be created so that I do not initialize connections for them.
254 ::std::vector
<OUString
> arrInvalidTables
;
256 TTableWindowData::reverse_iterator aIter
= rTabWinDataList
.rbegin();
257 // Create the window and add it
259 for(;aIter
!= rTabWinDataList
.rend();++aIter
)
261 OQueryTableWindowData
* pData
= static_cast<OQueryTableWindowData
*>(aIter
->get());
262 VclPtr
<OTableWindow
> pTabWin
= createWindow(*aIter
);
264 // I dont't use ShowTabWin as this adds the window data to the list of documents.
265 // This would be bad as I am getting them from there.
266 // Instead, I do it step by step
267 if (!pTabWin
->Init())
269 // The initialisation has gone wrong, this TabWin is not available, so
270 // I must clean up the data and the document
271 pTabWin
->clearListBox();
272 pTabWin
.disposeAndClear();
273 arrInvalidTables
.push_back(pData
->GetAliasName());
275 rTabWinDataList
.erase( ::std::remove(rTabWinDataList
.begin(), rTabWinDataList
.end(), *aIter
), rTabWinDataList
.end());
279 GetTabWinMap()[pData
->GetAliasName()] = pTabWin
; // add at the beginning as I am going backwards through the DataList
280 // Use the default if there is no position or size
281 if (!pData
->HasPosition() && !pData
->HasSize())
282 SetDefaultTabWinPosSize(pTabWin
);
287 // Add the connections
288 TTableConnectionData
& rTabConnDataList
= m_pView
->getController().getTableConnectionData();
289 TTableConnectionData::reverse_iterator aConIter
= rTabConnDataList
.rbegin();
291 for(;aConIter
!= rTabConnDataList
.rend();++aConIter
)
293 OQueryTableConnectionData
* pTabConnData
= static_cast<OQueryTableConnectionData
*>(aConIter
->get());
295 // do both tables for the connection exist ?
296 OUString strTabExistenceTest
= pTabConnData
->getReferencingTable()->GetWinName();
297 bool bInvalid
= ::std::find(arrInvalidTables
.begin(),arrInvalidTables
.end(),strTabExistenceTest
) != arrInvalidTables
.end();
298 strTabExistenceTest
= pTabConnData
->getReferencedTable()->GetWinName();
299 bInvalid
= bInvalid
&& ::std::find(arrInvalidTables
.begin(),arrInvalidTables
.end(),strTabExistenceTest
) != arrInvalidTables
.end();
303 // no -> bad luck, no connection
304 rTabConnDataList
.erase( ::std::remove(rTabConnDataList
.begin(), rTabConnDataList
.end(), *aConIter
), rTabConnDataList
.end());
308 // adds a new connection to join view and notifies our accessible and invaldates the controller
309 addConnection(VclPtr
<OQueryTableConnection
>::Create(this, *aConIter
));
313 void OQueryTableView::ClearAll()
315 OJoinTableView::ClearAll();
318 m_pView
->getController().setModified(sal_True
);
321 VclPtr
<OTableWindow
> OQueryTableView::createWindow(const TTableWindowData::value_type
& _pData
)
323 return VclPtr
<OQueryTableWindow
>::Create(this,_pData
);
326 void OQueryTableView::NotifyTabConnection(const OQueryTableConnection
& rNewConn
, bool _bCreateUndoAction
)
328 // let's first check if I have the connection already
329 OQueryTableConnection
* pTabConn
= NULL
;
330 const auto& rConnections
= getTableConnections();
331 auto aEnd
= rConnections
.end();
332 auto aIter
= ::std::find( rConnections
.begin(),
334 VclPtr
<OTableConnection
>(const_cast<OTableConnection
*>(static_cast<const OTableConnection
*>(&rNewConn
)))
338 aIter
= rConnections
.begin();
339 for(;aIter
!= aEnd
;++aIter
)
341 if(*static_cast<OQueryTableConnection
*>((*aIter
).get()) == rNewConn
)
343 pTabConn
= static_cast<OQueryTableConnection
*>((*aIter
).get());
349 pTabConn
= static_cast<OQueryTableConnection
*>((*aIter
).get());
352 if (pTabConn
== NULL
)
355 OQueryTableConnectionData
* pNewData
= static_cast< OQueryTableConnectionData
*>(rNewConn
.GetData()->NewInstance());
356 pNewData
->CopyFrom(*rNewConn
.GetData());
357 TTableConnectionData::value_type
aData(pNewData
);
358 VclPtrInstance
<OQueryTableConnection
> pNewConn(this, aData
);
359 GetConnection(pNewConn
);
361 connectionModified(this,pNewConn
,_bCreateUndoAction
);
365 OTableWindowData
* OQueryTableView::CreateImpl(const OUString
& _rComposedName
366 ,const OUString
& _sTableName
367 ,const OUString
& _rWinName
)
369 return new OQueryTableWindowData( _rComposedName
, _sTableName
,_rWinName
);
372 void OQueryTableView::AddTabWin(const OUString
& _rTableName
, const OUString
& _rAliasName
, bool bNewTable
)
374 // this method has been inherited from the base class, linking back to the parent and which constructs
375 // an Alias and which passes on to my other AddTabWin
377 // pity _rTableName is fully qualified, OQueryDesignView expects a string which only
378 // contains schema and tables but no catalog.
379 Reference
< XConnection
> xConnection
= m_pView
->getController().getConnection();
380 if(!xConnection
.is())
384 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
385 OUString sCatalog
, sSchema
, sTable
;
386 ::dbtools::qualifiedNameComponents(xMetaData
,
391 ::dbtools::eInDataManipulation
);
392 OUString
sRealName(sSchema
);
393 if (!sRealName
.isEmpty())
394 sRealName
+= OUString('.');
397 AddTabWin(_rTableName
, sRealName
, _rAliasName
, bNewTable
);
401 OSL_FAIL("qualifiedNameComponents");
405 // find the table which has a foreign key with this referencedTable name
406 Reference
<XPropertySet
> getKeyReferencedTo(const Reference
<XIndexAccess
>& _rxKeys
,const OUString
& _rReferencedTable
)
409 return Reference
<XPropertySet
>();
412 return Reference
<XPropertySet
>();
413 // search the one and only primary key
414 const sal_Int32 nCount
= _rxKeys
->getCount();
415 for(sal_Int32 i
=0;i
<nCount
;++i
)
417 Reference
<XPropertySet
> xKey(_rxKeys
->getByIndex(i
),UNO_QUERY
);
420 sal_Int32 nKeyType
= 0;
421 xKey
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
422 if(KeyType::FOREIGN
== nKeyType
)
424 OUString sReferencedTable
;
425 xKey
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= sReferencedTable
;
427 if(sReferencedTable
== _rReferencedTable
)
432 return Reference
<XPropertySet
>();
435 void OQueryTableView::AddTabWin(const OUString
& _rComposedName
, const OUString
& _rTableName
, const OUString
& strAlias
, bool bNewTable
)
437 OSL_ENSURE(!_rTableName
.isEmpty() || !strAlias
.isEmpty(), "OQueryTableView::AddTabWin : no tables or aliases !");
438 // If the table is not set, then it is a dummy window, but at least the alias must be set
440 // build a new data structure
441 // first check if this already has its data
442 bool bAppend
= bNewTable
;
443 TTableWindowData::value_type pNewTabWinData
;
444 TTableWindowData
& rWindowData
= getDesignView()->getController().getTableWindowData();
445 TTableWindowData::iterator aWinIter
= rWindowData
.begin();
446 TTableWindowData::iterator aWinEnd
= rWindowData
.end();
447 for(;aWinIter
!= aWinEnd
;++aWinIter
)
449 pNewTabWinData
= *aWinIter
;
450 if (pNewTabWinData
&& pNewTabWinData
->GetWinName() == strAlias
&& pNewTabWinData
->GetComposedName() == _rComposedName
&& pNewTabWinData
->GetTableName() == _rTableName
)
454 bAppend
= ( aWinIter
== aWinEnd
);
456 pNewTabWinData
= createTableWindowData(_rComposedName
, _rTableName
, strAlias
);
457 // I do not need to add TabWinData to the DocShell list, ShowTabWin does that.
459 // Create a new window
460 VclPtr
<OQueryTableWindow
> pNewTabWin
= static_cast<OQueryTableWindow
*>(createWindow(pNewTabWinData
).get());
461 // No need to initialize, as that happens in ShowTabWin
464 OQueryTabWinShowUndoAct
* pUndoAction
= new OQueryTabWinShowUndoAct(this);
465 pUndoAction
->SetTabWin(pNewTabWin
); // Window
466 bool bSuccess
= ShowTabWin(pNewTabWin
, pUndoAction
,bAppend
);
469 // reset table window
470 pUndoAction
->SetTabWin(NULL
);
471 pUndoAction
->SetOwnership(false);
477 // Show the relations between the individual tables
478 OTableWindowMap
& rTabWins
= GetTabWinMap();
479 if(bNewTable
&& !rTabWins
.empty() && !_rTableName
.isEmpty())
483 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
485 makeAny(pNewTabWin
->GetAccessible())
490 if ( pNewTabWin
->GetData()->isQuery() )
495 // find relations between the table an the tables already inserted
496 Reference
< XIndexAccess
> xKeyIndex
= pNewTabWin
->GetData()->getKeys();
497 if ( !xKeyIndex
.is() )
500 Reference
<XNameAccess
> xFKeyColumns
;
501 OUString aReferencedTable
;
502 Reference
<XColumnsSupplier
> xColumnsSupplier
;
504 const sal_Int32 nKeyCount
= xKeyIndex
->getCount();
505 for ( sal_Int32 i
=0; i
<nKeyCount
; ++i
)
507 Reference
< XPropertySet
> xProp( xKeyIndex
->getByIndex(i
), UNO_QUERY_THROW
);
508 xColumnsSupplier
.set( xProp
, UNO_QUERY_THROW
);
509 xFKeyColumns
.set( xColumnsSupplier
->getColumns(), UNO_QUERY_THROW
);
511 sal_Int32 nKeyType
= 0;
512 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
516 case KeyType::FOREIGN
:
517 { // our new table has a foreign key
518 // so look if the referenced table is already in our list
519 xProp
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= aReferencedTable
;
520 OSL_ENSURE(!aReferencedTable
.isEmpty(),"Foreign key without referencedTableName");
522 OTableWindowMap::const_iterator aIter
= rTabWins
.find(aReferencedTable
);
523 OTableWindowMap::const_iterator aEnd
= rTabWins
.end();
526 for(aIter
= rTabWins
.begin();aIter
!= aEnd
;++aIter
)
528 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(aIter
->second
.get());
529 OSL_ENSURE( pTabWinTmp
,"TableWindow is null!" );
530 if ( pTabWinTmp
!= pNewTabWin
&& pTabWinTmp
->GetComposedName() == aReferencedTable
)
534 if ( aIter
!= aEnd
&& pNewTabWin
.get() != aIter
->second
.get() )
535 addConnections( this, *pNewTabWin
, *static_cast<OQueryTableWindow
*>(aIter
->second
.get()), xFKeyColumns
);
539 case KeyType::PRIMARY
:
541 // we have a primary key so look in our list if there exists a key which this is referred to
542 OTableWindowMap::const_iterator aIter
= rTabWins
.begin();
543 OTableWindowMap::const_iterator aEnd
= rTabWins
.end();
544 for(;aIter
!= aEnd
;++aIter
)
546 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(aIter
->second
.get());
547 if ( pTabWinTmp
== pNewTabWin
)
550 if ( pTabWinTmp
->GetData()->isQuery() )
553 OSL_ENSURE(pTabWinTmp
,"TableWindow is null!");
554 Reference
< XPropertySet
> xFKKey
= getKeyReferencedTo( pTabWinTmp
->GetData()->getKeys(), pNewTabWin
->GetComposedName() );
558 Reference
<XColumnsSupplier
> xFKColumnsSupplier( xFKKey
, UNO_QUERY_THROW
);
559 Reference
< XNameAccess
> xTColumns( xFKColumnsSupplier
->getColumns(), UNO_QUERY_THROW
);
560 addConnections( this, *pTabWinTmp
, *pNewTabWin
, xTColumns
);
567 catch( const Exception
& )
569 DBG_UNHANDLED_EXCEPTION();
575 // My parent needs to be informed about the delete
576 m_pView
->getController().addUndoActionAndInvalidate( pUndoAction
);
578 if (bSuccess
&& m_lnkTabWinsChangeHandler
.IsSet())
580 TabWinsChangeNotification
aHint(TabWinsChangeNotification::AT_ADDED_WIN
, pNewTabWin
->GetAliasName());
581 m_lnkTabWinsChangeHandler
.Call(&aHint
);
585 void OQueryTableView::AddConnection(const OJoinExchangeData
& jxdSource
, const OJoinExchangeData
& jxdDest
)
587 OQueryTableWindow
* pSourceWin
= static_cast< OQueryTableWindow
*>(jxdSource
.pListBox
->GetTabWin());
588 OQueryTableWindow
* pDestWin
= static_cast< OQueryTableWindow
*>(jxdDest
.pListBox
->GetTabWin());
590 OUString aSourceFieldName
, aDestFieldName
;
591 aSourceFieldName
= jxdSource
.pListBox
->GetEntryText(jxdSource
.pEntry
);
592 aDestFieldName
= jxdDest
.pListBox
->GetEntryText(jxdDest
.pEntry
);
594 OTableConnection
* pConn
= GetTabConn(pSourceWin
,pDestWin
,true);
598 OQueryTableConnectionData
* pNewConnectionData
= new OQueryTableConnectionData(pSourceWin
->GetData(), pDestWin
->GetData());
599 TTableConnectionData::value_type
aNewConnectionData(pNewConnectionData
);
601 sal_uInt32 nSourceFieldIndex
, nDestFieldIndex
;
602 ETableFieldType eSourceFieldType
, eDestFieldType
;
604 // Get name/position/type of both affected fields ...
607 nSourceFieldIndex
= jxdSource
.pListBox
->GetModel()->GetAbsPos(jxdSource
.pEntry
);
608 eSourceFieldType
= static_cast< OTableFieldInfo
*>(jxdSource
.pEntry
->GetUserData())->GetKeyType();
612 nDestFieldIndex
= jxdDest
.pListBox
->GetModel()->GetAbsPos(jxdDest
.pEntry
);
613 eDestFieldType
= static_cast< OTableFieldInfo
*>(jxdDest
.pEntry
->GetUserData())->GetKeyType();
616 pNewConnectionData
->SetFieldIndex(JTCS_FROM
, nSourceFieldIndex
);
617 pNewConnectionData
->SetFieldIndex(JTCS_TO
, nDestFieldIndex
);
619 pNewConnectionData
->SetFieldType(JTCS_FROM
, eSourceFieldType
);
620 pNewConnectionData
->SetFieldType(JTCS_TO
, eDestFieldType
);
622 pNewConnectionData
->AppendConnLine( aSourceFieldName
,aDestFieldName
);
624 ScopedVclPtrInstance
< OQueryTableConnection
> aNewConnection(this, aNewConnectionData
);
625 NotifyTabConnection(*aNewConnection
.get());
626 // As usual with NotifyTabConnection, using a local variable is fine because a copy is made
630 // the connection could point on the other side
631 if(pConn
->GetSourceWin() == pDestWin
)
633 OUString
aTmp(aSourceFieldName
);
634 aSourceFieldName
= aDestFieldName
;
635 aDestFieldName
= aTmp
;
638 pConn
->GetData()->AppendConnLine( aSourceFieldName
,aDestFieldName
);
640 connectionModified(this,pConn
,false);
644 void OQueryTableView::ConnDoubleClicked(OTableConnection
* pConnection
)
646 if( openJoinDialog(this,pConnection
->GetData(),false) )
648 connectionModified(this,pConnection
,false);
649 SelectConn( pConnection
);
653 void OQueryTableView::createNewConnection()
655 TTableConnectionData::value_type
pData(new OQueryTableConnectionData());
656 if( openJoinDialog(this,pData
,true) )
658 OTableWindowMap
& rMap
= GetTabWinMap();
659 OQueryTableWindow
* pSourceWin
= static_cast< OQueryTableWindow
*>(rMap
[pData
->getReferencingTable()->GetWinName()].get());
660 OQueryTableWindow
* pDestWin
= static_cast< OQueryTableWindow
*>(rMap
[pData
->getReferencedTable()->GetWinName()].get());
661 // first we have to look if the this connection already exists
662 OTableConnection
* pConn
= GetTabConn(pSourceWin
,pDestWin
,true);
666 pConn
->GetData()->CopyFrom( *pData
);
671 // create a new conenction and append it
672 VclPtrInstance
<OQueryTableConnection
> pQConn(this, pData
);
673 GetConnection(pQConn
);
676 connectionModified(this,pConn
,bNew
);
677 if ( !bNew
&& pConn
== GetSelectedConn() ) // our connection was selected before so we have to reselect it
682 bool OQueryTableView::RemoveConnection( OTableConnection
* _pConnection
,bool /*_bDelete*/ )
685 // we don't want that our connection will be deleted, we put it in the undo manager
686 bool bRet
= OJoinTableView::RemoveConnection( _pConnection
,false);
690 new OQueryDelTabConnUndoAction(this),
691 static_cast< OQueryTableConnection
*>(_pConnection
),
696 void OQueryTableView::KeyInput( const KeyEvent
& rEvt
)
698 OJoinTableView::KeyInput( rEvt
);
701 OQueryTableWindow
* OQueryTableView::FindTable(const OUString
& rAliasName
)
703 OSL_ENSURE(!rAliasName
.isEmpty(), "OQueryTableView::FindTable : the AliasName should not be empty !");
704 // (it is harmless but does not make sense and indicates that there is probably an error in the caller)
705 OTableWindowMap::const_iterator aIter
= GetTabWinMap().find(rAliasName
);
706 if(aIter
!= GetTabWinMap().end())
707 return static_cast<OQueryTableWindow
*>(aIter
->second
.get());
711 bool OQueryTableView::FindTableFromField(const OUString
& rFieldName
, OTableFieldDescRef
& rInfo
, sal_uInt16
& rCnt
)
714 OTableWindowMap::const_iterator aIter
= GetTabWinMap().begin();
715 OTableWindowMap::const_iterator aEnd
= GetTabWinMap().end();
716 for(;aIter
!= aEnd
;++aIter
)
718 if(static_cast<OQueryTableWindow
*>(aIter
->second
.get())->ExistsField(rFieldName
, rInfo
))
725 bool OQueryTableView::ContainsTabWin(const OTableWindow
& rTabWin
)
727 OTableWindowMap
& rTabWins
= GetTabWinMap();
729 OTableWindowMap::iterator aIter
= rTabWins
.begin();
730 OTableWindowMap::iterator aEnd
= rTabWins
.end();
732 for ( ;aIter
!= aEnd
; ++aIter
)
734 if ( aIter
->second
== &rTabWin
)
743 void OQueryTableView::RemoveTabWin(OTableWindow
* pTabWin
)
745 OSL_ENSURE(pTabWin
!= NULL
, "OQueryTableView::RemoveTabWin : Window should not be NULL !");
747 if(pTabWin
&& ContainsTabWin(*pTabWin
)) // #i122589# check if registered before deleting
749 // I need my parent so it can be informed about the deletion
750 OQueryDesignView
* pParent
= static_cast<OQueryDesignView
*>(getDesignView());
752 SfxUndoManager
& rUndoMgr
= m_pView
->getController().GetUndoManager();
753 rUndoMgr
.EnterListAction( OUString( ModuleRes(STR_QUERY_UNDO_TABWINDELETE
) ), OUString() );
755 // add the Undo-Action
756 OQueryTabWinDelUndoAct
* pUndoAction
= new OQueryTabWinDelUndoAct(this);
757 pUndoAction
->SetTabWin(static_cast< OQueryTableWindow
*>(pTabWin
));
759 // and hide the window
760 HideTabWin(static_cast< OQueryTableWindow
*>(pTabWin
), pUndoAction
);
762 // Undo Actions and delete the fields in SelectionBrowseBox
763 pParent
->TableDeleted( static_cast< OQueryTableWindowData
*>(pTabWin
->GetData().get())->GetAliasName() );
765 m_pView
->getController().addUndoActionAndInvalidate( pUndoAction
);
766 rUndoMgr
.LeaveListAction();
768 if (m_lnkTabWinsChangeHandler
.IsSet())
770 TabWinsChangeNotification
aHint(TabWinsChangeNotification::AT_REMOVED_WIN
, static_cast< OQueryTableWindow
*>(pTabWin
)->GetAliasName());
771 m_lnkTabWinsChangeHandler
.Call(&aHint
);
776 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
777 makeAny(pTabWin
->GetAccessible()),
783 void OQueryTableView::EnsureVisible(const OTableWindow
* pWin
)
786 Invalidate(INVALIDATE_NOCHILDREN
);
787 OJoinTableView::EnsureVisible(pWin
);
790 void OQueryTableView::GetConnection(OQueryTableConnection
* pConn
)
792 // add to me and the document
794 addConnection( pConn
);
797 void OQueryTableView::DropConnection(OQueryTableConnection
* pConn
)
799 // Pay attention to the selection
800 // remove from me and the document
801 RemoveConnection( pConn
,false);
804 void OQueryTableView::HideTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
)
806 OTableWindowMap
& rTabWins
= GetTabWinMap();
809 // save the position in its data
810 getDesignView()->SaveTabWinUIConfig(pTabWin
);
811 // (I need to go via the parent, as only the parent knows the position of the scrollbars)
812 // and then out of the TabWins list and hide
813 OTableWindowMap::iterator aIter
= rTabWins
.begin();
814 OTableWindowMap::iterator aEnd
= rTabWins
.end();
815 for ( ;aIter
!= aEnd
; ++aIter
)
816 if ( aIter
->second
== pTabWin
)
818 rTabWins
.erase( aIter
);
822 pTabWin
->Hide(); // do not destroy it, as it is still in the undo list!!
824 // the TabWin data must also be passed out of my responsibility
825 TTableWindowData
& rTabWinDataList
= m_pView
->getController().getTableWindowData();
826 rTabWinDataList
.erase( ::std::remove(rTabWinDataList
.begin(), rTabWinDataList
.end(), pTabWin
->GetData()), rTabWinDataList
.end());
827 // The data should not be destroyed as TabWin itself - which is still alive - needs them
828 // Either it goes back into my responsibility, (via ShowTabWin), then I add the data back,
829 // or the Undo-Action, which currently has full responsibility for the window
830 // and its data, gets destroyed and destroys both the window and its data
832 if (m_pLastFocusTabWin
== pTabWin
)
833 m_pLastFocusTabWin
= NULL
;
835 // collect connections belonging to the window and pass to UndoAction
837 const auto& rTabConList
= getTableConnections();
838 auto aIter2
= rTabConList
.begin();
839 for(;aIter2
!= rTabConList
.end();)// the end may change
841 OQueryTableConnection
* pTmpEntry
= static_cast<OQueryTableConnection
*>((*aIter2
).get());
842 OSL_ENSURE(pTmpEntry
,"OQueryTableConnection is null!");
843 if( pTmpEntry
->GetAliasName(JTCS_FROM
) == pTabWin
->GetAliasName() ||
844 pTmpEntry
->GetAliasName(JTCS_TO
) == pTabWin
->GetAliasName() )
847 pUndoAction
->InsertConnection(pTmpEntry
);
849 // call base class because we append an undo action
850 // but this time we are in a undo action list
851 OJoinTableView::RemoveConnection(pTmpEntry
,false);
852 aIter2
= rTabConList
.begin();
860 InvalidateConnections();
862 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
864 // inform the UndoAction that the window and connections belong to it
865 pUndoAction
->SetOwnership(true);
867 // by doing so, we have modified the document
868 m_pView
->getController().setModified( sal_True
);
869 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
872 bool OQueryTableView::ShowTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
, bool _bAppend
)
875 bool bSuccess
= false;
881 TTableWindowData::value_type pData
= pTabWin
->GetData();
882 OSL_ENSURE(pData
!= 0, "OQueryTableView::ShowTabWin : TabWin has no data !");
883 // If there is a position and size defined, we use them
884 if (pData
->HasPosition() && pData
->HasSize())
886 Size
aSize(CalcZoom(pData
->GetSize().Width()),CalcZoom(pData
->GetSize().Height()));
887 pTabWin
->SetPosSizePixel(pData
->GetPosition(), aSize
);
890 // else set a default position
891 SetDefaultTabWinPosSize(pTabWin
);
893 // Show the window and add to the list
894 OUString sName
= static_cast< OQueryTableWindowData
*>(pData
.get())->GetAliasName();
895 OSL_ENSURE(GetTabWinMap().find(sName
) == GetTabWinMap().end(),"Alias name already in list!");
896 GetTabWinMap().insert(OTableWindowMap::value_type(sName
,pTabWin
));
901 // We must call Update() in order to show the connections in the window correctly. This sounds strange,
902 // but the Listbox has an internal Member which is initialized when the Listbox is first shown (after the Listbox
903 // is filled in Init). This Member will eventually be needed for
904 // GetEntryPos, and then in turn by the Connection, when its starting point to the window must be determined.
907 auto rTableCon
= pUndoAction
->GetTabConnList();
908 for(auto conn
: rTableCon
)
909 addConnection(conn
); // add all connections from the undo action
913 // and add the window's data to the list (of the document)
915 m_pView
->getController().getTableWindowData().push_back(pTabWin
->GetData());
917 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
919 // and inform the UndoAction that the window belongs to me
920 pUndoAction
->SetOwnership(false);
926 // Initialisation failed
927 // (for example when the Connection to the database is not available at the moment)
928 pTabWin
->clearListBox();
929 pTabWin
->disposeOnce();
933 // show that I have changed the document
934 if(!m_pView
->getController().isReadOnly())
935 m_pView
->getController().setModified( sal_True
);
937 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
942 void OQueryTableView::InsertField(const OTableFieldDescRef
& rInfo
)
944 OSL_ENSURE(getDesignView() != NULL
, "OQueryTableView::InsertField : has no Parent !");
945 static_cast<OQueryDesignView
*>(getDesignView())->InsertField(rInfo
);
948 bool OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow
* pFrom
) const
950 for(auto conn
: getTableConnections())
952 OQueryTableConnection
* pTemp
= static_cast<OQueryTableConnection
*>(conn
.get());
953 if (pTemp
->IsVisited() &&
954 (pFrom
== static_cast< OQueryTableWindow
*>(pTemp
->GetSourceWin()) || pFrom
== static_cast< OQueryTableWindow
*>(pTemp
->GetDestWin())))
961 void OQueryTableView::onNoColumns_throw()
963 OUString
sError( ModuleRes( STR_STATEMENT_WITHOUT_RESULT_SET
) );
964 ::dbtools::throwSQLException( sError
, ::dbtools::SQL_GENERAL_ERROR
, NULL
);
967 bool OQueryTableView::supressCrossNaturalJoin(const TTableConnectionData::value_type
& _pData
) const
969 OQueryTableConnectionData
* pQueryData
= static_cast<OQueryTableConnectionData
*>(_pData
.get());
970 return pQueryData
&& (pQueryData
->GetJoinType() == CROSS_JOIN
);
973 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */