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