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_TABLETREE_HXX_
32 #include "tabletree.hxx"
33 #endif
34 #ifndef _DBAUI_TABLETREE_HRC_
35 #include "tabletree.hrc"
36 #endif
37 #ifndef DBACCESS_IMAGEPROVIDER_HXX
38 #include "imageprovider.hxx"
39 #endif
40 #ifndef _DBAUI_MODULE_DBU_HXX_
41 #include "moduledbu.hxx"
42 #endif
43 #ifndef _DBU_CONTROL_HRC_
44 #include "dbu_control.hrc"
45 #endif
46 #ifndef _SV_MENU_HXX
47 #include <vcl/menu.hxx>
48 #endif
49 #ifndef _CONNECTIVITY_DBTOOLS_HXX_
50 #include <connectivity/dbtools.hxx>
51 #endif
52 #ifndef _COMPHELPER_TYPES_HXX_
53 #include <comphelper/types.hxx>
54 #endif
55 #ifndef DBACCESS_SHARED_DBUSTRINGS_HRC
56 #include "dbustrings.hrc"
57 #endif
58 #ifndef _COM_SUN_STAR_SDB_APPLICATION_DATABASEOBJECT_HPP_
59 #include <com/sun/star/sdb/application/DatabaseObject.hpp>
60 #endif
61 #ifndef _COM_SUN_STAR_SDB_APPLICATION_DATABASEOBJECTFOLDER_HPP_
62 #include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
63 #endif
64 #ifndef _COM_SUN_STAR_SDBC_XDRIVERACCESS_HPP_
65 #include <com/sun/star/sdbc/XDriverAccess.hpp>
66 #endif
67 #ifndef _COM_SUN_STAR_SDBCX_XDATADEFINITIONSUPPLIER_HPP_
68 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
69 #endif
70 #ifndef _COM_SUN_STAR_SDBCX_XVIEWSSUPPLIER_HPP_
71 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
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_SDB_SQLCONTEXT_HPP_
77 #include <com/sun/star/sdb/SQLContext.hpp>
78 #endif
79 #ifndef _COM_SUN_STAR_SDBC_XROW_HPP_
80 #include <com/sun/star/sdbc/XRow.hpp>
81 #endif
82 #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
83 #include <com/sun/star/beans/XPropertySet.hpp>
84 #endif
85 #ifndef _DBAUI_COMMON_TYPES_HXX_
86 #include "commontypes.hxx"
87 #endif
88 #ifndef _DBAUI_LISTVIEWITEMS_HXX_
89 #include "listviewitems.hxx"
90 #endif
91 #ifndef TOOLS_DIAGNOSE_EX_H
92 #include <tools/diagnose_ex.h>
93 #endif
94 #ifndef _RTL_USTRBUF_HXX_
95 #include <rtl/ustrbuf.hxx>
96 #endif
97 #include <connectivity/dbmetadata.hxx>
98 
99 #include <algorithm>
100 
101 //.........................................................................
102 namespace dbaui
103 {
104 //.........................................................................
105 
106 using namespace ::com::sun::star::uno;
107 using namespace ::com::sun::star::sdb;
108 using namespace ::com::sun::star::lang;
109 using namespace ::com::sun::star::sdbc;
110 using namespace ::com::sun::star::sdbcx;
111 using namespace ::com::sun::star::beans;
112 using namespace ::com::sun::star::container;
113 using namespace ::com::sun::star::sdb::application;
114 
115 using namespace ::dbtools;
116 using namespace ::comphelper;
117 
118 namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject;
119 namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer;
120 
121 //========================================================================
122 //= OTableTreeListBox
123 //========================================================================
124 OTableTreeListBox::OTableTreeListBox( Window* pParent, const Reference< XMultiServiceFactory >& _rxORB, WinBits nWinStyle,sal_Bool _bVirtualRoot )
125 	:OMarkableTreeListBox(pParent,_rxORB,nWinStyle)
126     ,m_pImageProvider( new ImageProvider )
127 	,m_bVirtualRoot(_bVirtualRoot)
128     ,m_bNoEmptyFolders( false )
129 {
130 	implSetDefaultImages();
131 }
132 //------------------------------------------------------------------------
133 OTableTreeListBox::OTableTreeListBox( Window* pParent, const Reference< XMultiServiceFactory >& _rxORB, const ResId& rResId ,sal_Bool _bVirtualRoot)
134 	:OMarkableTreeListBox(pParent,_rxORB,rResId)
135     ,m_pImageProvider( new ImageProvider )
136 	,m_bVirtualRoot(_bVirtualRoot)
137     ,m_bNoEmptyFolders( false )
138 {
139 	implSetDefaultImages();
140 }
141 
142 // -----------------------------------------------------------------------------
143 OTableTreeListBox::~OTableTreeListBox()
144 {
145 }
146 
147 // -----------------------------------------------------------------------------
148 void OTableTreeListBox::implSetDefaultImages()
149 {
150     ImageProvider aImageProvider;
151     SetDefaultExpandedEntryBmp( aImageProvider.getFolderImage( DatabaseObject::TABLE, false ), BMP_COLOR_NORMAL );
152     SetDefaultExpandedEntryBmp( aImageProvider.getFolderImage( DatabaseObject::TABLE, true ), BMP_COLOR_HIGHCONTRAST );
153     SetDefaultCollapsedEntryBmp( aImageProvider.getFolderImage( DatabaseObject::TABLE, false ), BMP_COLOR_NORMAL );
154     SetDefaultCollapsedEntryBmp( aImageProvider.getFolderImage( DatabaseObject::TABLE, true ), BMP_COLOR_HIGHCONTRAST );
155 }
156 
157 // -----------------------------------------------------------------------------
158 bool  OTableTreeListBox::isFolderEntry( const SvLBoxEntry* _pEntry ) const
159 {
160     sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() );
161     if  (   ( nEntryType == DatabaseObjectContainer::TABLES )
162         ||  ( nEntryType == DatabaseObjectContainer::CATALOG )
163         ||  ( nEntryType == DatabaseObjectContainer::SCHEMA )
164         )
165         return true;
166     return false;
167 }
168 
169 // -----------------------------------------------------------------------------
170 void OTableTreeListBox::notifyHiContrastChanged()
171 {
172     implSetDefaultImages();
173 
174 	SvLBoxEntry* pEntryLoop = First();
175 	while (pEntryLoop)
176 	{
177 		sal_uInt16 nCount = pEntryLoop->ItemCount();
178 		for (sal_uInt16 i=0;i<nCount;++i)
179 		{
180 			SvLBoxItem* pItem = pEntryLoop->GetItem(i);
181 			if ( pItem && pItem->IsA() == SV_ITEM_ID_LBOXCONTEXTBMP)
182 			{
183                 SvLBoxContextBmp* pContextBitmapItem = static_cast< SvLBoxContextBmp* >( pItem );
184 
185                 Image aImage, aImageHC;
186                 if ( isFolderEntry( pEntryLoop ) )
187                 {
188                     aImage = m_pImageProvider->getFolderImage( DatabaseObject::TABLE, false );
189                     aImageHC = m_pImageProvider->getFolderImage( DatabaseObject::TABLE, true );
190                 }
191                 else
192                 {
193                     String sCompleteName( getQualifiedTableName( pEntryLoop ) );
194                     m_pImageProvider->getImages( sCompleteName, DatabaseObject::TABLE, aImage, aImageHC );
195                 }
196 
197 				pContextBitmapItem->SetBitmap1( aImage, BMP_COLOR_NORMAL );
198 				pContextBitmapItem->SetBitmap2( aImage, BMP_COLOR_NORMAL );
199 				pContextBitmapItem->SetBitmap1( aImageHC, BMP_COLOR_HIGHCONTRAST );
200 				pContextBitmapItem->SetBitmap2( aImageHC, BMP_COLOR_HIGHCONTRAST );
201                 // TODO: Now that we give both images to the entry item, it is not necessary anymore
202                 // to do this anytime HC changes - the tree control will do this itself now.
203                 // We would only need to properly initialize newly inserted entries.
204 				break;
205 			}
206 		}
207 		pEntryLoop = Next(pEntryLoop);
208 	}
209 }
210 
211 //------------------------------------------------------------------------
212 void OTableTreeListBox::implOnNewConnection( const Reference< XConnection >& _rxConnection )
213 {
214     m_xConnection = _rxConnection;
215     m_pImageProvider.reset( new ImageProvider( m_xConnection  ) );
216 }
217 
218 //------------------------------------------------------------------------
219 void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection ) throw(SQLException)
220 {
221 	Sequence< ::rtl::OUString > sTables, sViews;
222 
223 	String sCurrentActionError;
224 	try
225 	{
226         Reference< XTablesSupplier > xTableSupp( _rxConnection, UNO_QUERY_THROW );
227 		sCurrentActionError = String(ModuleRes(STR_NOTABLEINFO));
228 
229 		Reference< XNameAccess > xTables,xViews;
230 
231 		Reference< XViewsSupplier > xViewSupp( _rxConnection, UNO_QUERY );
232 		if ( xViewSupp.is() )
233 		{
234 			xViews = xViewSupp->getViews();
235 			if (xViews.is())
236 				sViews = xViews->getElementNames();
237 		}
238 
239 		xTables = xTableSupp->getTables();
240 		if (xTables.is())
241 			sTables = xTables->getElementNames();
242 	}
243 	catch(RuntimeException&)
244 	{
245 		DBG_ERROR("OTableTreeListBox::UpdateTableList : caught an RuntimeException!");
246 	}
247     catch ( const SQLException& )
248     {
249         throw;
250     }
251 	catch(Exception&)
252 	{
253 		// a non-SQLException exception occured ... simply throw an SQLException
254 		SQLException aInfo;
255         aInfo.Message = sCurrentActionError;
256 		throw aInfo;
257 	}
258 
259 	UpdateTableList( _rxConnection, sTables, sViews );
260 }
261 // -----------------------------------------------------------------------------
262 namespace
263 {
264 	struct OViewSetter : public ::std::unary_function< OTableTreeListBox::TNames::value_type, bool>
265 	{
266 		const Sequence< ::rtl::OUString> m_aViews;
267 		::comphelper::TStringMixEqualFunctor m_aEqualFunctor;
268 
269 		OViewSetter(const Sequence< ::rtl::OUString>& _rViews,sal_Bool _bCase) : m_aViews(_rViews),m_aEqualFunctor(_bCase){}
270 		OTableTreeListBox::TNames::value_type operator() (const ::rtl::OUString& lhs)
271 		{
272 			OTableTreeListBox::TNames::value_type aRet;
273 			aRet.first = lhs;
274 			const ::rtl::OUString* pIter = m_aViews.getConstArray();
275 			const ::rtl::OUString* pEnd = m_aViews.getConstArray() + m_aViews.getLength();
276 			aRet.second = (::std::find_if(pIter,pEnd,::std::bind2nd(m_aEqualFunctor,lhs)) != pEnd);
277 
278 			return aRet;
279 		}
280 	};
281 
282 }
283 // -----------------------------------------------------------------------------
284 void OTableTreeListBox::UpdateTableList(
285 				const Reference< XConnection >& _rxConnection,
286 				const Sequence< ::rtl::OUString>& _rTables,
287 				const Sequence< ::rtl::OUString>& _rViews
288 			)
289 {
290 	TNames aTables;
291 	aTables.resize(_rTables.getLength());
292 	const ::rtl::OUString* pIter = _rTables.getConstArray();
293 	const ::rtl::OUString* pEnd = _rTables.getConstArray() + _rTables.getLength();
294 	try
295 	{
296         Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_QUERY_THROW );
297 		::std::transform( pIter, pEnd,
298             aTables.begin(), OViewSetter( _rViews, xMeta->supportsMixedCaseQuotedIdentifiers() ) );
299 	}
300 	catch(Exception&)
301 	{
302         DBG_UNHANDLED_EXCEPTION();
303 	}
304     UpdateTableList( _rxConnection, aTables );
305 }
306 
307 //------------------------------------------------------------------------
308 namespace
309 {
310     ::std::vector< ::rtl::OUString > lcl_getMetaDataStrings_throw( const Reference< XResultSet >& _rxMetaDataResult, sal_Int32 _nColumnIndex )
311     {
312         ::std::vector< ::rtl::OUString > aStrings;
313         Reference< XRow > xRow( _rxMetaDataResult, UNO_QUERY_THROW );
314         while ( _rxMetaDataResult->next() )
315             aStrings.push_back( xRow->getString( _nColumnIndex ) );
316         return aStrings;
317     }
318 
319     bool lcl_shouldDisplayEmptySchemasAndCatalogs( const Reference< XConnection >& _rxConnection )
320     {
321         ::dbtools::DatabaseMetaData aMetaData( _rxConnection );
322         return aMetaData.displayEmptyTableFolders();
323     }
324 }
325 
326 //------------------------------------------------------------------------
327 void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection, const TNames& _rTables )
328 {
329     implOnNewConnection( _rxConnection );
330 
331 	// throw away all the old stuff
332 	Clear();
333 
334 	try
335 	{
336 		// the root entry saying "all objects"
337 		SvLBoxEntry* pAllObjects = NULL;
338 		if (haveVirtualRoot())
339 		{
340 			String sRootEntryText;
341 			TNames::const_iterator aViews = ::std::find_if(_rTables.begin(),_rTables.end(),
342 			::std::compose1(::std::bind2nd(::std::equal_to<sal_Bool>(),sal_False),::std::select2nd<TNames::value_type>()));
343 			TNames::const_iterator aTables = ::std::find_if(_rTables.begin(),_rTables.end(),
344 			::std::compose1(::std::bind2nd(::std::equal_to<sal_Bool>(),sal_True),::std::select2nd<TNames::value_type>()));
345 
346 			if ( aViews == _rTables.end() )
347 				sRootEntryText  = String(ModuleRes(STR_ALL_TABLES));
348 			else if ( aTables == _rTables.end() )
349 				sRootEntryText  = String(ModuleRes(STR_ALL_VIEWS));
350 			else
351 				sRootEntryText  = String(ModuleRes(STR_ALL_TABLES_AND_VIEWS));
352             pAllObjects = InsertEntry( sRootEntryText, NULL, sal_False, LIST_APPEND, reinterpret_cast< void* >( DatabaseObjectContainer::TABLES ) );
353 		}
354 
355 		if ( _rTables.empty() )
356 			// nothing to do (besides inserting the root entry)
357 			return;
358 
359 		// get the table/view names
360 		TNames::const_iterator aIter = _rTables.begin();
361 		TNames::const_iterator aEnd = _rTables.end();
362 
363         Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_QUERY_THROW );
364 		for ( ;	aIter != aEnd; ++aIter )
365 		{
366 			// add the entry
367 			implAddEntry(
368 				xMeta,
369 				aIter->first,
370 				sal_False
371 			);
372 		}
373 
374         if ( !m_bNoEmptyFolders && lcl_shouldDisplayEmptySchemasAndCatalogs( _rxConnection ) )
375         {
376             sal_Bool bSupportsCatalogs = xMeta->supportsCatalogsInDataManipulation();
377             sal_Bool bSupportsSchemas = xMeta->supportsSchemasInDataManipulation();
378 
379             if ( bSupportsCatalogs || bSupportsSchemas )
380             {
381                 // we display empty catalogs if the DB supports catalogs, and they're noted at the beginning of a
382                 // composed name. Otherwise, we display empty schematas. (also see the tree structure explained in
383                 // implAddEntry)
384                 bool bCatalogs = bSupportsCatalogs && xMeta->isCatalogAtStart();
385 
386                 ::std::vector< ::rtl::OUString > aFolderNames( lcl_getMetaDataStrings_throw(
387                     bCatalogs ? xMeta->getCatalogs() : xMeta->getSchemas(), 1 ) );
388                 sal_Int32 nFolderType = bCatalogs ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA;
389 
390                 SvLBoxEntry* pRootEntry = getAllObjectsEntry();
391                 for (   ::std::vector< ::rtl::OUString >::const_iterator folder = aFolderNames.begin();
392                         folder != aFolderNames.end();
393                         ++folder
394                     )
395                 {
396 		            SvLBoxEntry* pFolder = GetEntryPosByName( *folder, pRootEntry );
397 		            if ( !pFolder )
398 			            pFolder = InsertEntry( *folder, pRootEntry, sal_False, LIST_APPEND, reinterpret_cast< void* >( nFolderType ) );
399                 }
400             }
401         }
402 	}
403 	catch ( const Exception& )
404 	{
405         DBG_UNHANDLED_EXCEPTION();
406 	}
407 }
408 //------------------------------------------------------------------------
409 sal_Bool OTableTreeListBox::isWildcardChecked(SvLBoxEntry* _pEntry) const
410 {
411 	if (_pEntry)
412 	{
413 		OBoldListboxString* pTextItem = static_cast<OBoldListboxString*>(_pEntry->GetFirstItem(SV_ITEM_ID_BOLDLBSTRING));
414 		if (pTextItem)
415 			return pTextItem->isEmphasized();
416 	}
417 	return sal_False;
418 }
419 
420 //------------------------------------------------------------------------
421 void OTableTreeListBox::checkWildcard(SvLBoxEntry* _pEntry)
422 {
423 	SetCheckButtonState(_pEntry, SV_BUTTON_CHECKED);
424 	checkedButton_noBroadcast(_pEntry);
425 }
426 
427 //------------------------------------------------------------------------
428 SvLBoxEntry* OTableTreeListBox::getAllObjectsEntry() const
429 {
430 	return haveVirtualRoot() ? First() : NULL;
431 }
432 
433 //------------------------------------------------------------------------
434 void OTableTreeListBox::checkedButton_noBroadcast(SvLBoxEntry* _pEntry)
435 {
436 	OMarkableTreeListBox::checkedButton_noBroadcast(_pEntry);
437 
438 	// if an entry has children, it makes a difference if the entry is checked because alls children are checked
439 	// or if the user checked it explicitly.
440 	// So we track explicit (un)checking
441 
442 	SvButtonState eState = GetCheckButtonState(_pEntry);
443 	DBG_ASSERT(SV_BUTTON_TRISTATE != eState, "OTableTreeListBox::CheckButtonHdl: user action which lead to TRISTATE?");
444 	implEmphasize(_pEntry, SV_BUTTON_CHECKED == eState);
445 }
446 
447 //------------------------------------------------------------------------
448 void OTableTreeListBox::implEmphasize(SvLBoxEntry* _pEntry, sal_Bool _bChecked, sal_Bool _bUpdateDescendants, sal_Bool _bUpdateAncestors)
449 {
450 	DBG_ASSERT(_pEntry, "OTableTreeListBox::implEmphasize: invalid entry (NULL)!");
451 
452 	// special emphasizing handling for the "all objects" entry
453 	// 89709 - 16.07.2001 - frank.schoenheit@sun.com
454 	sal_Bool bAllObjectsEntryAffected = haveVirtualRoot() && (getAllObjectsEntry() == _pEntry);
455 	if	(	GetModel()->HasChilds(_pEntry)				// the entry has children
456 		||	bAllObjectsEntryAffected					// or it is the "all objects" entry
457 		)
458 	{
459 		OBoldListboxString* pTextItem = static_cast<OBoldListboxString*>(_pEntry->GetFirstItem(SV_ITEM_ID_BOLDLBSTRING));
460 		if (pTextItem)
461 			pTextItem->emphasize(_bChecked);
462 
463 		if (bAllObjectsEntryAffected)
464 			InvalidateEntry(_pEntry);
465 	}
466 
467 	if (_bUpdateDescendants)
468 	{
469 		// remove the mark for all children of the checked entry
470 		SvLBoxEntry* pChildLoop = FirstChild(_pEntry);
471 		while (pChildLoop)
472 		{
473 			if (GetModel()->HasChilds(pChildLoop))
474 				implEmphasize(pChildLoop, sal_False, sal_True, sal_False);
475 			pChildLoop = NextSibling(pChildLoop);
476 		}
477 	}
478 
479 	if (_bUpdateAncestors)
480 	{
481 		// remove the mark for all ancestors of the entry
482 		if (GetModel()->HasParent(_pEntry))
483 			implEmphasize(GetParent(_pEntry), sal_False, sal_False, sal_True);
484 	}
485 }
486 
487 //------------------------------------------------------------------------
488 void OTableTreeListBox::InitEntry(SvLBoxEntry* _pEntry, const XubString& _rString, const Image& _rCollapsedBitmap, const Image& _rExpandedBitmap, SvLBoxButtonKind _eButtonKind)
489 {
490 	OMarkableTreeListBox::InitEntry(_pEntry, _rString, _rCollapsedBitmap, _rExpandedBitmap, _eButtonKind);
491 
492 	// replace the text item with our own one
493 	SvLBoxItem* pTextItem = _pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING);
494 	DBG_ASSERT(pTextItem, "OTableTreeListBox::InitEntry: no text item!?");
495 	sal_uInt16 nTextPos = _pEntry->GetPos(pTextItem);
496 	DBG_ASSERT(((sal_uInt16)-1) != nTextPos, "OTableTreeListBox::InitEntry: no text item pos!");
497 
498 	_pEntry->ReplaceItem(new OBoldListboxString(_pEntry, 0, _rString), nTextPos);
499 }
500 
501 //------------------------------------------------------------------------
502 SvLBoxEntry* OTableTreeListBox::implAddEntry(
503 		const Reference< XDatabaseMetaData >& _rxMeta,
504 		const ::rtl::OUString& _rTableName,
505 		sal_Bool _bCheckName
506 	)
507 {
508     OSL_PRECOND( _rxMeta.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" );
509     if ( !_rxMeta.is() )
510         return NULL;
511 
512 	// split the complete name into it's components
513 	::rtl::OUString sCatalog, sSchema, sName;
514 	qualifiedNameComponents( _rxMeta, _rTableName, sCatalog, sSchema, sName, ::dbtools::eInDataManipulation );
515 
516     SvLBoxEntry* pParentEntry = getAllObjectsEntry();
517 
518     // if the DB uses catalog at the start of identifiers, then our hierarchy is
519     //   catalog
520     //   +- schema
521     //      +- table
522     // else it is
523     //   schema
524     //   +- catalog
525     //      +- table
526     sal_Bool bCatalogAtStart = _rxMeta->isCatalogAtStart();
527     const ::rtl::OUString& rFirstName  = bCatalogAtStart ? sCatalog : sSchema;
528     const sal_Int32 nFirstFolderType   = bCatalogAtStart ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA;
529     const ::rtl::OUString& rSecondName = bCatalogAtStart ? sSchema : sCatalog;
530     const sal_Int32 nSecondFolderType  = bCatalogAtStart ? DatabaseObjectContainer::SCHEMA : DatabaseObjectContainer::CATALOG;
531 
532 	if ( rFirstName.getLength() )
533 	{
534 		SvLBoxEntry* pFolder = GetEntryPosByName( rFirstName, pParentEntry );
535 		if ( !pFolder )
536 			pFolder = InsertEntry( rFirstName, pParentEntry, sal_False, LIST_APPEND, reinterpret_cast< void* >( nFirstFolderType ) );
537 		pParentEntry = pFolder;
538 	}
539 
540 	if ( rSecondName.getLength() )
541 	{
542 		SvLBoxEntry* pFolder = GetEntryPosByName( rSecondName, pParentEntry );
543 		if ( !pFolder )
544 			pFolder = InsertEntry( rSecondName, pParentEntry, sal_False, LIST_APPEND, reinterpret_cast< void* >( nSecondFolderType ) );
545 		pParentEntry = pFolder;
546 	}
547 
548 	SvLBoxEntry* pRet = NULL;
549 	if ( !_bCheckName || !GetEntryPosByName( sName, pParentEntry ) )
550     {
551 		pRet = InsertEntry( sName, pParentEntry, sal_False, LIST_APPEND );
552 
553         Image aImage, aImageHC;
554         m_pImageProvider->getImages( _rTableName, DatabaseObject::TABLE, aImage, aImageHC );
555 
556         SetExpandedEntryBmp( pRet, aImage, BMP_COLOR_NORMAL );
557         SetCollapsedEntryBmp( pRet, aImage, BMP_COLOR_NORMAL );
558         SetExpandedEntryBmp( pRet, aImageHC, BMP_COLOR_HIGHCONTRAST );
559         SetCollapsedEntryBmp( pRet, aImageHC, BMP_COLOR_HIGHCONTRAST );
560     }
561 	return pRet;
562 }
563 
564 //------------------------------------------------------------------------
565 NamedDatabaseObject OTableTreeListBox::describeObject( SvLBoxEntry* _pEntry )
566 {
567     NamedDatabaseObject aObject;
568 
569     sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() );
570 
571     if  ( nEntryType == DatabaseObjectContainer::TABLES )
572     {
573         aObject.Type = DatabaseObjectContainer::TABLES;
574     }
575     else if (   ( nEntryType == DatabaseObjectContainer::CATALOG )
576             ||  ( nEntryType == DatabaseObjectContainer::SCHEMA )
577             )
578     {
579         SvLBoxEntry* pParent = GetParent( _pEntry );
580         sal_Int32 nParentEntryType = pParent ? reinterpret_cast< sal_IntPtr >( pParent->GetUserData() ) : -1;
581 
582         ::rtl::OUStringBuffer buffer;
583         if  ( nEntryType == DatabaseObjectContainer::CATALOG )
584         {
585             if ( nParentEntryType == DatabaseObjectContainer::SCHEMA )
586             {
587                 buffer.append( GetEntryText( pParent ) );
588                 buffer.append( sal_Unicode( '.' ) );
589             }
590             buffer.append( GetEntryText( _pEntry ) );
591         }
592         else if ( nEntryType == DatabaseObjectContainer::SCHEMA )
593         {
594             if ( nParentEntryType == DatabaseObjectContainer::CATALOG )
595             {
596                 buffer.append( GetEntryText( pParent ) );
597                 buffer.append( sal_Unicode( '.' ) );
598             }
599             buffer.append( GetEntryText( _pEntry ) );
600         }
601     }
602     else
603     {
604         aObject.Type = DatabaseObject::TABLE;
605         aObject.Name = getQualifiedTableName( _pEntry );
606     }
607 
608     return aObject;
609 }
610 
611 //------------------------------------------------------------------------
612 SvLBoxEntry* OTableTreeListBox::addedTable( const ::rtl::OUString& _rName )
613 {
614 	try
615 	{
616         Reference< XDatabaseMetaData > xMeta;
617         if ( impl_getAndAssertMetaData( xMeta ) )
618 		    return implAddEntry( xMeta, _rName );
619 	}
620     catch( const Exception& )
621     {
622         DBG_UNHANDLED_EXCEPTION();
623     }
624 	return NULL;
625 }
626 
627 //------------------------------------------------------------------------
628 bool OTableTreeListBox::impl_getAndAssertMetaData( Reference< XDatabaseMetaData >& _out_rMetaData ) const
629 {
630 	if ( m_xConnection.is() )
631         _out_rMetaData = m_xConnection->getMetaData();
632     OSL_PRECOND( _out_rMetaData.is(), "OTableTreeListBox::impl_getAndAssertMetaData: invalid current connection!" );
633     return _out_rMetaData.is();
634 }
635 
636 //------------------------------------------------------------------------
637 String OTableTreeListBox::getQualifiedTableName( SvLBoxEntry* _pEntry ) const
638 {
639     OSL_PRECOND( !isFolderEntry( _pEntry ), "OTableTreeListBox::getQualifiedTableName: folder entries not allowed here!" );
640 
641     try
642     {
643         Reference< XDatabaseMetaData > xMeta;
644         if ( !impl_getAndAssertMetaData( xMeta ) )
645             return String();
646 
647         ::rtl::OUString sCatalog;
648 	    ::rtl::OUString sSchema;
649 	    ::rtl::OUString sTable;
650 
651 	    SvLBoxEntry* pSchema = GetParent( _pEntry );
652 	    if ( pSchema )
653 	    {
654 		    SvLBoxEntry* pCatalog = GetParent( pSchema );
655 		    if  (   pCatalog
656                 ||  (   xMeta->supportsCatalogsInDataManipulation()
657                     &&  !xMeta->supportsSchemasInDataManipulation()
658                     )   // here we support catalog but no schema
659                 )
660 		    {
661 			    if ( pCatalog == NULL )
662 			    {
663 				    pCatalog = pSchema;
664 				    pSchema = NULL;
665 			    }
666 			    sCatalog = GetEntryText( pCatalog );
667 		    }
668 		    if ( pSchema )
669 			    sSchema = GetEntryText(pSchema);
670 	    }
671 	    sTable = GetEntryText( _pEntry );
672 
673 	    return ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sTable, sal_False, ::dbtools::eInDataManipulation );
674     }
675     catch( const Exception& )
676     {
677         DBG_UNHANDLED_EXCEPTION();
678     }
679     return String();
680 }
681 
682 //------------------------------------------------------------------------
683 SvLBoxEntry* OTableTreeListBox::getEntryByQualifiedName( const ::rtl::OUString& _rName )
684 {
685 	try
686 	{
687         Reference< XDatabaseMetaData > xMeta;
688         if ( !impl_getAndAssertMetaData( xMeta ) )
689             return NULL;
690 
691 		// split the complete name into it's components
692 		::rtl::OUString sCatalog, sSchema, sName;
693 		qualifiedNameComponents(xMeta, _rName, sCatalog, sSchema, sName,::dbtools::eInDataManipulation);
694 
695 		SvLBoxEntry* pParent = getAllObjectsEntry();
696 		SvLBoxEntry* pCat = NULL;
697 		SvLBoxEntry* pSchema = NULL;
698 		if ( sCatalog.getLength() )
699 		{
700 			pCat = GetEntryPosByName(sCatalog, pParent);
701 			if ( pCat )
702 				pParent = pCat;
703 		}
704 
705 		if ( sSchema.getLength() )
706 		{
707 			pSchema = GetEntryPosByName(sSchema, pParent);
708 			if ( pSchema )
709 				pParent = pSchema;
710 		}
711 
712 		return GetEntryPosByName(sName, pParent);
713 	}
714     catch( const Exception& )
715     {
716         DBG_UNHANDLED_EXCEPTION();
717     }
718 	return NULL;
719 }
720 //------------------------------------------------------------------------
721 void OTableTreeListBox::removedTable( const ::rtl::OUString& _rName )
722 {
723 	try
724 	{
725 		SvLBoxEntry* pEntry = getEntryByQualifiedName( _rName );
726 		if ( pEntry )
727 			GetModel()->Remove( pEntry );
728 	}
729     catch( const Exception& )
730     {
731         DBG_UNHANDLED_EXCEPTION();
732     }
733 }
734 
735 //.........................................................................
736 }	// namespace dbaui
737 //.........................................................................
738 
739