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 .
21 #include "QueryTableView.hxx"
22 #include "TableFieldInfo.hxx"
23 #include "TableFieldDescription.hxx"
24 #include <tools/diagnose_ex.h>
25 #include <osl/diagnose.h>
26 #include "dbaccess_helpid.hrc"
27 #include "QTableWindow.hxx"
28 #include "QTableConnection.hxx"
29 #include "QTableConnectionData.hxx"
30 #include "QueryDesignView.hxx"
31 #include "querycontroller.hxx"
32 #include "QueryAddTabConnUndoAction.hxx"
33 #include "QueryTabWinShowUndoAct.hxx"
34 #include "browserids.hxx"
35 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
36 #include <com/sun/star/sdbc/XConnection.hpp>
37 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
38 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
39 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
40 #include "JAccess.hxx"
41 #include <com/sun/star/sdbcx/KeyType.hpp>
42 #include <com/sun/star/container/XIndexAccess.hpp>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include "dbustrings.hrc"
45 #include <connectivity/dbtools.hxx>
46 #include <comphelper/sequence.hxx>
47 #include "querydlg.hxx"
48 #include "JoinExchange.hxx"
49 #include <comphelper/extract.hxx>
50 #include "dbu_qry.hrc"
51 #include <vcl/msgbox.hxx>
52 #include "svtools/treelistentry.hxx"
54 using namespace dbaui
;
55 using namespace ::com::sun::star::uno
;
56 using namespace ::com::sun::star::sdbc
;
57 using namespace ::com::sun::star::sdbcx
;
58 using namespace ::com::sun::star::beans
;
59 using namespace ::com::sun::star::container
;
60 using namespace ::com::sun::star::accessibility
;
62 //------------------------------------------------------------------------------
65 // -----------------------------------------------------------------------------
66 sal_Bool
isColumnInKeyType(const Reference
<XIndexAccess
>& _rxKeys
,const OUString
& _rColumnName
,sal_Int32 _nKeyType
)
68 sal_Bool bReturn
= sal_False
;
71 Reference
<XColumnsSupplier
> xColumnsSupplier
;
72 // search the one and only primary key
73 const sal_Int32 nCount
= _rxKeys
->getCount();
74 for(sal_Int32 i
=0;i
< nCount
;++i
)
76 Reference
<XPropertySet
> xProp(_rxKeys
->getByIndex(i
),UNO_QUERY
);
79 sal_Int32 nKeyType
= 0;
80 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
81 if(_nKeyType
== nKeyType
)
83 xColumnsSupplier
.set(xProp
,UNO_QUERY
);
84 if(xColumnsSupplier
.is())
86 Reference
<XNameAccess
> xColumns
= xColumnsSupplier
->getColumns();
87 if(xColumns
.is() && xColumns
->hasByName(_rColumnName
))
99 // -----------------------------------------------------------------------------
100 /** appends a new TabAdd Undo action at controller
101 @param _pView the view which we use
102 @param _pUndoAction the undo action which should be added
103 @param _pConnection the connection for which the undo action should be appended
104 @param _bOwner is the undo action the owner
106 // -----------------------------------------------------------------------------
107 void addUndoAction( OQueryTableView
* _pView
,
108 OQueryTabConnUndoAction
* _pUndoAction
,
109 OQueryTableConnection
* _pConnection
,
110 sal_Bool _bOwner
= sal_False
)
112 _pUndoAction
->SetOwnership(_bOwner
);
113 _pUndoAction
->SetConnection(_pConnection
);
114 _pView
->getDesignView()->getController().addUndoActionAndInvalidate(_pUndoAction
);
116 // -----------------------------------------------------------------------------
117 /** openJoinDialog opens the join dialog with this connection data
118 @param _pView the view which we use
119 @param _pConnectionData the connection data
121 @return true when OK was pressed otherwise false
123 sal_Bool
openJoinDialog(OQueryTableView
* _pView
,const TTableConnectionData::value_type
& _pConnectionData
,sal_Bool _bSelectableTables
)
125 OQueryTableConnectionData
* pData
= static_cast< OQueryTableConnectionData
*>(_pConnectionData
.get());
127 DlgQryJoin
aDlg(_pView
,_pConnectionData
,_pView
->GetTabWinMap(),_pView
->getDesignView()->getController().getConnection(),_bSelectableTables
);
128 sal_Bool bOk
= aDlg
.Execute() == RET_OK
;
131 pData
->SetJoinType(aDlg
.GetJoinType());
132 _pView
->getDesignView()->getController().setModified(sal_True
);
137 // -----------------------------------------------------------------------------
138 /** connectionModified adds an undo action for the modified connection and forces an redraw
139 @param _pView the view which we use
140 @param _pConnection the connection which was modified
141 @param _bAddUndo true when an undo action should be appended
143 void connectionModified(OQueryTableView
* _pView
,
144 OTableConnection
* _pConnection
,
147 OSL_ENSURE(_pConnection
,"Invalid connection!");
148 _pConnection
->UpdateLineList();
150 // add an undo action
152 addUndoAction( _pView
,
153 new OQueryAddTabConnUndoAction(_pView
),
154 static_cast< OQueryTableConnection
*>(_pConnection
));
156 _pConnection
->RecalcLines();
157 // force an invalidation of the bounding rectangle
158 _pConnection
->InvalidateConnection();
160 _pView
->Invalidate(INVALIDATE_NOCHILDREN
);
162 // -----------------------------------------------------------------------------
163 void addConnections(OQueryTableView
* _pView
,
164 const OQueryTableWindow
& _rSource
,
165 const OQueryTableWindow
& _rDest
,
166 const Reference
<XNameAccess
>& _rxSourceForeignKeyColumns
)
168 if ( _rSource
.GetData()->isQuery() || _rDest
.GetData()->isQuery() )
169 // nothing to do if one of both denotes a query
172 // we found a table in our view where we can insert some connections
173 // the key columns have a property called RelatedColumn
174 // OQueryTableConnectionData aufbauen
175 OQueryTableConnectionData
* pNewConnData
= new OQueryTableConnectionData( _rSource
.GetData(), _rDest
.GetData() );
176 TTableConnectionData::value_type
aNewConnData(pNewConnData
);
178 Reference
<XIndexAccess
> xReferencedKeys( _rDest
.GetData()->getKeys());
179 OUString sRelatedColumn
;
181 // iterate through all foreignkey columns to create the connections
182 Sequence
< OUString
> aElements(_rxSourceForeignKeyColumns
->getElementNames());
183 const OUString
* pIter
= aElements
.getConstArray();
184 const OUString
* pEnd
= pIter
+ aElements
.getLength();
185 for(sal_Int32 i
=0;pIter
!= pEnd
;++pIter
,++i
)
187 Reference
<XPropertySet
> xColumn
;
188 if ( !( _rxSourceForeignKeyColumns
->getByName(*pIter
) >>= xColumn
) )
190 OSL_FAIL( "addConnections: invalid foreign key column!" );
194 pNewConnData
->SetFieldType(JTCS_FROM
,TAB_NORMAL_FIELD
);
196 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
197 pNewConnData
->SetFieldType(JTCS_TO
,isColumnInKeyType(xReferencedKeys
,sRelatedColumn
,KeyType::PRIMARY
) ? TAB_PRIMARY_FIELD
: TAB_NORMAL_FIELD
);
200 Sequence
< sal_Int16
> aFind(::comphelper::findValue(_rSource
.GetOriginalColumns()->getElementNames(),*pIter
,sal_True
));
201 if(aFind
.getLength())
202 pNewConnData
->SetFieldIndex(JTCS_FROM
,aFind
[0]+1);
204 OSL_FAIL("Column not found!");
206 // get the position inside the tabe
207 Reference
<XNameAccess
> xRefColumns
= _rDest
.GetOriginalColumns();
210 Sequence
< sal_Int16
> aFind(::comphelper::findValue(xRefColumns
->getElementNames(),sRelatedColumn
,sal_True
));
211 if(aFind
.getLength())
212 pNewConnData
->SetFieldIndex(JTCS_TO
,aFind
[0]+1);
214 OSL_FAIL("Column not found!");
216 pNewConnData
->AppendConnLine(*pIter
,sRelatedColumn
);
218 // now add the Conn itself
219 OQueryTableConnection
aNewConn(_pView
, aNewConnData
);
220 // refering to the local variable is not important, as NotifyQueryTabConn creates a new copy
221 // to add me (if not existent)
222 _pView
->NotifyTabConnection(aNewConn
, sal_False
);
223 // don't create an Undo-Action for the new connection : the connection is
224 // covered by the Undo-Action for the tabwin, as the "Undo the insert" will
225 // automatically remove all connections adjacent to the win.
226 // (Because of this automatism we would have an ownerhsip ambiguity for
227 // the connection data if we would insert the conn-Undo-Action)
231 //==================================================================
232 // class OQueryTableView
233 //==================================================================
234 DBG_NAME(OQueryTableView
)
235 //------------------------------------------------------------------------
236 OQueryTableView::OQueryTableView( Window
* pParent
,OQueryDesignView
* pView
)
237 : OJoinTableView( pParent
,pView
)
239 DBG_CTOR(OQueryTableView
,NULL
);
240 SetHelpId(HID_CTL_QRYDGNTAB
);
243 //------------------------------------------------------------------------
244 OQueryTableView::~OQueryTableView()
246 DBG_DTOR(OQueryTableView
,NULL
);
249 //------------------------------------------------------------------------
250 sal_Int32
OQueryTableView::CountTableAlias(const String
& rName
, sal_Int32
& rMax
)
252 DBG_CHKTHIS(OQueryTableView
,NULL
);
255 OTableWindowMapIterator aIter
= GetTabWinMap()->find(rName
);
256 while(aIter
!= GetTabWinMap()->end())
258 OUString aNewName
= OUString(rName
) + "_" + OUString::number(++nRet
);
259 aIter
= GetTabWinMap()->find(aNewName
);
266 //------------------------------------------------------------------------
267 void OQueryTableView::ReSync()
269 DBG_CHKTHIS(OQueryTableView
,NULL
);
270 TTableWindowData
* pTabWinDataList
= m_pView
->getController().getTableWindowData();
271 OSL_ENSURE((getTableConnections()->size()==0) && (GetTabWinMap()->size()==0),
272 "before calling OQueryTableView::ReSync() please call ClearAll !");
275 // I need a collection of all window names that cannot be created so that I do not initialize connections for them.
276 ::std::vector
<String
> arrInvalidTables
;
278 TTableWindowData::reverse_iterator aIter
= pTabWinDataList
->rbegin();
279 // Create the window and add it
281 for(;aIter
!= pTabWinDataList
->rend();++aIter
)
283 OQueryTableWindowData
* pData
= static_cast<OQueryTableWindowData
*>(aIter
->get());
284 OTableWindow
* pTabWin
= createWindow(*aIter
);
286 // I dont't use ShowTabWin as this adds the window data to the list of documents.
287 // This would be bad as I am getting them from there.
288 // Instead, I do it step by step
289 if (!pTabWin
->Init())
291 // The initialisation has gone wrong, this TabWin is not available, so
292 // I must clean up the data and the document
293 pTabWin
->clearListBox();
295 arrInvalidTables
.push_back(pData
->GetAliasName());
297 pTabWinDataList
->erase( ::std::remove(pTabWinDataList
->begin(),pTabWinDataList
->end(),*aIter
) ,pTabWinDataList
->end());
301 (*GetTabWinMap())[pData
->GetAliasName()] = pTabWin
; // add at the beginning as I am going backwards through the DataList
302 // Use the default if there is no position or size
303 if (!pData
->HasPosition() && !pData
->HasSize())
304 SetDefaultTabWinPosSize(pTabWin
);
309 // Add the connections
310 TTableConnectionData
* pTabConnDataList
= m_pView
->getController().getTableConnectionData();
311 TTableConnectionData::reverse_iterator aConIter
= pTabConnDataList
->rbegin();
313 for(;aConIter
!= pTabConnDataList
->rend();++aConIter
)
315 OQueryTableConnectionData
* pTabConnData
= static_cast<OQueryTableConnectionData
*>(aConIter
->get());
317 // do both tables for the connection exist ?
318 String strTabExistenceTest
= pTabConnData
->getReferencingTable()->GetWinName();
319 sal_Bool bInvalid
= ::std::find(arrInvalidTables
.begin(),arrInvalidTables
.end(),strTabExistenceTest
) != arrInvalidTables
.end();
320 strTabExistenceTest
= pTabConnData
->getReferencedTable()->GetWinName();
321 bInvalid
= bInvalid
&& ::std::find(arrInvalidTables
.begin(),arrInvalidTables
.end(),strTabExistenceTest
) != arrInvalidTables
.end();
325 // no -> bad luck, no connection
326 pTabConnDataList
->erase( ::std::remove(pTabConnDataList
->begin(),pTabConnDataList
->end(),*aConIter
) ,pTabConnDataList
->end());
330 // adds a new connection to join view and notifies our accessible and invaldates the controller
331 addConnection(new OQueryTableConnection(this, *aConIter
));
335 //------------------------------------------------------------------------
336 void OQueryTableView::ClearAll()
338 DBG_CHKTHIS(OQueryTableView
,NULL
);
339 OJoinTableView::ClearAll();
341 SetUpdateMode(sal_True
);
342 m_pView
->getController().setModified(sal_True
);
345 // -----------------------------------------------------------------------------
346 OTableWindow
* OQueryTableView::createWindow(const TTableWindowData::value_type
& _pData
)
348 return new OQueryTableWindow(this,_pData
);
351 //------------------------------------------------------------------------------
352 void OQueryTableView::NotifyTabConnection(const OQueryTableConnection
& rNewConn
, sal_Bool _bCreateUndoAction
)
354 DBG_CHKTHIS(OQueryTableView
,NULL
);
355 // let's first check if I have the connection already
356 OQueryTableConnection
* pTabConn
= NULL
;
357 const ::std::vector
<OTableConnection
*>* pConnections
= getTableConnections();
358 ::std::vector
<OTableConnection
*>::const_iterator aEnd
= pConnections
->end();
359 ::std::vector
<OTableConnection
*>::const_iterator aIter
= ::std::find( pConnections
->begin(),
361 static_cast<const OTableConnection
*>(&rNewConn
)
365 aIter
= pConnections
->begin();
366 for(;aIter
!= aEnd
;++aIter
)
368 if(*static_cast<OQueryTableConnection
*>(*aIter
) == rNewConn
)
370 pTabConn
= static_cast<OQueryTableConnection
*>(*aIter
);
376 pTabConn
= static_cast<OQueryTableConnection
*>(*aIter
);
379 if (pTabConn
== NULL
)
382 OQueryTableConnectionData
* pNewData
= static_cast< OQueryTableConnectionData
*>(rNewConn
.GetData()->NewInstance());
383 pNewData
->CopyFrom(*rNewConn
.GetData());
384 TTableConnectionData::value_type
aData(pNewData
);
385 OQueryTableConnection
* pNewConn
= new OQueryTableConnection(this, aData
);
386 GetConnection(pNewConn
);
388 connectionModified(this,pNewConn
,_bCreateUndoAction
);
391 // -----------------------------------------------------------------------------
392 OTableWindowData
* OQueryTableView::CreateImpl(const OUString
& _rComposedName
393 ,const OUString
& _sTableName
394 ,const OUString
& _rWinName
)
396 return new OQueryTableWindowData( _rComposedName
, _sTableName
,_rWinName
);
398 //------------------------------------------------------------------------------
399 void OQueryTableView::AddTabWin(const OUString
& _rTableName
, const OUString
& _rAliasName
, sal_Bool bNewTable
)
401 DBG_CHKTHIS(OQueryTableView
,NULL
);
402 // this method has been inherited from the base class, linking back to the parent and which constructs
403 // an Alias and which passes on to my other AddTabWin
405 // pity _rTableName is fully qualified, OQueryDesignView expects a string which only
406 // contains schema and tables but no catalog.
407 Reference
< XConnection
> xConnection
= m_pView
->getController().getConnection();
408 if(!xConnection
.is())
412 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
413 OUString sCatalog
, sSchema
, sTable
;
414 ::dbtools::qualifiedNameComponents(xMetaData
,
419 ::dbtools::eInDataManipulation
);
420 OUString
sRealName(sSchema
);
421 if (!sRealName
.isEmpty())
422 sRealName
+= OUString('.');
425 AddTabWin(_rTableName
, sRealName
, _rAliasName
, bNewTable
);
429 OSL_FAIL("qualifiedNameComponents");
432 // -----------------------------------------------------------------------------
433 // find the table which has a foreign key with this referencedTable name
434 Reference
<XPropertySet
> getKeyReferencedTo(const Reference
<XIndexAccess
>& _rxKeys
,const OUString
& _rReferencedTable
)
437 return Reference
<XPropertySet
>();
440 return Reference
<XPropertySet
>();
441 // search the one and only primary key
442 const sal_Int32 nCount
= _rxKeys
->getCount();
443 for(sal_Int32 i
=0;i
<nCount
;++i
)
445 Reference
<XPropertySet
> xKey(_rxKeys
->getByIndex(i
),UNO_QUERY
);
448 sal_Int32 nKeyType
= 0;
449 xKey
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
450 if(KeyType::FOREIGN
== nKeyType
)
452 OUString sReferencedTable
;
453 xKey
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= sReferencedTable
;
455 if(sReferencedTable
== _rReferencedTable
)
460 return Reference
<XPropertySet
>();
462 //------------------------------------------------------------------------------
463 void OQueryTableView::AddTabWin(const OUString
& _rComposedName
, const OUString
& _rTableName
, const OUString
& strAlias
, sal_Bool bNewTable
)
465 DBG_CHKTHIS(OQueryTableView
,NULL
);
466 OSL_ENSURE(!_rTableName
.isEmpty() || !strAlias
.isEmpty(), "OQueryTableView::AddTabWin : no tables or aliases !");
467 // If the table is not set, then it is a dummy window, but at least the alias must be set
469 // build a new data structure
470 // first check if this already has its data
471 sal_Bool bAppend
= bNewTable
;
472 TTableWindowData::value_type pNewTabWinData
;
473 TTableWindowData
* pWindowData
= getDesignView()->getController().getTableWindowData();
474 TTableWindowData::iterator aWinIter
= pWindowData
->begin();
475 TTableWindowData::iterator aWinEnd
= pWindowData
->end();
476 for(;aWinIter
!= aWinEnd
;++aWinIter
)
478 pNewTabWinData
= *aWinIter
;
479 if (pNewTabWinData
&& pNewTabWinData
->GetWinName() == strAlias
&& pNewTabWinData
->GetComposedName() == _rComposedName
&& pNewTabWinData
->GetTableName() == _rTableName
)
483 bAppend
= ( aWinIter
== aWinEnd
);
485 pNewTabWinData
= createTableWindowData(_rComposedName
, _rTableName
, strAlias
);
486 // I do not need to add TabWinData to the DocShell list, ShowTabWin does that.
488 // Create a new window
489 OQueryTableWindow
* pNewTabWin
= static_cast<OQueryTableWindow
*>(createWindow(pNewTabWinData
));
490 // No need to initialize, as that happens in ShowTabWin
493 OQueryTabWinShowUndoAct
* pUndoAction
= new OQueryTabWinShowUndoAct(this);
494 pUndoAction
->SetTabWin(pNewTabWin
); // Window
495 sal_Bool bSuccess
= ShowTabWin(pNewTabWin
, pUndoAction
,bAppend
);
498 // reset table window
499 pUndoAction
->SetTabWin(NULL
);
500 pUndoAction
->SetOwnership(sal_False
);
506 // Show the relations between the individual tables
507 OTableWindowMap
* pTabWins
= GetTabWinMap();
508 if(bNewTable
&& !pTabWins
->empty() && !_rTableName
.isEmpty())
512 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
514 makeAny(pNewTabWin
->GetAccessible())
519 if ( pNewTabWin
->GetData()->isQuery() )
524 //////////////////////////////////////////////////////////////////////
525 // find relations between the table an the tables already inserted
526 Reference
< XIndexAccess
> xKeyIndex
= pNewTabWin
->GetData()->getKeys();
527 if ( !xKeyIndex
.is() )
530 Reference
<XNameAccess
> xFKeyColumns
;
531 OUString aReferencedTable
;
532 Reference
<XColumnsSupplier
> xColumnsSupplier
;
534 const sal_Int32 nKeyCount
= xKeyIndex
->getCount();
535 for ( sal_Int32 i
=0; i
<nKeyCount
; ++i
)
537 Reference
< XPropertySet
> xProp( xKeyIndex
->getByIndex(i
), UNO_QUERY_THROW
);
538 xColumnsSupplier
.set( xProp
, UNO_QUERY_THROW
);
539 xFKeyColumns
.set( xColumnsSupplier
->getColumns(), UNO_QUERY_THROW
);
541 sal_Int32 nKeyType
= 0;
542 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
546 case KeyType::FOREIGN
:
547 { // our new table has a foreign key
548 // so look if the referenced table is already in our list
549 xProp
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= aReferencedTable
;
550 OSL_ENSURE(!aReferencedTable
.isEmpty(),"Foreign key without referencedTableName");
552 OTableWindowMap::const_iterator aIter
= pTabWins
->find(aReferencedTable
);
553 OTableWindowMap::const_iterator aEnd
= pTabWins
->end();
556 for(aIter
= pTabWins
->begin();aIter
!= aEnd
;++aIter
)
558 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(aIter
->second
);
559 OSL_ENSURE( pTabWinTmp
,"TableWindow is null!" );
560 if ( pTabWinTmp
!= pNewTabWin
&& pTabWinTmp
->GetComposedName() == aReferencedTable
)
564 if ( aIter
!= aEnd
&& pNewTabWin
!= aIter
->second
)
565 addConnections( this, *pNewTabWin
, *static_cast<OQueryTableWindow
*>(aIter
->second
), xFKeyColumns
);
569 case KeyType::PRIMARY
:
571 // we have a primary key so look in our list if there exsits a key which this is refered to
572 OTableWindowMap::const_iterator aIter
= pTabWins
->begin();
573 OTableWindowMap::const_iterator aEnd
= pTabWins
->end();
574 for(;aIter
!= aEnd
;++aIter
)
576 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(aIter
->second
);
577 if ( pTabWinTmp
== pNewTabWin
)
580 if ( pTabWinTmp
->GetData()->isQuery() )
583 OSL_ENSURE(pTabWinTmp
,"TableWindow is null!");
584 Reference
< XPropertySet
> xFKKey
= getKeyReferencedTo( pTabWinTmp
->GetData()->getKeys(), pNewTabWin
->GetComposedName() );
588 Reference
<XColumnsSupplier
> xFKColumnsSupplier( xFKKey
, UNO_QUERY_THROW
);
589 Reference
< XNameAccess
> xTColumns( xFKColumnsSupplier
->getColumns(), UNO_QUERY_THROW
);
590 addConnections( this, *pTabWinTmp
, *pNewTabWin
, xTColumns
);
597 catch( const Exception
& )
599 DBG_UNHANDLED_EXCEPTION();
605 // My parent needs to be informed about the delete
606 m_pView
->getController().addUndoActionAndInvalidate( pUndoAction
);
608 if (bSuccess
&& m_lnkTabWinsChangeHandler
.IsSet())
610 TabWinsChangeNotification
aHint(TabWinsChangeNotification::AT_ADDED_WIN
, pNewTabWin
->GetAliasName());
611 m_lnkTabWinsChangeHandler
.Call(&aHint
);
614 // -----------------------------------------------------------------------------
615 // -----------------------------------------------------------------------------
616 void OQueryTableView::AddConnection(const OJoinExchangeData
& jxdSource
, const OJoinExchangeData
& jxdDest
)
618 DBG_CHKTHIS(OQueryTableView
,NULL
);
619 OQueryTableWindow
* pSourceWin
= static_cast< OQueryTableWindow
*>(jxdSource
.pListBox
->GetTabWin());
620 OQueryTableWindow
* pDestWin
= static_cast< OQueryTableWindow
*>(jxdDest
.pListBox
->GetTabWin());
622 String aSourceFieldName
, aDestFieldName
;
623 aSourceFieldName
= jxdSource
.pListBox
->GetEntryText(jxdSource
.pEntry
);
624 aDestFieldName
= jxdDest
.pListBox
->GetEntryText(jxdDest
.pEntry
);
626 OTableConnection
* pConn
= GetTabConn(pSourceWin
,pDestWin
,true);
630 OQueryTableConnectionData
* pNewConnectionData
= new OQueryTableConnectionData(pSourceWin
->GetData(), pDestWin
->GetData());
631 TTableConnectionData::value_type
aNewConnectionData(pNewConnectionData
);
633 sal_uInt32 nSourceFieldIndex
, nDestFieldIndex
;
634 ETableFieldType eSourceFieldType
, eDestFieldType
;
636 // Get name/position/type of both affected fields ...
639 nSourceFieldIndex
= jxdSource
.pListBox
->GetModel()->GetAbsPos(jxdSource
.pEntry
);
640 eSourceFieldType
= static_cast< OTableFieldInfo
*>(jxdSource
.pEntry
->GetUserData())->GetKeyType();
644 nDestFieldIndex
= jxdDest
.pListBox
->GetModel()->GetAbsPos(jxdDest
.pEntry
);
645 eDestFieldType
= static_cast< OTableFieldInfo
*>(jxdDest
.pEntry
->GetUserData())->GetKeyType();
648 pNewConnectionData
->SetFieldIndex(JTCS_FROM
, nSourceFieldIndex
);
649 pNewConnectionData
->SetFieldIndex(JTCS_TO
, nDestFieldIndex
);
651 pNewConnectionData
->SetFieldType(JTCS_FROM
, eSourceFieldType
);
652 pNewConnectionData
->SetFieldType(JTCS_TO
, eDestFieldType
);
654 pNewConnectionData
->AppendConnLine( aSourceFieldName
,aDestFieldName
);
656 OQueryTableConnection
aNewConnection(this, aNewConnectionData
);
657 NotifyTabConnection(aNewConnection
);
658 // As usual with NotifyTabConnection, using a local variable is fine because a copy is made
662 // the connection could point on the other side
663 if(pConn
->GetSourceWin() == pDestWin
)
665 String
aTmp(aSourceFieldName
);
666 aSourceFieldName
= aDestFieldName
;
667 aDestFieldName
= aTmp
;
670 pConn
->GetData()->AppendConnLine( aSourceFieldName
,aDestFieldName
);
672 connectionModified(this,pConn
,sal_False
);
675 // -----------------------------------------------------------------------------
676 void OQueryTableView::ConnDoubleClicked(OTableConnection
* pConnection
)
678 DBG_CHKTHIS(OQueryTableView
,NULL
);
679 if( openJoinDialog(this,pConnection
->GetData(),sal_False
) )
681 connectionModified(this,pConnection
,sal_False
);
682 SelectConn( pConnection
);
685 // -----------------------------------------------------------------------------
686 void OQueryTableView::createNewConnection()
688 TTableConnectionData::value_type
pData(new OQueryTableConnectionData());
689 if( openJoinDialog(this,pData
,sal_True
) )
691 OTableWindowMap
* pMap
= GetTabWinMap();
692 OQueryTableWindow
* pSourceWin
= static_cast< OQueryTableWindow
*>((*pMap
)[pData
->getReferencingTable()->GetWinName()]);
693 OQueryTableWindow
* pDestWin
= static_cast< OQueryTableWindow
*>((*pMap
)[pData
->getReferencedTable()->GetWinName()]);
694 // first we have to look if the this connection already exists
695 OTableConnection
* pConn
= GetTabConn(pSourceWin
,pDestWin
,true);
696 sal_Bool bNew
= sal_True
;
699 pConn
->GetData()->CopyFrom( *pData
);
704 // create a new conenction and append it
705 OQueryTableConnection
* pQConn
= new OQueryTableConnection(this, pData
);
706 GetConnection(pQConn
);
709 connectionModified(this,pConn
,bNew
);
710 if ( !bNew
&& pConn
== GetSelectedConn() ) // our connection was selected before so we have to reselect it
714 //------------------------------------------------------------------------------
715 bool OQueryTableView::RemoveConnection( OTableConnection
* _pConnection
,sal_Bool
/*_bDelete*/ )
717 DBG_CHKTHIS(OQueryTableView
,NULL
);
719 // we don't want that our connection will be deleted, we put it in the undo manager
720 bool bRet
= OJoinTableView::RemoveConnection( _pConnection
,sal_False
);
724 new OQueryDelTabConnUndoAction(this),
725 static_cast< OQueryTableConnection
*>(_pConnection
),
730 //------------------------------------------------------------------------------
731 void OQueryTableView::KeyInput( const KeyEvent
& rEvt
)
733 DBG_CHKTHIS(OQueryTableView
,NULL
);
734 OJoinTableView::KeyInput( rEvt
);
737 //------------------------------------------------------------------------------
738 OQueryTableWindow
* OQueryTableView::FindTable(const String
& rAliasName
)
740 DBG_CHKTHIS(OQueryTableView
,NULL
);
741 OSL_ENSURE(rAliasName
.Len(), "OQueryTableView::FindTable : the AliasName should not be empty !");
742 // (it is harmless but does not make sense and indicates that there is probably an error in the caller)
743 OTableWindowMap::const_iterator aIter
= GetTabWinMap()->find(rAliasName
);
744 if(aIter
!= GetTabWinMap()->end())
745 return static_cast<OQueryTableWindow
*>(aIter
->second
);
749 //------------------------------------------------------------------------------
750 sal_Bool
OQueryTableView::FindTableFromField(const String
& rFieldName
, OTableFieldDescRef
& rInfo
, sal_uInt16
& rCnt
)
752 DBG_CHKTHIS(OQueryTableView
,NULL
);
754 OTableWindowMap::const_iterator aIter
= GetTabWinMap()->begin();
755 OTableWindowMap::const_iterator aEnd
= GetTabWinMap()->end();
756 for(;aIter
!= aEnd
;++aIter
)
758 if(static_cast<OQueryTableWindow
*>(aIter
->second
)->ExistsField(rFieldName
, rInfo
))
765 //------------------------------------------------------------------------------
766 void OQueryTableView::RemoveTabWin(OTableWindow
* pTabWin
)
768 DBG_CHKTHIS(OQueryTableView
,NULL
);
769 OSL_ENSURE(pTabWin
!= NULL
, "OQueryTableView::RemoveTabWin : Window should not be NULL !");
771 // I need my parent so it can be informed about the deletion
772 OQueryDesignView
* pParent
= static_cast<OQueryDesignView
*>(getDesignView());
774 SfxUndoManager
& rUndoMgr
= m_pView
->getController().GetUndoManager();
775 rUndoMgr
.EnterListAction( String( ModuleRes(STR_QUERY_UNDO_TABWINDELETE
) ), String() );
777 // add the Undo-Action
778 OQueryTabWinDelUndoAct
* pUndoAction
= new OQueryTabWinDelUndoAct(this);
779 pUndoAction
->SetTabWin(static_cast< OQueryTableWindow
*>(pTabWin
));
781 // and hide the window
782 HideTabWin(static_cast< OQueryTableWindow
*>(pTabWin
), pUndoAction
);
784 // Undo Actions and delete the fields in SelectionBrowseBox
785 pParent
->TableDeleted( static_cast< OQueryTableWindowData
*>(pTabWin
->GetData().get())->GetAliasName() );
787 m_pView
->getController().addUndoActionAndInvalidate( pUndoAction
);
788 rUndoMgr
.LeaveListAction();
790 if (m_lnkTabWinsChangeHandler
.IsSet())
792 TabWinsChangeNotification
aHint(TabWinsChangeNotification::AT_REMOVED_WIN
, static_cast< OQueryTableWindow
*>(pTabWin
)->GetAliasName());
793 m_lnkTabWinsChangeHandler
.Call(&aHint
);
798 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
799 makeAny(pTabWin
->GetAccessible()),
804 //------------------------------------------------------------------------
805 void OQueryTableView::EnsureVisible(const OTableWindow
* pWin
)
807 DBG_CHKTHIS(OQueryTableView
,NULL
);
809 Invalidate(INVALIDATE_NOCHILDREN
);
810 OJoinTableView::EnsureVisible(pWin
);
813 //------------------------------------------------------------------------
814 void OQueryTableView::GetConnection(OQueryTableConnection
* pConn
)
816 DBG_CHKTHIS(OQueryTableView
,NULL
);
817 // add to me and the document
819 addConnection( pConn
);
822 //------------------------------------------------------------------------
823 void OQueryTableView::DropConnection(OQueryTableConnection
* pConn
)
825 DBG_CHKTHIS(OQueryTableView
,NULL
);
826 // Pay attention to the selection
827 // remove from me and the document
828 RemoveConnection( pConn
,sal_False
);
831 //------------------------------------------------------------------------
832 void OQueryTableView::HideTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
)
834 DBG_CHKTHIS(OQueryTableView
,NULL
);
835 OTableWindowMap
* pTabWins
= GetTabWinMap();
836 OSL_ENSURE(pTabWins
!= NULL
, "OQueryTableView::HideTabWin : have no TabWins !");
841 // save the position in its data
842 getDesignView()->SaveTabWinUIConfig(pTabWin
);
843 // (I need to go via the parent, as only the parent knows the position of the scrollbars)
844 // and then out of the TabWins list and hide
845 OTableWindowMap::iterator aIter
= pTabWins
->begin();
846 OTableWindowMap::iterator aEnd
= pTabWins
->end();
847 for ( ;aIter
!= aEnd
; ++aIter
)
848 if ( aIter
->second
== pTabWin
)
850 pTabWins
->erase( aIter
);
854 pTabWin
->Hide(); // do not destroy it, as it is still in the undo list!!
856 // the TabWin data must also be passed out of my responsibility
857 TTableWindowData
* pTabWinDataList
= m_pView
->getController().getTableWindowData();
858 pTabWinDataList
->erase( ::std::remove(pTabWinDataList
->begin(),pTabWinDataList
->end(),pTabWin
->GetData()),pTabWinDataList
->end());
859 // The data should not be destroyed as TabWin itself - which is still alive - needs them
860 // Either it goes back into my responsibility, (via ShowTabWin), then I add the data back,
861 // or the Undo-Action, which currently has full responsibility for the window
862 // and its data, gets destroyed and destroys both the window and its data
864 if (m_pLastFocusTabWin
== pTabWin
)
865 m_pLastFocusTabWin
= NULL
;
867 // collect connections belonging to the window and pass to UndoAction
869 const ::std::vector
<OTableConnection
*>* pTabConList
= getTableConnections();
870 ::std::vector
<OTableConnection
*>::const_iterator aIter2
= pTabConList
->begin();
871 for(;aIter2
!= pTabConList
->end();)// the end may change
873 OQueryTableConnection
* pTmpEntry
= static_cast<OQueryTableConnection
*>(*aIter2
);
874 OSL_ENSURE(pTmpEntry
,"OQueryTableConnection is null!");
875 if( pTmpEntry
->GetAliasName(JTCS_FROM
) == pTabWin
->GetAliasName() ||
876 pTmpEntry
->GetAliasName(JTCS_TO
) == pTabWin
->GetAliasName() )
879 pUndoAction
->InsertConnection(pTmpEntry
);
881 // call base class because we append an undo action
882 // but this time we are in a undo action list
883 OJoinTableView::RemoveConnection(pTmpEntry
,sal_False
);
884 aIter2
= pTabConList
->begin();
892 InvalidateConnections();
894 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
896 // inform the UndoAction that the window and connections belong to it
897 pUndoAction
->SetOwnership(sal_True
);
899 // by doing so, we have modified the document
900 m_pView
->getController().setModified( sal_True
);
901 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
905 //------------------------------------------------------------------------
906 sal_Bool
OQueryTableView::ShowTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
,sal_Bool _bAppend
)
908 DBG_CHKTHIS(OQueryTableView
,NULL
);
910 sal_Bool bSuccess
= sal_False
;
916 TTableWindowData::value_type pData
= pTabWin
->GetData();
917 OSL_ENSURE(pData
!= NULL
, "OQueryTableView::ShowTabWin : TabWin has no data !");
918 // If there is a position and size defined, we use them
919 if (pData
->HasPosition() && pData
->HasSize())
921 Size
aSize(CalcZoom(pData
->GetSize().Width()),CalcZoom(pData
->GetSize().Height()));
922 pTabWin
->SetPosSizePixel(pData
->GetPosition(), aSize
);
925 // else set a default position
926 SetDefaultTabWinPosSize(pTabWin
);
928 // Show the window and add to the list
929 OUString sName
= static_cast< OQueryTableWindowData
*>(pData
.get())->GetAliasName();
930 OSL_ENSURE(GetTabWinMap()->find(sName
) == GetTabWinMap()->end(),"Alias name already in list!");
931 GetTabWinMap()->insert(OTableWindowMap::value_type(sName
,pTabWin
));
936 // We must call Update() in order to show the connections in the window correctly. This sounds strange,
937 // but the Listbox has an internal Member which is initialized when the Listbox is first shown (after the Listbox
938 // is filled in Init). This Member will eventually be needed for
939 // GetEntryPos, and then in turn by the Connection, when its starting point to the window must be determined.
942 ::std::vector
<OTableConnection
*>* pTableCon
= pUndoAction
->GetTabConnList();
943 ::std::vector
<OTableConnection
*>::iterator aIter
= pTableCon
->begin();
944 ::std::vector
<OTableConnection
*>::iterator aEnd
= pTableCon
->end();
946 for(;aIter
!= aEnd
;++aIter
)
947 addConnection(*aIter
); // add all connections from the undo action
951 // and add the window's data to the list (of the document)
953 m_pView
->getController().getTableWindowData()->push_back(pTabWin
->GetData());
955 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
957 // and inform the UndoAction that the window belongs to me
958 pUndoAction
->SetOwnership(sal_False
);
964 // Initialisation failed
965 // (for example when the Connection to the database is not available at the moment)
966 pTabWin
->clearListBox();
971 // show that I have changed the document
972 if(!m_pView
->getController().isReadOnly())
973 m_pView
->getController().setModified( sal_True
);
975 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
979 //------------------------------------------------------------------------
980 void OQueryTableView::InsertField(const OTableFieldDescRef
& rInfo
)
982 DBG_CHKTHIS(OQueryTableView
,NULL
);
983 OSL_ENSURE(getDesignView() != NULL
, "OQueryTableView::InsertField : has no Parent !");
984 static_cast<OQueryDesignView
*>(getDesignView())->InsertField(rInfo
);
986 //------------------------------------------------------------------------------
987 sal_Bool
OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow
* pFrom
) const
989 DBG_CHKTHIS(OQueryTableView
,NULL
);
990 const ::std::vector
<OTableConnection
*>* pList
= getTableConnections();
993 ::std::vector
<OTableConnection
*>::const_iterator aIter
= pList
->begin();
994 ::std::vector
<OTableConnection
*>::const_iterator aEnd
= pList
->end();
995 for(;aIter
!= aEnd
;++aIter
)
997 OQueryTableConnection
* pTemp
= static_cast<OQueryTableConnection
*>(*aIter
);
998 if (pTemp
->IsVisited() &&
999 (pFrom
== static_cast< OQueryTableWindow
*>(pTemp
->GetSourceWin()) || pFrom
== static_cast< OQueryTableWindow
*>(pTemp
->GetDestWin())))
1000 return pTemp
!= NULL
;
1006 // -----------------------------------------------------------------------------
1007 void OQueryTableView::onNoColumns_throw()
1009 String
sError( ModuleRes( STR_STATEMENT_WITHOUT_RESULT_SET
) );
1010 ::dbtools::throwSQLException( sError
, ::dbtools::SQL_GENERAL_ERROR
, NULL
);
1012 //------------------------------------------------------------------------------
1013 bool OQueryTableView::supressCrossNaturalJoin(const TTableConnectionData::value_type
& _pData
) const
1015 OQueryTableConnectionData
* pQueryData
= static_cast<OQueryTableConnectionData
*>(_pData
.get());
1016 return pQueryData
&& (pQueryData
->GetJoinType() == CROSS_JOIN
);
1018 // -----------------------------------------------------------------------------
1020 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */