xref: /trunk/main/dbaccess/source/ui/dlg/adtabdlg.cxx (revision b63233d8)
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_dbui.hxx"
26 
27 #include "adtabdlg.hxx"
28 #include "adtabdlg.hrc"
29 #include "sqlmessage.hxx"
30 #include <tools/debug.hxx>
31 #include <tools/diagnose_ex.h>
32 #include <svtools/localresaccess.hxx>
33 #include "dbaccess_helpid.hrc"
34 #include "dbu_resource.hrc"
35 #include "dbu_dlg.hrc"
36 #include <sfx2/sfxsids.hrc>
37 #include "QueryTableView.hxx"
38 #include "QueryDesignView.hxx"
39 #include "querycontroller.hxx"
40 #include <connectivity/dbtools.hxx>
41 #include "browserids.hxx"
42 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
43 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
44 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
45 #include <com/sun/star/container/XNameAccess.hpp>
46 #include "UITools.hxx"
47 #include "imageprovider.hxx"
48 
49 #include <comphelper/containermultiplexer.hxx>
50 #include "cppuhelper/basemutex.hxx"
51 #include <algorithm>
52 
53 // slot ids
54 using namespace dbaui;
55 using namespace ::com::sun::star;
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::container;
58 using namespace ::com::sun::star::sdb;
59 using namespace ::com::sun::star::sdbc;
60 using namespace ::com::sun::star::sdbcx;
61 using namespace dbtools;
62 
63 //==============================================================================
64 //= TableObjectListFacade
65 //==============================================================================
~TableObjectListFacade()66 TableObjectListFacade::~TableObjectListFacade()
67 {
68 }
69 
70 //==============================================================================
71 //= TableListFacade
72 //==============================================================================
73 class TableListFacade : public ::cppu::BaseMutex
74                     ,   public TableObjectListFacade
75                     ,   public ::comphelper::OContainerListener
76 {
77     OTableTreeListBox&          m_rTableList;
78     Reference< XConnection >    m_xConnection;
79     ::rtl::Reference< comphelper::OContainerListenerAdapter>
80                                 m_pContainerListener;
81     bool                        m_bAllowViews;
82 
83 public:
TableListFacade(OTableTreeListBox & _rTableList,const Reference<XConnection> & _rxConnection)84     TableListFacade( OTableTreeListBox& _rTableList, const Reference< XConnection >& _rxConnection )
85         : ::comphelper::OContainerListener(m_aMutex)
86         ,m_rTableList( _rTableList )
87         ,m_xConnection( _rxConnection )
88         ,m_bAllowViews(true)
89     {
90     }
91     virtual ~TableListFacade();
92 
93 
94 private:
95     virtual void    updateTableObjectList( bool _bAllowViews );
96     virtual String  getSelectedName( String& _out_rAliasName ) const;
97     virtual bool    isLeafSelected() const;
98     // OContainerListener
99     virtual void _elementInserted( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException);
100 	virtual void _elementRemoved( const  ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException);
101 	virtual void _elementReplaced( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException);
102 };
103 
~TableListFacade()104 TableListFacade::~TableListFacade()
105 {
106     if ( m_pContainerListener.is() )
107         m_pContainerListener->dispose();
108 }
109 //------------------------------------------------------------------------------
getSelectedName(String & _out_rAliasName) const110 String TableListFacade::getSelectedName( String& _out_rAliasName ) const
111 {
112 	SvLBoxEntry* pEntry = m_rTableList.FirstSelected();
113     if ( !pEntry )
114         return String();
115 
116     ::rtl::OUString aCatalog, aSchema, aTableName;
117 	SvLBoxEntry* pSchema = m_rTableList.GetParent(pEntry);
118 	if(pSchema && pSchema != m_rTableList.getAllObjectsEntry())
119 	{
120 		SvLBoxEntry* pCatalog = m_rTableList.GetParent(pSchema);
121 		if(pCatalog && pCatalog != m_rTableList.getAllObjectsEntry())
122 			aCatalog = m_rTableList.GetEntryText(pCatalog);
123 		aSchema = m_rTableList.GetEntryText(pSchema);
124 	}
125 	aTableName = m_rTableList.GetEntryText(pEntry);
126 
127 	::rtl::OUString aComposedName;
128 	try
129 	{
130         Reference< XDatabaseMetaData > xMeta( m_xConnection->getMetaData(), UNO_QUERY_THROW );
131         if (  !aCatalog.getLength()
132 			&& aSchema.getLength()
133 			&& xMeta->supportsCatalogsInDataManipulation()
134 			&& !xMeta->supportsSchemasInDataManipulation() )
135 		{
136 			aCatalog = aSchema;
137 			aSchema = ::rtl::OUString();
138 		}
139 
140 		aComposedName = ::dbtools::composeTableName(
141             xMeta, aCatalog, aSchema, aTableName, sal_False, ::dbtools::eInDataManipulation );
142 	}
143 	catch ( const Exception& )
144 	{
145         DBG_UNHANDLED_EXCEPTION();
146 	}
147 
148     _out_rAliasName = aTableName;
149     return aComposedName;
150 }
151 // -----------------------------------------------------------------------------
_elementInserted(const container::ContainerEvent &)152 void TableListFacade::_elementInserted( const container::ContainerEvent& /*_rEvent*/ )  throw(::com::sun::star::uno::RuntimeException)
153 {
154     updateTableObjectList(m_bAllowViews);
155 }
156 // -----------------------------------------------------------------------------
_elementRemoved(const container::ContainerEvent &)157 void TableListFacade::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ ) throw(::com::sun::star::uno::RuntimeException)
158 {
159     updateTableObjectList(m_bAllowViews);
160 }
161 // -----------------------------------------------------------------------------
_elementReplaced(const container::ContainerEvent &)162 void TableListFacade::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) throw(::com::sun::star::uno::RuntimeException)
163 {
164 }
165 //------------------------------------------------------------------------------
updateTableObjectList(bool _bAllowViews)166 void TableListFacade::updateTableObjectList( bool _bAllowViews )
167 {
168     m_bAllowViews = _bAllowViews;
169     m_rTableList.Clear();
170     try
171     {
172 	    Reference< XTablesSupplier > xTableSupp( m_xConnection, UNO_QUERY_THROW );
173 
174 	    Reference< XViewsSupplier > xViewSupp;
175 	    Reference< XNameAccess > xTables, xViews;
176 	    Sequence< ::rtl::OUString > sTables, sViews;
177 
178 	    xTables = xTableSupp->getTables();
179 	    if ( xTables.is() )
180         {
181             if ( !m_pContainerListener.is() )
182             {
183                 Reference< XContainer> xContainer(xTables,uno::UNO_QUERY);
184                 if ( xContainer.is() )
185                     m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
186             }
187 		    sTables = xTables->getElementNames();
188         } // if ( xTables.is() )
189 
190 	    xViewSupp.set( xTableSupp, UNO_QUERY );
191 	    if ( xViewSupp.is() )
192 	    {
193 		    xViews = xViewSupp->getViews();
194 		    if ( xViews.is() )
195 			    sViews = xViews->getElementNames();
196 	    }
197 
198         // if no views are allowed remove the views also out the table name filter
199 	    if ( !_bAllowViews )
200 	    {
201 		    const ::rtl::OUString* pTableBegin	= sTables.getConstArray();
202 		    const ::rtl::OUString* pTableEnd	= pTableBegin + sTables.getLength();
203 		    ::std::vector< ::rtl::OUString > aTables(pTableBegin,pTableEnd);
204 
205 		    const ::rtl::OUString* pViewBegin = sViews.getConstArray();
206 		    const ::rtl::OUString* pViewEnd	  = pViewBegin + sViews.getLength();
207 		    ::comphelper::TStringMixEqualFunctor aEqualFunctor;
208 		    for(;pViewBegin != pViewEnd;++pViewBegin)
209 			    aTables.erase(::std::remove_if(aTables.begin(),aTables.end(),::std::bind2nd(aEqualFunctor,*pViewBegin)),aTables.end());
210 		    ::rtl::OUString* pTables = aTables.empty() ? 0 : &aTables[0];
211 		    sTables = Sequence< ::rtl::OUString>(pTables, aTables.size());
212 		    sViews = Sequence< ::rtl::OUString>();
213 	    }
214 
215 	    m_rTableList.UpdateTableList( m_xConnection, sTables, sViews );
216 	    SvLBoxEntry* pEntry = m_rTableList.First();
217 	    while( pEntry && m_rTableList.GetModel()->HasChilds( pEntry ) )
218 	    {
219 		    m_rTableList.Expand( pEntry );
220 		    pEntry = m_rTableList.Next( pEntry );
221 	    }
222 	    if ( pEntry )
223 		    m_rTableList.Select(pEntry);
224     }
225     catch( const Exception& )
226     {
227     	DBG_UNHANDLED_EXCEPTION();
228     }
229 }
230 
231 //------------------------------------------------------------------------------
isLeafSelected() const232 bool TableListFacade::isLeafSelected() const
233 {
234 	SvLBoxEntry* pEntry = m_rTableList.FirstSelected();
235 	return pEntry && !m_rTableList.GetModel()->HasChilds( pEntry );
236 }
237 
238 //==============================================================================
239 //= QueryListFacade
240 //==============================================================================
241 class QueryListFacade : public ::cppu::BaseMutex
242                     ,   public TableObjectListFacade
243                     ,   public ::comphelper::OContainerListener
244 {
245     SvTreeListBox&              m_rQueryList;
246     Reference< XConnection >    m_xConnection;
247     ::rtl::Reference< comphelper::OContainerListenerAdapter>
248                                 m_pContainerListener;
249 
250 public:
QueryListFacade(SvTreeListBox & _rQueryList,const Reference<XConnection> & _rxConnection)251     QueryListFacade( SvTreeListBox& _rQueryList, const Reference< XConnection >& _rxConnection )
252         : ::comphelper::OContainerListener(m_aMutex)
253         ,m_rQueryList( _rQueryList )
254         ,m_xConnection( _rxConnection )
255     {
256     }
257     virtual ~QueryListFacade();
258 private:
259     virtual void    updateTableObjectList( bool _bAllowViews );
260     virtual String  getSelectedName( String& _out_rAliasName ) const;
261     virtual bool    isLeafSelected() const;
262     // OContainerListener
263     virtual void _elementInserted( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException);
264 	virtual void _elementRemoved( const  ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException);
265 	virtual void _elementReplaced( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException);
266 };
~QueryListFacade()267 QueryListFacade::~QueryListFacade()
268 {
269     if ( m_pContainerListener.is() )
270         m_pContainerListener->dispose();
271 }
272 // -----------------------------------------------------------------------------
_elementInserted(const container::ContainerEvent & _rEvent)273 void QueryListFacade::_elementInserted( const container::ContainerEvent& _rEvent )  throw(::com::sun::star::uno::RuntimeException)
274 {
275     ::rtl::OUString sName;
276     if ( _rEvent.Accessor >>= sName )
277         m_rQueryList.InsertEntry( sName );
278 }
279 // -----------------------------------------------------------------------------
_elementRemoved(const container::ContainerEvent &)280 void QueryListFacade::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ ) throw(::com::sun::star::uno::RuntimeException)
281 {
282     updateTableObjectList(true);
283 }
284 // -----------------------------------------------------------------------------
_elementReplaced(const container::ContainerEvent &)285 void QueryListFacade::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) throw(::com::sun::star::uno::RuntimeException)
286 {
287 }
288 
289 //------------------------------------------------------------------------------
updateTableObjectList(bool)290 void QueryListFacade::updateTableObjectList( bool /*_bAllowViews*/ )
291 {
292     m_rQueryList.Clear();
293     try
294     {
295         ImageProvider aImageProvider( m_xConnection );
296         Image aQueryImage( aImageProvider.getDefaultImage( DatabaseObject::QUERY, false ) );
297         Image aQueryImageHC( aImageProvider.getDefaultImage( DatabaseObject::QUERY, true ) );
298 
299         m_rQueryList.SetDefaultExpandedEntryBmp( aQueryImage, BMP_COLOR_NORMAL );
300         m_rQueryList.SetDefaultCollapsedEntryBmp( aQueryImage, BMP_COLOR_NORMAL );
301         m_rQueryList.SetDefaultExpandedEntryBmp( aQueryImageHC, BMP_COLOR_HIGHCONTRAST );
302         m_rQueryList.SetDefaultCollapsedEntryBmp( aQueryImageHC, BMP_COLOR_HIGHCONTRAST );
303 
304         Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY_THROW );
305         Reference< XNameAccess > xQueries( xSuppQueries->getQueries(), UNO_QUERY_THROW );
306         if ( !m_pContainerListener.is() )
307         {
308             Reference< XContainer> xContainer(xQueries,UNO_QUERY_THROW);
309             m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
310         }
311         Sequence< ::rtl::OUString > aQueryNames = xQueries->getElementNames();
312 
313         const ::rtl::OUString* pQuery = aQueryNames.getConstArray();
314         const ::rtl::OUString* pQueryEnd = aQueryNames.getConstArray() + aQueryNames.getLength();
315         while ( pQuery != pQueryEnd )
316             m_rQueryList.InsertEntry( *pQuery++ );
317     }
318     catch( const Exception& )
319     {
320     	DBG_UNHANDLED_EXCEPTION();
321     }
322 }
323 
324 //------------------------------------------------------------------------------
getSelectedName(String & _out_rAliasName) const325 String QueryListFacade::getSelectedName( String& _out_rAliasName ) const
326 {
327     String sSelected;
328 	SvLBoxEntry* pEntry = m_rQueryList.FirstSelected();
329     if ( pEntry )
330         sSelected = _out_rAliasName = m_rQueryList.GetEntryText( pEntry );
331     return sSelected;
332 }
333 
334 //------------------------------------------------------------------------------
isLeafSelected() const335 bool QueryListFacade::isLeafSelected() const
336 {
337 	SvLBoxEntry* pEntry = m_rQueryList.FirstSelected();
338 	return pEntry && !m_rQueryList.GetModel()->HasChilds( pEntry );
339 }
340 
341 //==============================================================================
342 //= OAddTableDlg
343 //==============================================================================
344 //------------------------------------------------------------------------------
OAddTableDlg(Window * pParent,IAddTableDialogContext & _rContext)345 OAddTableDlg::OAddTableDlg( Window* pParent, IAddTableDialogContext& _rContext )
346 			 :ModelessDialog( pParent, ModuleRes(DLG_JOIN_TABADD) )
347              ,m_aCaseTables( this, ModuleRes( RB_CASE_TABLES ) )
348              ,m_aCaseQueries( this, ModuleRes( RB_CASE_QUERIES ) )
349 			 ,m_aTableList( this, NULL, ModuleRes( LB_TABLE_OR_QUERY ), sal_False )
350 			 ,m_aQueryList( this, ModuleRes( LB_TABLE_OR_QUERY ) )
351 			 ,aAddButton( this, ModuleRes( PB_ADDTABLE ) )
352 			 ,aCloseButton( this, ModuleRes( PB_CLOSE ) )
353 			 ,aHelpButton( this, ModuleRes( PB_HELP ) )
354 			 ,m_rContext( _rContext )
355 {
356 	// der Close-Button hat schon einen Standard-Help-Text, den ich aber hier nicht haben moechte, also den Text ruecksetzen
357 	// und eine neue ID verteilen
358 	aCloseButton.SetHelpText(String());
359 	aCloseButton.SetHelpId(HID_JOINSH_ADDTAB_CLOSE);
360 
361 	m_aTableList.SetHelpId( HID_JOINSH_ADDTAB_TABLELIST );
362     m_aQueryList.SetHelpId( HID_JOINSH_ADDTAB_QUERYLIST );
363 
364 	//////////////////////////////////////////////////////////////////////
365     m_aCaseTables.SetClickHdl( LINK( this, OAddTableDlg, OnTypeSelected ) );
366     m_aCaseQueries.SetClickHdl( LINK( this, OAddTableDlg, OnTypeSelected ) );
367 	aAddButton.SetClickHdl( LINK( this, OAddTableDlg, AddClickHdl ) );
368 	aCloseButton.SetClickHdl( LINK( this, OAddTableDlg, CloseClickHdl ) );
369 	m_aTableList.SetDoubleClickHdl( LINK( this, OAddTableDlg, TableListDoubleClickHdl ) );
370 	m_aTableList.SetSelectHdl( LINK( this, OAddTableDlg, TableListSelectHdl ) );
371 	m_aQueryList.SetDoubleClickHdl( LINK( this, OAddTableDlg, TableListDoubleClickHdl ) );
372 	m_aQueryList.SetSelectHdl( LINK( this, OAddTableDlg, TableListSelectHdl ) );
373 
374 	//////////////////////////////////////////////////////////////////////
375 	m_aTableList.EnableInplaceEditing( sal_False );
376 	m_aTableList.SetStyle(m_aTableList.GetStyle() | WB_BORDER | WB_HASLINES |WB_HASBUTTONS | WB_HASBUTTONSATROOT | WB_HASLINESATROOT | WB_SORT | WB_HSCROLL );
377 	m_aTableList.EnableCheckButton( NULL ); // do not show any buttons
378 	m_aTableList.SetSelectionMode( SINGLE_SELECTION );
379 	m_aTableList.notifyHiContrastChanged();
380     m_aTableList.suppressEmptyFolders();
381 
382 	//////////////////////////////////////////////////////////////////////
383     m_aQueryList.EnableInplaceEditing( sal_False );
384 	m_aQueryList.SetSelectionMode( SINGLE_SELECTION );
385 
386 	//////////////////////////////////////////////////////////////////////
387     if ( !m_rContext.allowQueries() )
388     {
389         m_aCaseTables.Hide();
390         m_aCaseQueries.Hide();
391 
392         long nPixelDiff = m_aTableList.GetPosPixel().Y() - m_aCaseTables.GetPosPixel().Y();
393 
394         Point aListPos( m_aTableList.GetPosPixel() );
395         aListPos.Y() -= nPixelDiff;
396 
397         Size aListSize( m_aTableList.GetSizePixel() );
398         aListSize.Height() += nPixelDiff;
399 
400         m_aTableList.SetPosSizePixel( aListPos, aListSize );
401     }
402 
403     FreeResource();
404 
405     SetText( getDialogTitleForContext( m_rContext ) );
406 }
407 
408 //------------------------------------------------------------------------------
~OAddTableDlg()409 OAddTableDlg::~OAddTableDlg()
410 {
411     m_rContext.onWindowClosing( this );
412 }
413 
414 //------------------------------------------------------------------------------
impl_switchTo(ObjectList _eList)415 void OAddTableDlg::impl_switchTo( ObjectList _eList )
416 {
417     switch ( _eList )
418     {
419     case Tables:
420         m_aTableList.Show( sal_True );  m_aCaseTables.Check( sal_True );
421         m_aQueryList.Show( sal_False ); m_aCaseQueries.Check( sal_False );
422         m_pCurrentList.reset( new TableListFacade( m_aTableList, m_rContext.getConnection() ) );
423         m_aTableList.GrabFocus();
424         break;
425 
426     case Queries:
427         m_aTableList.Show( sal_False ); m_aCaseTables.Check( sal_False );
428         m_aQueryList.Show( sal_True );  m_aCaseQueries.Check( sal_True );
429         m_pCurrentList.reset( new QueryListFacade( m_aQueryList, m_rContext.getConnection() ) );
430         m_aQueryList.GrabFocus();
431         break;
432     }
433     m_pCurrentList->updateTableObjectList( m_rContext.allowViews() );
434 }
435 
436 //------------------------------------------------------------------------------
Update()437 void OAddTableDlg::Update()
438 {
439     if ( !m_pCurrentList.get() )
440         impl_switchTo( Tables );
441     else
442         m_pCurrentList->updateTableObjectList( m_rContext.allowViews() );
443 }
444 
445 //------------------------------------------------------------------------------
impl_addTable()446 void OAddTableDlg::impl_addTable()
447 {
448     if ( m_pCurrentList->isLeafSelected() )
449     {
450         String sSelectedName, sAliasName;
451         sSelectedName = m_pCurrentList->getSelectedName( sAliasName );
452 
453         m_rContext.addTableWindow( sSelectedName, sAliasName );
454     }
455 }
456 
457 //------------------------------------------------------------------------------
458 IMPL_LINK( OAddTableDlg, AddClickHdl, Button*, /*pButton*/ )
459 {
460 	TableListDoubleClickHdl(NULL);
461 	return 0;
462 }
463 
464 //------------------------------------------------------------------------------
465 IMPL_LINK( OAddTableDlg, TableListDoubleClickHdl, void*, /*EMPTY_ARG*/ )
466 {
467 	if ( impl_isAddAllowed() )
468     {
469 		impl_addTable();
470 	    if ( !impl_isAddAllowed() )
471 		    Close();
472         return 1L;  // handled
473     }
474 
475 	return 0L;  // not handled
476 }
477 
478 //------------------------------------------------------------------------------
479 IMPL_LINK( OAddTableDlg, TableListSelectHdl, void*, /*EMPTY_ARG*/ )
480 {
481 	aAddButton.Enable( m_pCurrentList->isLeafSelected() );
482 	return 0;
483 }
484 
485 //------------------------------------------------------------------------------
486 IMPL_LINK( OAddTableDlg, CloseClickHdl, Button*, /*pButton*/ )
487 {
488 	return Close();
489 }
490 
491 //------------------------------------------------------------------------------
492 IMPL_LINK( OAddTableDlg, OnTypeSelected, void*, /*EMPTY_ARG*/ )
493 {
494     if ( m_aCaseTables.IsChecked() )
495         impl_switchTo( Tables );
496     else
497         impl_switchTo( Queries );
498     return 0;
499 }
500 
501 //------------------------------------------------------------------------------
Close()502 sal_Bool OAddTableDlg::Close()
503 {
504     m_rContext.onWindowClosing( this );
505 	return ModelessDialog::Close();
506 }
507 
508 //------------------------------------------------------------------------------
impl_isAddAllowed()509 bool OAddTableDlg::impl_isAddAllowed()
510 {
511 	return	m_rContext.allowAddition();
512 }
513 
514 //------------------------------------------------------------------------------
getDialogTitleForContext(IAddTableDialogContext & _rContext)515 String OAddTableDlg::getDialogTitleForContext( IAddTableDialogContext& _rContext )
516 {
517     String sTitle;
518 
519     ::svt::OLocalResourceAccess aLocalRes( ModuleRes( DLG_JOIN_TABADD ), RSC_MODELESSDIALOG );
520     if ( _rContext.allowQueries() )
521         sTitle = String( ModuleRes( STR_ADD_TABLE_OR_QUERY ) );
522     else
523         sTitle = String( ModuleRes( STR_ADD_TABLES ) );
524 
525     return sTitle;
526 }
527 
528 // -----------------------------------------------------------------------------
529 
530