1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: QueryTableView.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dbaccess.hxx"
34 #ifndef DBAUI_QUERYTABLEVIEW_HXX
35 #include "QueryTableView.hxx"
37 #ifndef DBAUI_TABLEFIELDINFO_HXX
38 #include "TableFieldInfo.hxx"
40 #ifndef DBAUI_TABLEFIELDDESC_HXX
41 #include "TableFieldDescription.hxx"
43 #ifndef _TOOLS_DEBUG_HXX
44 #include <tools/debug.hxx>
46 #ifndef TOOLS_DIAGNOSE_EX_H
47 #include <tools/diagnose_ex.h>
49 #ifndef _DBA_DBACCESS_HELPID_HRC_
50 #include "dbaccess_helpid.hrc"
52 #ifndef DBAUI_QUERY_TABLEWINDOW_HXX
53 #include "QTableWindow.hxx"
55 #ifndef DBAUI_QUERYTABLECONNECTION_HXX
56 #include "QTableConnection.hxx"
58 #ifndef DBAUI_QTABLECONNECTIONDATA_HXX
59 #include "QTableConnectionData.hxx"
61 #ifndef DBAUI_QUERYDESIGNVIEW_HXX
62 #include "QueryDesignView.hxx"
64 #ifndef DBAUI_QUERYCONTROLLER_HXX
65 #include "querycontroller.hxx"
67 #ifndef DBAUI_QUERYADDTABCONNUNDOACTION_HXX
68 #include "QueryAddTabConnUndoAction.hxx"
70 #ifndef DBAUI_QUERYTABWINSHOWUNDOACT_HXX
71 #include "QueryTabWinShowUndoAct.hxx"
73 #ifndef DBACCESS_UI_BROWSER_ID_HXX
74 #include "browserids.hxx"
76 #ifndef _COM_SUN_STAR_SDBCX_XTABLESSUPPLIER_HPP_
77 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
79 #ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_
80 #include <com/sun/star/sdbc/XConnection.hpp>
82 #ifndef _COM_SUN_STAR_SDBCX_XKEYSSUPPLIER_HPP_
83 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
85 #ifndef _COM_SUN_STAR_SDBCX_XCOLUMNSSUPPLIER_HPP_
86 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
88 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
89 #ifndef DBACCESS_JACCESS_HXX
90 #include "JAccess.hxx"
92 #ifndef _COM_SUN_STAR_SDBCX_KEYTYPE_HPP_
93 #include <com/sun/star/sdbcx/KeyType.hpp>
95 #ifndef _COM_SUN_STAR_CONTAINER_XINDEXACCESS_HPP_
96 #include <com/sun/star/container/XIndexAccess.hpp>
98 #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
99 #include <com/sun/star/beans/XPropertySet.hpp>
101 #ifndef DBACCESS_SHARED_DBUSTRINGS_HRC
102 #include "dbustrings.hrc"
104 #ifndef _CONNECTIVITY_DBTOOLS_HXX_
105 #include <connectivity/dbtools.hxx>
107 #ifndef _COMPHELPER_SEQUENCE_HXX_
108 #include <comphelper/sequence.hxx>
110 #ifndef DBAUI_QUERYDLG_HXX
111 #include "querydlg.hxx"
113 #ifndef DBAUI_JOINEXCHANGE_HXX
114 #include "JoinExchange.hxx"
116 #ifndef _COMPHELPER_EXTRACT_HXX_
117 #include <comphelper/extract.hxx>
119 #ifndef DBAUI_QUERYDESIGNVIEW_HXX
120 #include "QueryDesignView.hxx"
122 #ifndef _DBU_QRY_HRC_
123 #include "dbu_qry.hrc"
125 #ifndef _SV_MSGBOX_HXX
126 #include <vcl/msgbox.hxx>
129 using namespace dbaui
;
130 using namespace ::com::sun::star::uno
;
131 using namespace ::com::sun::star::sdbc
;
132 using namespace ::com::sun::star::sdbcx
;
133 using namespace ::com::sun::star::beans
;
134 using namespace ::com::sun::star::container
;
135 using namespace ::com::sun::star::accessibility
;
137 //------------------------------------------------------------------------------
140 // -----------------------------------------------------------------------------
141 sal_Bool
isColumnInKeyType(const Reference
<XIndexAccess
>& _rxKeys
,const ::rtl::OUString
& _rColumnName
,sal_Int32 _nKeyType
)
143 sal_Bool bReturn
= sal_False
;
146 Reference
<XColumnsSupplier
> xColumnsSupplier
;
147 // search the one and only primary key
148 const sal_Int32 nCount
= _rxKeys
->getCount();
149 for(sal_Int32 i
=0;i
< nCount
;++i
)
151 Reference
<XPropertySet
> xProp(_rxKeys
->getByIndex(i
),UNO_QUERY
);
154 sal_Int32 nKeyType
= 0;
155 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
156 if(_nKeyType
== nKeyType
)
158 xColumnsSupplier
.set(xProp
,UNO_QUERY
);
159 if(xColumnsSupplier
.is())
161 Reference
<XNameAccess
> xColumns
= xColumnsSupplier
->getColumns();
162 if(xColumns
.is() && xColumns
->hasByName(_rColumnName
))
174 // -----------------------------------------------------------------------------
175 /** appends a new TabAdd Undo action at controller
176 @param _pView the view which we use
177 @param _pUndoAction the undo action which should be added
178 @param _pConnection the connection for which the undo action should be appended
179 @param _bOwner is the undo action the owner
181 // -----------------------------------------------------------------------------
182 void addUndoAction( OQueryTableView
* _pView
,
183 OQueryTabConnUndoAction
* _pUndoAction
,
184 OQueryTableConnection
* _pConnection
,
185 sal_Bool _bOwner
= sal_False
)
187 _pUndoAction
->SetOwnership(_bOwner
);
188 _pUndoAction
->SetConnection(_pConnection
);
189 _pView
->getDesignView()->getController().addUndoActionAndInvalidate(_pUndoAction
);
191 // -----------------------------------------------------------------------------
192 /** openJoinDialog opens the join dialog with this connection data
193 @param _pView the view which we use
194 @param _pConnectionData the connection data
196 @return true when OK was pressed otherwise false
198 sal_Bool
openJoinDialog(OQueryTableView
* _pView
,const TTableConnectionData::value_type
& _pConnectionData
,BOOL _bSelectableTables
)
200 OQueryTableConnectionData
* pData
= static_cast< OQueryTableConnectionData
*>(_pConnectionData
.get());
202 DlgQryJoin
aDlg(_pView
,_pConnectionData
,_pView
->GetTabWinMap(),_pView
->getDesignView()->getController().getConnection(),_bSelectableTables
);
203 sal_Bool bOk
= aDlg
.Execute() == RET_OK
;
206 pData
->SetJoinType(aDlg
.GetJoinType());
207 _pView
->getDesignView()->getController().setModified(sal_True
);
212 // -----------------------------------------------------------------------------
213 /** connectionModified adds an undo action for the modified connection and forces an redraw
214 @param _pView the view which we use
215 @param _pConnection the connection which was modified
216 @param _bAddUndo true when an undo action should be appended
218 void connectionModified(OQueryTableView
* _pView
,
219 OTableConnection
* _pConnection
,
222 OSL_ENSURE(_pConnection
,"Invalid connection!");
223 _pConnection
->UpdateLineList();
225 // add an undo action
227 addUndoAction( _pView
,
228 new OQueryAddTabConnUndoAction(_pView
),
229 static_cast< OQueryTableConnection
*>(_pConnection
));
231 _pConnection
->RecalcLines();
232 // force an invalidation of the bounding rectangle
233 _pConnection
->InvalidateConnection();
235 _pView
->Invalidate(INVALIDATE_NOCHILDREN
);
237 // -----------------------------------------------------------------------------
238 void addConnections(OQueryTableView
* _pView
,
239 const OQueryTableWindow
& _rSource
,
240 const OQueryTableWindow
& _rDest
,
241 const Reference
<XNameAccess
>& _rxSourceForeignKeyColumns
)
243 if ( _rSource
.GetData()->isQuery() || _rDest
.GetData()->isQuery() )
244 // nothing to do if one of both denotes a query
247 // we found a table in our view where we can insert some connections
248 // the key columns have a property called RelatedColumn
249 // OQueryTableConnectionData aufbauen
250 OQueryTableConnectionData
* pNewConnData
= new OQueryTableConnectionData( _rSource
.GetData(), _rDest
.GetData() );
251 TTableConnectionData::value_type
aNewConnData(pNewConnData
);
253 Reference
<XIndexAccess
> xReferencedKeys( _rDest
.GetData()->getKeys());
254 ::rtl::OUString sRelatedColumn
;
256 // iterate through all foreignkey columns to create the connections
257 Sequence
< ::rtl::OUString
> aElements(_rxSourceForeignKeyColumns
->getElementNames());
258 const ::rtl::OUString
* pIter
= aElements
.getConstArray();
259 const ::rtl::OUString
* pEnd
= pIter
+ aElements
.getLength();
260 for(sal_Int32 i
=0;pIter
!= pEnd
;++pIter
,++i
)
262 Reference
<XPropertySet
> xColumn
;
263 if ( !( _rxSourceForeignKeyColumns
->getByName(*pIter
) >>= xColumn
) )
265 OSL_ENSURE( false, "addConnections: invalid foreign key column!" );
269 pNewConnData
->SetFieldType(JTCS_FROM
,TAB_NORMAL_FIELD
);
271 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
272 pNewConnData
->SetFieldType(JTCS_TO
,isColumnInKeyType(xReferencedKeys
,sRelatedColumn
,KeyType::PRIMARY
) ? TAB_PRIMARY_FIELD
: TAB_NORMAL_FIELD
);
275 Sequence
< sal_Int16
> aFind(::comphelper::findValue(_rSource
.GetOriginalColumns()->getElementNames(),*pIter
,sal_True
));
276 if(aFind
.getLength())
277 pNewConnData
->SetFieldIndex(JTCS_FROM
,aFind
[0]+1);
279 OSL_ENSURE(0,"Column not found!");
281 // get the position inside the tabe
282 Reference
<XNameAccess
> xRefColumns
= _rDest
.GetOriginalColumns();
285 Sequence
< sal_Int16
> aFind(::comphelper::findValue(xRefColumns
->getElementNames(),sRelatedColumn
,sal_True
));
286 if(aFind
.getLength())
287 pNewConnData
->SetFieldIndex(JTCS_TO
,aFind
[0]+1);
289 OSL_ENSURE(0,"Column not found!");
291 pNewConnData
->AppendConnLine(*pIter
,sRelatedColumn
);
293 // dann die Conn selber dazu
294 OQueryTableConnection
aNewConn(_pView
, aNewConnData
);
295 // der Verweis auf die lokale Variable ist unkritisch, da NotifyQueryTabConn eine neue Kopie anlegt
296 // und mir hinzufuegen (wenn nicht schon existent)
297 _pView
->NotifyTabConnection(aNewConn
, sal_False
);
298 // don't create an Undo-Action for the new connection : the connection is
299 // covered by the Undo-Action for the tabwin, as the "Undo the insert" will
300 // automatically remove all connections adjacent to the win.
301 // (Because of this automatism we would have an ownerhsip ambiguity for
302 // the connection data if we would insert the conn-Undo-Action)
303 // FS - 21.10.99 - 69183
307 //==================================================================
308 // class OQueryTableView
309 //==================================================================
310 DBG_NAME(OQueryTableView
)
311 //------------------------------------------------------------------------
312 OQueryTableView::OQueryTableView( Window
* pParent
,OQueryDesignView
* pView
)
313 : OJoinTableView( pParent
,pView
)
315 DBG_CTOR(OQueryTableView
,NULL
);
316 SetHelpId(HID_CTL_QRYDGNTAB
);
319 //------------------------------------------------------------------------
320 OQueryTableView::~OQueryTableView()
322 DBG_DTOR(OQueryTableView
,NULL
);
325 //------------------------------------------------------------------------
326 sal_Int32
OQueryTableView::CountTableAlias(const String
& rName
, sal_Int32
& rMax
)
328 DBG_CHKTHIS(OQueryTableView
,NULL
);
331 OTableWindowMapIterator aIter
= GetTabWinMap()->find(rName
);
332 while(aIter
!= GetTabWinMap()->end())
337 aNewName
+= String::CreateFromInt32(++nRet
);
339 aIter
= GetTabWinMap()->find(aNewName
);
346 //------------------------------------------------------------------------
347 void OQueryTableView::ReSync()
349 DBG_CHKTHIS(OQueryTableView
,NULL
);
350 TTableWindowData
* pTabWinDataList
= m_pView
->getController().getTableWindowData();
351 DBG_ASSERT((getTableConnections()->size()==0) && (GetTabWinMap()->size()==0),
352 "vor OQueryTableView::ReSync() bitte ClearAll aufrufen !");
354 // ich brauche eine Sammlung aller Fensternamen, deren Anlegen schief geht, damit ich die entsprechenden Connections
355 // gar nicht erst anlege
356 ::std::vector
<String
> arrInvalidTables
;
358 TTableWindowData::reverse_iterator aIter
= pTabWinDataList
->rbegin();
359 // Fenster kreieren und einfuegen
361 for(;aIter
!= pTabWinDataList
->rend();++aIter
)
363 OQueryTableWindowData
* pData
= static_cast<OQueryTableWindowData
*>(aIter
->get());
364 OTableWindow
* pTabWin
= createWindow(*aIter
);
366 // ich gehe jetzt NICHT ueber ShowTabWin, da dieses die Daten des Fensters in die Liste des Docs einfuegt, was
367 // schlecht waere, denn genau von dort hole ich sie ja gerade
368 // also Schritt fuer Schritt
369 if (!pTabWin
->Init())
371 // das Initialisieren ging schief, dass heisst, dieses TabWin steht nicht zur Verfuegung, also muss ich es inklusive
372 // seiner Daten am Dokument aufraeumen
373 pTabWin
->clearListBox();
375 arrInvalidTables
.push_back(pData
->GetAliasName());
377 pTabWinDataList
->erase( ::std::remove(pTabWinDataList
->begin(),pTabWinDataList
->end(),*aIter
) ,pTabWinDataList
->end());
381 (*GetTabWinMap())[pData
->GetAliasName()] = pTabWin
; // am Anfang einfuegen, da ich die DataList ja rueckwaerts durchlaufe
382 // wenn in den Daten keine Position oder Groesse steht -> Default
383 if (!pData
->HasPosition() && !pData
->HasSize())
384 SetDefaultTabWinPosSize(pTabWin
);
389 // Verbindungen einfuegen
390 TTableConnectionData
* pTabConnDataList
= m_pView
->getController().getTableConnectionData();
391 TTableConnectionData::reverse_iterator aConIter
= pTabConnDataList
->rbegin();
393 for(;aConIter
!= pTabConnDataList
->rend();++aConIter
)
395 OQueryTableConnectionData
* pTabConnData
= static_cast<OQueryTableConnectionData
*>(aConIter
->get());
397 // gibt es die beiden Tabellen zur Connection ?
398 String strTabExistenceTest
= pTabConnData
->getReferencingTable()->GetWinName();
399 sal_Bool bInvalid
= ::std::find(arrInvalidTables
.begin(),arrInvalidTables
.end(),strTabExistenceTest
) != arrInvalidTables
.end();
400 strTabExistenceTest
= pTabConnData
->getReferencedTable()->GetWinName();
401 bInvalid
= bInvalid
&& ::std::find(arrInvalidTables
.begin(),arrInvalidTables
.end(),strTabExistenceTest
) != arrInvalidTables
.end();
404 { // nein -> Pech gehabt, die Connection faellt weg
405 pTabConnDataList
->erase( ::std::remove(pTabConnDataList
->begin(),pTabConnDataList
->end(),*aConIter
) ,pTabConnDataList
->end());
409 // adds a new connection to join view and notifies our accessible and invaldates the controller
410 addConnection(new OQueryTableConnection(this, *aConIter
));
414 //------------------------------------------------------------------------
415 void OQueryTableView::ClearAll()
417 DBG_CHKTHIS(OQueryTableView
,NULL
);
418 OJoinTableView::ClearAll();
420 SetUpdateMode(sal_True
);
421 m_pView
->getController().setModified(sal_True
);
424 // -----------------------------------------------------------------------------
425 OTableWindow
* OQueryTableView::createWindow(const TTableWindowData::value_type
& _pData
)
427 return new OQueryTableWindow(this,_pData
);
430 //------------------------------------------------------------------------------
431 void OQueryTableView::NotifyTabConnection(const OQueryTableConnection
& rNewConn
, sal_Bool _bCreateUndoAction
)
433 DBG_CHKTHIS(OQueryTableView
,NULL
);
434 // erst mal schauen, ob ich diese Connection schon habe
435 OQueryTableConnection
* pTabConn
= NULL
;
436 const ::std::vector
<OTableConnection
*>* pConnections
= getTableConnections();
437 ::std::vector
<OTableConnection
*>::const_iterator aEnd
= pConnections
->end();
438 ::std::vector
<OTableConnection
*>::const_iterator aIter
= ::std::find( pConnections
->begin(),
440 static_cast<const OTableConnection
*>(&rNewConn
)
444 aIter
= pConnections
->begin();
445 for(;aIter
!= aEnd
;++aIter
)
447 if(*static_cast<OQueryTableConnection
*>(*aIter
) == rNewConn
)
449 pTabConn
= static_cast<OQueryTableConnection
*>(*aIter
);
455 pTabConn
= static_cast<OQueryTableConnection
*>(*aIter
);
457 if (pTabConn
== NULL
)
459 // die neuen Daten ...
460 OQueryTableConnectionData
* pNewData
= static_cast< OQueryTableConnectionData
*>(rNewConn
.GetData()->NewInstance());
461 pNewData
->CopyFrom(*rNewConn
.GetData());
462 TTableConnectionData::value_type
aData(pNewData
);
463 OQueryTableConnection
* pNewConn
= new OQueryTableConnection(this, aData
);
464 GetConnection(pNewConn
);
466 connectionModified(this,pNewConn
,_bCreateUndoAction
);
469 // -----------------------------------------------------------------------------
470 OTableWindowData
* OQueryTableView::CreateImpl(const ::rtl::OUString
& _rComposedName
471 ,const ::rtl::OUString
& _sTableName
472 ,const ::rtl::OUString
& _rWinName
)
474 return new OQueryTableWindowData( _rComposedName
, _sTableName
,_rWinName
);
476 //------------------------------------------------------------------------------
477 void OQueryTableView::AddTabWin(const ::rtl::OUString
& _rTableName
, const ::rtl::OUString
& _rAliasName
, sal_Bool bNewTable
)
479 DBG_CHKTHIS(OQueryTableView
,NULL
);
480 // das ist die aus der Basisklasse geerbte Methode, die fuehre ich auf die an meinem Parent zurueck, die mir eventuell einen
481 // Alias dazu bastelt und das an mein anderes AddTabWin weiterreicht
483 // leider ist _rTableName voll qualifiziert, das OQueryDesignView erwartet aber einen String, der
484 // nur aus Schema und Tabelle besteht und keinen Katalog enthaelt.
485 Reference
< XConnection
> xConnection
= m_pView
->getController().getConnection();
486 if(!xConnection
.is())
490 Reference
< XDatabaseMetaData
> xMetaData
= xConnection
->getMetaData();
491 ::rtl::OUString sCatalog
, sSchema
, sTable
;
492 ::dbtools::qualifiedNameComponents(xMetaData
,
497 ::dbtools::eInDataManipulation
);
498 ::rtl::OUString
sRealName(sSchema
);
499 if (sRealName
.getLength())
500 sRealName
+= ::rtl::OUString('.');
503 AddTabWin(_rTableName
, sRealName
, _rAliasName
, bNewTable
);
507 OSL_ASSERT(!"qualifiedNameComponents");
510 // -----------------------------------------------------------------------------
511 // find the table which has a foreign key with this referencedTable name
512 Reference
<XPropertySet
> getKeyReferencedTo(const Reference
<XIndexAccess
>& _rxKeys
,const ::rtl::OUString
& _rReferencedTable
)
515 return Reference
<XPropertySet
>();
518 return Reference
<XPropertySet
>();
519 // search the one and only primary key
520 const sal_Int32 nCount
= _rxKeys
->getCount();
521 for(sal_Int32 i
=0;i
<nCount
;++i
)
523 Reference
<XPropertySet
> xKey(_rxKeys
->getByIndex(i
),UNO_QUERY
);
526 sal_Int32 nKeyType
= 0;
527 xKey
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
528 if(KeyType::FOREIGN
== nKeyType
)
530 ::rtl::OUString sReferencedTable
;
531 xKey
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= sReferencedTable
;
533 if(sReferencedTable
== _rReferencedTable
)
538 return Reference
<XPropertySet
>();
540 //------------------------------------------------------------------------------
541 void OQueryTableView::AddTabWin(const ::rtl::OUString
& _rComposedName
, const ::rtl::OUString
& _rTableName
, const ::rtl::OUString
& strAlias
, sal_Bool bNewTable
)
543 DBG_CHKTHIS(OQueryTableView
,NULL
);
544 DBG_ASSERT(_rTableName
.getLength() || strAlias
.getLength(), "OQueryTableView::AddTabWin : kein Tabellen- und kein Aliasname !");
545 // wenn der Tabellenname nicht gesetzt ist, steht das fuer ein Dummy-Fenster, das braucht aber wenigstens einen Alias-Namen
547 // neue Datenstruktur erzeugen
548 // first check if this already hav it's data
549 sal_Bool bAppend
= bNewTable
;
550 TTableWindowData::value_type pNewTabWinData
;
551 TTableWindowData
* pWindowData
= getDesignView()->getController().getTableWindowData();
552 TTableWindowData::iterator aWinIter
= pWindowData
->begin();
553 TTableWindowData::iterator aWinEnd
= pWindowData
->end();
554 for(;aWinIter
!= aWinEnd
;++aWinIter
)
556 pNewTabWinData
= *aWinIter
;
557 if (pNewTabWinData
&& pNewTabWinData
->GetWinName() == strAlias
&& pNewTabWinData
->GetComposedName() == _rComposedName
&& pNewTabWinData
->GetTableName() == _rTableName
)
561 bAppend
= ( aWinIter
== aWinEnd
);
563 pNewTabWinData
= createTableWindowData(_rComposedName
, _rTableName
, strAlias
);
564 // die TabWinData brauche ich nicht in die entsprechende Liste der DocShell eintragen, das macht ShowTabWin
566 // neues Fenster erzeugen
567 OQueryTableWindow
* pNewTabWin
= static_cast<OQueryTableWindow
*>(createWindow(pNewTabWinData
));
568 // das Init kann ich hier weglassen, da das in ShowTabWin passiert
571 OQueryTabWinShowUndoAct
* pUndoAction
= new OQueryTabWinShowUndoAct(this);
572 pUndoAction
->SetTabWin(pNewTabWin
); // Fenster
573 sal_Bool bSuccess
= ShowTabWin(pNewTabWin
, pUndoAction
,bAppend
);
576 // reset table window
577 pUndoAction
->SetTabWin(NULL
);
578 pUndoAction
->SetOwnership(sal_False
);
584 // Relationen zwischen den einzelnen Tabellen anzeigen
585 OTableWindowMap
* pTabWins
= GetTabWinMap();
586 if(bNewTable
&& !pTabWins
->empty() && _rTableName
.getLength())
590 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
592 makeAny(pNewTabWin
->GetAccessible())
597 if ( pNewTabWin
->GetData()->isQuery() )
602 //////////////////////////////////////////////////////////////////////
603 // find relations between the table an the tables already inserted
604 Reference
< XIndexAccess
> xKeyIndex
= pNewTabWin
->GetData()->getKeys();
605 if ( !xKeyIndex
.is() )
608 Reference
<XNameAccess
> xFKeyColumns
;
609 ::rtl::OUString aReferencedTable
;
610 Reference
<XColumnsSupplier
> xColumnsSupplier
;
612 const sal_Int32 nKeyCount
= xKeyIndex
->getCount();
613 for ( sal_Int32 i
=0; i
<nKeyCount
; ++i
)
615 Reference
< XPropertySet
> xProp( xKeyIndex
->getByIndex(i
), UNO_QUERY_THROW
);
616 xColumnsSupplier
.set( xProp
, UNO_QUERY_THROW
);
617 xFKeyColumns
.set( xColumnsSupplier
->getColumns(), UNO_QUERY_THROW
);
619 sal_Int32 nKeyType
= 0;
620 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
624 case KeyType::FOREIGN
:
625 { // our new table has a foreign key
626 // so look if the referenced table is already in our list
627 xProp
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= aReferencedTable
;
628 OSL_ENSURE(aReferencedTable
.getLength(),"Foreign key without referencedTableName");
630 OTableWindowMap::const_iterator aIter
= pTabWins
->find(aReferencedTable
);
631 OTableWindowMap::const_iterator aEnd
= pTabWins
->end();
634 for(aIter
= pTabWins
->begin();aIter
!= aEnd
;++aIter
)
636 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(aIter
->second
);
637 OSL_ENSURE( pTabWinTmp
,"TableWindow is null!" );
638 if ( pTabWinTmp
!= pNewTabWin
&& pTabWinTmp
->GetComposedName() == aReferencedTable
)
642 if ( aIter
!= aEnd
&& pNewTabWin
!= aIter
->second
)
643 addConnections( this, *pNewTabWin
, *static_cast<OQueryTableWindow
*>(aIter
->second
), xFKeyColumns
);
647 case KeyType::PRIMARY
:
649 // we have a primary key so look in our list if there exsits a key which this is refered to
650 OTableWindowMap::const_iterator aIter
= pTabWins
->begin();
651 OTableWindowMap::const_iterator aEnd
= pTabWins
->end();
652 for(;aIter
!= aEnd
;++aIter
)
654 OQueryTableWindow
* pTabWinTmp
= static_cast<OQueryTableWindow
*>(aIter
->second
);
655 if ( pTabWinTmp
== pNewTabWin
)
658 if ( pTabWinTmp
->GetData()->isQuery() )
661 OSL_ENSURE(pTabWinTmp
,"TableWindow is null!");
662 Reference
< XPropertySet
> xFKKey
= getKeyReferencedTo( pTabWinTmp
->GetData()->getKeys(), pNewTabWin
->GetComposedName() );
666 Reference
<XColumnsSupplier
> xFKColumnsSupplier( xFKKey
, UNO_QUERY_THROW
);
667 Reference
< XNameAccess
> xTColumns( xFKColumnsSupplier
->getColumns(), UNO_QUERY_THROW
);
668 addConnections( this, *pTabWinTmp
, *pNewTabWin
, xTColumns
);
675 catch( const Exception
& )
677 DBG_UNHANDLED_EXCEPTION();
683 // mein Parent brauche ich, da es vom Loeschen erfahren soll
684 m_pView
->getController().addUndoActionAndInvalidate( pUndoAction
);
686 if (bSuccess
&& m_lnkTabWinsChangeHandler
.IsSet())
688 TabWinsChangeNotification
aHint(TabWinsChangeNotification::AT_ADDED_WIN
, pNewTabWin
->GetAliasName());
689 m_lnkTabWinsChangeHandler
.Call(&aHint
);
692 // -----------------------------------------------------------------------------
693 // -----------------------------------------------------------------------------
694 void OQueryTableView::AddConnection(const OJoinExchangeData
& jxdSource
, const OJoinExchangeData
& jxdDest
)
696 DBG_CHKTHIS(OQueryTableView
,NULL
);
697 OQueryTableWindow
* pSourceWin
= static_cast< OQueryTableWindow
*>(jxdSource
.pListBox
->GetTabWin());
698 OQueryTableWindow
* pDestWin
= static_cast< OQueryTableWindow
*>(jxdDest
.pListBox
->GetTabWin());
700 String aSourceFieldName
, aDestFieldName
;
701 aSourceFieldName
= jxdSource
.pListBox
->GetEntryText(jxdSource
.pEntry
);
702 aDestFieldName
= jxdDest
.pListBox
->GetEntryText(jxdDest
.pEntry
);
704 OTableConnection
* pConn
= GetTabConn(pSourceWin
,pDestWin
,true);
707 // neues Daten-Objekt
708 OQueryTableConnectionData
* pNewConnectionData
= new OQueryTableConnectionData(pSourceWin
->GetData(), pDestWin
->GetData());
709 TTableConnectionData::value_type
aNewConnectionData(pNewConnectionData
);
711 sal_uInt32 nSourceFieldIndex
, nDestFieldIndex
;
712 ETableFieldType eSourceFieldType
, eDestFieldType
;
714 // Namen/Position/Typ der beiden betroffenen Felder besorgen ...
717 nSourceFieldIndex
= jxdSource
.pListBox
->GetModel()->GetAbsPos(jxdSource
.pEntry
);
718 eSourceFieldType
= static_cast< OTableFieldInfo
*>(jxdSource
.pEntry
->GetUserData())->GetKeyType();
722 nDestFieldIndex
= jxdDest
.pListBox
->GetModel()->GetAbsPos(jxdDest
.pEntry
);
723 eDestFieldType
= static_cast< OTableFieldInfo
*>(jxdDest
.pEntry
->GetUserData())->GetKeyType();
727 pNewConnectionData
->SetFieldIndex(JTCS_FROM
, nSourceFieldIndex
);
728 pNewConnectionData
->SetFieldIndex(JTCS_TO
, nDestFieldIndex
);
730 pNewConnectionData
->SetFieldType(JTCS_FROM
, eSourceFieldType
);
731 pNewConnectionData
->SetFieldType(JTCS_TO
, eDestFieldType
);
733 pNewConnectionData
->AppendConnLine( aSourceFieldName
,aDestFieldName
);
735 OQueryTableConnection
aNewConnection(this, aNewConnectionData
);
736 NotifyTabConnection(aNewConnection
);
737 // wie immer bei NotifyTabConnection ist das Verwenden lokaler Variablen unkritisch, da sowieso eine Kopie erzeugt wird
741 // the connection could point on the other side
742 if(pConn
->GetSourceWin() == pDestWin
)
744 String
aTmp(aSourceFieldName
);
745 aSourceFieldName
= aDestFieldName
;
746 aDestFieldName
= aTmp
;
749 pConn
->GetData()->AppendConnLine( aSourceFieldName
,aDestFieldName
);
751 connectionModified(this,pConn
,sal_False
);
754 // -----------------------------------------------------------------------------
755 void OQueryTableView::ConnDoubleClicked(OTableConnection
* pConnection
)
757 DBG_CHKTHIS(OQueryTableView
,NULL
);
758 if( openJoinDialog(this,pConnection
->GetData(),FALSE
) )
760 connectionModified(this,pConnection
,sal_False
);
761 SelectConn( pConnection
);
764 // -----------------------------------------------------------------------------
765 void OQueryTableView::createNewConnection()
767 TTableConnectionData::value_type
pData(new OQueryTableConnectionData());
768 if( openJoinDialog(this,pData
,TRUE
) )
770 OTableWindowMap
* pMap
= GetTabWinMap();
771 OQueryTableWindow
* pSourceWin
= static_cast< OQueryTableWindow
*>((*pMap
)[pData
->getReferencingTable()->GetWinName()]);
772 OQueryTableWindow
* pDestWin
= static_cast< OQueryTableWindow
*>((*pMap
)[pData
->getReferencedTable()->GetWinName()]);
773 // first we have to look if the this connection already exists
774 OTableConnection
* pConn
= GetTabConn(pSourceWin
,pDestWin
,true);
775 sal_Bool bNew
= sal_True
;
778 pConn
->GetData()->CopyFrom( *pData
);
783 // create a new conenction and append it
784 OQueryTableConnection
* pQConn
= new OQueryTableConnection(this, pData
);
785 GetConnection(pQConn
);
788 connectionModified(this,pConn
,bNew
);
789 if ( !bNew
&& pConn
== GetSelectedConn() ) // our connection was selected before so we have to reselect it
793 //------------------------------------------------------------------------------
794 bool OQueryTableView::RemoveConnection( OTableConnection
* _pConnection
,sal_Bool
/*_bDelete*/ )
796 DBG_CHKTHIS(OQueryTableView
,NULL
);
798 // we don't want that our connection will be deleted, we put it in the undo manager
799 bool bRet
= OJoinTableView::RemoveConnection( _pConnection
,sal_False
);
803 new OQueryDelTabConnUndoAction(this),
804 static_cast< OQueryTableConnection
*>(_pConnection
),
809 //------------------------------------------------------------------------------
810 void OQueryTableView::KeyInput( const KeyEvent
& rEvt
)
812 DBG_CHKTHIS(OQueryTableView
,NULL
);
813 OJoinTableView::KeyInput( rEvt
);
816 //------------------------------------------------------------------------------
817 OQueryTableWindow
* OQueryTableView::FindTable(const String
& rAliasName
)
819 DBG_CHKTHIS(OQueryTableView
,NULL
);
820 DBG_ASSERT(rAliasName
.Len(), "OQueryTableView::FindTable : der AliasName sollte nicht leer sein !");
821 // (nicht dass es schadet, aber es ist sinnlos und weist vielleicht auf Fehler beim Aufrufer hin)
822 OTableWindowMap::const_iterator aIter
= GetTabWinMap()->find(rAliasName
);
823 if(aIter
!= GetTabWinMap()->end())
824 return static_cast<OQueryTableWindow
*>(aIter
->second
);
828 //------------------------------------------------------------------------------
829 sal_Bool
OQueryTableView::FindTableFromField(const String
& rFieldName
, OTableFieldDescRef
& rInfo
, sal_uInt16
& rCnt
)
831 DBG_CHKTHIS(OQueryTableView
,NULL
);
833 OTableWindowMap::const_iterator aIter
= GetTabWinMap()->begin();
834 OTableWindowMap::const_iterator aEnd
= GetTabWinMap()->end();
835 for(;aIter
!= aEnd
;++aIter
)
837 if(static_cast<OQueryTableWindow
*>(aIter
->second
)->ExistsField(rFieldName
, rInfo
))
844 //------------------------------------------------------------------------------
845 void OQueryTableView::RemoveTabWin(OTableWindow
* pTabWin
)
847 DBG_CHKTHIS(OQueryTableView
,NULL
);
848 DBG_ASSERT(pTabWin
!= NULL
, "OQueryTableView::RemoveTabWin : Fenster sollte ungleich NULL sein !");
850 // mein Parent brauche ich, da es vom Loeschen erfahren soll
851 OQueryDesignView
* pParent
= static_cast<OQueryDesignView
*>(getDesignView());
853 SfxUndoManager
* pUndoMgr
= m_pView
->getController().getUndoMgr();
854 pUndoMgr
->EnterListAction( String( ModuleRes(STR_QUERY_UNDO_TABWINDELETE
) ), String() );
856 // Undo-Action anlegen
857 OQueryTabWinDelUndoAct
* pUndoAction
= new OQueryTabWinDelUndoAct(this);
858 pUndoAction
->SetTabWin(static_cast< OQueryTableWindow
*>(pTabWin
));
860 // und Fenster verstecken
861 HideTabWin(static_cast< OQueryTableWindow
*>(pTabWin
), pUndoAction
);
863 // Undo Actions und Loeschen der Felder in SelectionBrowseBox
864 pParent
->TableDeleted( static_cast< OQueryTableWindowData
*>(pTabWin
->GetData().get())->GetAliasName() );
866 m_pView
->getController().addUndoActionAndInvalidate( pUndoAction
);
867 pUndoMgr
->LeaveListAction();
869 if (m_lnkTabWinsChangeHandler
.IsSet())
871 TabWinsChangeNotification
aHint(TabWinsChangeNotification::AT_REMOVED_WIN
, static_cast< OQueryTableWindow
*>(pTabWin
)->GetAliasName());
872 m_lnkTabWinsChangeHandler
.Call(&aHint
);
877 m_pAccessible
->notifyAccessibleEvent( AccessibleEventId::CHILD
,
878 makeAny(pTabWin
->GetAccessible()),
883 //------------------------------------------------------------------------
884 void OQueryTableView::EnsureVisible(const OTableWindow
* pWin
)
886 DBG_CHKTHIS(OQueryTableView
,NULL
);
888 Invalidate(INVALIDATE_NOCHILDREN
);
889 OJoinTableView::EnsureVisible(pWin
);
892 //------------------------------------------------------------------------
893 void OQueryTableView::GetConnection(OQueryTableConnection
* pConn
)
895 DBG_CHKTHIS(OQueryTableView
,NULL
);
896 // bei mir und dem Dokument einfuegen
898 addConnection( pConn
);
899 // invalidieren (damit es neu gezeichnet wird)
900 // pConn->Invalidate();
903 //------------------------------------------------------------------------
904 void OQueryTableView::DropConnection(OQueryTableConnection
* pConn
)
906 DBG_CHKTHIS(OQueryTableView
,NULL
);
907 // Selektion beachten
908 // bei mir und dem Dokument rausnehmen
909 RemoveConnection( pConn
,sal_False
);
912 //------------------------------------------------------------------------
913 void OQueryTableView::HideTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
)
915 DBG_CHKTHIS(OQueryTableView
,NULL
);
916 OTableWindowMap
* pTabWins
= GetTabWinMap();
917 DBG_ASSERT(pTabWins
!= NULL
, "OQueryTableView::HideTabWin : habe keine TabWins !");
922 // die Position in seinen Daten speichern
923 getDesignView()->SaveTabWinUIConfig(pTabWin
);
924 // (ich muss ueber das Parent gehen, da nur das die Position der Scrollbars kennt)
925 // dann aus der Liste der TabWins raus und verstecken
926 OTableWindowMap::iterator aIter
= pTabWins
->begin();
927 OTableWindowMap::iterator aEnd
= pTabWins
->end();
928 for ( ;aIter
!= aEnd
; ++aIter
)
929 if ( aIter
->second
== pTabWin
)
931 pTabWins
->erase( aIter
);
935 pTabWin
->Hide(); // nicht zerstoeren, steht im Undo!!
937 // die Daten zum TabWin muessen auch aus meiner Verantwortung entlassen werden
938 TTableWindowData
* pTabWinDataList
= m_pView
->getController().getTableWindowData();
939 pTabWinDataList
->erase( ::std::remove(pTabWinDataList
->begin(),pTabWinDataList
->end(),pTabWin
->GetData()),pTabWinDataList
->end());
940 // NICHT loeschen, da ja das TabWin selber - das noch lebt - sie auch noch braucht
941 // Entweder geht es irgendwann wieder in meine Verantwortung ueber, (ueber ShowTabWin), dann fuege ich
942 // auch die Daten wieder ein, oder die Undo-Action, die im Augenblick die alleinige Verantwortung fuer das Fenster
943 // und dessen Daten hat, wird zestoert, dann loescht es beides
945 if (m_pLastFocusTabWin
== pTabWin
)
946 m_pLastFocusTabWin
= NULL
;
948 // Verbindungen, die zum Fenster gehoeren, einsammeln und der UndoAction uebergeben
950 const ::std::vector
<OTableConnection
*>* pTabConList
= getTableConnections();
951 ::std::vector
<OTableConnection
*>::const_iterator aIter2
= pTabConList
->begin();
952 for(;aIter2
!= pTabConList
->end();)// the end may change
954 OQueryTableConnection
* pTmpEntry
= static_cast<OQueryTableConnection
*>(*aIter2
);
955 OSL_ENSURE(pTmpEntry
,"OQueryTableConnection is null!");
956 if( pTmpEntry
->GetAliasName(JTCS_FROM
) == pTabWin
->GetAliasName() ||
957 pTmpEntry
->GetAliasName(JTCS_TO
) == pTabWin
->GetAliasName() )
960 pUndoAction
->InsertConnection(pTmpEntry
);
962 // call base class because we append an undo action
963 // but this time we are in a undo action list
964 OJoinTableView::RemoveConnection(pTmpEntry
,sal_False
);
965 aIter2
= pTabConList
->begin();
973 InvalidateConnections();
975 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
977 // der UndoAction sagen, dass das Fenster (inklusive der Connections) jetzt in seinem Besitzt ist
978 pUndoAction
->SetOwnership(sal_True
);
980 // damit habe ich das Doc natuerlich modifiziert
981 m_pView
->getController().setModified( sal_True
);
982 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
986 //------------------------------------------------------------------------
987 sal_Bool
OQueryTableView::ShowTabWin( OQueryTableWindow
* pTabWin
, OQueryTabWinUndoAct
* pUndoAction
,sal_Bool _bAppend
)
989 DBG_CHKTHIS(OQueryTableView
,NULL
);
991 sal_Bool bSuccess
= sal_False
;
997 TTableWindowData::value_type pData
= pTabWin
->GetData();
998 DBG_ASSERT(pData
!= NULL
, "OQueryTableView::ShowTabWin : TabWin hat keine Daten !");
999 // Wenn die Daten schon PosSize haben, diese benutzen
1000 if (pData
->HasPosition() && pData
->HasSize())
1002 Size
aSize(CalcZoom(pData
->GetSize().Width()),CalcZoom(pData
->GetSize().Height()));
1003 pTabWin
->SetPosSizePixel(pData
->GetPosition(), aSize
);
1006 // ansonsten selber eine Default-Position ermitteln
1007 SetDefaultTabWinPosSize(pTabWin
);
1009 // Fenster zeigen und in Liste eintragen
1010 ::rtl::OUString sName
= static_cast< OQueryTableWindowData
*>(pData
.get())->GetAliasName();
1011 OSL_ENSURE(GetTabWinMap()->find(sName
) == GetTabWinMap()->end(),"Alias name already in list!");
1012 GetTabWinMap()->insert(OTableWindowMap::value_type(sName
,pTabWin
));
1017 // Das Update ist notwendig, damit die Connections an dem Fenster richtig gezeichnet werden. Klingt absurd,
1018 // ich weiss. Aber die Listbox haelt sich intern ein Member, was bei ersten Zeichnen (nachdem die Listbox im Init
1019 // gerade neu gefuellt wurde) initialisiert wird, und genau dieses Member wird irgendwann benoetigt fuer
1020 // GetEntryPos, und dieses wiederum von der Connection, wenn sie ihren Ansatzpunkt am Fenster feststellen will.
1023 ::std::vector
<OTableConnection
*>* pTableCon
= pUndoAction
->GetTabConnList();
1024 ::std::vector
<OTableConnection
*>::iterator aIter
= pTableCon
->begin();
1025 ::std::vector
<OTableConnection
*>::iterator aEnd
= pTableCon
->end();
1027 for(;aIter
!= aEnd
;++aIter
)
1028 addConnection(*aIter
); // add all connections from the undo action
1030 // each connection should invalidated inside addConnection so we don't need this here any longer
1031 // if ( !pOwnList->empty() )
1032 // InvalidateConnections();
1035 // und die Daten des Fensters ebenfalls in Liste (des Docs)
1037 m_pView
->getController().getTableWindowData()->push_back(pTabWin
->GetData());
1039 m_pView
->getController().InvalidateFeature(ID_BROWSER_ADDTABLE
);
1041 // und der UndoAction sagen, dass das Fenster jetzt meine ist ...
1042 pUndoAction
->SetOwnership(sal_False
);
1044 bSuccess
= sal_True
;
1048 //////////////////////////////////////////////////////////////////
1049 // Initialisierung fehlgeschlagen
1050 // (z.B. wenn Verbindung zur Datenbank in diesem Augenblick unterbrochen worden ist)
1051 pTabWin
->clearListBox();
1056 // damit habe ich das Doc natuerlich modifiziert
1057 if(!m_pView
->getController().isReadOnly())
1058 m_pView
->getController().setModified( sal_True
);
1060 m_pView
->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY
);
1064 //------------------------------------------------------------------------
1065 void OQueryTableView::InsertField(const OTableFieldDescRef
& rInfo
)
1067 DBG_CHKTHIS(OQueryTableView
,NULL
);
1068 DBG_ASSERT(getDesignView() != NULL
, "OQueryTableView::InsertField : habe kein Parent !");
1069 static_cast<OQueryDesignView
*>(getDesignView())->InsertField(rInfo
);
1071 //------------------------------------------------------------------------------
1072 sal_Bool
OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow
* pFrom
) const
1074 DBG_CHKTHIS(OQueryTableView
,NULL
);
1075 const ::std::vector
<OTableConnection
*>* pList
= getTableConnections();
1078 ::std::vector
<OTableConnection
*>::const_iterator aIter
= pList
->begin();
1079 ::std::vector
<OTableConnection
*>::const_iterator aEnd
= pList
->end();
1080 for(;aIter
!= aEnd
;++aIter
)
1082 OQueryTableConnection
* pTemp
= static_cast<OQueryTableConnection
*>(*aIter
);
1083 if (pTemp
->IsVisited() &&
1084 (pFrom
== static_cast< OQueryTableWindow
*>(pTemp
->GetSourceWin()) || pFrom
== static_cast< OQueryTableWindow
*>(pTemp
->GetDestWin())))
1085 return pTemp
!= NULL
;
1091 // -----------------------------------------------------------------------------
1092 void OQueryTableView::onNoColumns_throw()
1094 String
sError( ModuleRes( STR_STATEMENT_WITHOUT_RESULT_SET
) );
1095 ::dbtools::throwSQLException( sError
, ::dbtools::SQL_GENERAL_ERROR
, NULL
);
1097 //------------------------------------------------------------------------------
1098 bool OQueryTableView::supressCrossNaturalJoin(const TTableConnectionData::value_type
& _pData
) const
1100 OQueryTableConnectionData
* pQueryData
= static_cast<OQueryTableConnectionData
*>(_pData
.get());
1101 return pQueryData
&& (pQueryData
->GetJoinType() == CROSS_JOIN
);
1103 // -----------------------------------------------------------------------------