1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_dbaccess.hxx"
30 
31 #ifndef DBAUI_QUERYTABLEVIEW_HXX
32 #include "QueryTableView.hxx"
33 #endif
34 #ifndef DBAUI_TABLEFIELDINFO_HXX
35 #include "TableFieldInfo.hxx"
36 #endif
37 #ifndef DBAUI_TABLEFIELDDESC_HXX
38 #include "TableFieldDescription.hxx"
39 #endif
40 #ifndef _TOOLS_DEBUG_HXX
41 #include <tools/debug.hxx>
42 #endif
43 #ifndef TOOLS_DIAGNOSE_EX_H
44 #include <tools/diagnose_ex.h>
45 #endif
46 #ifndef _DBA_DBACCESS_HELPID_HRC_
47 #include "dbaccess_helpid.hrc"
48 #endif
49 #ifndef DBAUI_QUERY_TABLEWINDOW_HXX
50 #include "QTableWindow.hxx"
51 #endif
52 #ifndef DBAUI_QUERYTABLECONNECTION_HXX
53 #include "QTableConnection.hxx"
54 #endif
55 #ifndef DBAUI_QTABLECONNECTIONDATA_HXX
56 #include "QTableConnectionData.hxx"
57 #endif
58 #ifndef DBAUI_QUERYDESIGNVIEW_HXX
59 #include "QueryDesignView.hxx"
60 #endif
61 #ifndef DBAUI_QUERYCONTROLLER_HXX
62 #include "querycontroller.hxx"
63 #endif
64 #ifndef DBAUI_QUERYADDTABCONNUNDOACTION_HXX
65 #include "QueryAddTabConnUndoAction.hxx"
66 #endif
67 #ifndef DBAUI_QUERYTABWINSHOWUNDOACT_HXX
68 #include "QueryTabWinShowUndoAct.hxx"
69 #endif
70 #ifndef DBACCESS_UI_BROWSER_ID_HXX
71 #include "browserids.hxx"
72 #endif
73 #ifndef _COM_SUN_STAR_SDBCX_XTABLESSUPPLIER_HPP_
74 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
75 #endif
76 #ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_
77 #include <com/sun/star/sdbc/XConnection.hpp>
78 #endif
79 #ifndef _COM_SUN_STAR_SDBCX_XKEYSSUPPLIER_HPP_
80 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
81 #endif
82 #ifndef _COM_SUN_STAR_SDBCX_XCOLUMNSSUPPLIER_HPP_
83 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
84 #endif
85 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
86 #ifndef DBACCESS_JACCESS_HXX
87 #include "JAccess.hxx"
88 #endif
89 #ifndef _COM_SUN_STAR_SDBCX_KEYTYPE_HPP_
90 #include <com/sun/star/sdbcx/KeyType.hpp>
91 #endif
92 #ifndef _COM_SUN_STAR_CONTAINER_XINDEXACCESS_HPP_
93 #include <com/sun/star/container/XIndexAccess.hpp>
94 #endif
95 #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
96 #include <com/sun/star/beans/XPropertySet.hpp>
97 #endif
98 #ifndef DBACCESS_SHARED_DBUSTRINGS_HRC
99 #include "dbustrings.hrc"
100 #endif
101 #ifndef _CONNECTIVITY_DBTOOLS_HXX_
102 #include <connectivity/dbtools.hxx>
103 #endif
104 #ifndef _COMPHELPER_SEQUENCE_HXX_
105 #include <comphelper/sequence.hxx>
106 #endif
107 #ifndef DBAUI_QUERYDLG_HXX
108 #include "querydlg.hxx"
109 #endif
110 #ifndef DBAUI_JOINEXCHANGE_HXX
111 #include "JoinExchange.hxx"
112 #endif
113 #ifndef _COMPHELPER_EXTRACT_HXX_
114 #include <comphelper/extract.hxx>
115 #endif
116 #ifndef DBAUI_QUERYDESIGNVIEW_HXX
117 #include "QueryDesignView.hxx"
118 #endif
119 #ifndef _DBU_QRY_HRC_
120 #include "dbu_qry.hrc"
121 #endif
122 #ifndef _SV_MSGBOX_HXX
123 #include <vcl/msgbox.hxx>
124 #endif
125 
126 using namespace dbaui;
127 using namespace ::com::sun::star::uno;
128 using namespace ::com::sun::star::sdbc;
129 using namespace ::com::sun::star::sdbcx;
130 using namespace ::com::sun::star::beans;
131 using namespace ::com::sun::star::container;
132 using namespace ::com::sun::star::accessibility;
133 
134 //------------------------------------------------------------------------------
135 namespace
136 {
137 	// -----------------------------------------------------------------------------
138 	sal_Bool isColumnInKeyType(const Reference<XIndexAccess>& _rxKeys,const ::rtl::OUString& _rColumnName,sal_Int32 _nKeyType)
139 	{
140 		sal_Bool bReturn = sal_False;
141 		if(_rxKeys.is())
142 		{
143 			Reference<XColumnsSupplier> xColumnsSupplier;
144 			// search the one and only primary key
145             const sal_Int32 nCount = _rxKeys->getCount();
146 			for(sal_Int32 i=0;i< nCount;++i)
147 			{
148 				Reference<XPropertySet> xProp(_rxKeys->getByIndex(i),UNO_QUERY);
149 				if(xProp.is())
150 				{
151 					sal_Int32 nKeyType = 0;
152 					xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
153 					if(_nKeyType == nKeyType)
154 					{
155 						xColumnsSupplier.set(xProp,UNO_QUERY);
156 						if(xColumnsSupplier.is())
157 						{
158 							Reference<XNameAccess> xColumns = xColumnsSupplier->getColumns();
159 							if(xColumns.is() && xColumns->hasByName(_rColumnName))
160 							{
161 								bReturn = sal_True;
162 								break;
163 							}
164 						}
165 					}
166 				}
167 			}
168 		}
169 		return bReturn;
170 	}
171 	// -----------------------------------------------------------------------------
172 	/** appends a new TabAdd Undo action at controller
173 		@param	_pView			the view which we use
174 		@param	_pUndoAction	the undo action which should be added
175 		@param	_pConnection	the connection for which the undo action should be appended
176 		@param	_bOwner			is the undo action the owner
177 	*/
178 	// -----------------------------------------------------------------------------
179 	void addUndoAction(	OQueryTableView* _pView,
180 						OQueryTabConnUndoAction* _pUndoAction,
181 						OQueryTableConnection* _pConnection,
182 						sal_Bool _bOwner = sal_False)
183 	{
184 		_pUndoAction->SetOwnership(_bOwner);
185 		_pUndoAction->SetConnection(_pConnection);
186 		_pView->getDesignView()->getController().addUndoActionAndInvalidate(_pUndoAction);
187 	}
188 	// -----------------------------------------------------------------------------
189 	/** openJoinDialog opens the join dialog with this connection data
190 		@param	_pView				the view which we use
191 		@param	_pConnectionData	the connection data
192 
193 		@return	true when OK was pressed otherwise false
194 	*/
195     sal_Bool openJoinDialog(OQueryTableView* _pView,const TTableConnectionData::value_type& _pConnectionData,sal_Bool _bSelectableTables)
196 	{
197 		OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pConnectionData.get());
198 
199 		DlgQryJoin aDlg(_pView,_pConnectionData,_pView->GetTabWinMap(),_pView->getDesignView()->getController().getConnection(),_bSelectableTables);
200 		sal_Bool bOk = aDlg.Execute() == RET_OK;
201 		if( bOk )
202 		{
203 			pData->SetJoinType(aDlg.GetJoinType());
204 			_pView->getDesignView()->getController().setModified(sal_True);
205 		}
206 
207 		return bOk;
208 	}
209 	// -----------------------------------------------------------------------------
210 	/** connectionModified adds an undo action for the modified connection and forces an redraw
211 		@param	_pView				the view which we use
212 		@param	_pConnection	the connection which was modified
213 		@param	_bAddUndo		true when an undo action should be appended
214 	*/
215 	void connectionModified(OQueryTableView* _pView,
216 							OTableConnection* _pConnection,
217 							sal_Bool _bAddUndo)
218 	{
219 		OSL_ENSURE(_pConnection,"Invalid connection!");
220 		_pConnection->UpdateLineList();
221 
222 		// add an undo action
223 		if ( _bAddUndo )
224 			addUndoAction(	_pView,
225 							new OQueryAddTabConnUndoAction(_pView),
226 							static_cast< OQueryTableConnection*>(_pConnection));
227 		// redraw
228 		_pConnection->RecalcLines();
229 		// force an invalidation of the bounding rectangle
230 		_pConnection->InvalidateConnection();
231 
232 		_pView->Invalidate(INVALIDATE_NOCHILDREN);
233 	}
234 	// -----------------------------------------------------------------------------
235 	void addConnections(OQueryTableView* _pView,
236 						const OQueryTableWindow& _rSource,
237 						const OQueryTableWindow& _rDest,
238 						const Reference<XNameAccess>& _rxSourceForeignKeyColumns)
239 	{
240         if ( _rSource.GetData()->isQuery() || _rDest.GetData()->isQuery() )
241             // nothing to do if one of both denotes a query
242             return;
243 
244 		// we found a table in our view where we can insert some connections
245 		// the key columns have a property called RelatedColumn
246 		// OQueryTableConnectionData aufbauen
247         OQueryTableConnectionData* pNewConnData = new OQueryTableConnectionData( _rSource.GetData(), _rDest.GetData() );
248         TTableConnectionData::value_type aNewConnData(pNewConnData);
249 
250 		Reference<XIndexAccess> xReferencedKeys( _rDest.GetData()->getKeys());
251 		::rtl::OUString sRelatedColumn;
252 
253 		// iterate through all foreignkey columns to create the connections
254 		Sequence< ::rtl::OUString> aElements(_rxSourceForeignKeyColumns->getElementNames());
255 		const ::rtl::OUString* pIter = aElements.getConstArray();
256 		const ::rtl::OUString* pEnd   = pIter + aElements.getLength();
257 		for(sal_Int32 i=0;pIter != pEnd;++pIter,++i)
258 		{
259 			Reference<XPropertySet> xColumn;
260             if ( !( _rxSourceForeignKeyColumns->getByName(*pIter) >>= xColumn ) )
261             {
262                 OSL_ENSURE( false, "addConnections: invalid foreign key column!" );
263                 continue;
264             }
265 
266 			pNewConnData->SetFieldType(JTCS_FROM,TAB_NORMAL_FIELD);
267 
268 			xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn;
269 			pNewConnData->SetFieldType(JTCS_TO,isColumnInKeyType(xReferencedKeys,sRelatedColumn,KeyType::PRIMARY) ? TAB_PRIMARY_FIELD : TAB_NORMAL_FIELD);
270 
271 			{
272 				Sequence< sal_Int16> aFind(::comphelper::findValue(_rSource.GetOriginalColumns()->getElementNames(),*pIter,sal_True));
273 				if(aFind.getLength())
274 					pNewConnData->SetFieldIndex(JTCS_FROM,aFind[0]+1);
275 				else
276 					OSL_ENSURE(0,"Column not found!");
277 			}
278 			// get the position inside the tabe
279 			Reference<XNameAccess> xRefColumns = _rDest.GetOriginalColumns();
280 			if(xRefColumns.is())
281 			{
282 				Sequence< sal_Int16> aFind(::comphelper::findValue(xRefColumns->getElementNames(),sRelatedColumn,sal_True));
283 				if(aFind.getLength())
284 					pNewConnData->SetFieldIndex(JTCS_TO,aFind[0]+1);
285 				else
286 					OSL_ENSURE(0,"Column not found!");
287 			}
288 			pNewConnData->AppendConnLine(*pIter,sRelatedColumn);
289 
290 			// dann die Conn selber dazu
291 			OQueryTableConnection aNewConn(_pView, aNewConnData);
292 				// der Verweis auf die lokale Variable ist unkritisch, da NotifyQueryTabConn eine neue Kopie anlegt
293 			// und mir hinzufuegen (wenn nicht schon existent)
294 			_pView->NotifyTabConnection(aNewConn, sal_False);
295 				// don't create an Undo-Action for the new connection : the connection is
296 				// covered by the Undo-Action for the tabwin, as the "Undo the insert" will
297 				// automatically remove all connections adjacent to the win.
298 				// (Because of this automatism we would have an ownerhsip ambiguity for
299 				// the connection data if we would insert the conn-Undo-Action)
300 				// FS - 21.10.99 - 69183
301 		}
302 	}
303 }
304 //==================================================================
305 // class OQueryTableView
306 //==================================================================
307 DBG_NAME(OQueryTableView)
308 //------------------------------------------------------------------------
309 OQueryTableView::OQueryTableView( Window* pParent,OQueryDesignView* pView)
310 	: OJoinTableView( pParent,pView)
311 {
312 	DBG_CTOR(OQueryTableView,NULL);
313 	SetHelpId(HID_CTL_QRYDGNTAB);
314 }
315 
316 //------------------------------------------------------------------------
317 OQueryTableView::~OQueryTableView()
318 {
319 	DBG_DTOR(OQueryTableView,NULL);
320 }
321 
322 //------------------------------------------------------------------------
323 sal_Int32 OQueryTableView::CountTableAlias(const String& rName, sal_Int32& rMax)
324 {
325 	DBG_CHKTHIS(OQueryTableView,NULL);
326 	sal_Int32 nRet = 0;
327 
328 	OTableWindowMapIterator aIter = GetTabWinMap()->find(rName);
329 	while(aIter != GetTabWinMap()->end())
330 	{
331 		String aNewName;
332 		aNewName = rName;
333 		aNewName += '_';
334 		aNewName += String::CreateFromInt32(++nRet);
335 
336 		aIter = GetTabWinMap()->find(aNewName);
337 	}
338 
339 	rMax = nRet;
340 
341 	return nRet;
342 }
343 //------------------------------------------------------------------------
344 void OQueryTableView::ReSync()
345 {
346 	DBG_CHKTHIS(OQueryTableView,NULL);
347 	TTableWindowData* pTabWinDataList = m_pView->getController().getTableWindowData();
348 	DBG_ASSERT((getTableConnections()->size()==0) && (GetTabWinMap()->size()==0),
349 		"vor OQueryTableView::ReSync() bitte ClearAll aufrufen !");
350 
351 	// ich brauche eine Sammlung aller Fensternamen, deren Anlegen schief geht, damit ich die entsprechenden Connections
352 	// gar nicht erst anlege
353 	::std::vector<String> arrInvalidTables;
354 
355 	TTableWindowData::reverse_iterator aIter = pTabWinDataList->rbegin();
356 	// Fenster kreieren und einfuegen
357 
358 	for(;aIter != pTabWinDataList->rend();++aIter)
359 	{
360 		OQueryTableWindowData* pData = static_cast<OQueryTableWindowData*>(aIter->get());
361 		OTableWindow* pTabWin = createWindow(*aIter);
362 
363 		// ich gehe jetzt NICHT ueber ShowTabWin, da dieses die Daten des Fensters in die Liste des Docs einfuegt, was
364 		// schlecht waere, denn genau von dort hole ich sie ja gerade
365 		// also Schritt fuer Schritt
366 		if (!pTabWin->Init())
367 		{
368 			// das Initialisieren ging schief, dass heisst, dieses TabWin steht nicht zur Verfuegung, also muss ich es inklusive
369 			// seiner Daten am Dokument aufraeumen
370 			pTabWin->clearListBox();
371 			delete pTabWin;
372 			arrInvalidTables.push_back(pData->GetAliasName());
373 
374 			pTabWinDataList->erase( ::std::remove(pTabWinDataList->begin(),pTabWinDataList->end(),*aIter) ,pTabWinDataList->end());
375 			continue;
376 		}
377 
378 		(*GetTabWinMap())[pData->GetAliasName()] = pTabWin;	// am Anfang einfuegen, da ich die DataList ja rueckwaerts durchlaufe
379 		// wenn in den Daten keine Position oder Groesse steht -> Default
380 		if (!pData->HasPosition() && !pData->HasSize())
381 			SetDefaultTabWinPosSize(pTabWin);
382 
383 		pTabWin->Show();
384 	}
385 
386 	// Verbindungen einfuegen
387 	TTableConnectionData* pTabConnDataList = m_pView->getController().getTableConnectionData();
388 	TTableConnectionData::reverse_iterator aConIter = pTabConnDataList->rbegin();
389 
390 	for(;aConIter != pTabConnDataList->rend();++aConIter)
391 	{
392 		OQueryTableConnectionData* pTabConnData =  static_cast<OQueryTableConnectionData*>(aConIter->get());
393 
394 		// gibt es die beiden Tabellen zur Connection ?
395 		String strTabExistenceTest = pTabConnData->getReferencingTable()->GetWinName();
396 		sal_Bool bInvalid = ::std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
397 		strTabExistenceTest = pTabConnData->getReferencedTable()->GetWinName();
398 		bInvalid = bInvalid && ::std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end();
399 
400 		if (bInvalid)
401 		{	// nein -> Pech gehabt, die Connection faellt weg
402 			pTabConnDataList->erase( ::std::remove(pTabConnDataList->begin(),pTabConnDataList->end(),*aConIter) ,pTabConnDataList->end());
403 			continue;
404 		}
405 
406 		// adds a new connection to join view and notifies our accessible and invaldates the controller
407 		addConnection(new OQueryTableConnection(this, *aConIter));
408 	}
409 }
410 
411 //------------------------------------------------------------------------
412 void OQueryTableView::ClearAll()
413 {
414 	DBG_CHKTHIS(OQueryTableView,NULL);
415 	OJoinTableView::ClearAll();
416 
417 	SetUpdateMode(sal_True);
418 	m_pView->getController().setModified(sal_True);
419 }
420 
421 // -----------------------------------------------------------------------------
422 OTableWindow* OQueryTableView::createWindow(const TTableWindowData::value_type& _pData)
423 {
424 	return new OQueryTableWindow(this,_pData);
425 }
426 
427 //------------------------------------------------------------------------------
428 void OQueryTableView::NotifyTabConnection(const OQueryTableConnection& rNewConn, sal_Bool _bCreateUndoAction)
429 {
430 	DBG_CHKTHIS(OQueryTableView,NULL);
431 	// erst mal schauen, ob ich diese Connection schon habe
432 	OQueryTableConnection* pTabConn = NULL;
433 	const ::std::vector<OTableConnection*>*	pConnections = getTableConnections();
434     ::std::vector<OTableConnection*>::const_iterator aEnd = pConnections->end();
435 	::std::vector<OTableConnection*>::const_iterator aIter = ::std::find(	pConnections->begin(),
436 													aEnd,
437 													static_cast<const OTableConnection*>(&rNewConn)
438 													);
439 	if(aIter == aEnd )
440 	{
441 		aIter = pConnections->begin();
442 		for(;aIter != aEnd;++aIter)
443 		{
444 			if(*static_cast<OQueryTableConnection*>(*aIter) == rNewConn)
445 			{
446 				pTabConn = static_cast<OQueryTableConnection*>(*aIter);
447 				break;
448 			}
449 		}
450 	}
451 	else
452 		pTabConn = static_cast<OQueryTableConnection*>(*aIter);
453 	// nein -> einfuegen
454 	if (pTabConn == NULL)
455 	{
456 		// die neuen Daten ...
457 		OQueryTableConnectionData* pNewData = static_cast< OQueryTableConnectionData*>(rNewConn.GetData()->NewInstance());
458 		pNewData->CopyFrom(*rNewConn.GetData());
459         TTableConnectionData::value_type aData(pNewData);
460 		OQueryTableConnection* pNewConn = new OQueryTableConnection(this, aData);
461 		GetConnection(pNewConn);
462 
463 		connectionModified(this,pNewConn,_bCreateUndoAction);
464 	}
465 }
466 // -----------------------------------------------------------------------------
467 OTableWindowData* OQueryTableView::CreateImpl(const ::rtl::OUString& _rComposedName
468                                              ,const ::rtl::OUString& _sTableName
469 											 ,const ::rtl::OUString& _rWinName)
470 {
471 	return new OQueryTableWindowData( _rComposedName, _sTableName,_rWinName );
472 }
473 //------------------------------------------------------------------------------
474 void OQueryTableView::AddTabWin(const ::rtl::OUString& _rTableName, const ::rtl::OUString& _rAliasName, sal_Bool bNewTable)
475 {
476 	DBG_CHKTHIS(OQueryTableView,NULL);
477 	// das ist die aus der Basisklasse geerbte Methode, die fuehre ich auf die an meinem Parent zurueck, die mir eventuell einen
478 	// Alias dazu bastelt und das an mein anderes AddTabWin weiterreicht
479 
480 	// leider ist _rTableName voll qualifiziert, das OQueryDesignView erwartet aber einen String, der
481 	// nur aus Schema und Tabelle besteht und keinen Katalog enthaelt.
482 	Reference< XConnection> xConnection = m_pView->getController().getConnection();
483 	if(!xConnection.is())
484 		return;
485 	try
486 	{
487 		Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData();
488 		::rtl::OUString sCatalog, sSchema, sTable;
489 		::dbtools::qualifiedNameComponents(xMetaData,
490 									_rTableName,
491 									sCatalog,
492 									sSchema,
493 									sTable,
494 									::dbtools::eInDataManipulation);
495 		::rtl::OUString sRealName(sSchema);
496 		if (sRealName.getLength())
497 			sRealName+= ::rtl::OUString('.');
498 		sRealName += sTable;
499 
500 		AddTabWin(_rTableName, sRealName, _rAliasName, bNewTable);
501 	}
502 	catch(SQLException&)
503 	{
504 		OSL_ASSERT(!"qualifiedNameComponents");
505 	}
506 }
507 // -----------------------------------------------------------------------------
508 // find the table which has a foreign key with this referencedTable name
509 Reference<XPropertySet> getKeyReferencedTo(const Reference<XIndexAccess>& _rxKeys,const ::rtl::OUString& _rReferencedTable)
510 {
511 	if(!_rxKeys.is())
512 		return Reference<XPropertySet>();
513 
514 	if ( !_rxKeys.is() )
515 		return Reference<XPropertySet>();
516 	// search the one and only primary key
517     const sal_Int32 nCount = _rxKeys->getCount();
518 	for(sal_Int32 i=0;i<nCount ;++i)
519 	{
520 		Reference<XPropertySet> xKey(_rxKeys->getByIndex(i),UNO_QUERY);
521 		if(xKey.is())
522 		{
523 			sal_Int32 nKeyType = 0;
524 			xKey->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
525 			if(KeyType::FOREIGN == nKeyType)
526 			{
527 				::rtl::OUString sReferencedTable;
528 				xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
529 				// TODO check case
530 				if(sReferencedTable == _rReferencedTable)
531 					return xKey;
532 			}
533 		}
534 	}
535 	return Reference<XPropertySet>();
536 }
537 //------------------------------------------------------------------------------
538 void OQueryTableView::AddTabWin(const ::rtl::OUString& _rComposedName, const ::rtl::OUString& _rTableName, const ::rtl::OUString& strAlias, sal_Bool bNewTable)
539 {
540 	DBG_CHKTHIS(OQueryTableView,NULL);
541 	DBG_ASSERT(_rTableName.getLength() || strAlias.getLength(), "OQueryTableView::AddTabWin : kein Tabellen- und kein Aliasname !");
542 		// wenn der Tabellenname nicht gesetzt ist, steht das fuer ein Dummy-Fenster, das braucht aber wenigstens einen Alias-Namen
543 
544 	// neue Datenstruktur erzeugen
545 	// first check if this already hav it's data
546 	sal_Bool bAppend = bNewTable;
547 	TTableWindowData::value_type pNewTabWinData;
548 	TTableWindowData* pWindowData = getDesignView()->getController().getTableWindowData();
549 	TTableWindowData::iterator aWinIter = pWindowData->begin();
550     TTableWindowData::iterator aWinEnd = pWindowData->end();
551 	for(;aWinIter != aWinEnd;++aWinIter)
552 	{
553 		pNewTabWinData = *aWinIter;
554 		if (pNewTabWinData && pNewTabWinData->GetWinName() == strAlias && pNewTabWinData->GetComposedName() == _rComposedName && pNewTabWinData->GetTableName() == _rTableName)
555 			break;
556 	}
557     if ( !bAppend )
558         bAppend = ( aWinIter == aWinEnd );
559 	if ( bAppend )
560 		pNewTabWinData = createTableWindowData(_rComposedName, _rTableName, strAlias);
561 		// die TabWinData brauche ich nicht in die entsprechende Liste der DocShell eintragen, das macht ShowTabWin
562 
563 	// neues Fenster erzeugen
564 	OQueryTableWindow* pNewTabWin = static_cast<OQueryTableWindow*>(createWindow(pNewTabWinData));
565 	// das Init kann ich hier weglassen, da das in ShowTabWin passiert
566 
567 	// Neue UndoAction
568 	OQueryTabWinShowUndoAct* pUndoAction = new OQueryTabWinShowUndoAct(this);
569 	pUndoAction->SetTabWin(pNewTabWin);	// Fenster
570 	sal_Bool bSuccess = ShowTabWin(pNewTabWin, pUndoAction,bAppend);
571 	if(!bSuccess)
572 	{
573 		// reset table window
574 		pUndoAction->SetTabWin(NULL);
575 		pUndoAction->SetOwnership(sal_False);
576 
577 		delete pUndoAction;
578 		return;
579 	}
580 
581 	// Relationen zwischen den einzelnen Tabellen anzeigen
582 	OTableWindowMap* pTabWins = GetTabWinMap();
583 	if(bNewTable && !pTabWins->empty() && _rTableName.getLength())
584 	{
585 		modified();
586 		if ( m_pAccessible )
587 			m_pAccessible->notifyAccessibleEvent(	AccessibleEventId::CHILD,
588 													Any(),
589 													makeAny(pNewTabWin->GetAccessible())
590 													);
591 
592         do {
593 
594         if ( pNewTabWin->GetData()->isQuery() )
595             break;
596 
597         try
598         {
599             //////////////////////////////////////////////////////////////////////
600 			// find relations between the table an the tables already inserted
601 			Reference< XIndexAccess> xKeyIndex = pNewTabWin->GetData()->getKeys();
602 			if ( !xKeyIndex.is() )
603                 break;
604 
605             Reference<XNameAccess> xFKeyColumns;
606 			::rtl::OUString aReferencedTable;
607 			Reference<XColumnsSupplier> xColumnsSupplier;
608 
609             const sal_Int32 nKeyCount = xKeyIndex->getCount();
610             for ( sal_Int32 i=0; i<nKeyCount ; ++i )
611 			{
612                 Reference< XPropertySet > xProp( xKeyIndex->getByIndex(i), UNO_QUERY_THROW );
613                 xColumnsSupplier.set( xProp, UNO_QUERY_THROW );
614 				xFKeyColumns.set( xColumnsSupplier->getColumns(), UNO_QUERY_THROW );
615 
616                 sal_Int32 nKeyType = 0;
617 				xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
618 
619                 switch ( nKeyType )
620                 {
621                 case KeyType::FOREIGN:
622 				{	// our new table has a foreign key
623 					// so look if the referenced table is already in our list
624 					xProp->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= aReferencedTable;
625 					OSL_ENSURE(aReferencedTable.getLength(),"Foreign key without referencedTableName");
626 
627 					OTableWindowMap::const_iterator aIter = pTabWins->find(aReferencedTable);
628                     OTableWindowMap::const_iterator aEnd  = pTabWins->end();
629 					if(aIter == aEnd)
630 					{
631 						for(aIter = pTabWins->begin();aIter != aEnd;++aIter)
632 						{
633 							OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(aIter->second);
634 							OSL_ENSURE( pTabWinTmp,"TableWindow is null!" );
635 							if ( pTabWinTmp != pNewTabWin && pTabWinTmp->GetComposedName() == aReferencedTable )
636 								break;
637 						}
638 					}
639 					if ( aIter != aEnd && pNewTabWin != aIter->second )
640 						addConnections( this, *pNewTabWin, *static_cast<OQueryTableWindow*>(aIter->second), xFKeyColumns );
641 				}
642                 break;
643 
644                 case KeyType::PRIMARY:
645 				{
646 					// we have a primary key so look in our list if there exsits a key which this is refered to
647 					OTableWindowMap::const_iterator aIter = pTabWins->begin();
648                     OTableWindowMap::const_iterator aEnd  = pTabWins->end();
649 					for(;aIter != aEnd;++aIter)
650 					{
651 						OQueryTableWindow* pTabWinTmp = static_cast<OQueryTableWindow*>(aIter->second);
652 						if ( pTabWinTmp == pNewTabWin )
653                             continue;
654 
655                         if ( pTabWinTmp->GetData()->isQuery() )
656                             continue;
657 
658                         OSL_ENSURE(pTabWinTmp,"TableWindow is null!");
659 						Reference< XPropertySet > xFKKey = getKeyReferencedTo( pTabWinTmp->GetData()->getKeys(), pNewTabWin->GetComposedName() );
660                         if ( !xFKKey.is() )
661                             continue;
662 
663                         Reference<XColumnsSupplier> xFKColumnsSupplier( xFKKey, UNO_QUERY_THROW );
664 						Reference< XNameAccess > xTColumns( xFKColumnsSupplier->getColumns(), UNO_QUERY_THROW );
665 						addConnections( this, *pTabWinTmp, *pNewTabWin, xTColumns );
666 					}
667 				}
668                 break;
669                 }
670             }
671 		}
672         catch( const Exception& )
673         {
674             DBG_UNHANDLED_EXCEPTION();
675         }
676 
677         } while ( false );
678 	}
679 
680 	// mein Parent brauche ich, da es vom Loeschen erfahren soll
681 	m_pView->getController().addUndoActionAndInvalidate( pUndoAction );
682 
683 	if (bSuccess && m_lnkTabWinsChangeHandler.IsSet())
684 	{
685 		TabWinsChangeNotification aHint(TabWinsChangeNotification::AT_ADDED_WIN, pNewTabWin->GetAliasName());
686 		m_lnkTabWinsChangeHandler.Call(&aHint);
687 	}
688 }
689 // -----------------------------------------------------------------------------
690 // -----------------------------------------------------------------------------
691 void OQueryTableView::AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest)
692 {
693 	DBG_CHKTHIS(OQueryTableView,NULL);
694 	OQueryTableWindow* pSourceWin = static_cast< OQueryTableWindow*>(jxdSource.pListBox->GetTabWin());
695 	OQueryTableWindow* pDestWin = static_cast< OQueryTableWindow*>(jxdDest.pListBox->GetTabWin());
696 
697 	String aSourceFieldName, aDestFieldName;
698 	aSourceFieldName	= jxdSource.pListBox->GetEntryText(jxdSource.pEntry);
699 	aDestFieldName		= jxdDest.pListBox->GetEntryText(jxdDest.pEntry);
700 
701 	OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true);
702 	if ( !pConn )
703 	{
704 		// neues Daten-Objekt
705 		OQueryTableConnectionData* pNewConnectionData = new OQueryTableConnectionData(pSourceWin->GetData(), pDestWin->GetData());
706         TTableConnectionData::value_type aNewConnectionData(pNewConnectionData);
707 
708 		sal_uInt32			nSourceFieldIndex, nDestFieldIndex;
709 		ETableFieldType	eSourceFieldType, eDestFieldType;
710 
711 		// Namen/Position/Typ der beiden betroffenen Felder besorgen ...
712 		// Source
713 
714 		nSourceFieldIndex = jxdSource.pListBox->GetModel()->GetAbsPos(jxdSource.pEntry);
715 		eSourceFieldType = static_cast< OTableFieldInfo*>(jxdSource.pEntry->GetUserData())->GetKeyType();
716 
717 		// Dest
718 
719 		nDestFieldIndex = jxdDest.pListBox->GetModel()->GetAbsPos(jxdDest.pEntry);
720 		eDestFieldType = static_cast< OTableFieldInfo*>(jxdDest.pEntry->GetUserData())->GetKeyType();
721 
722 		// ... und setzen
723 
724 		pNewConnectionData->SetFieldIndex(JTCS_FROM, nSourceFieldIndex);
725 		pNewConnectionData->SetFieldIndex(JTCS_TO, nDestFieldIndex);
726 
727 		pNewConnectionData->SetFieldType(JTCS_FROM, eSourceFieldType);
728 		pNewConnectionData->SetFieldType(JTCS_TO, eDestFieldType);
729 
730 		pNewConnectionData->AppendConnLine( aSourceFieldName,aDestFieldName );
731 
732 		OQueryTableConnection aNewConnection(this, aNewConnectionData);
733 		NotifyTabConnection(aNewConnection);
734 			// wie immer bei NotifyTabConnection ist das Verwenden lokaler Variablen unkritisch, da sowieso eine Kopie erzeugt wird
735 	}
736 	else
737 	{
738 		// the connection could point on the other side
739 		if(pConn->GetSourceWin() == pDestWin)
740 		{
741 			String aTmp(aSourceFieldName);
742 			aSourceFieldName = aDestFieldName;
743 			aDestFieldName = aTmp;
744 		}
745 
746 		pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName );
747 
748 		connectionModified(this,pConn,sal_False);
749 	}
750 }
751 // -----------------------------------------------------------------------------
752 void OQueryTableView::ConnDoubleClicked(OTableConnection* pConnection)
753 {
754 	DBG_CHKTHIS(OQueryTableView,NULL);
755 	if( openJoinDialog(this,pConnection->GetData(),sal_False) )
756 	{
757 		connectionModified(this,pConnection,sal_False);
758 		SelectConn( pConnection );
759 	}
760 }
761 // -----------------------------------------------------------------------------
762 void OQueryTableView::createNewConnection()
763 {
764     TTableConnectionData::value_type pData(new OQueryTableConnectionData());
765 	if( openJoinDialog(this,pData,sal_True) )
766 	{
767 		OTableWindowMap* pMap = GetTabWinMap();
768 		OQueryTableWindow* pSourceWin	= static_cast< OQueryTableWindow*>((*pMap)[pData->getReferencingTable()->GetWinName()]);
769 		OQueryTableWindow* pDestWin		= static_cast< OQueryTableWindow*>((*pMap)[pData->getReferencedTable()->GetWinName()]);
770 		// first we have to look if the this connection already exists
771 		OTableConnection* pConn = GetTabConn(pSourceWin,pDestWin,true);
772 		sal_Bool bNew = sal_True;
773 		if ( pConn )
774 		{
775 			pConn->GetData()->CopyFrom( *pData );
776 			bNew = sal_False;
777 		}
778 		else
779 		{
780 			// create a new conenction and append it
781 			OQueryTableConnection* pQConn = new OQueryTableConnection(this, pData);
782 			GetConnection(pQConn);
783 			pConn = pQConn;
784 		}
785 		connectionModified(this,pConn,bNew);
786 		if ( !bNew && pConn == GetSelectedConn() ) // our connection was selected before so we have to reselect it
787 			SelectConn( pConn );
788 	}
789 }
790 //------------------------------------------------------------------------------
791 bool OQueryTableView::RemoveConnection( OTableConnection* _pConnection,sal_Bool /*_bDelete*/ )
792 {
793 	DBG_CHKTHIS(OQueryTableView,NULL);
794 
795 	// we don't want that our connection will be deleted, we put it in the undo manager
796 	bool bRet = OJoinTableView::RemoveConnection( _pConnection,sal_False);
797 
798 	// add undo action
799 	addUndoAction(	this,
800 					new OQueryDelTabConnUndoAction(this),
801 					static_cast< OQueryTableConnection*>(_pConnection),
802 					sal_True);
803 	return bRet;
804 }
805 
806 //------------------------------------------------------------------------------
807 void OQueryTableView::KeyInput( const KeyEvent& rEvt )
808 {
809 	DBG_CHKTHIS(OQueryTableView,NULL);
810 	OJoinTableView::KeyInput( rEvt );
811 }
812 
813 //------------------------------------------------------------------------------
814 OQueryTableWindow* OQueryTableView::FindTable(const String& rAliasName)
815 {
816 	DBG_CHKTHIS(OQueryTableView,NULL);
817 	DBG_ASSERT(rAliasName.Len(), "OQueryTableView::FindTable : der AliasName sollte nicht leer sein !");
818 		// (nicht dass es schadet, aber es ist sinnlos und weist vielleicht auf Fehler beim Aufrufer hin)
819 	OTableWindowMap::const_iterator aIter = GetTabWinMap()->find(rAliasName);
820 	if(aIter != GetTabWinMap()->end())
821 		return static_cast<OQueryTableWindow*>(aIter->second);
822 	return NULL;
823 }
824 
825 //------------------------------------------------------------------------------
826 sal_Bool OQueryTableView::FindTableFromField(const String& rFieldName, OTableFieldDescRef& rInfo, sal_uInt16& rCnt)
827 {
828 	DBG_CHKTHIS(OQueryTableView,NULL);
829 	rCnt = 0;
830 	OTableWindowMap::const_iterator aIter = GetTabWinMap()->begin();
831     OTableWindowMap::const_iterator aEnd  = GetTabWinMap()->end();
832 	for(;aIter != aEnd;++aIter)
833 	{
834 		if(static_cast<OQueryTableWindow*>(aIter->second)->ExistsField(rFieldName, rInfo))
835 			++rCnt;
836 	}
837 
838 	return rCnt == 1;
839 }
840 
841 //------------------------------------------------------------------------------
842 void OQueryTableView::RemoveTabWin(OTableWindow* pTabWin)
843 {
844 	DBG_CHKTHIS(OQueryTableView,NULL);
845 	DBG_ASSERT(pTabWin != NULL, "OQueryTableView::RemoveTabWin : Fenster sollte ungleich NULL sein !");
846 
847 	// mein Parent brauche ich, da es vom Loeschen erfahren soll
848 	OQueryDesignView* pParent = static_cast<OQueryDesignView*>(getDesignView());
849 
850 	SfxUndoManager& rUndoMgr = m_pView->getController().GetUndoManager();
851 	rUndoMgr.EnterListAction( String( ModuleRes(STR_QUERY_UNDO_TABWINDELETE) ), String() );
852 
853 	// Undo-Action anlegen
854 	OQueryTabWinDelUndoAct* pUndoAction = new OQueryTabWinDelUndoAct(this);
855 	pUndoAction->SetTabWin(static_cast< OQueryTableWindow*>(pTabWin));
856 
857 	// und Fenster verstecken
858 	HideTabWin(static_cast< OQueryTableWindow*>(pTabWin), pUndoAction);
859 
860 	// Undo Actions und Loeschen der Felder in SelectionBrowseBox
861 	pParent->TableDeleted( static_cast< OQueryTableWindowData*>(pTabWin->GetData().get())->GetAliasName() );
862 
863 	m_pView->getController().addUndoActionAndInvalidate( pUndoAction );
864 	rUndoMgr.LeaveListAction();
865 
866 	if (m_lnkTabWinsChangeHandler.IsSet())
867 	{
868 		TabWinsChangeNotification aHint(TabWinsChangeNotification::AT_REMOVED_WIN, static_cast< OQueryTableWindow*>(pTabWin)->GetAliasName());
869 		m_lnkTabWinsChangeHandler.Call(&aHint);
870 	}
871 
872 	modified();
873 	if ( m_pAccessible )
874 		m_pAccessible->notifyAccessibleEvent(	AccessibleEventId::CHILD,
875 												makeAny(pTabWin->GetAccessible()),
876 												Any()
877 												);
878 }
879 
880 //------------------------------------------------------------------------
881 void OQueryTableView::EnsureVisible(const OTableWindow* pWin)
882 {
883 	DBG_CHKTHIS(OQueryTableView,NULL);
884 
885 	Invalidate(INVALIDATE_NOCHILDREN);
886 	OJoinTableView::EnsureVisible(pWin);
887 }
888 
889 //------------------------------------------------------------------------
890 void OQueryTableView::GetConnection(OQueryTableConnection* pConn)
891 {
892 	DBG_CHKTHIS(OQueryTableView,NULL);
893 	// bei mir und dem Dokument einfuegen
894 
895 	addConnection( pConn );
896 	// invalidieren (damit es neu gezeichnet wird)
897 	//	pConn->Invalidate();
898 }
899 
900 //------------------------------------------------------------------------
901 void OQueryTableView::DropConnection(OQueryTableConnection* pConn)
902 {
903 	DBG_CHKTHIS(OQueryTableView,NULL);
904 	// Selektion beachten
905 	// bei mir und dem Dokument rausnehmen
906 	RemoveConnection( pConn ,sal_False);
907 }
908 
909 //------------------------------------------------------------------------
910 void OQueryTableView::HideTabWin( OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction )
911 {
912 	DBG_CHKTHIS(OQueryTableView,NULL);
913 	OTableWindowMap* pTabWins = GetTabWinMap();
914 	DBG_ASSERT(pTabWins != NULL, "OQueryTableView::HideTabWin : habe keine TabWins !");
915 
916 	if (pTabWin)
917 	{
918 		// Fenster
919 		// die Position in seinen Daten speichern
920 		getDesignView()->SaveTabWinUIConfig(pTabWin);
921 			// (ich muss ueber das Parent gehen, da nur das die Position der Scrollbars kennt)
922 		// dann aus der Liste der TabWins raus und verstecken
923         OTableWindowMap::iterator aIter = pTabWins->begin();
924         OTableWindowMap::iterator aEnd  = pTabWins->end();
925         for ( ;aIter != aEnd ; ++aIter )
926             if ( aIter->second == pTabWin )
927             {
928                 pTabWins->erase( aIter );
929                 break;
930             }
931 
932 		pTabWin->Hide();	// nicht zerstoeren, steht im Undo!!
933 
934 		// die Daten zum TabWin muessen auch aus meiner Verantwortung entlassen werden
935 		TTableWindowData* pTabWinDataList = m_pView->getController().getTableWindowData();
936 		pTabWinDataList->erase( ::std::remove(pTabWinDataList->begin(),pTabWinDataList->end(),pTabWin->GetData()),pTabWinDataList->end());
937 			// NICHT loeschen, da ja das TabWin selber - das noch lebt - sie auch noch braucht
938 			// Entweder geht es irgendwann wieder in meine Verantwortung ueber, (ueber ShowTabWin), dann fuege ich
939 			// auch die Daten wieder ein, oder die Undo-Action, die im Augenblick die alleinige Verantwortung fuer das Fenster
940 			// und dessen Daten hat, wird zestoert, dann loescht es beides
941 
942 		if (m_pLastFocusTabWin == pTabWin)
943 			m_pLastFocusTabWin = NULL;
944 
945 		// Verbindungen, die zum Fenster gehoeren, einsammeln und der UndoAction uebergeben
946 		sal_Int16 nCnt = 0;
947 		const ::std::vector<OTableConnection*>* pTabConList = getTableConnections();
948 		::std::vector<OTableConnection*>::const_iterator aIter2 = pTabConList->begin();
949 		for(;aIter2 != pTabConList->end();)// the end may change
950 		{
951 			OQueryTableConnection* pTmpEntry = static_cast<OQueryTableConnection*>(*aIter2);
952 			OSL_ENSURE(pTmpEntry,"OQueryTableConnection is null!");
953 			if( pTmpEntry->GetAliasName(JTCS_FROM) == pTabWin->GetAliasName() ||
954 				pTmpEntry->GetAliasName(JTCS_TO) == pTabWin->GetAliasName() )
955 			{
956 				// add to undo list
957 				pUndoAction->InsertConnection(pTmpEntry);
958 
959 				// call base class because we append an undo action
960 				// but this time we are in a undo action list
961 				OJoinTableView::RemoveConnection(pTmpEntry,sal_False);
962                 aIter2 = pTabConList->begin();
963 				++nCnt;
964 			}
965 			else
966 				++aIter2;
967 		}
968 
969 		if (nCnt)
970 			InvalidateConnections();
971 
972 		m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE);
973 
974 		// der UndoAction sagen, dass das Fenster (inklusive der Connections) jetzt in seinem Besitzt ist
975 		pUndoAction->SetOwnership(sal_True);
976 
977 		// damit habe ich das Doc natuerlich modifiziert
978 		m_pView->getController().setModified( sal_True );
979 		m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
980 	}
981 }
982 
983 //------------------------------------------------------------------------
984 sal_Bool OQueryTableView::ShowTabWin( OQueryTableWindow* pTabWin, OQueryTabWinUndoAct* pUndoAction,sal_Bool _bAppend )
985 {
986 	DBG_CHKTHIS(OQueryTableView,NULL);
987 
988 	sal_Bool bSuccess = sal_False;
989 
990 	if (pTabWin)
991 	{
992 		if (pTabWin->Init())
993 		{
994 			TTableWindowData::value_type pData = pTabWin->GetData();
995 			DBG_ASSERT(pData != NULL, "OQueryTableView::ShowTabWin : TabWin hat keine Daten !");
996 			// Wenn die Daten schon PosSize haben, diese benutzen
997 			if (pData->HasPosition() && pData->HasSize())
998 			{
999 				Size aSize(CalcZoom(pData->GetSize().Width()),CalcZoom(pData->GetSize().Height()));
1000 				pTabWin->SetPosSizePixel(pData->GetPosition(), aSize);
1001 			}
1002 			else
1003 				// ansonsten selber eine Default-Position ermitteln
1004 				SetDefaultTabWinPosSize(pTabWin);
1005 
1006 			// Fenster zeigen und in Liste eintragen
1007 			::rtl::OUString sName = static_cast< OQueryTableWindowData*>(pData.get())->GetAliasName();
1008 			OSL_ENSURE(GetTabWinMap()->find(sName) == GetTabWinMap()->end(),"Alias name already in list!");
1009 			GetTabWinMap()->insert(OTableWindowMap::value_type(sName,pTabWin));
1010 
1011 			pTabWin->Show();
1012 
1013 			pTabWin->Update();
1014 				// Das Update ist notwendig, damit die Connections an dem Fenster richtig gezeichnet werden. Klingt absurd,
1015 				// ich weiss. Aber die Listbox haelt sich intern ein Member, was bei ersten Zeichnen (nachdem die Listbox im Init
1016 				// gerade neu gefuellt wurde) initialisiert wird, und genau dieses Member wird irgendwann benoetigt fuer
1017 				// GetEntryPos, und dieses wiederum von der Connection, wenn sie ihren Ansatzpunkt am Fenster feststellen will.
1018 
1019 			// die Connections
1020 			::std::vector<OTableConnection*>* pTableCon = pUndoAction->GetTabConnList();
1021 			::std::vector<OTableConnection*>::iterator aIter = pTableCon->begin();
1022             ::std::vector<OTableConnection*>::iterator aEnd = pTableCon->end();
1023 
1024 			for(;aIter != aEnd;++aIter)
1025 				addConnection(*aIter); // add all connections from the undo action
1026 
1027 			// each connection should invalidated inside addConnection so we don't need this here any longer
1028 //			if ( !pOwnList->empty() )
1029 //				InvalidateConnections();
1030 			pTableCon->clear();
1031 
1032 			// und die Daten des Fensters ebenfalls in Liste (des Docs)
1033 			if(_bAppend)
1034 				m_pView->getController().getTableWindowData()->push_back(pTabWin->GetData());
1035 
1036 			m_pView->getController().InvalidateFeature(ID_BROWSER_ADDTABLE);
1037 
1038 			// und der UndoAction sagen, dass das Fenster jetzt meine ist ...
1039 			pUndoAction->SetOwnership(sal_False);
1040 
1041 			bSuccess = sal_True;
1042 		}
1043 		else
1044 		{
1045 			//////////////////////////////////////////////////////////////////
1046 			// Initialisierung fehlgeschlagen
1047 			// (z.B. wenn Verbindung zur Datenbank in diesem Augenblick unterbrochen worden ist)
1048 			pTabWin->clearListBox();
1049 			delete pTabWin;
1050 		}
1051 	}
1052 
1053 	// damit habe ich das Doc natuerlich modifiziert
1054 	if(!m_pView->getController().isReadOnly())
1055 		m_pView->getController().setModified( sal_True );
1056 
1057 	m_pView->getController().InvalidateFeature(SID_BROWSER_CLEAR_QUERY);
1058 
1059 	return bSuccess;
1060 }
1061 //------------------------------------------------------------------------
1062 void OQueryTableView::InsertField(const OTableFieldDescRef& rInfo)
1063 {
1064 	DBG_CHKTHIS(OQueryTableView,NULL);
1065 	DBG_ASSERT(getDesignView() != NULL, "OQueryTableView::InsertField : habe kein Parent !");
1066 	static_cast<OQueryDesignView*>(getDesignView())->InsertField(rInfo);
1067 }
1068 //------------------------------------------------------------------------------
1069 sal_Bool OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow* pFrom) const
1070 {
1071 	DBG_CHKTHIS(OQueryTableView,NULL);
1072 	const ::std::vector<OTableConnection*>* pList = getTableConnections();
1073 	if (pList)
1074 	{
1075 		::std::vector<OTableConnection*>::const_iterator aIter = pList->begin();
1076         ::std::vector<OTableConnection*>::const_iterator aEnd = pList->end();
1077 		for(;aIter != aEnd;++aIter)
1078 		{
1079 			OQueryTableConnection* pTemp = static_cast<OQueryTableConnection*>(*aIter);
1080 			if (pTemp->IsVisited() &&
1081 				(pFrom == static_cast< OQueryTableWindow*>(pTemp->GetSourceWin()) || pFrom == static_cast< OQueryTableWindow*>(pTemp->GetDestWin())))
1082 				return pTemp != NULL;
1083 		}
1084 	}
1085 
1086 	return sal_False;
1087 }
1088 // -----------------------------------------------------------------------------
1089 void OQueryTableView::onNoColumns_throw()
1090 {
1091     String sError( ModuleRes( STR_STATEMENT_WITHOUT_RESULT_SET ) );
1092     ::dbtools::throwSQLException( sError, ::dbtools::SQL_GENERAL_ERROR, NULL );
1093 }
1094 //------------------------------------------------------------------------------
1095 bool OQueryTableView::supressCrossNaturalJoin(const TTableConnectionData::value_type& _pData) const
1096 {
1097     OQueryTableConnectionData* pQueryData = static_cast<OQueryTableConnectionData*>(_pData.get());
1098     return pQueryData && (pQueryData->GetJoinType() == CROSS_JOIN);
1099 }
1100 // -----------------------------------------------------------------------------
1101