xref: /core/dbaccess/source/ui/browser/unodatbr.cxx (revision 6311f7ff)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <browserids.hxx>
21 #include <core_resource.hxx>
22 #include <helpids.h>
23 #include <dbexchange.hxx>
24 #include <dbtreelistbox.hxx>
25 #include "dbtreemodel.hxx"
26 #include "dbtreeview.hxx"
27 #include <dbu_reghelper.hxx>
28 #include <stringconstants.hxx>
29 #include <strings.hrc>
30 #include <dlgsave.hxx>
31 #include <uiservices.hxx>
32 #include <HtmlReader.hxx>
33 #include <imageprovider.hxx>
34 #include <listviewitems.hxx>
35 #include <QEnumTypes.hxx>
36 #include <RtfReader.hxx>
37 #include <sbagrid.hrc>
38 #include <sbagrid.hxx>
39 #include <sqlmessage.hxx>
40 #include <TokenWriter.hxx>
41 #include <UITools.hxx>
42 #include <unodatbr.hxx>
43 #include <WColumnSelect.hxx>
44 #include <WCopyTable.hxx>
45 #include <WCPage.hxx>
46 #include <WExtendPages.hxx>
47 #include <WNameMatch.hxx>
48 
49 #include <com/sun/star/awt/LineEndFormat.hpp>
50 #include <com/sun/star/awt/MouseWheelBehavior.hpp>
51 #include <com/sun/star/awt/TextAlign.hpp>
52 #include <com/sun/star/awt/VisualEffect.hpp>
53 #include <com/sun/star/beans/NamedValue.hpp>
54 #include <com/sun/star/beans/PropertyValue.hpp>
55 #include <com/sun/star/container/XNameContainer.hpp>
56 #include <com/sun/star/form/XForm.hpp>
57 #include <com/sun/star/form/XGridColumnFactory.hpp>
58 #include <com/sun/star/form/XLoadable.hpp>
59 #include <com/sun/star/form/XReset.hpp>
60 #include <com/sun/star/frame/Desktop.hpp>
61 #include <com/sun/star/frame/FrameSearchFlag.hpp>
62 #include <com/sun/star/frame/XLayoutManager.hpp>
63 #include <com/sun/star/lang/DisposedException.hpp>
64 #include <com/sun/star/i18n/Collator.hpp>
65 #include <com/sun/star/sdb/CommandType.hpp>
66 #include <com/sun/star/sdb/SQLContext.hpp>
67 #include <com/sun/star/sdb/XBookmarksSupplier.hpp>
68 #include <com/sun/star/sdb/XCompletedConnection.hpp>
69 #include <com/sun/star/sdb/XDatabaseContext.hpp>
70 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
71 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
72 #include <com/sun/star/sdb/XParametersSupplier.hpp>
73 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
74 #include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
75 #include <com/sun/star/sdb/XResultSetAccess.hpp>
76 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
77 #include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
78 #include <com/sun/star/sdbc/ColumnValue.hpp>
79 #include <com/sun/star/sdbc/DataType.hpp>
80 #include <com/sun/star/sdbc/FetchDirection.hpp>
81 #include <com/sun/star/sdbc/SQLWarning.hpp>
82 #include <com/sun/star/sdbc/XDataSource.hpp>
83 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
84 #include <com/sun/star/sdbc/XWarningsSupplier.hpp>
85 #include <com/sun/star/sdbcx/Privilege.hpp>
86 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
87 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
88 #include <com/sun/star/sdbcx/XDrop.hpp>
89 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
90 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
91 #include <com/sun/star/task/InteractionHandler.hpp>
92 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
93 #include <com/sun/star/util/XFlushable.hpp>
94 #include <com/sun/star/document/MacroExecMode.hpp>
95 #include <com/sun/star/ui/XContextMenuInterceptor.hpp>
96 
97 #include <comphelper/processfactory.hxx>
98 #include <comphelper/extract.hxx>
99 #include <comphelper/sequence.hxx>
100 #include <comphelper/types.hxx>
101 #include <connectivity/dbexception.hxx>
102 #include <cppuhelper/exc_hlp.hxx>
103 #include <cppuhelper/typeprovider.hxx>
104 #include <sfx2/app.hxx>
105 #include <sfx2/dispatch.hxx>
106 #include <sot/storage.hxx>
107 #include <svl/filenotation.hxx>
108 #include <svl/intitem.hxx>
109 #include <unotools/moduleoptions.hxx>
110 #include <vcl/svlbitm.hxx>
111 #include <vcl/treelistbox.hxx>
112 #include <vcl/treelistentry.hxx>
113 #include <svx/algitem.hxx>
114 #include <svx/dataaccessdescriptor.hxx>
115 #include <svx/databaseregistrationui.hxx>
116 #include <toolkit/helper/vclunohelper.hxx>
117 #include <tools/diagnose_ex.h>
118 #include <osl/diagnose.h>
119 #include <sal/log.hxx>
120 #include <tools/multisel.hxx>
121 #include <tools/urlobj.hxx>
122 #include <unotools/confignode.hxx>
123 #include <vcl/split.hxx>
124 #include <vcl/stdtext.hxx>
125 #include <vcl/svapp.hxx>
126 #include <vcl/toolbox.hxx>
127 #include <vcl/waitobj.hxx>
128 #include <vcl/wrkwin.hxx>
129 #include <vcl/settings.hxx>
130 
131 #include <memory>
132 
133 using namespace ::com::sun::star::uno;
134 using namespace ::com::sun::star::awt;
135 using namespace ::com::sun::star::sdb;
136 using namespace ::com::sun::star::sdb::application;
137 using namespace ::com::sun::star::sdbc;
138 using namespace ::com::sun::star::sdbcx;
139 using namespace ::com::sun::star::beans;
140 using namespace ::com::sun::star::util;
141 using namespace ::com::sun::star::frame;
142 using namespace ::com::sun::star::container;
143 using namespace ::com::sun::star::lang;
144 using namespace ::com::sun::star::ui::dialogs;
145 using namespace ::com::sun::star::task;
146 using namespace ::com::sun::star::form;
147 using namespace ::com::sun::star::io;
148 using namespace ::com::sun::star::i18n;
149 using namespace ::com::sun::star::view;
150 using namespace ::com::sun::star::datatransfer;
151 using namespace ::com::sun::star::document;
152 using namespace ::com::sun::star::ui;
153 using namespace ::dbtools;
154 using namespace ::comphelper;
155 using namespace ::svx;
156 
157 // SbaTableQueryBrowser
158 extern "C" void createRegistryInfo_OBrowser()
159 {
160     static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::SbaTableQueryBrowser > aAutoRegistration;
161 }
162 
163 namespace dbaui
164 {
165 
166 namespace DatabaseObject = css::sdb::application::DatabaseObject;
167 namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer;
168 
169 static void SafeAddPropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
170 {
171     Reference< XPropertySetInfo >  xInfo = xSet->getPropertySetInfo();
172     if (xInfo->hasPropertyByName(rPropName))
173         xSet->addPropertyChangeListener(rPropName, pListener);
174 }
175 
176 static void SafeRemovePropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
177 {
178     Reference< XPropertySetInfo >  xInfo = xSet->getPropertySetInfo();
179     if (xInfo->hasPropertyByName(rPropName))
180         xSet->removePropertyChangeListener(rPropName, pListener);
181 }
182 
183 OUString SAL_CALL SbaTableQueryBrowser::getImplementationName()
184 {
185     return getImplementationName_Static();
186 }
187 
188 css::uno::Sequence<OUString> SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames()
189 {
190     return getSupportedServiceNames_Static();
191 }
192 
193 OUString SbaTableQueryBrowser::getImplementationName_Static()
194 {
195     return OUString("org.openoffice.comp.dbu.ODatasourceBrowser");
196 }
197 
198 css::uno::Sequence<OUString> SbaTableQueryBrowser::getSupportedServiceNames_Static()
199 {
200     css::uno::Sequence<OUString> aSupported { "com.sun.star.sdb.DataSourceBrowser" };
201     return aSupported;
202 }
203 
204 Reference< XInterface > SbaTableQueryBrowser::Create(const Reference<XMultiServiceFactory >& _rxFactory)
205 {
206     SolarMutexGuard aGuard;
207     return *(new SbaTableQueryBrowser(comphelper::getComponentContext(_rxFactory)));
208 }
209 
210 SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM)
211     :SbaXDataBrowserController(_rM)
212     ,m_aSelectionListeners( getMutex() )
213     ,m_aContextMenuInterceptors( getMutex() )
214     ,m_aTableCopyHelper(this)
215     ,m_pTreeView(nullptr)
216     ,m_pSplitter(nullptr)
217     ,m_pCurrentlyDisplayed(nullptr)
218     ,m_nAsyncDrop(nullptr)
219     ,m_bQueryEscapeProcessing( false )
220     ,m_bShowMenu(false)
221     ,m_bInSuspend(false)
222     ,m_bEnableBrowser(true)
223 {
224 }
225 
226 SbaTableQueryBrowser::~SbaTableQueryBrowser()
227 {
228     if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
229     {
230         SAL_WARN("dbaccess.ui", "Please check who doesn't dispose this component!");
231         // increment ref count to prevent double call of Dtor
232         osl_atomic_increment( &m_refCount );
233         dispose();
234     }
235     SolarMutexGuard g;
236     m_pTreeView.reset();
237     m_pSplitter.reset();
238 }
239 
240 Any SAL_CALL SbaTableQueryBrowser::queryInterface(const Type& _rType)
241 {
242     if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) )
243     {
244         OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" );
245         if ( !!m_aDocScriptSupport && *m_aDocScriptSupport )
246             return makeAny( Reference< XScriptInvocationContext >( this ) );
247         return Any();
248     }
249 
250     Any aReturn = SbaXDataBrowserController::queryInterface(_rType);
251     if (!aReturn.hasValue())
252         aReturn = SbaTableQueryBrowser_Base::queryInterface(_rType);
253     return aReturn;
254 }
255 
256 Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes(  )
257 {
258     Sequence< Type > aTypes( ::comphelper::concatSequences(
259         SbaXDataBrowserController::getTypes(),
260         SbaTableQueryBrowser_Base::getTypes()
261     ) );
262 
263     OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" );
264     if ( !m_aDocScriptSupport || !*m_aDocScriptSupport )
265     {
266         auto newEnd = std::remove_if( aTypes.begin(), aTypes.end(),
267                                       [](const Type& type)
268                                       { return type == cppu::UnoType<XScriptInvocationContext>::get(); } );
269         aTypes.realloc( std::distance(aTypes.begin(), newEnd) );
270     }
271     return aTypes;
272 }
273 
274 Sequence< sal_Int8 > SAL_CALL SbaTableQueryBrowser::getImplementationId(  )
275 {
276     return css::uno::Sequence<sal_Int8>();
277 }
278 
279 void SAL_CALL SbaTableQueryBrowser::disposing()
280 {
281     SolarMutexGuard aGuard;
282         // doin' a lot of VCL stuff here -> lock the SolarMutex
283 
284     // kiss our listeners goodbye
285     css::lang::EventObject aEvt(*this);
286     m_aSelectionListeners.disposeAndClear(aEvt);
287     m_aContextMenuInterceptors.disposeAndClear(aEvt);
288 
289     if (getBrowserView())
290     {
291         // Need to do some cleaup of the data pointed to the tree view entries before we remove the treeview
292         clearTreeModel();
293         m_pTreeView = nullptr;
294         getBrowserView()->setTreeView(nullptr);
295     }
296 
297     // remove ourself as status listener
298     implRemoveStatusListeners();
299 
300     // remove the container listener from the database context
301     try
302     {
303         Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
304         xDatabaseRegistrations->removeDatabaseRegistrationsListener( this );
305     }
306     catch( const Exception& )
307     {
308         DBG_UNHANDLED_EXCEPTION("dbaccess");
309     }
310 
311     // check out from all the objects we are listening
312     // the frame
313     if (m_xCurrentFrameParent.is())
314         m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
315     SbaXDataBrowserController::disposing();
316 }
317 
318 bool SbaTableQueryBrowser::Construct(vcl::Window* pParent)
319 {
320     if ( !SbaXDataBrowserController::Construct( pParent ) )
321         return false;
322 
323     try
324     {
325         Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
326         xDatabaseRegistrations->addDatabaseRegistrationsListener( this );
327 
328         // the collator for the string compares
329         m_xCollator = Collator::create( getORB() );
330         m_xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
331     }
332     catch(const Exception&)
333     {
334         SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Construct: could not create (or start listening at) the database context!");
335     }
336     // some help ids
337     if (getBrowserView() && getBrowserView()->getVclControl())
338     {
339 
340         // create controls and set sizes
341         const long  nFrameWidth = getBrowserView()->LogicToPixel(::Size(3, 0), MapMode(MapUnit::MapAppFont)).Width();
342 
343         m_pSplitter = VclPtr<Splitter>::Create(getBrowserView(),WB_HSCROLL);
344         m_pSplitter->SetPosSizePixel( ::Point(0,0), ::Size(nFrameWidth,0) );
345         m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) );
346 
347         m_pTreeView = VclPtr<DBTreeView>::Create(getBrowserView(), WB_TABSTOP | WB_BORDER);
348         m_pTreeView->SetPreExpandHandler(LINK(this, SbaTableQueryBrowser, OnExpandEntry));
349 
350         m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry));
351 
352         m_pTreeView->getListBox().setContextMenuProvider( this );
353         m_pTreeView->getListBox().setControlActionListener( this );
354         m_pTreeView->SetHelpId(HID_CTL_TREEVIEW);
355 
356         // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide
357         m_pSplitter->SetSplitPosPixel(getBrowserView()->LogicToPixel(::Size(80, 0), MapMode(MapUnit::MapAppFont)).Width());
358 
359         getBrowserView()->setSplitter(m_pSplitter);
360         getBrowserView()->setTreeView(m_pTreeView);
361 
362         // fill view with data
363         auto pTreeModel = m_pTreeView->GetTreeModel();
364         pTreeModel->SetSortMode(SortAscending);
365         pTreeModel->SetCompareHdl(LINK(this, SbaTableQueryBrowser, OnTreeEntryCompare));
366         m_pTreeView->setSelChangeHdl( LINK( this, SbaTableQueryBrowser, OnSelectionChange ) );
367 
368         // TODO
369         getBrowserView()->getVclControl()->SetHelpId(HID_CTL_TABBROWSER);
370         if (getBrowserView()->getVclControl()->GetHeaderBar())
371             getBrowserView()->getVclControl()->GetHeaderBar()->SetHelpId(HID_DATABROWSE_HEADER);
372         InvalidateFeature(ID_BROWSER_EXPLORER);
373     }
374 
375     return true;
376 }
377 
378 namespace
379 {
380     struct SelectValueByName
381     {
382         const Any& operator()( OUString const& i_name ) const
383         {
384             return m_rCollection.get( i_name );
385         }
386 
387         explicit SelectValueByName( ::comphelper::NamedValueCollection const& i_collection )
388             :m_rCollection( i_collection )
389         {
390         }
391 
392         ::comphelper::NamedValueCollection const&   m_rCollection;
393     };
394 }
395 
396 void SbaTableQueryBrowser::impl_sanitizeRowSetClauses_nothrow()
397 {
398     try
399     {
400         Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW );
401         bool bEscapeProcessing = false;
402         OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
403         if ( !bEscapeProcessing )
404             // don't touch or interpret anything if escape processing is disabled
405             return;
406 
407         Reference< XSingleSelectQueryComposer > xComposer( createParser_nothrow() );
408         if ( !xComposer.is() )
409             // can't do anything. Already reported via assertion in createParser_nothrow.
410             return;
411 
412         // the tables participating in the statement
413         const Reference< XTablesSupplier > xSuppTables( xComposer, UNO_QUERY_THROW );
414         const Reference< XNameAccess > xTableNames( xSuppTables->getTables(), UNO_QUERY_THROW );
415 
416         // the columns participating in the statement
417         const Reference< XColumnsSupplier > xSuppColumns( xComposer, UNO_QUERY_THROW );
418         const Reference< XNameAccess > xColumnNames( xSuppColumns->getColumns(), UNO_QUERY_THROW );
419 
420         // check if the order columns apply to tables which really exist in the statement
421         const Reference< XIndexAccess > xOrderColumns( xComposer->getOrderColumns(), UNO_SET_THROW );
422         const sal_Int32 nOrderColumns( xOrderColumns->getCount() );
423         bool invalidColumn = nOrderColumns == 0;
424         for ( sal_Int32 c=0; ( c < nOrderColumns ) && !invalidColumn; ++c )
425         {
426             const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW );
427             OUString sTableName;
428             OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName );
429             OUString sColumnName;
430             OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName );
431 
432             if ( sTableName.isEmpty() )
433             {
434                 if ( !xColumnNames->hasByName( sColumnName ) )
435                 {
436                     invalidColumn = true;
437                     break;
438                 }
439             }
440             else
441             {
442                 if ( !xTableNames->hasByName( sTableName ) )
443                 {
444                     invalidColumn = true;
445                     break;
446                 }
447 
448                 const Reference< XColumnsSupplier > xSuppTableColumns( xTableNames->getByName( sTableName ), UNO_QUERY_THROW );
449                 const Reference< XNameAccess > xTableColumnNames( xSuppTableColumns->getColumns(), UNO_QUERY_THROW );
450                 if ( !xTableColumnNames->hasByName( sColumnName ) )
451                 {
452                     invalidColumn = true;
453                     break;
454                 }
455             }
456         }
457 
458         if ( invalidColumn )
459         {
460             // reset the complete order statement at both the row set and the parser
461             xRowSetProps->setPropertyValue( PROPERTY_ORDER, makeAny( OUString() ) );
462             xComposer->setOrder( "" );
463         }
464 
465         // check if the columns participating in the filter refer to existing tables
466         // TODO: there's no API at all for this. The method which comes nearest to what we need is
467         // "getStructuredFilter", but it returns pure column names only. That is, for a statement like
468         // "SELECT * FROM <table> WHERE <other_table>.<column> = <value>", it will return "<column>". But
469         // there's no API at all to retrieve the information about  "<other_table>" - which is what would
470         // be needed here.
471         // That'd be a chance to replace getStructuredFilter with something more reasonable.
472         // So, what really would be handy, is some
473         //   XNormalizedFilter getNormalizedFilter();
474         // with
475         //   interface XDisjunctiveFilterExpression
476         //   {
477         //     XConjunctiveFilterTerm getTerm( int index );
478         //   }
479         //   interface XConjunctiveFilterTerm
480         //   {
481         //     ComparisonPredicate getPredicate( int index );
482         //   }
483         //   struct ComparisonPredicate
484         //   {
485         //     XComparisonOperand   Lhs;
486         //     SQLFilterOperator    Operator;
487         //     XComparisonOperand   Rhs;
488         //   }
489         //   interface XComparisonOperand
490         //   {
491         //     SQLFilterOperand Type;
492         //     XPropertySet     getColumn();
493         //     string           getLiteral();
494         //     ...
495         //   }
496         //   enum SQLFilterOperand { Column, Literal, ... }
497         // ... or something like this ....
498     }
499     catch( const Exception& )
500     {
501         DBG_UNHANDLED_EXCEPTION("dbaccess");
502     }
503 }
504 
505 bool SbaTableQueryBrowser::InitializeForm( const Reference< XPropertySet > & i_formProperties )
506 {
507     if(!m_pCurrentlyDisplayed)
508         return true;
509 
510     // this method set all format settings from the original table or query
511     try
512     {
513         DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
514         ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" );
515         ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" );
516 
517         Reference< XPropertySetInfo > xPSI( pData->xObjectProperties->getPropertySetInfo(), UNO_SET_THROW );
518 
519         ::comphelper::NamedValueCollection aPropertyValues;
520 
521         const OUString aTransferProperties[] =
522         {
523             OUString(PROPERTY_APPLYFILTER),
524             OUString(PROPERTY_FILTER),
525             OUString(PROPERTY_HAVING_CLAUSE),
526             OUString(PROPERTY_ORDER)
527         };
528         for (const auto & aTransferPropertie : aTransferProperties)
529         {
530             if ( !xPSI->hasPropertyByName( aTransferPropertie ) )
531                 continue;
532             aPropertyValues.put( aTransferPropertie, pData->xObjectProperties->getPropertyValue( aTransferPropertie ) );
533         }
534 
535         std::vector< OUString > aNames( aPropertyValues.getNames() );
536         std::sort(aNames.begin(), aNames.end());
537         Sequence< OUString > aPropNames( comphelper::containerToSequence(aNames) );
538 
539         Sequence< Any > aPropValues( aNames.size() );
540         std::transform( aNames.begin(), aNames.end(), aPropValues.getArray(), SelectValueByName( aPropertyValues ) );
541 
542         Reference< XMultiPropertySet > xFormMultiSet( i_formProperties, UNO_QUERY_THROW );
543         xFormMultiSet->setPropertyValues( aPropNames, aPropValues );
544 
545         impl_sanitizeRowSetClauses_nothrow();
546     }
547     catch ( const Exception& )
548     {
549         DBG_UNHANDLED_EXCEPTION("dbaccess");
550         return false;
551     }
552 
553     return true;
554 }
555 
556 void SbaTableQueryBrowser::initializePreviewMode()
557 {
558     if ( getBrowserView() && getBrowserView()->getVclControl() )
559     {
560         getBrowserView()->getVclControl()->AlwaysEnableInput( false );
561         getBrowserView()->getVclControl()->EnableInput( false );
562         getBrowserView()->getVclControl()->ForceHideScrollbars();
563     }
564     Reference< XPropertySet >  xDataSourceSet(getRowSet(), UNO_QUERY);
565     if ( xDataSourceSet.is() )
566     {
567         xDataSourceSet->setPropertyValue("AllowInserts",makeAny(false));
568         xDataSourceSet->setPropertyValue("AllowUpdates",makeAny(false));
569         xDataSourceSet->setPropertyValue("AllowDeletes",makeAny(false));
570     }
571 }
572 
573 void SbaTableQueryBrowser::InitializeGridModel(const Reference< css::form::XFormComponent > & xGrid)
574 {
575     try
576     {
577         Reference< css::form::XGridColumnFactory >  xColFactory(xGrid, UNO_QUERY);
578         Reference< XNameContainer >  xColContainer(xGrid, UNO_QUERY);
579         clearGridColumns( xColContainer );
580 
581         Reference< XChild > xGridAsChild(xGrid, UNO_QUERY);
582         Reference< XLoadable > xFormAsLoadable;
583         if (xGridAsChild.is())
584             xFormAsLoadable.set(xGridAsChild->getParent(), css::uno::UNO_QUERY);
585         if (xFormAsLoadable.is() && xFormAsLoadable->isLoaded())
586         {
587             // set the formats from the table
588             if(m_pCurrentlyDisplayed)
589             {
590                 Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 ));
591                 Sequence< Any> aValues(7 + ( m_bPreview ? 5 : 0 ));
592 
593                 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
594                 OSL_ENSURE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeGridModel: No table available!" );
595                 if ( !pData->xObjectProperties.is() )
596                     return;
597 
598                 OUString* pStringIter = aProperties.getArray();
599                 Any* pValueIter = aValues.getArray();
600                 if ( m_bPreview )
601                 {
602                     *pStringIter++  = "AlwaysShowCursor";
603                     *pValueIter++   <<= false;
604                     *pStringIter++  = PROPERTY_BORDER;
605                     *pValueIter++   <<= sal_Int16(0);
606                 }
607 
608                 *pStringIter++  = PROPERTY_FONT;
609                 *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_FONT);
610                 *pStringIter++  = PROPERTY_TEXTEMPHASIS;
611                 *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTEMPHASIS);
612                 *pStringIter++  = PROPERTY_TEXTRELIEF;
613                 *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTRELIEF);
614                 if ( m_bPreview )
615                 {
616                     *pStringIter++  = "HasNavigationBar";
617                     *pValueIter++       <<= false;
618                     *pStringIter++  = "HasRecordMarker";
619                     *pValueIter++       <<= false;
620                 }
621                 *pStringIter++  = PROPERTY_ROW_HEIGHT;
622                 *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_ROW_HEIGHT);
623                 if ( m_bPreview )
624                 {
625                     *pStringIter++  = "Tabstop";
626                     *pValueIter++       <<= false;
627                 }
628                 *pStringIter++  = PROPERTY_TEXTCOLOR;
629                 *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTCOLOR);
630                 *pStringIter++  = PROPERTY_TEXTLINECOLOR;
631                 *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTLINECOLOR);
632 
633                 Reference< XMultiPropertySet >  xFormMultiSet(xGrid, UNO_QUERY);
634                 xFormMultiSet->setPropertyValues(aProperties, aValues);
635             }
636 
637             // get the formats supplier of the database we're working with
638             Reference< css::util::XNumberFormatsSupplier >  xSupplier = getNumberFormatter()->getNumberFormatsSupplier();
639 
640             Reference<XConnection> xConnection;
641             Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
642             xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
643             OSL_ENSURE(xConnection.is(),"A ActiveConnection should normally exists!");
644 
645             Reference<XChild> xChild(xConnection,UNO_QUERY);
646             Reference<XPropertySet> xDataSourceProp(xChild->getParent(),UNO_QUERY);
647             bool bSuppressVersionCol = false;
648             OSL_VERIFY( xDataSourceProp->getPropertyValue( PROPERTY_SUPPRESSVERSIONCL ) >>= bSuppressVersionCol );
649 
650             // insert the column into the gridcontrol so that we see something :-)
651             OUString aCurrentModelType;
652             Reference<XColumnsSupplier> xSupCols(getRowSet(),UNO_QUERY);
653             Reference<XNameAccess> xColumns     = xSupCols->getColumns();
654 
655             OUString sDefaultProperty;
656             Reference< XPropertySet > xColumn;
657             Reference< XPropertySetInfo > xColPSI;
658             for (const OUString& rName : xColumns->getElementNames())
659             {
660                 xColumn.set( xColumns->getByName( rName ), UNO_QUERY_THROW );
661                 xColPSI.set( xColumn->getPropertySetInfo(), UNO_SET_THROW );
662 
663                 // ignore the column when it is a rowversion one
664                 if  (   bSuppressVersionCol
665                     &&  xColPSI->hasPropertyByName( PROPERTY_ISROWVERSION )
666                     &&  ::cppu::any2bool( xColumn->getPropertyValue( PROPERTY_ISROWVERSION ) )
667                     )
668                     continue;
669 
670                 // use the result set column's type to determine the type of grid column to create
671                 bool bFormattedIsNumeric    = true;
672                 sal_Int32 nType = ::comphelper::getINT32( xColumn->getPropertyValue( PROPERTY_TYPE ) );
673 
674                 std::vector< NamedValue > aInitialValues;
675                 std::vector< OUString > aCopyProperties;
676                 Any aDefault;
677 
678                 switch(nType)
679                 {
680                     case DataType::BIT:
681                     case DataType::BOOLEAN:
682                     {
683                         aCurrentModelType = "CheckBox";
684                         aInitialValues.emplace_back( "VisualEffect", makeAny( VisualEffect::FLAT ) );
685                         sDefaultProperty = PROPERTY_DEFAULTSTATE;
686 
687                         sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
688                         OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
689                         aInitialValues.emplace_back(
690                             "TriState",
691                             makeAny( ColumnValue::NO_NULLS != nNullable )
692                         );
693                         if ( ColumnValue::NO_NULLS == nNullable )
694                             aDefault <<= sal_Int16(TRISTATE_FALSE);
695                     }
696                     break;
697 
698                     case DataType::LONGVARCHAR:
699                     case DataType::CLOB:
700                         aInitialValues.emplace_back( "MultiLine", makeAny( true ) );
701                         SAL_FALLTHROUGH;
702                     case DataType::BINARY:
703                     case DataType::VARBINARY:
704                     case DataType::LONGVARBINARY:
705                         aCurrentModelType = "TextField";
706                         sDefaultProperty = PROPERTY_DEFAULTTEXT;
707                         break;
708 
709                     case DataType::VARCHAR:
710                     case DataType::CHAR:
711                         bFormattedIsNumeric = false;
712                         SAL_FALLTHROUGH;
713                     default:
714                         aCurrentModelType = "FormattedField";
715                         sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT;
716 
717                         if ( xSupplier.is() )
718                             aInitialValues.emplace_back( "FormatsSupplier", makeAny( xSupplier ) );
719                         aInitialValues.emplace_back( "TreatAsNumber", makeAny( bFormattedIsNumeric ) );
720                         aCopyProperties.emplace_back(PROPERTY_FORMATKEY );
721                         break;
722                 }
723 
724                 aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, makeAny( rName ) );
725                 OUString sLabel;
726                 xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
727                 if ( !sLabel.isEmpty() )
728                     aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( sLabel ) );
729                 else
730                     aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( rName ) );
731 
732                 Reference< XPropertySet > xGridCol( xColFactory->createColumn( aCurrentModelType ), UNO_SET_THROW );
733                 Reference< XPropertySetInfo > xGridColPSI( xGridCol->getPropertySetInfo(), UNO_SET_THROW );
734 
735                 // calculate the default
736                 if ( xGridColPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) )
737                 {
738                     aDefault = xColumn->getPropertyValue( PROPERTY_CONTROLDEFAULT );
739                     // default value
740                     if ( nType == DataType::BIT || nType == DataType::BOOLEAN )
741                     {
742                         if ( aDefault.hasValue() )
743                             aDefault <<= (comphelper::getString(aDefault).toInt32() == 0) ? sal_Int16(TRISTATE_FALSE) : sal_Int16(TRISTATE_TRUE);
744                         else
745                             aDefault <<= sal_Int16(TRISTATE_INDET);
746                     }
747                 }
748 
749                 if ( aDefault.hasValue() )
750                     aInitialValues.emplace_back( sDefaultProperty, aDefault );
751 
752                 // transfer properties from the definition to the UNO-model :
753                 aCopyProperties.emplace_back(PROPERTY_HIDDEN );
754                 aCopyProperties.emplace_back(PROPERTY_WIDTH );
755 
756                 // help text to display for the column
757                 Any aDescription;
758                 if ( xColPSI->hasPropertyByName( PROPERTY_HELPTEXT ) )
759                     aDescription = xColumn->getPropertyValue( PROPERTY_HELPTEXT );
760                 OUString sTemp;
761                 aDescription >>= sTemp;
762                 if ( sTemp.isEmpty() )
763                     xColumn->getPropertyValue( PROPERTY_DESCRIPTION ) >>= sTemp;
764 
765                 aDescription <<= sTemp;
766                 aInitialValues.emplace_back( PROPERTY_HELPTEXT, aDescription );
767 
768                 // ... horizontal justify
769                 Any aAlign; aAlign <<= sal_Int16( 0 );
770                 Any aColAlign( xColumn->getPropertyValue( PROPERTY_ALIGN ) );
771                 if ( aColAlign.hasValue() )
772                     aAlign <<= sal_Int16( ::comphelper::getINT32( aColAlign ) );
773                 aInitialValues.emplace_back( PROPERTY_ALIGN, aAlign );
774 
775                 // don't allow the mouse to scroll in the cells
776                 if ( xGridColPSI->hasPropertyByName( PROPERTY_MOUSE_WHEEL_BEHAVIOR ) )
777                     aInitialValues.emplace_back( PROPERTY_MOUSE_WHEEL_BEHAVIOR, makeAny( MouseWheelBehavior::SCROLL_DISABLED ) );
778 
779                 // now set all those values
780                 for (auto const& property : aInitialValues)
781                 {
782                     xGridCol->setPropertyValue( property.Name, property.Value );
783                 }
784                 for (auto const& copyPropertyName : aCopyProperties)
785                     xGridCol->setPropertyValue( copyPropertyName, xColumn->getPropertyValue(copyPropertyName) );
786 
787                 xColContainer->insertByName(rName, makeAny(xGridCol));
788             }
789         }
790     }
791     catch(const Exception&)
792     {
793         DBG_UNHANDLED_EXCEPTION("dbaccess");
794     }
795 }
796 
797 static Reference<XPropertySet> getColumnHelper(SvTreeListEntry const * _pCurrentlyDisplayed, const Reference<XPropertySet>& _rxSource)
798 {
799     Reference<XPropertySet> xRet;
800     if(_pCurrentlyDisplayed)
801     {
802         DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pCurrentlyDisplayed->GetUserData());
803         Reference<XColumnsSupplier> xColumnsSup(pData->xObjectProperties,UNO_QUERY);
804         Reference<XNameAccess> xNames = xColumnsSup->getColumns();
805         OUString aName;
806         _rxSource->getPropertyValue(PROPERTY_NAME) >>= aName;
807         if(xNames.is() && xNames->hasByName(aName))
808             xRet.set(xNames->getByName(aName),UNO_QUERY);
809     }
810     return xRet;
811 }
812 
813 void SbaTableQueryBrowser::transferChangedControlProperty(const OUString& _rProperty, const Any& _rNewValue)
814 {
815     if(m_pCurrentlyDisplayed)
816     {
817         DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
818         Reference< XPropertySet > xObjectProps(pData->xObjectProperties, UNO_QUERY);
819         OSL_ENSURE(xObjectProps.is(),"SbaTableQueryBrowser::transferChangedControlProperty: no table/query object!");
820         if (xObjectProps.is())
821             xObjectProps->setPropertyValue(_rProperty, _rNewValue);
822     }
823 }
824 
825 void SbaTableQueryBrowser::propertyChange(const PropertyChangeEvent& evt)
826 {
827     SbaXDataBrowserController::propertyChange(evt);
828 
829     try
830     {
831         Reference< XPropertySet >  xSource(evt.Source, UNO_QUERY);
832         if (!xSource.is())
833             return;
834 
835         // one of the many properties which require us to update the definition ?
836         // a column's width ?
837         else if (evt.PropertyName == PROPERTY_WIDTH)
838         {   // a column width has changed -> update the model
839             // (the update of the view is done elsewhere)
840             Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource);
841             if(xProp.is())
842             {
843                 if(!evt.NewValue.hasValue())
844                     xProp->setPropertyValue(PROPERTY_WIDTH,makeAny(sal_Int32(227)));
845                 else
846                     xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue);
847             }
848         }
849 
850         // a column's 'visible' state ?
851         else if (evt.PropertyName == PROPERTY_HIDDEN)
852         {
853             Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource);
854             if(xProp.is())
855                 xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue);
856         }
857 
858         // a columns alignment ?
859         else if (evt.PropertyName == PROPERTY_ALIGN)
860         {
861             Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource);
862             try
863             {
864                 if(xProp.is())
865                 {
866                     if(evt.NewValue.hasValue())
867                     {
868                         sal_Int16 nAlign = 0;
869                         if(evt.NewValue >>= nAlign)
870                             xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(sal_Int32(nAlign)));
871                         else
872                             xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue);
873                     }
874                     else
875                         xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(css::awt::TextAlign::LEFT));
876                 }
877             }
878             catch( const Exception& )
879             {
880                 DBG_UNHANDLED_EXCEPTION("dbaccess");
881             }
882         }
883 
884         // a column's format ?
885         else if (   evt.PropertyName == PROPERTY_FORMATKEY
886             &&  (TypeClass_LONG == evt.NewValue.getValueTypeClass())
887             )
888         {
889             // update the model (means the definition object)
890             Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource);
891             if(xProp.is())
892                 xProp->setPropertyValue(PROPERTY_FORMATKEY,evt.NewValue);
893         }
894 
895         // some table definition properties ?
896         // the height of the rows in the grid ?
897         else if (evt.PropertyName == PROPERTY_ROW_HEIGHT)
898         {
899             if(m_pCurrentlyDisplayed)
900             {
901                 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
902                 OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" );
903 
904                 bool bDefault = !evt.NewValue.hasValue();
905                 if (bDefault)
906                     pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,makeAny(sal_Int32(45)));
907                 else
908                     pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,evt.NewValue);
909             }
910         }
911 
912         else if (   evt.PropertyName == PROPERTY_FONT          // the font ?
913                 ||  evt.PropertyName == PROPERTY_TEXTCOLOR     // the text color ?
914                 ||  evt.PropertyName == PROPERTY_FILTER        // the filter ?
915                 ||  evt.PropertyName == PROPERTY_HAVING_CLAUSE // the having clause ?
916                 ||  evt.PropertyName == PROPERTY_ORDER         // the sort ?
917                 ||  evt.PropertyName == PROPERTY_APPLYFILTER   // the appliance of the filter ?
918                 ||  evt.PropertyName == PROPERTY_TEXTLINECOLOR // the text line color ?
919                 ||  evt.PropertyName == PROPERTY_TEXTEMPHASIS  // the text emphasis ?
920                 ||  evt.PropertyName == PROPERTY_TEXTRELIEF    // the text relief ?
921                 )
922         {
923             transferChangedControlProperty(evt.PropertyName, evt.NewValue);
924         }
925     }
926     catch( const Exception& )
927     {
928         DBG_UNHANDLED_EXCEPTION("dbaccess");
929     }
930 }
931 
932 sal_Bool SbaTableQueryBrowser::suspend(sal_Bool bSuspend)
933 {
934     SolarMutexGuard aSolarGuard;
935     ::osl::MutexGuard aGuard( getMutex() );
936     if ( getView() && getView()->IsInModalMode() )
937         return false;
938     bool bRet = false;
939     if ( !m_bInSuspend )
940     {
941         m_bInSuspend = true;
942         if ( rBHelper.bDisposed )
943             throw DisposedException( OUString(), *this );
944 
945         bRet = SbaXDataBrowserController::suspend(bSuspend);
946         if ( bRet && getView() )
947             getView()->Hide();
948 
949         m_bInSuspend = false;
950     }
951 
952     return bRet;
953 }
954 
955 void SAL_CALL SbaTableQueryBrowser::statusChanged( const FeatureStateEvent& _rEvent )
956 {
957     // search the external dispatcher causing this call
958     Reference< XDispatch > xSource(_rEvent.Source, UNO_QUERY);
959     bool bFound = false;
960     for (auto & externalFeature : m_aExternalFeatures)
961     {
962         if ( _rEvent.FeatureURL.Complete == externalFeature.second.aURL.Complete)
963         {
964             bFound = true;
965             OSL_ENSURE( xSource.get() == externalFeature.second.xDispatcher.get(), "SbaTableQueryBrowser::statusChanged: inconsistent!" );
966             // update the enabled state
967             externalFeature.second.bEnabled = _rEvent.IsEnabled;
968 
969             switch ( externalFeature.first )
970             {
971                 case ID_BROWSER_DOCUMENT_DATASOURCE:
972                 {
973                     // if it's the slot for the document data source, remember the state
974                     Sequence< PropertyValue > aDescriptor;
975                     bool bProperFormat = _rEvent.State >>= aDescriptor;
976                     OSL_ENSURE(bProperFormat, "SbaTableQueryBrowser::statusChanged: need a data access descriptor here!");
977                     m_aDocumentDataSource.initializeFrom(aDescriptor);
978 
979                     OSL_ENSURE( (   m_aDocumentDataSource.has(DataAccessDescriptorProperty::DataSource)
980                                 ||  m_aDocumentDataSource.has(DataAccessDescriptorProperty::DatabaseLocation)
981                                 )
982                                 &&  m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command)
983                                 &&  m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType),
984                         "SbaTableQueryBrowser::statusChanged: incomplete descriptor!");
985 
986                     // check if we know the object which is set as document data source
987                     checkDocumentDataSource();
988                 }
989                 break;
990 
991                 default:
992                     // update the toolbox
993                     implCheckExternalSlot( externalFeature.first );
994                     break;
995             }
996             break;
997         }
998     }
999 
1000     OSL_ENSURE(bFound, "SbaTableQueryBrowser::statusChanged: don't know who sent this!");
1001 }
1002 
1003 void SbaTableQueryBrowser::checkDocumentDataSource()
1004 {
1005     SvTreeListEntry* pDataSourceEntry = nullptr;
1006     SvTreeListEntry* pContainerEntry = nullptr;
1007     SvTreeListEntry* pObjectEntry = getObjectEntry( m_aDocumentDataSource, &pDataSourceEntry, &pContainerEntry );
1008     bool bKnownDocDataSource = (nullptr != pObjectEntry);
1009     if (!bKnownDocDataSource)
1010     {
1011         if (nullptr != pDataSourceEntry)
1012         {   // at least the data source is known
1013             if (nullptr != pContainerEntry)
1014                 bKnownDocDataSource = true; // assume we know it.
1015                 // TODO: should we expand the object container? This may be too expensive just for checking ....
1016             else
1017             {
1018                 if ((nullptr == pObjectEntry) && m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType) && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command))
1019                 {   // maybe we have a command to be displayed ?
1020                     sal_Int32 nCommandType = CommandType::TABLE;
1021                     m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
1022 
1023                     OUString sCommand;
1024                     m_aDocumentDataSource[DataAccessDescriptorProperty::Command] >>= sCommand;
1025 
1026                     bKnownDocDataSource = (CommandType::COMMAND == nCommandType) && (!sCommand.isEmpty());
1027                 }
1028             }
1029         }
1030     }
1031 
1032     if ( !bKnownDocDataSource )
1033         m_aExternalFeatures[ ID_BROWSER_DOCUMENT_DATASOURCE ].bEnabled = false;
1034 
1035     // update the toolbox
1036     implCheckExternalSlot(ID_BROWSER_DOCUMENT_DATASOURCE);
1037 }
1038 
1039 void SbaTableQueryBrowser::extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor, OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing)
1040 {
1041     _rDataSource = _rDescriptor.getDataSource();
1042     if ( _rDescriptor.has(DataAccessDescriptorProperty::Command) )
1043         _rDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand;
1044     if ( _rDescriptor.has(DataAccessDescriptorProperty::CommandType) )
1045         _rDescriptor[DataAccessDescriptorProperty::CommandType] >>= _rCommandType;
1046 
1047     // escape processing is the only one allowed not to be present
1048     _rEscapeProcessing = true;
1049     if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing))
1050         _rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]);
1051 }
1052 
1053 namespace
1054 {
1055     bool getDataSourceDisplayName_isURL( const OUString& _rDS, OUString& _rDisplayName, OUString& _rUniqueId )
1056     {
1057         INetURLObject aURL( _rDS );
1058         if ( aURL.GetProtocol() != INetProtocol::NotValid )
1059         {
1060             _rDisplayName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
1061             _rUniqueId = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1062             return true;
1063         }
1064         _rDisplayName = _rDS;
1065         _rUniqueId.clear();
1066         return false;
1067     }
1068 
1069     struct FilterByEntryDataId : public IEntryFilter
1070     {
1071         OUString sId;
1072         explicit FilterByEntryDataId( const OUString& _rId ) : sId( _rId ) { }
1073 
1074         virtual ~FilterByEntryDataId() {}
1075 
1076         virtual bool    includeEntry( SvTreeListEntry* _pEntry ) const override;
1077     };
1078 
1079     bool FilterByEntryDataId::includeEntry( SvTreeListEntry* _pEntry ) const
1080     {
1081         DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( _pEntry->GetUserData() );
1082         return ( !pData || ( pData->sAccessor == sId ) );
1083     }
1084 }
1085 
1086 OUString SbaTableQueryBrowser::getDataSourceAccessor( SvTreeListEntry* _pDataSourceEntry ) const
1087 {
1088     OSL_ENSURE( _pDataSourceEntry, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry!" );
1089 
1090     DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( _pDataSourceEntry->GetUserData() );
1091     OSL_ENSURE( pData, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry data!" );
1092     OSL_ENSURE( pData->eType == etDatasource, "SbaTableQueryBrowser::getDataSourceAccessor: entry does not denote a data source!" );
1093     return !pData->sAccessor.isEmpty() ? pData->sAccessor : GetEntryText( _pDataSourceEntry );
1094 }
1095 
1096 SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 _nCommandType,
1097         SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _ppContainerEntry, bool _bExpandAncestors,
1098         const SharedConnection& _rxConnection )
1099 {
1100     if (_ppDataSourceEntry)
1101         *_ppDataSourceEntry = nullptr;
1102     if (_ppContainerEntry)
1103         *_ppContainerEntry = nullptr;
1104 
1105     SvTreeListEntry* pObject = nullptr;
1106     if ( m_pTreeView )
1107     {
1108         // look for the data source entry
1109         OUString sDisplayName, sDataSourceId;
1110         bool bIsDataSourceURL = getDataSourceDisplayName_isURL( _rDataSource, sDisplayName, sDataSourceId );
1111             // the display name may differ from the URL for readability reasons
1112             // #i33699#
1113 
1114         FilterByEntryDataId aFilter( sDataSourceId );
1115         SvTreeListEntry* pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter );
1116         if ( !pDataSource ) // check if the data source name is a file location
1117         {
1118             if ( bIsDataSourceURL )
1119             {
1120                 // special case, the data source is a URL
1121                 // add new entries to the list box model
1122                 implAddDatasource( _rDataSource, _rxConnection );
1123                 pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter );
1124                 OSL_ENSURE( pDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" );
1125             }
1126         }
1127         if (_ppDataSourceEntry)
1128             // (caller wants to have it ...)
1129             *_ppDataSourceEntry = pDataSource;
1130 
1131         if (pDataSource)
1132         {
1133             // expand if required so
1134             if (_bExpandAncestors)
1135                 m_pTreeView->getListBox().Expand(pDataSource);
1136 
1137             // look for the object container
1138             SvTreeListEntry* pCommandType = nullptr;
1139             switch (_nCommandType)
1140             {
1141                 case CommandType::TABLE:
1142                     pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_TABLES);
1143                     break;
1144 
1145                 case CommandType::QUERY:
1146                     pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_QUERIES);
1147                     break;
1148             }
1149 
1150             if (_ppContainerEntry)
1151                 *_ppContainerEntry = pCommandType;
1152 
1153             if (pCommandType)
1154             {
1155                 // expand if required so
1156                 if (_bExpandAncestors)
1157                 {
1158                     m_pTreeView->getListBox().Expand(pCommandType);
1159                 }
1160 
1161                 // look for the object
1162                 sal_Int32 nIndex = 0;
1163                 do
1164                 {
1165                     OUString sPath;
1166                     switch (_nCommandType)
1167                     {
1168                     case CommandType::TABLE:
1169                         sPath = _rCommand;
1170                         nIndex = -1;
1171                         break;
1172 
1173                     case CommandType::QUERY:
1174                         sPath = _rCommand.getToken( 0, '/', nIndex );
1175                         break;
1176 
1177                     default:
1178                         assert(false);
1179                     }
1180                     pObject = m_pTreeView->getListBox().GetEntryPosByName(sPath, pCommandType);
1181                     pCommandType = pObject;
1182                     if ( nIndex >= 0 )
1183                     {
1184                         if (ensureEntryObject(pObject))
1185                         {
1186                             DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( pObject->GetUserData() );
1187                             Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
1188                             sal_Int32 nIndex2 = nIndex;
1189                             sPath = _rCommand.getToken( 0, '/', nIndex2 );
1190                             try
1191                             {
1192                                 if ( xCollection->hasByName(sPath) )
1193                                 {
1194                                     if(!m_pTreeView->getListBox().GetEntryPosByName(sPath,pObject))
1195                                     {
1196                                         Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY);
1197                                         DBTreeListUserData* pEntryData = new DBTreeListUserData;
1198                                         pEntryData->eType = etQuery;
1199                                         if ( xChild.is() )
1200                                         {
1201                                             pEntryData->eType = etQueryContainer;
1202                                         }
1203                                         implAppendEntry( pObject, sPath, pEntryData, pEntryData->eType );
1204                                     }
1205                                 }
1206                             }
1207                             catch(const Exception&)
1208                             {
1209                                 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
1210                             }
1211                         }
1212                     }
1213                 }
1214                 while ( nIndex >= 0 );
1215             }
1216         }
1217     }
1218     return pObject;
1219 }
1220 
1221 SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& _rDescriptor,
1222         SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _ppContainerEntry)
1223 {
1224     // extract the props from the descriptor
1225     OUString sDataSource;
1226     OUString sCommand;
1227     sal_Int32 nCommandType = CommandType::COMMAND;
1228     bool bEscapeProcessing = true;
1229     extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);
1230 
1231     return getObjectEntry( sDataSource, sCommand, nCommandType, _ppDataSourceEntry, _ppContainerEntry, false/*_bExpandAncestors*/ );
1232 }
1233 
1234 void SbaTableQueryBrowser::connectExternalDispatches()
1235 {
1236     Reference< XDispatchProvider >  xProvider( getFrame(), UNO_QUERY );
1237     OSL_ENSURE(xProvider.is(), "SbaTableQueryBrowser::connectExternalDispatches: no DispatchProvider !");
1238     if (xProvider.is())
1239     {
1240         if ( m_aExternalFeatures.empty() )
1241         {
1242             const sal_Char* pURLs[] = {
1243                 ".uno:DataSourceBrowser/DocumentDataSource",
1244                 ".uno:DataSourceBrowser/FormLetter",
1245                 ".uno:DataSourceBrowser/InsertColumns",
1246                 ".uno:DataSourceBrowser/InsertContent",
1247             };
1248             const sal_uInt16 nIds[] = {
1249                 ID_BROWSER_DOCUMENT_DATASOURCE,
1250                 ID_BROWSER_FORMLETTER,
1251                 ID_BROWSER_INSERTCOLUMNS,
1252                 ID_BROWSER_INSERTCONTENT
1253             };
1254 
1255             for ( size_t i=0; i < SAL_N_ELEMENTS( pURLs ); ++i )
1256             {
1257                 URL aURL;
1258                 aURL.Complete = OUString::createFromAscii( pURLs[i] );
1259                 if ( m_xUrlTransformer.is() )
1260                     m_xUrlTransformer->parseStrict( aURL );
1261                 m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( aURL );
1262             }
1263         }
1264 
1265         for (auto & externalFeature : m_aExternalFeatures)
1266         {
1267             externalFeature.second.xDispatcher = xProvider->queryDispatch(
1268                 externalFeature.second.aURL, "_parent", FrameSearchFlag::PARENT
1269             );
1270 
1271             if ( externalFeature.second.xDispatcher.get() == static_cast< XDispatch* >( this ) )
1272             {
1273                 SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::connectExternalDispatches: this should not happen anymore!" );
1274                     // (nowadays, the URLs aren't in our SupportedFeatures list anymore, so we should
1275                     // not supply a dispatcher for this)
1276                 externalFeature.second.xDispatcher.clear();
1277             }
1278 
1279             if ( externalFeature.second.xDispatcher.is() )
1280             {
1281                 try
1282                 {
1283                     externalFeature.second.xDispatcher->addStatusListener( this, externalFeature.second.aURL );
1284                 }
1285                 catch( const Exception& )
1286                 {
1287                     DBG_UNHANDLED_EXCEPTION("dbaccess");
1288                 }
1289             }
1290 
1291             implCheckExternalSlot( externalFeature.first );
1292         }
1293     }
1294 }
1295 
1296 void SbaTableQueryBrowser::implCheckExternalSlot( sal_uInt16 _nId )
1297 {
1298     if ( !m_xMainToolbar.is() )
1299         return;
1300 
1301     VclPtr<vcl::Window> pToolboxWindow = VCLUnoHelper::GetWindow( m_xMainToolbar );
1302     ToolBox* pToolbox = dynamic_cast< ToolBox* >( pToolboxWindow.get() );
1303     OSL_ENSURE( pToolbox, "SbaTableQueryBrowser::implCheckExternalSlot: cannot obtain the toolbox window!" );
1304 
1305     // check if we have to hide this item from the toolbox
1306     if ( pToolbox )
1307     {
1308         bool bHaveDispatcher = m_aExternalFeatures[ _nId ].xDispatcher.is();
1309         if ( bHaveDispatcher != pToolbox->IsItemVisible( _nId ) )
1310             bHaveDispatcher ? pToolbox->ShowItem( _nId ) : pToolbox->HideItem( _nId );
1311     }
1312 
1313     // and invalidate this feature in general
1314     InvalidateFeature( _nId );
1315 }
1316 
1317 void SAL_CALL SbaTableQueryBrowser::disposing( const css::lang::EventObject& _rSource )
1318 {
1319     // our frame ?
1320     Reference< css::frame::XFrame >  xSourceFrame(_rSource.Source, UNO_QUERY);
1321     if (m_xCurrentFrameParent.is() && (xSourceFrame == m_xCurrentFrameParent))
1322         m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
1323     else
1324     {
1325         // search the external dispatcher causing this call in our map
1326         Reference< XDispatch > xSource(_rSource.Source, UNO_QUERY);
1327         if(xSource.is())
1328         {
1329             ExternalFeaturesMap::const_iterator aLoop = m_aExternalFeatures.begin();
1330             ExternalFeaturesMap::const_iterator aEnd = m_aExternalFeatures.end();
1331             while (aLoop != aEnd)
1332             {
1333                 if ( aLoop->second.xDispatcher.get() == xSource.get() )
1334                 {
1335                     sal_uInt16 nSlot = aLoop->first;
1336 
1337                     // remove it
1338                     aLoop = m_aExternalFeatures.erase(aLoop);
1339 
1340                     // maybe update the UI
1341                     implCheckExternalSlot(nSlot);
1342 
1343                     // continue, the same XDispatch may be responsible for more than one URL
1344                 }
1345                 ++aLoop;
1346             }
1347         }
1348         else
1349         {
1350             Reference<XConnection> xCon(_rSource.Source, UNO_QUERY);
1351             if ( xCon.is() && m_pTreeView )
1352             {   // our connection is in dispose so we have to find the entry equal with this connection
1353                 // and close it what means to collapse the entry
1354                 // get the top-level representing the removed data source
1355                 SvTreeListEntry* pDSLoop = m_pTreeView->getListBox().FirstChild(nullptr);
1356                 while (pDSLoop)
1357                 {
1358                     DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pDSLoop->GetUserData());
1359                     if ( pData && pData->xConnection == xCon )
1360                     {
1361                         // we set the connection to null to avoid a second disposing of the connection
1362                         pData->xConnection.clear();
1363                         closeConnection(pDSLoop,false);
1364                         break;
1365                     }
1366 
1367                     pDSLoop = pDSLoop->NextSibling();
1368                 }
1369             }
1370             else
1371                 SbaXDataBrowserController::disposing(_rSource);
1372         }
1373     }
1374 }
1375 
1376 void SbaTableQueryBrowser::implRemoveStatusListeners()
1377 {
1378     // clear all old dispatches
1379     for (auto const& externalFeature : m_aExternalFeatures)
1380     {
1381         if ( externalFeature.second.xDispatcher.is() )
1382         {
1383             try
1384             {
1385                 externalFeature.second.xDispatcher->removeStatusListener( this, externalFeature.second.aURL );
1386             }
1387             catch (Exception&)
1388             {
1389                 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implRemoveStatusListeners: could not remove a status listener!");
1390             }
1391         }
1392     }
1393     m_aExternalFeatures.clear();
1394 }
1395 
1396 sal_Bool SAL_CALL SbaTableQueryBrowser::select( const Any& _rSelection )
1397 {
1398     SolarMutexGuard aGuard;
1399         // doin' a lot of VCL stuff here -> lock the SolarMutex
1400 
1401     Sequence< PropertyValue > aDescriptorSequence;
1402     if (!(_rSelection >>= aDescriptorSequence))
1403         throw IllegalArgumentException(OUString(), *this, 1);
1404         // TODO: error message
1405 
1406     ODataAccessDescriptor aDescriptor;
1407     try
1408     {
1409         aDescriptor = ODataAccessDescriptor(aDescriptorSequence);
1410     }
1411     catch(const Exception&)
1412     {
1413         SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::select: could not extract the descriptor!");
1414     }
1415 
1416     // check the presence of the props we need
1417     if ( !(aDescriptor.has(DataAccessDescriptorProperty::DataSource) || aDescriptor.has(DataAccessDescriptorProperty::DatabaseLocation)) || !aDescriptor.has(DataAccessDescriptorProperty::Command) || !aDescriptor.has(DataAccessDescriptorProperty::CommandType))
1418         throw IllegalArgumentException(OUString(), *this, 1);
1419         // TODO: error message
1420 
1421     return implSelect(aDescriptor,true);
1422 }
1423 
1424 Any SAL_CALL SbaTableQueryBrowser::getSelection(  )
1425 {
1426     Any aReturn;
1427 
1428     try
1429     {
1430         Reference< XLoadable > xLoadable(getRowSet(), UNO_QUERY);
1431         if (xLoadable.is() && xLoadable->isLoaded())
1432         {
1433             Reference< XPropertySet > aFormProps(getRowSet(), UNO_QUERY);
1434             ODataAccessDescriptor aDescriptor(aFormProps);
1435             // remove properties which are not part of our "selection"
1436             aDescriptor.erase(DataAccessDescriptorProperty::Connection);
1437             aDescriptor.erase(DataAccessDescriptorProperty::Cursor);
1438 
1439             aReturn <<= aDescriptor.createPropertyValueSequence();
1440         }
1441     }
1442     catch( const Exception& )
1443     {
1444         DBG_UNHANDLED_EXCEPTION("dbaccess");
1445     }
1446 
1447     return aReturn;
1448 }
1449 
1450 void SAL_CALL SbaTableQueryBrowser::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
1451 {
1452     m_aSelectionListeners.addInterface(_rxListener);
1453 }
1454 
1455 void SAL_CALL SbaTableQueryBrowser::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
1456 {
1457     m_aSelectionListeners.removeInterface(_rxListener);
1458 }
1459 
1460 void SbaTableQueryBrowser::attachFrame(const Reference< css::frame::XFrame > & _xFrame)
1461 {
1462     implRemoveStatusListeners();
1463 
1464     if (m_xCurrentFrameParent.is())
1465         m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
1466 
1467     SbaXDataBrowserController::attachFrame(_xFrame);
1468 
1469     Reference< XFrame > xCurrentFrame( getFrame() );
1470     if ( xCurrentFrame.is() )
1471     {
1472         m_xCurrentFrameParent = xCurrentFrame->findFrame("_parent",FrameSearchFlag::PARENT);
1473         if ( m_xCurrentFrameParent.is() )
1474             m_xCurrentFrameParent->addFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
1475 
1476         // obtain our toolbox
1477         try
1478         {
1479             Reference< XPropertySet > xFrameProps( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW );
1480             Reference< XLayoutManager > xLayouter(
1481                 xFrameProps->getPropertyValue("LayoutManager"),
1482                 UNO_QUERY );
1483 
1484             if ( xLayouter.is() )
1485             {
1486                 Reference< XUIElement > xUI(
1487                     xLayouter->getElement( "private:resource/toolbar/toolbar" ),
1488                     UNO_SET_THROW );
1489                 m_xMainToolbar.set(xUI->getRealInterface(), css::uno::UNO_QUERY);
1490                 OSL_ENSURE( m_xMainToolbar.is(), "SbaTableQueryBrowser::attachFrame: where's my toolbox?" );
1491             }
1492         }
1493         catch( const Exception& )
1494         {
1495             DBG_UNHANDLED_EXCEPTION("dbaccess");
1496         }
1497     }
1498 
1499     // get the dispatchers for the external slots
1500     connectExternalDispatches();
1501 }
1502 
1503 void SbaTableQueryBrowser::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
1504 {
1505     SbaXDataBrowserController::addModelListeners(_xGridControlModel);
1506     Reference< XPropertySet >  xSourceSet(_xGridControlModel, UNO_QUERY);
1507     if (xSourceSet.is())
1508     {
1509         xSourceSet->addPropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
1510         xSourceSet->addPropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
1511         xSourceSet->addPropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
1512         xSourceSet->addPropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
1513         xSourceSet->addPropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
1514         xSourceSet->addPropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
1515     }
1516 
1517 }
1518 
1519 void SbaTableQueryBrowser::removeModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
1520 {
1521     SbaXDataBrowserController::removeModelListeners(_xGridControlModel);
1522     Reference< XPropertySet >  xSourceSet(_xGridControlModel, UNO_QUERY);
1523     if (xSourceSet.is())
1524     {
1525         xSourceSet->removePropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
1526         xSourceSet->removePropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
1527         xSourceSet->removePropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
1528         xSourceSet->removePropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
1529         xSourceSet->removePropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
1530         xSourceSet->removePropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
1531     }
1532 }
1533 
1534 void SbaTableQueryBrowser::RowChanged()
1535 {
1536     if(getBrowserView())
1537     {
1538         SbaGridControl* pControl = getBrowserView()->getVclControl();
1539         if (!pControl->IsEditing())
1540             InvalidateFeature(ID_BROWSER_COPY);
1541     }
1542     SbaXDataBrowserController::RowChanged();
1543 }
1544 
1545 void SbaTableQueryBrowser::ColumnChanged()
1546 {
1547     if(getBrowserView())
1548     {
1549         SbaGridControl* pControl = getBrowserView()->getVclControl();
1550         if (!pControl->IsEditing())
1551             InvalidateFeature(ID_BROWSER_COPY);
1552     }
1553     SbaXDataBrowserController::ColumnChanged();
1554 }
1555 
1556 void SbaTableQueryBrowser::AddColumnListener(const Reference< XPropertySet > & xCol)
1557 {
1558     SbaXDataBrowserController::AddColumnListener(xCol);
1559     SafeAddPropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
1560     SafeAddPropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
1561     SafeAddPropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
1562     SafeAddPropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
1563 }
1564 
1565 void SbaTableQueryBrowser::RemoveColumnListener(const Reference< XPropertySet > & xCol)
1566 {
1567     SbaXDataBrowserController::RemoveColumnListener(xCol);
1568     SafeRemovePropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
1569     SafeRemovePropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
1570     SafeRemovePropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
1571     SafeRemovePropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
1572 }
1573 
1574 void SbaTableQueryBrowser::criticalFail()
1575 {
1576     SbaXDataBrowserController::criticalFail();
1577     unloadAndCleanup( false );
1578 }
1579 
1580 void SbaTableQueryBrowser::LoadFinished(bool _bWasSynch)
1581 {
1582     SbaXDataBrowserController::LoadFinished(_bWasSynch);
1583 
1584     m_sQueryCommand.clear();
1585     m_bQueryEscapeProcessing = false;
1586 
1587     if (isValid() && !loadingCancelled())
1588     {
1589         // did we load a query?
1590         bool bTemporary;    // needed because we m_bQueryEscapeProcessing is only one bit wide (and we want to pass it by reference)
1591         if ( implGetQuerySignature( m_sQueryCommand, bTemporary ) )
1592             m_bQueryEscapeProcessing = bTemporary;
1593     }
1594 
1595     // if the form has been loaded, this means that our "selection" has changed
1596     css::lang::EventObject aEvent( *this );
1597     m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent );
1598 }
1599 
1600 bool SbaTableQueryBrowser::getExternalSlotState( sal_uInt16 _nId ) const
1601 {
1602     bool bEnabled = false;
1603     ExternalFeaturesMap::const_iterator aPos = m_aExternalFeatures.find( _nId );
1604     if ( ( m_aExternalFeatures.end() != aPos ) && aPos->second.xDispatcher.is() )
1605         bEnabled = aPos->second.bEnabled;
1606     return bEnabled;
1607 }
1608 
1609 FeatureState SbaTableQueryBrowser::GetState(sal_uInt16 nId) const
1610 {
1611     FeatureState aReturn;
1612         // (disabled automatically)
1613 
1614     // no chance without a view
1615     if (!getBrowserView() || !getBrowserView()->getVclControl())
1616         return aReturn;
1617 
1618     switch ( nId )
1619     {
1620         case ID_TREE_ADMINISTRATE:
1621             aReturn.bEnabled = true;
1622             return aReturn;
1623 
1624         case ID_BROWSER_CLOSE:
1625             // the close button should always be enabled
1626             aReturn.bEnabled = !m_bEnableBrowser;
1627             return aReturn;
1628 
1629             // "toggle explorer" is always enabled (if we have a explorer)
1630         case ID_BROWSER_EXPLORER:
1631             aReturn.bEnabled = m_bEnableBrowser;
1632             aReturn.bChecked = haveExplorer();
1633             return aReturn;
1634 
1635         case ID_BROWSER_REMOVEFILTER:
1636             return SbaXDataBrowserController::GetState( nId );
1637 
1638         case ID_BROWSER_COPY:
1639             if ( !m_pTreeView->HasChildPathFocus() )
1640                 // handled below
1641                 break;
1642             SAL_FALLTHROUGH;
1643         case ID_TREE_CLOSE_CONN:
1644         case ID_TREE_EDIT_DATABASE:
1645         {
1646             SvTreeListEntry* pCurrentEntry( m_pTreeView->getListBox().GetCurEntry() );
1647             EntryType eType = getEntryType( pCurrentEntry );
1648             if ( eType == etUnknown )
1649                 return aReturn;
1650 
1651             SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent( pCurrentEntry );
1652             DBTreeListUserData* pDSData
1653                 =   pDataSourceEntry
1654                 ?   static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() )
1655                 :   nullptr;
1656 
1657             if ( nId == ID_TREE_CLOSE_CONN )
1658             {
1659                 aReturn.bEnabled = ( pDSData != nullptr ) && pDSData->xConnection.is();
1660             }
1661             else if ( nId == ID_TREE_EDIT_DATABASE )
1662             {
1663                 ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( getORB(),
1664                     "/org.openoffice.Office.DataAccess/Policies/Features/Common" ) );
1665                 bool bHaveEditDatabase( true );
1666                 OSL_VERIFY( aConfig.getNodeValue( "EditDatabaseFromDataSourceView" ) >>= bHaveEditDatabase );
1667                 aReturn.bEnabled = getORB().is() && ( pDataSourceEntry != nullptr ) && bHaveEditDatabase;
1668             }
1669             else if ( nId == ID_BROWSER_COPY )
1670             {
1671                 aReturn.bEnabled = isEntryCopyAllowed( pCurrentEntry );
1672             }
1673 
1674             return aReturn;
1675         }
1676     }
1677 
1678     // all slots not handled above are not available if no form is loaded
1679     if (!isLoaded())
1680         return aReturn;
1681 
1682     try
1683     {
1684         bool bHandled = false;
1685         switch (nId)
1686         {
1687             case ID_BROWSER_DOCUMENT_DATASOURCE:
1688                 // the slot is enabled if we have an external dispatcher able to handle it,
1689                 // and the dispatcher must have enabled the slot in general
1690                 aReturn.bEnabled = getExternalSlotState( ID_BROWSER_DOCUMENT_DATASOURCE );
1691                 bHandled = true;
1692                 break;
1693             case ID_BROWSER_REFRESH:
1694                 aReturn.bEnabled = true;
1695                 bHandled = true;
1696                 break;
1697         }
1698 
1699         if (bHandled)
1700             return aReturn;
1701 
1702         // no chance without valid models
1703         if (isValid() && !isValidCursor() && nId != ID_BROWSER_CLOSE)
1704             return aReturn;
1705 
1706         switch (nId)
1707         {
1708             case ID_BROWSER_INSERTCOLUMNS:
1709             case ID_BROWSER_INSERTCONTENT:
1710             case ID_BROWSER_FORMLETTER:
1711             {
1712                 // the slot is enabled if we have an external dispatcher able to handle it,
1713                 // and the dispatcher must have enabled the slot in general
1714                 aReturn.bEnabled = getExternalSlotState( nId );
1715 
1716                 // for the Insert* slots, we need at least one selected row
1717                 if (ID_BROWSER_FORMLETTER != nId)
1718                     aReturn.bEnabled = aReturn.bEnabled && getBrowserView()->getVclControl()->GetSelectRowCount();
1719 
1720                 // disabled for native queries which are not saved within the database
1721                 Reference< XPropertySet >  xDataSource(getRowSet(), UNO_QUERY);
1722                 try
1723                 {
1724                     aReturn.bEnabled = aReturn.bEnabled && xDataSource.is();
1725 
1726                     if (xDataSource.is())
1727                     {
1728                         sal_Int32 nType = ::comphelper::getINT32(xDataSource->getPropertyValue(PROPERTY_COMMAND_TYPE));
1729                         aReturn.bEnabled = aReturn.bEnabled &&
1730                                            ( ::comphelper::getBOOL(xDataSource->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) ||
1731                                              (nType == css::sdb::CommandType::QUERY) );
1732                     }
1733                 }
1734                 catch(DisposedException&)
1735                 {
1736                     SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: object already disposed!");
1737                 }
1738                 catch( const Exception& )
1739                 {
1740                     DBG_UNHANDLED_EXCEPTION("dbaccess");
1741                 }
1742             }
1743             break;
1744 
1745             case ID_BROWSER_TITLE:
1746                 {
1747                     Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
1748                     sal_Int32 nCommandType = CommandType::TABLE;
1749                     xProp->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nCommandType;
1750                     OUString sTitle;
1751                     switch (nCommandType)
1752                     {
1753                         case CommandType::TABLE:
1754                             sTitle = DBA_RES(STR_TBL_TITLE); break;
1755                         case CommandType::QUERY:
1756                         case CommandType::COMMAND:
1757                             sTitle = DBA_RES(STR_QRY_TITLE); break;
1758                         default:
1759                             SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: unknown command type!");
1760                     }
1761                     OUString aName;
1762                     xProp->getPropertyValue(PROPERTY_COMMAND) >>= aName;
1763                     OUString sObject(aName);
1764 
1765                     aReturn.sTitle = sTitle.replaceFirst("#", sObject);
1766                     aReturn.bEnabled = true;
1767                 }
1768                 break;
1769             case ID_BROWSER_TABLEATTR:
1770             case ID_BROWSER_ROWHEIGHT:
1771             case ID_BROWSER_COLATTRSET:
1772             case ID_BROWSER_COLWIDTH:
1773                 aReturn.bEnabled = getBrowserView() && getBrowserView()->getVclControl() && isValid() && isValidCursor();
1774                 //  aReturn.bEnabled &= getDefinition() && !getDefinition()->GetDatabase()->IsReadOnly();
1775                 break;
1776 
1777             case ID_BROWSER_COPY:
1778                 OSL_ENSURE( !m_pTreeView->HasChildPathFocus(), "SbaTableQueryBrowser::GetState( ID_BROWSER_COPY ): this should have been handled above!" );
1779                 if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing())
1780                 {
1781                     SbaGridControl* pControl = getBrowserView()->getVclControl();
1782                     if ( pControl->GetSelectRowCount() )
1783                     {
1784                         aReturn.bEnabled = m_aCurrentFrame.isActive();
1785                         break;
1786                     }
1787                     else
1788                         aReturn.bEnabled = pControl->canCopyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
1789                     break;
1790                 }
1791                 SAL_FALLTHROUGH;
1792             default:
1793                 return SbaXDataBrowserController::GetState(nId);
1794         }
1795     }
1796     catch(const Exception&)
1797     {
1798         DBG_UNHANDLED_EXCEPTION("dbaccess");
1799     }
1800 
1801     return aReturn;
1802 
1803 }
1804 
1805 void SbaTableQueryBrowser::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& aArgs)
1806 {
1807     switch (nId)
1808     {
1809         default:
1810             SbaXDataBrowserController::Execute(nId,aArgs);
1811             break;
1812 
1813         case ID_TREE_EDIT_DATABASE:
1814             implAdministrate( m_pTreeView->getListBox().GetCurEntry() );
1815             break;
1816 
1817         case ID_TREE_CLOSE_CONN:
1818             closeConnection( m_pTreeView->getListBox().GetRootLevelParent( m_pTreeView->getListBox().GetCurEntry() ) );
1819             break;
1820 
1821         case ID_TREE_ADMINISTRATE:
1822             svx::administrateDatabaseRegistration( getView() );
1823             break;
1824 
1825         case ID_BROWSER_REFRESH:
1826         {
1827             if ( !SaveModified( ) )
1828                 // nothing to do
1829                 break;
1830 
1831             bool bFullReinit = false;
1832             // check if the query signature (if the form is based on a query) has changed
1833             if ( !m_sQueryCommand.isEmpty() )
1834             {
1835                 OUString sNewQueryCommand;
1836                 bool bNewQueryEP;
1837 
1838                 bool bIsQuery =
1839                     implGetQuerySignature( sNewQueryCommand, bNewQueryEP );
1840                 OSL_ENSURE( bIsQuery, "SbaTableQueryBrowser::Execute: was a query before, but is not anymore?" );
1841 
1842                 bFullReinit = ( sNewQueryCommand != m_sQueryCommand ) || ( m_bQueryEscapeProcessing != bNewQueryEP );
1843             }
1844             if ( !bFullReinit )
1845             {
1846                 // let the base class do a simple reload
1847                 SbaXDataBrowserController::Execute(nId,aArgs);
1848                 break;
1849             }
1850             SAL_FALLTHROUGH;
1851         }
1852 
1853         case ID_BROWSER_REFRESH_REBUILD:
1854         {
1855             if ( !SaveModified() )
1856                 // nothing to do
1857                 break;
1858 
1859             SvTreeListEntry* pSelected = m_pCurrentlyDisplayed;
1860             // unload
1861             unloadAndCleanup( false );
1862 
1863             // reselect the entry
1864             if ( pSelected )
1865             {
1866                 implSelect( pSelected );
1867             }
1868             else
1869             {
1870                 Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
1871                 implSelect(svx::ODataAccessDescriptor(xProp));
1872             }
1873         }
1874         break;
1875 
1876         case ID_BROWSER_EXPLORER:
1877             toggleExplorer();
1878             break;
1879 
1880         case ID_BROWSER_DOCUMENT_DATASOURCE:
1881             implSelect(m_aDocumentDataSource);
1882             break;
1883 
1884         case ID_BROWSER_INSERTCOLUMNS:
1885         case ID_BROWSER_INSERTCONTENT:
1886         case ID_BROWSER_FORMLETTER:
1887             if (getBrowserView() && isValidCursor())
1888             {
1889                 // the URL the slot id is assigned to
1890                 OSL_ENSURE( m_aExternalFeatures.find( nId ) != m_aExternalFeatures.end(),
1891                     "SbaTableQueryBrowser::Execute( ID_BROWSER_?): how could this ever be enabled?" );
1892                 URL aParentUrl = m_aExternalFeatures[ nId ].aURL;
1893 
1894                 // let the dispatcher execute the slot
1895                 Reference< XDispatch > xDispatch( m_aExternalFeatures[ nId ].xDispatcher );
1896                 if (xDispatch.is())
1897                 {
1898                     // set the properties for the dispatch
1899 
1900                     // first fill the selection
1901                     SbaGridControl* pGrid = getBrowserView()->getVclControl();
1902                     MultiSelection* pSelection = const_cast<MultiSelection*>(pGrid->GetSelection());
1903                     Sequence< Any > aSelection;
1904                     if ( !pGrid->IsAllSelected() )
1905                     {   // transfer the selected rows only if not all rows are selected
1906                         // (all rows means the whole table)
1907                         // #i3832#
1908                         if (pSelection != nullptr)
1909                         {
1910                             aSelection.realloc(pSelection->GetSelectCount());
1911                             long nIdx = pSelection->FirstSelected();
1912                             Any* pSelectionNos = aSelection.getArray();
1913                             while (nIdx != SFX_ENDOFSELECTION)
1914                             {
1915                                 *pSelectionNos++ <<= static_cast<sal_Int32>(nIdx + 1);
1916                                 nIdx = pSelection->NextSelected();
1917                             }
1918                         }
1919                     }
1920 
1921                     Reference< XResultSet > xCursorClone;
1922                     try
1923                     {
1924                         Reference< XResultSetAccess > xResultSetAccess(getRowSet(),UNO_QUERY);
1925                         if (xResultSetAccess.is())
1926                             xCursorClone = xResultSetAccess->createResultSet();
1927                     }
1928                     catch(DisposedException&)
1929                     {
1930                         SAL_WARN("dbaccess.ui", "Object already disposed!");
1931                     }
1932                     catch(const Exception&)
1933                     {
1934                         SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Execute(ID_BROWSER_?): could not clone the cursor!");
1935                     }
1936 
1937                     Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
1938 
1939                     try
1940                     {
1941                         ODataAccessDescriptor aDescriptor;
1942                         OUString sDataSourceName;
1943                         xProp->getPropertyValue(PROPERTY_DATASOURCENAME) >>= sDataSourceName;
1944 
1945                         aDescriptor.setDataSource(sDataSourceName);
1946                         aDescriptor[DataAccessDescriptorProperty::Command]      =   xProp->getPropertyValue(PROPERTY_COMMAND);
1947                         aDescriptor[DataAccessDescriptorProperty::CommandType]  =   xProp->getPropertyValue(PROPERTY_COMMAND_TYPE);
1948                         aDescriptor[DataAccessDescriptorProperty::Connection]   =   xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION);
1949                         aDescriptor[DataAccessDescriptorProperty::Cursor]       <<= xCursorClone;
1950                         if ( aSelection.getLength() )
1951                         {
1952                             aDescriptor[DataAccessDescriptorProperty::Selection]            <<= aSelection;
1953                             aDescriptor[DataAccessDescriptorProperty::BookmarkSelection]    <<= false;
1954                                 // these are selection indices
1955                                 // before we change this, all clients have to be adjusted
1956                                 // so that they recognize the new BookmarkSelection property!
1957                         }
1958 
1959                         xDispatch->dispatch(aParentUrl, aDescriptor.createPropertyValueSequence());
1960                     }
1961                     catch( const Exception& )
1962                     {
1963                         DBG_UNHANDLED_EXCEPTION("dbaccess");
1964                     }
1965                 }
1966             }
1967             break;
1968 
1969         case ID_BROWSER_CLOSE:
1970             closeTask();
1971             // if it's not 0, such a async close is already pending
1972             break;
1973 
1974         case ID_BROWSER_COPY:
1975             if(m_pTreeView->HasChildPathFocus())
1976             {
1977                 copyEntry(m_pTreeView->getListBox().GetCurEntry());
1978             }
1979             else if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing() && getBrowserView()->getVclControl()->GetSelectRowCount() < 1)
1980             {
1981                 SbaGridControl* pControl = getBrowserView()->getVclControl();
1982                 pControl->copyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
1983             }
1984             else
1985                 SbaXDataBrowserController::Execute(nId,aArgs);
1986             break;
1987     }
1988 }
1989 
1990 void SbaTableQueryBrowser::implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection )
1991 {
1992     Image a, b, c;
1993     OUString d, e;
1994     implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection );
1995 }
1996 
1997 void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, Image& _rDbImage,
1998         OUString& _rQueryName, Image& _rQueryImage, OUString& _rTableName, Image& _rTableImage,
1999         const SharedConnection& _rxConnection)
2000 {
2001     SolarMutexGuard aGuard;
2002     // initialize the names/images if necessary
2003     if (_rQueryName.isEmpty())
2004         _rQueryName = DBA_RES(RID_STR_QUERIES_CONTAINER);
2005     if (_rTableName.isEmpty())
2006         _rTableName = DBA_RES(RID_STR_TABLES_CONTAINER);
2007 
2008     if (!_rQueryImage)
2009         _rQueryImage = ImageProvider::getFolderImage( DatabaseObject::QUERY );
2010     if (!_rTableImage)
2011         _rTableImage = ImageProvider::getFolderImage( DatabaseObject::TABLE );
2012 
2013     if (!_rDbImage)
2014         _rDbImage = ImageProvider::getDatabaseImage();
2015 
2016     // add the entry for the data source
2017     // special handling for data sources denoted by URLs - we do not want to display this ugly URL, do we?
2018     // #i33699#
2019     OUString sDSDisplayName, sDataSourceId;
2020     getDataSourceDisplayName_isURL( _rDbName, sDSDisplayName, sDataSourceId );
2021 
2022     SvTreeListEntry* pDatasourceEntry = m_pTreeView->getListBox().InsertEntry( sDSDisplayName, _rDbImage, _rDbImage );
2023     DBTreeListUserData* pDSData = new DBTreeListUserData;
2024     pDSData->eType = etDatasource;
2025     pDSData->sAccessor = sDataSourceId;
2026     pDSData->xConnection = _rxConnection;
2027     pDatasourceEntry->SetUserData(pDSData);
2028 
2029     // the child for the queries container
2030     {
2031         DBTreeListUserData* pQueriesData = new DBTreeListUserData;
2032         pQueriesData->eType = etQueryContainer;
2033 
2034         m_pTreeView->getListBox().InsertEntry(
2035             _rQueryName, _rQueryImage, _rQueryImage, pDatasourceEntry,
2036             true /*ChildrenOnDemand*/, TREELIST_APPEND, pQueriesData );
2037     }
2038 
2039     // the child for the tables container
2040     {
2041         DBTreeListUserData* pTablesData = new DBTreeListUserData;
2042         pTablesData->eType = etTableContainer;
2043 
2044         m_pTreeView->getListBox().InsertEntry(
2045             _rTableName, _rTableImage, _rTableImage, pDatasourceEntry,
2046             true /*ChildrenOnDemand*/, TREELIST_APPEND, pTablesData );
2047     }
2048 
2049 }
2050 
2051 void SbaTableQueryBrowser::initializeTreeModel()
2052 {
2053     if (m_xDatabaseContext.is())
2054     {
2055         Image aDBImage, aQueriesImage, aTablesImage;
2056         OUString sQueriesName, sTablesName;
2057 
2058         // fill the model with the names of the registered datasources
2059         for (const OUString& rDatasource : m_xDatabaseContext->getElementNames())
2060             implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() );
2061     }
2062 }
2063 
2064 void SbaTableQueryBrowser::populateTree(const Reference<XNameAccess>& _xNameAccess,
2065                                             SvTreeListEntry* _pParent,
2066                                             EntryType _eEntryType)
2067 {
2068     DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pParent->GetUserData());
2069     if(pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables
2070         pData->xContainer = _xNameAccess;
2071 
2072     try
2073     {
2074         for (const OUString& rName : _xNameAccess->getElementNames())
2075         {
2076             if( !m_pTreeView->getListBox().GetEntryPosByName(rName,_pParent))
2077             {
2078                 DBTreeListUserData* pEntryData = new DBTreeListUserData;
2079                 pEntryData->eType = _eEntryType;
2080                 if ( _eEntryType == etQuery )
2081                 {
2082                     Reference<XNameAccess> xChild(_xNameAccess->getByName(rName),UNO_QUERY);
2083                     if ( xChild.is() )
2084                         pEntryData->eType = etQueryContainer;
2085                 }
2086                 implAppendEntry( _pParent, rName, pEntryData, pEntryData->eType );
2087             }
2088         }
2089     }
2090     catch(const Exception&)
2091     {
2092         SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
2093     }
2094 }
2095 
2096 SvTreeListEntry* SbaTableQueryBrowser::implAppendEntry( SvTreeListEntry* _pParent, const OUString& _rName, void* _pUserData, EntryType _eEntryType )
2097 {
2098     std::unique_ptr< ImageProvider > pImageProvider( getImageProviderFor( _pParent ) );
2099 
2100     Image aImage;
2101     pImageProvider->getImages( _rName, getDatabaseObjectType( _eEntryType ), aImage );
2102 
2103     SvTreeListEntry* pNewEntry = m_pTreeView->getListBox().InsertEntry( _rName, _pParent, _eEntryType == etQueryContainer , TREELIST_APPEND, _pUserData );
2104 
2105     m_pTreeView->getListBox().SetExpandedEntryBmp(  pNewEntry, aImage );
2106     m_pTreeView->getListBox().SetCollapsedEntryBmp( pNewEntry, aImage );
2107 
2108     return pNewEntry;
2109 }
2110 
2111 IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, SvTreeListEntry*, _pParent, bool)
2112 {
2113     if (_pParent->HasChildren())
2114         // nothing to do...
2115         return true;
2116 
2117     SvTreeListEntry* pFirstParent = m_pTreeView->getListBox().GetRootLevelParent(_pParent);
2118     OSL_ENSURE(pFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!");
2119 
2120     DBTreeListUserData* pData = static_cast< DBTreeListUserData* >(_pParent->GetUserData());
2121     assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!");
2122 #if OSL_DEBUG_LEVEL > 0
2123     SvLBoxString* pString = static_cast<SvLBoxString*>(pFirstParent->GetFirstItem(SvLBoxItemType::String));
2124     OSL_ENSURE(pString,"SbaTableQueryBrowser::OnExpandEntry: No string item!");
2125 #endif
2126 
2127     if (etTableContainer == pData->eType)
2128     {
2129         WaitObject aWaitCursor(getBrowserView());
2130 
2131         // it could be that we already have a connection
2132         SharedConnection xConnection;
2133         ensureConnection( pFirstParent, xConnection );
2134 
2135         if ( xConnection.is() )
2136         {
2137             SQLExceptionInfo aInfo;
2138             try
2139             {
2140                 Reference< XWarningsSupplier > xWarnings(xConnection, UNO_QUERY);
2141                 if (xWarnings.is())
2142                     xWarnings->clearWarnings();
2143 
2144                 // first insert the views because the tables can also include
2145                 // views but that time the bitmap is the wrong one
2146                 // the nameaccess will be overwritten in populateTree
2147                 Reference<XViewsSupplier> xViewSup(xConnection,UNO_QUERY);
2148                 if(xViewSup.is())
2149                     populateTree( xViewSup->getViews(), _pParent, etTableOrView );
2150 
2151                 Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY);
2152                 if(xTabSup.is())
2153                 {
2154                     populateTree( xTabSup->getTables(), _pParent, etTableOrView );
2155                     Reference<XContainer> xCont(xTabSup->getTables(),UNO_QUERY);
2156                     if(xCont.is())
2157                         // add as listener to know when elements are inserted or removed
2158                         xCont->addContainerListener(this);
2159                 }
2160 
2161                 if (xWarnings.is())
2162                 {
2163                     SQLExceptionInfo aWarnings(xWarnings->getWarnings());
2164 #if 0
2165 // Obviously this if test is always false. So to avoid a Clang warning
2166 // "use of logical '&&' with constant operand" I put this in #if
2167 // 0. Yeah, I know it is fairly likely nobody will ever read this
2168 // comment and make a decision what to do here, so I could as well
2169 // have just binned this...
2170                     if (aWarnings.isValid() && sal_False)
2171                     {
2172                         SQLContext aContext;
2173                         aContext.Message = DBA_RES(STR_OPENTABLES_WARNINGS);
2174                         aContext.Details = DBA_RES(STR_OPENTABLES_WARNINGS_DETAILS);
2175                         aContext.NextException = aWarnings.get();
2176                         aWarnings = aContext;
2177                         showError(aWarnings);
2178                     }
2179 #endif
2180                     // TODO: we need a better concept for these warnings:
2181                     // something like "don't show any warnings for this datasource, again" would be nice
2182                     // But this requires an extension of the InteractionHandler and an additional property on the data source
2183                 }
2184             }
2185             catch(const SQLContext& e) { aInfo = e; }
2186             catch(const SQLWarning& e) { aInfo = e; }
2187             catch(const SQLException& e) { aInfo = e; }
2188             catch(const WrappedTargetException& e)
2189             {
2190                 SQLException aSql;
2191                 if(e.TargetException >>= aSql)
2192                     aInfo = aSql;
2193                 else
2194                     SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: something strange happened!");
2195             }
2196             catch( const Exception& )
2197             {
2198                 DBG_UNHANDLED_EXCEPTION("dbaccess");
2199             }
2200             if (aInfo.isValid())
2201                 showError(aInfo);
2202         }
2203         else
2204             return false;
2205                 // 0 indicates that an error occurred
2206     }
2207     else
2208     {   // we have to expand the queries or bookmarks
2209         if (ensureEntryObject(_pParent))
2210         {
2211             DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( _pParent->GetUserData() );
2212             Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
2213             populateTree( xCollection, _pParent, etQuery );
2214         }
2215     }
2216     return true;
2217 }
2218 
2219 bool SbaTableQueryBrowser::ensureEntryObject( SvTreeListEntry* _pEntry )
2220 {
2221     OSL_ENSURE(_pEntry, "SbaTableQueryBrowser::ensureEntryObject: invalid argument!");
2222     if (!_pEntry)
2223         return false;
2224 
2225     EntryType eType = getEntryType( _pEntry );
2226 
2227     // the user data of the entry
2228     DBTreeListUserData* pEntryData = static_cast<DBTreeListUserData*>(_pEntry->GetUserData());
2229     OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!");
2230 
2231     SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent(_pEntry);
2232 
2233     bool bSuccess = false;
2234     switch (eType)
2235     {
2236         case etQueryContainer:
2237             if ( pEntryData->xContainer.is() )
2238             {
2239                 // nothing to do
2240                 bSuccess = true;
2241                 break;
2242             }
2243 
2244             {
2245                 SvTreeListEntry* pParent = m_pTreeView->getListBox().GetParent(_pEntry);
2246                 if ( pParent != pDataSourceEntry )
2247                 {
2248                     SvLBoxString* pString = static_cast<SvLBoxString*>(_pEntry->GetFirstItem(SvLBoxItemType::String));
2249                     OSL_ENSURE(pString,"There must be a string item!");
2250                     OUString aName(pString->GetText());
2251                     DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pParent->GetUserData());
2252                     try
2253                     {
2254                         Reference< XNameAccess > xNameAccess(pData->xContainer,UNO_QUERY);
2255                         if ( xNameAccess.is() )
2256                             pEntryData->xContainer.set(xNameAccess->getByName(aName),UNO_QUERY);
2257                     }
2258                     catch(const Exception& )
2259                     {
2260                         DBG_UNHANDLED_EXCEPTION("dbaccess");
2261                     }
2262 
2263                     bSuccess = pEntryData->xContainer.is();
2264                 }
2265                 else
2266                 {
2267                     try
2268                     {
2269                         Reference< XQueryDefinitionsSupplier > xQuerySup;
2270                         m_xDatabaseContext->getByName( getDataSourceAccessor( pDataSourceEntry ) ) >>= xQuerySup;
2271                         if (xQuerySup.is())
2272                         {
2273                             Reference< XNameAccess > xQueryDefs = xQuerySup->getQueryDefinitions();
2274                             Reference< XContainer > xCont(xQueryDefs, UNO_QUERY);
2275                             if (xCont.is())
2276                                 // add as listener to get notified if elements are inserted or removed
2277                                 xCont->addContainerListener(this);
2278 
2279                             pEntryData->xContainer = xQueryDefs;
2280                             bSuccess = pEntryData->xContainer.is();
2281                         }
2282                         else {
2283                             SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: no XQueryDefinitionsSupplier interface!");
2284                         }
2285                     }
2286                     catch( const Exception& )
2287                     {
2288                         DBG_UNHANDLED_EXCEPTION("dbaccess");
2289                     }
2290                 }
2291             }
2292             break;
2293 
2294         default:
2295             SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: ooops ... missing some implementation here!");
2296             // TODO ...
2297             break;
2298     }
2299 
2300     return bSuccess;
2301 }
2302 
2303 bool SbaTableQueryBrowser::implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect)
2304 {
2305     // extract the props
2306     OUString sDataSource;
2307     OUString sCommand;
2308     sal_Int32 nCommandType = CommandType::COMMAND;
2309     bool bEscapeProcessing = true;
2310     extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);
2311 
2312     // select it
2313     return implSelect( sDataSource, sCommand, nCommandType, bEscapeProcessing, SharedConnection(), _bSelectDirect );
2314 }
2315 
2316 bool SbaTableQueryBrowser::implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand,
2317     const sal_Int32 _nCommandType, const bool _bEscapeProcessing, const SharedConnection& _rxConnection)
2318 {
2319     try
2320     {
2321         Reference<XPropertySet> xProp( getRowSet(), UNO_QUERY_THROW );
2322         Reference< XLoadable >  xLoadable( xProp, UNO_QUERY_THROW );
2323         // the values allowing the RowSet to re-execute
2324         xProp->setPropertyValue(PROPERTY_DATASOURCENAME, makeAny(_rDataSourceName));
2325         if(_rxConnection.is())
2326             xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( _rxConnection.getTyped() ) );
2327 
2328             // set this _before_ setting the connection, else the rowset would rebuild it ...
2329         xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, makeAny(_nCommandType));
2330         xProp->setPropertyValue(PROPERTY_COMMAND, makeAny(_rCommand));
2331         xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny(_bEscapeProcessing));
2332         if ( m_bPreview )
2333         {
2334             xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, makeAny(FetchDirection::FORWARD));
2335         }
2336 
2337         // the formatter depends on the data source we're working on, so rebuild it here ...
2338         initFormatter();
2339 
2340         // switch the grid to design mode while loading
2341         getBrowserView()->getGridControl()->setDesignMode(true);
2342         InitializeForm( xProp );
2343 
2344         bool bSuccess = true;
2345 
2346         {
2347             {
2348                 Reference< XNameContainer >  xColContainer(getFormComponent(), UNO_QUERY);
2349                 // first we have to clear the grid
2350                 clearGridColumns(xColContainer);
2351             }
2352             FormErrorHelper aHelper(this);
2353             // load the form
2354             bSuccess = reloadForm(xLoadable);
2355 
2356             // initialize the model
2357             InitializeGridModel(getFormComponent());
2358 
2359             Any aVal = xProp->getPropertyValue(PROPERTY_ISNEW);
2360             if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
2361             {
2362                 // then set the default values and the parameters given from the parent
2363                 Reference< XReset> xReset(xProp, UNO_QUERY);
2364                 xReset->reset();
2365             }
2366 
2367             if ( m_bPreview )
2368                 initializePreviewMode();
2369 
2370             LoadFinished(true);
2371         }
2372 
2373         InvalidateAll();
2374         return bSuccess;
2375     }
2376     catch( const SQLException& )
2377     {
2378         Any aException( ::cppu::getCaughtException() );
2379         showError( SQLExceptionInfo( aException ) );
2380     }
2381     catch( const WrappedTargetException& e )
2382     {
2383         if  ( e.TargetException.isExtractableTo( ::cppu::UnoType< SQLException >::get() ) )
2384             showError( SQLExceptionInfo( e.TargetException ) );
2385         else
2386             SAL_WARN("dbaccess", e);
2387     }
2388     catch(const Exception&)
2389     {
2390         DBG_UNHANDLED_EXCEPTION("dbaccess");
2391     }
2392 
2393     InvalidateAll();
2394     return false;
2395 }
2396 
2397 bool SbaTableQueryBrowser::implSelect(const OUString& _rDataSourceName, const OUString& _rCommand,
2398                                       const sal_Int32 _nCommandType, const bool _bEscapeProcessing,
2399                                       const SharedConnection& _rxConnection,
2400                                       bool _bSelectDirect)
2401 {
2402     if (_rDataSourceName.getLength() && _rCommand.getLength() && (-1 != _nCommandType))
2403     {
2404         SvTreeListEntry* pDataSource = nullptr;
2405         SvTreeListEntry* pCommandType = nullptr;
2406         SvTreeListEntry* pCommand = getObjectEntry( _rDataSourceName, _rCommand, _nCommandType, &pDataSource, &pCommandType, true, _rxConnection );
2407 
2408         if (pCommand)
2409         {
2410             bool bSuccess = true;
2411             if ( _bSelectDirect )
2412             {
2413                 bSuccess = implSelect( pCommand );
2414             }
2415             else
2416             {
2417                 m_pTreeView->getListBox().Select( pCommand );
2418             }
2419 
2420             if ( bSuccess )
2421             {
2422                 m_pTreeView->getListBox().MakeVisible(pCommand);
2423                 m_pTreeView->getListBox().SetCursor(pCommand);
2424             }
2425         }
2426         else if (!pCommandType)
2427         {
2428             if ( m_pCurrentlyDisplayed )
2429             {   // tell the old entry (if any) it has been deselected
2430                 selectPath(m_pCurrentlyDisplayed, false);
2431                 m_pCurrentlyDisplayed = nullptr;
2432             }
2433 
2434             // we have a command and need to display this in the rowset
2435             return implLoadAnything(_rDataSourceName, _rCommand, _nCommandType, _bEscapeProcessing, _rxConnection);
2436         }
2437     }
2438     return false;
2439 }
2440 
2441 IMPL_LINK_NOARG(SbaTableQueryBrowser, OnSelectionChange, LinkParamNone*, void)
2442 {
2443     implSelect( m_pTreeView->getListBox().FirstSelected() );
2444 }
2445 
2446 SvTreeListEntry* SbaTableQueryBrowser::implGetConnectionEntry(SvTreeListEntry* _pEntry) const
2447 {
2448     SvTreeListEntry* pCurrentEntry = _pEntry;
2449     DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() );
2450     while(pEntryData->eType != etDatasource )
2451     {
2452         pCurrentEntry = m_pTreeView->GetTreeModel()->GetParent(pCurrentEntry);
2453         pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() );
2454     }
2455     return pCurrentEntry;
2456 }
2457 
2458 bool SbaTableQueryBrowser::implSelect( SvTreeListEntry* _pEntry )
2459 {
2460     if ( !_pEntry )
2461         return false;
2462 
2463     DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( _pEntry->GetUserData() );
2464     switch (pEntryData->eType)
2465     {
2466         case etTableOrView:
2467         case etQuery:
2468             break;
2469         default:
2470             // nothing to do
2471             return false;
2472     }
2473 
2474     OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(_pEntry), "SbaTableQueryBrowser::implSelect: invalid entry (1)!");
2475     OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(m_pTreeView->GetTreeModel()->GetParent(_pEntry)), "SbaTableQueryBrowser::implSelect: invalid entry (2)!");
2476 
2477     // get the entry for the tables or queries
2478     SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(_pEntry);
2479     DBTreeListUserData* pContainerData = static_cast<DBTreeListUserData*>(pContainer->GetUserData());
2480 
2481     // get the entry for the datasource
2482     SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer);
2483     DBTreeListUserData* pConData = static_cast<DBTreeListUserData*>(pConnection->GetUserData());
2484 
2485     // reinitialize the rowset
2486     // but first check if it is necessary
2487     // get all old properties
2488     Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
2489     OUString aOldName;
2490     xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName;
2491     sal_Int32 nOldType = 0;
2492     xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType;
2493     Reference<XConnection> xOldConnection(xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
2494 
2495     // the name of the table or query
2496     SvLBoxString* pString = static_cast<SvLBoxString*>(_pEntry->GetFirstItem(SvLBoxItemType::String));
2497     OSL_ENSURE(pString,"There must be a string item!");
2498     const OUString sSimpleName = pString->GetText();
2499     OUStringBuffer sNameBuffer(sSimpleName);
2500     if ( etQueryContainer == pContainerData->eType )
2501     {
2502         SvTreeListEntry* pTemp = pContainer;
2503         while( m_pTreeView->GetTreeModel()->GetParent(pTemp) != pConnection )
2504         {
2505             sNameBuffer.insert(0,'/');
2506             pString = static_cast<SvLBoxString*>(pTemp->GetFirstItem(SvLBoxItemType::String));
2507             OSL_ENSURE(pString,"There must be a string item!");
2508             sNameBuffer.insert(0,pString->GetText());
2509             pTemp = m_pTreeView->GetTreeModel()->GetParent(pTemp);
2510         }
2511     }
2512     OUString aName = sNameBuffer.makeStringAndClear();
2513 
2514     sal_Int32 nCommandType =    ( etTableContainer == pContainerData->eType)
2515                             ?   CommandType::TABLE
2516                             :   CommandType::QUERY;
2517 
2518     // check if need to rebuild the rowset
2519     bool bRebuild = ( xOldConnection != pConData->xConnection )
2520                      || ( nOldType != nCommandType )
2521                      || ( aName != aOldName );
2522 
2523     Reference< css::form::XLoadable >  xLoadable = getLoadable();
2524     bRebuild |= !xLoadable->isLoaded();
2525     bool bSuccess = true;
2526     if ( bRebuild )
2527     {
2528         try
2529         {
2530             WaitObject aWaitCursor(getBrowserView());
2531 
2532             // tell the old entry it has been deselected
2533             selectPath(m_pCurrentlyDisplayed, false);
2534             m_pCurrentlyDisplayed = nullptr;
2535 
2536             // not really loaded
2537             m_pCurrentlyDisplayed = _pEntry;
2538             // tell the new entry it has been selected
2539             selectPath(m_pCurrentlyDisplayed);
2540 
2541             // get the name of the data source currently selected
2542             ensureConnection( m_pCurrentlyDisplayed, pConData->xConnection );
2543 
2544             if ( !pConData->xConnection.is() )
2545             {
2546                 unloadAndCleanup( false );
2547                 return false;
2548             }
2549 
2550             Reference<XNameAccess> xNameAccess;
2551             switch(nCommandType)
2552             {
2553                 case CommandType::TABLE:
2554                     {
2555                         // only for tables
2556                         if ( !pContainerData->xContainer.is() )
2557                         {
2558                             Reference<XTablesSupplier> xSup( pConData->xConnection, UNO_QUERY );
2559                             if(xSup.is())
2560                                 xNameAccess = xSup->getTables();
2561 
2562                             pContainerData->xContainer = xNameAccess;
2563                         }
2564                         else
2565                             xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
2566                     }
2567                     break;
2568                 case CommandType::QUERY:
2569                     {
2570                         if ( pContainerData->xContainer.is() )
2571                             xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
2572                         else
2573                         {
2574                             Reference<XQueriesSupplier> xSup( pConData->xConnection, UNO_QUERY );
2575                             if(xSup.is())
2576                                 xNameAccess = xSup->getQueries();
2577                         }
2578                     }
2579                     break;
2580             }
2581             OUString sStatus(DBA_RES(CommandType::TABLE == nCommandType ? STR_LOADING_TABLE : STR_LOADING_QUERY));
2582             sStatus = sStatus.replaceFirst("$name$", aName);
2583             BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sStatus);
2584 
2585             bool bEscapeProcessing = true;
2586             if(xNameAccess.is() && xNameAccess->hasByName(sSimpleName))
2587             {
2588                 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pEntry->GetUserData());
2589                 if ( !pData->xObjectProperties.is() )
2590                 {
2591                     Reference<XInterface> xObject;
2592                     if(xNameAccess->getByName(sSimpleName) >>= xObject) // remember the table or query object
2593                     {
2594                         pData->xObjectProperties.set(xObject, css::uno::UNO_QUERY);
2595                         // if the query contains a parameterized statement and preview is enabled we won't get any data.
2596                         if ( nCommandType == CommandType::QUERY && xObject.is() )
2597                         {
2598                             Reference<XPropertySet> xObjectProps(xObject,UNO_QUERY);
2599                             xObjectProps->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bEscapeProcessing;
2600                             if ( m_bPreview )
2601                             {
2602                                 OUString sSql;
2603                                 xObjectProps->getPropertyValue(PROPERTY_COMMAND) >>= sSql;
2604                                 Reference< XMultiServiceFactory >  xFactory( pConData->xConnection, UNO_QUERY );
2605                                 if (xFactory.is())
2606                                 {
2607                                     try
2608                                     {
2609                                         Reference<XSingleSelectQueryAnalyzer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
2610                                         if ( xAnalyzer.is() )
2611                                         {
2612                                             xAnalyzer->setQuery(sSql);
2613                                             Reference<XParametersSupplier> xParSup(xAnalyzer,UNO_QUERY);
2614                                             if ( xParSup->getParameters()->getCount() > 0 )
2615                                             {
2616                                                 OUString sFilter = " WHERE ";
2617                                                 sFilter = sFilter + xAnalyzer->getFilter();
2618                                                 OUString sReplace(sSql);
2619                                                 sReplace = sReplace.replaceFirst(sFilter, "");
2620                                                 xAnalyzer->setQuery(sReplace);
2621                                                 Reference<XSingleSelectQueryComposer> xComposer(xAnalyzer,UNO_QUERY);
2622                                                 xComposer->setFilter("0=1");
2623                                                 aName = xAnalyzer->getQuery();
2624                                                 nCommandType = CommandType::COMMAND;
2625                                             }
2626                                         }
2627                                     }
2628                                     catch (Exception&)
2629                                     {
2630                                         DBG_UNHANDLED_EXCEPTION("dbaccess");
2631                                     }
2632                                 }
2633                             }
2634                         }
2635                     }
2636                 }
2637             }
2638 
2639             OUString sDataSourceName( getDataSourceAccessor( pConnection ) );
2640             bSuccess = implLoadAnything( sDataSourceName, aName, nCommandType, bEscapeProcessing, pConData->xConnection );
2641             if ( !bSuccess )
2642             {   // clean up
2643                 criticalFail();
2644             }
2645         }
2646         catch(const SQLException& e)
2647         {
2648             showError(SQLExceptionInfo(e));
2649             // reset the values
2650             xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
2651             xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
2652             bSuccess = false;
2653         }
2654         catch(WrappedTargetException& e)
2655         {
2656             SQLException aSql;
2657             if(e.TargetException >>= aSql)
2658                 showError(SQLExceptionInfo(aSql));
2659             else
2660                 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implSelect: something strange happened!");
2661             // reset the values
2662             xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
2663             xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
2664             bSuccess = false;
2665         }
2666         catch(const Exception&)
2667         {
2668             // reset the values
2669             xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
2670             xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
2671             bSuccess = false;
2672         }
2673     }
2674     return bSuccess;
2675 }
2676 
2677 SvTreeListEntry* SbaTableQueryBrowser::getEntryFromContainer(const Reference<XNameAccess>& _rxNameAccess)
2678 {
2679     DBTreeListBox& rListBox = m_pTreeView->getListBox();
2680     SvTreeListEntry* pContainer = nullptr;
2681     SvTreeListEntry* pDSLoop = rListBox.FirstChild(nullptr);
2682     while (pDSLoop)
2683     {
2684         pContainer  = rListBox.GetEntry(pDSLoop, CONTAINER_QUERIES);
2685         DBTreeListUserData* pQueriesData = static_cast<DBTreeListUserData*>(pContainer->GetUserData());
2686         if ( pQueriesData && pQueriesData->xContainer == _rxNameAccess )
2687             break;
2688 
2689         pContainer  = rListBox.GetEntry(pDSLoop, CONTAINER_TABLES);
2690         DBTreeListUserData* pTablesData = static_cast<DBTreeListUserData*>(pContainer->GetUserData());
2691         if ( pTablesData && pTablesData->xContainer == _rxNameAccess )
2692             break;
2693 
2694         pDSLoop     = pDSLoop->NextSibling();
2695         pContainer  = nullptr;
2696     }
2697     return pContainer;
2698 }
2699 
2700 void SAL_CALL SbaTableQueryBrowser::elementInserted( const ContainerEvent& _rEvent )
2701 {
2702     SolarMutexGuard aSolarGuard;
2703 
2704     Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
2705     // first search for a definition container where we can insert this element
2706 
2707     SvTreeListEntry* pEntry = getEntryFromContainer(xNames);
2708     if(pEntry)  // found one
2709     {
2710         // insert the new entry into the tree
2711         DBTreeListUserData* pContainerData = static_cast<DBTreeListUserData*>(pEntry->GetUserData());
2712         OSL_ENSURE(pContainerData, "elementInserted: There must be user data for this type!");
2713 
2714         DBTreeListUserData* pNewData = new DBTreeListUserData;
2715         bool bIsTable = etTableContainer == pContainerData->eType;
2716         if ( bIsTable )
2717         {
2718             _rEvent.Element >>= pNewData->xObjectProperties;// remember the new element
2719             pNewData->eType = etTableOrView;
2720         }
2721         else
2722         {
2723             if (static_cast<sal_Int32>(m_pTreeView->getListBox().GetChildCount(pEntry)) < ( xNames->getElementNames().getLength() - 1 ) )
2724             {
2725                 // the item inserts its children on demand, but it has not been expanded yet. So ensure here and
2726                 // now that it has all items
2727                 populateTree(xNames, pEntry, etQuery );
2728             }
2729             pNewData->eType = etQuery;
2730         }
2731         implAppendEntry( pEntry, ::comphelper::getString( _rEvent.Accessor ), pNewData, pNewData->eType );
2732     }
2733     else
2734         SbaXDataBrowserController::elementInserted(_rEvent);
2735 }
2736 
2737 bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(const OUString& _sName, SvTreeListEntry const * _pContainer)
2738 {
2739     return m_pCurrentlyDisplayed
2740             &&  getEntryType(m_pCurrentlyDisplayed) == getChildType(_pContainer)
2741             &&  m_pTreeView->getListBox().GetParent(m_pCurrentlyDisplayed) == _pContainer
2742             &&  m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed) == _sName;
2743 }
2744 
2745 void SAL_CALL SbaTableQueryBrowser::elementRemoved( const ContainerEvent& _rEvent )
2746 {
2747     SolarMutexGuard aSolarGuard;
2748 
2749     Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
2750     // get the top-level representing the removed data source
2751     // and search for the queries and tables
2752     SvTreeListEntry* pContainer = getEntryFromContainer(xNames);
2753     if ( pContainer )
2754     { // a query or table has been removed
2755         OUString aName = ::comphelper::getString(_rEvent.Accessor);
2756 
2757         if ( isCurrentlyDisplayedChanged( aName, pContainer) )
2758         {   // the element displayed currently has been replaced
2759 
2760             // we need to remember the old value
2761             SvTreeListEntry* pTemp = m_pCurrentlyDisplayed;
2762 
2763             // unload
2764             unloadAndCleanup( false ); // don't dispose the connection
2765 
2766             DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pTemp->GetUserData());
2767             pTemp->SetUserData(nullptr);
2768             delete pData;
2769                 // the data could be null because we have a table which isn't correct
2770             m_pTreeView->GetTreeModel()->Remove(pTemp);
2771         }
2772         else
2773         {
2774             // remove the entry from the model
2775             SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer);
2776             while(pChild)
2777             {
2778                 if (m_pTreeView->getListBox().GetEntryText(pChild) == aName)
2779                 {
2780                     DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pChild->GetUserData());
2781                     pChild->SetUserData(nullptr);
2782                     delete pData;
2783                     m_pTreeView->GetTreeModel()->Remove(pChild);
2784                     break;
2785                 }
2786                 pChild = pChild->NextSibling();
2787             }
2788         }
2789 
2790         // maybe the object which is part of the document data source has been removed
2791         checkDocumentDataSource();
2792     }
2793     else
2794         SbaXDataBrowserController::elementRemoved(_rEvent);
2795 }
2796 
2797 void SAL_CALL SbaTableQueryBrowser::elementReplaced( const ContainerEvent& _rEvent )
2798 {
2799     SolarMutexGuard aSolarGuard;
2800 
2801     Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
2802     SvTreeListEntry* pContainer = getEntryFromContainer(xNames);
2803     if ( pContainer )
2804     {    // a table or query as been replaced
2805         OUString aName = ::comphelper::getString(_rEvent.Accessor);
2806 
2807         if ( isCurrentlyDisplayedChanged( aName, pContainer) )
2808         {   // the element displayed currently has been replaced
2809 
2810             // we need to remember the old value
2811             SvTreeListEntry* pTemp = m_pCurrentlyDisplayed;
2812             unloadAndCleanup( false ); // don't dispose the connection
2813 
2814             DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pTemp->GetUserData());
2815             if (pData)
2816             {
2817                 if ( etTableOrView == pData->eType )
2818                 { // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
2819                      _rEvent.Element >>= pData->xObjectProperties;  // remember the new element
2820                 }
2821                 else
2822                 {
2823                     pTemp->SetUserData(nullptr);
2824                     delete pData;
2825                 }
2826             }
2827         }
2828         else
2829         {
2830             // find the entry for this name
2831             SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer);
2832             while(pChild)
2833             {
2834                 if (m_pTreeView->getListBox().GetEntryText(pChild) == aName)
2835                 {
2836                     DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pChild->GetUserData());
2837                     if (pData)
2838                     {
2839                         if ( etTableOrView == pData->eType )
2840                         { // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
2841                             _rEvent.Element >>= pData->xObjectProperties;   // remember the new element
2842                         }
2843                         else
2844                         {
2845                             pChild->SetUserData(nullptr);
2846                             delete pData;
2847                         }
2848                     }
2849                     break;
2850                 }
2851                 pChild = pChild->NextSibling();
2852             }
2853         }
2854 
2855         // maybe the object which is part of the document data source has been removed
2856         checkDocumentDataSource();
2857     }
2858     else if (xNames.get() == m_xDatabaseContext.get())
2859     {   // a datasource has been replaced in the context
2860         SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::elementReplaced: no support for replaced data sources!");
2861             // very suspicious: the database context should not allow to replace data source, only to register
2862             // and revoke them
2863     }
2864     else
2865         SbaXDataBrowserController::elementReplaced(_rEvent);
2866 }
2867 
2868 void SbaTableQueryBrowser::impl_releaseConnection( SharedConnection& _rxConnection )
2869 {
2870     // remove as event listener
2871     Reference< XComponent > xComponent( _rxConnection, UNO_QUERY );
2872     if ( xComponent.is() )
2873     {
2874         Reference< XEventListener > xListener( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY );
2875         xComponent->removeEventListener( xListener );
2876     }
2877 
2878     try
2879     {
2880         // temporary (hopefully!) hack for #i55274#
2881         Reference< XFlushable > xFlush( _rxConnection, UNO_QUERY );
2882         if ( xFlush.is() )
2883             xFlush->flush();
2884     }
2885     catch( const Exception& )
2886     {
2887         DBG_UNHANDLED_EXCEPTION("dbaccess");
2888     }
2889 
2890     // clear
2891     _rxConnection.clear();
2892         // will implicitly dispose if we have the ownership, since xConnection is a SharedConnection
2893 }
2894 
2895 void SbaTableQueryBrowser::disposeConnection( SvTreeListEntry* _pDSEntry )
2896 {
2897     OSL_ENSURE( _pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" );
2898     OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" );
2899 
2900     if ( _pDSEntry )
2901     {
2902         DBTreeListUserData* pTreeListData = static_cast< DBTreeListUserData* >( _pDSEntry->GetUserData() );
2903         if ( pTreeListData )
2904             impl_releaseConnection( pTreeListData->xConnection );
2905     }
2906 }
2907 
2908 void SbaTableQueryBrowser::closeConnection(SvTreeListEntry* _pDSEntry, bool _bDisposeConnection)
2909 {
2910     OSL_ENSURE(_pDSEntry, "SbaTableQueryBrowser::closeConnection: invalid entry (NULL)!");
2911     OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!");
2912 
2913     // if one of the entries of the given DS is displayed currently, unload the form
2914     if (m_pCurrentlyDisplayed && (m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed) == _pDSEntry))
2915         unloadAndCleanup(_bDisposeConnection);
2916 
2917     // collapse the query/table container
2918     for (SvTreeListEntry* pContainers = m_pTreeView->GetTreeModel()->FirstChild(_pDSEntry); pContainers; pContainers = pContainers->NextSibling())
2919     {
2920         SvTreeListEntry* pElements = m_pTreeView->GetTreeModel()->FirstChild(pContainers);
2921         if ( pElements )
2922             m_pTreeView->getListBox().Collapse(pContainers);
2923         m_pTreeView->getListBox().EnableExpandHandler(pContainers);
2924         // and delete their children (they are connection-relative)
2925         for (; pElements; )
2926         {
2927             SvTreeListEntry* pRemove = pElements;
2928             pElements = pElements->NextSibling();
2929             DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pRemove->GetUserData());
2930             pRemove->SetUserData(nullptr);
2931             delete pData;
2932             m_pTreeView->GetTreeModel()->Remove(pRemove);
2933         }
2934     }
2935     // collapse the entry itself
2936     m_pTreeView->getListBox().Collapse(_pDSEntry);
2937 
2938     // dispose/reset the connection
2939     if ( _bDisposeConnection )
2940         disposeConnection( _pDSEntry );
2941 }
2942 
2943 void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection )
2944 {
2945     if (!m_pCurrentlyDisplayed)
2946         // nothing to do
2947         return;
2948 
2949     SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed);
2950 
2951     // de-select the path for the currently displayed table/query
2952     if (m_pCurrentlyDisplayed)
2953     {
2954         selectPath(m_pCurrentlyDisplayed, false);
2955     }
2956     m_pCurrentlyDisplayed = nullptr;
2957 
2958     try
2959     {
2960         // get the active connection. We need to dispose it.
2961         Reference< XPropertySet > xRowSetProps(getRowSet(),UNO_QUERY);
2962         Reference< XConnection > xConn;
2963         xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION) >>= xConn;
2964 #if OSL_DEBUG_LEVEL > 0
2965         {
2966             Reference< XComponent > xComp(
2967                 xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),
2968                 css::uno::UNO_QUERY);
2969         }
2970 #endif
2971 
2972         // unload the form
2973         Reference< XLoadable > xLoadable = getLoadable();
2974         if (xLoadable->isLoaded())
2975             xLoadable->unload();
2976 
2977         // clear the grid control
2978         Reference< XNameContainer > xConta(getControlModel(),UNO_QUERY);
2979         clearGridColumns(xConta);
2980 
2981         // dispose the connection
2982         if(_bDisposeConnection)
2983             disposeConnection( pDSEntry );
2984     }
2985     catch(SQLException& e)
2986     {
2987         showError(SQLExceptionInfo(e));
2988     }
2989     catch(WrappedTargetException& e)
2990     {
2991         SQLException aSql;
2992         if(e.TargetException >>= aSql)
2993             showError(SQLExceptionInfo(aSql));
2994         else
2995             SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: something strange happened!");
2996     }
2997     catch(const Exception&)
2998     {
2999         SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: could not reset the form");
3000     }
3001 }
3002 
3003 namespace
3004 {
3005     Reference< XInterface > lcl_getDataSource( const Reference< XDatabaseContext >& _rxDatabaseContext,
3006         const OUString& _rDataSourceName, const Reference< XConnection >& _rxConnection )
3007     {
3008         Reference< XDataSource > xDataSource;
3009         try
3010         {
3011             if ( !_rDataSourceName.isEmpty() && _rxDatabaseContext->hasByName( _rDataSourceName ) )
3012                 xDataSource.set( _rxDatabaseContext->getByName( _rDataSourceName ), UNO_QUERY_THROW );
3013 
3014             if ( !xDataSource.is() )
3015             {
3016                 Reference< XChild > xConnAsChild( _rxConnection, UNO_QUERY );
3017                 if ( xConnAsChild.is() )
3018                     xDataSource.set( xConnAsChild->getParent(), UNO_QUERY_THROW );
3019             }
3020         }
3021         catch( const Exception& )
3022         {
3023             DBG_UNHANDLED_EXCEPTION("dbaccess");
3024         }
3025         return xDataSource.get();
3026     }
3027 }
3028 
3029 void SbaTableQueryBrowser::impl_initialize()
3030 {
3031     SolarMutexGuard aGuard;
3032         // doin' a lot of VCL stuff here -> lock the SolarMutex
3033 
3034     // first initialize the parent
3035     SbaXDataBrowserController::impl_initialize();
3036 
3037     Reference<XConnection> xForeignConnection;
3038     Reference< XFrame > xFrame;
3039 
3040     OUString aTableName, aCatalogName, aSchemaName;
3041 
3042     bool bEscapeProcessing = true;
3043     sal_Int32 nInitialDisplayCommandType = CommandType::COMMAND;
3044     OUString sInitialDataSourceName;
3045     OUString sInitialCommand;
3046 
3047     const NamedValueCollection& rArguments( getInitParams() );
3048 
3049     rArguments.get_ensureType( PROPERTY_DATASOURCENAME, sInitialDataSourceName );
3050     rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, nInitialDisplayCommandType );
3051     rArguments.get_ensureType( PROPERTY_COMMAND, sInitialCommand );
3052     rArguments.get_ensureType( PROPERTY_ACTIVE_CONNECTION, xForeignConnection );
3053     rArguments.get_ensureType( PROPERTY_UPDATE_CATALOGNAME, aCatalogName );
3054     rArguments.get_ensureType( PROPERTY_UPDATE_SCHEMANAME, aSchemaName );
3055     rArguments.get_ensureType( PROPERTY_UPDATE_TABLENAME, aTableName );
3056     rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing );
3057     rArguments.get_ensureType( "Frame", xFrame );
3058     rArguments.get_ensureType( PROPERTY_SHOWMENU, m_bShowMenu );
3059 
3060     // disable the browser if either of ShowTreeViewButton (compatibility name) or EnableBrowser
3061     // is present and set to FALSE
3062     bool bDisableBrowser =  !rArguments.getOrDefault( "ShowTreeViewButton", true )   // compatibility name
3063                             ||  !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true );
3064     OSL_ENSURE( !rArguments.has( "ShowTreeViewButton" ),
3065         "SbaTableQueryBrowser::impl_initialize: ShowTreeViewButton is superseded by EnableBrowser!" );
3066     m_bEnableBrowser = !bDisableBrowser;
3067 
3068     // hide the tree view it is disabled in general, or if the settings tell to hide it initially
3069     bool bHideTreeView =    ( !m_bEnableBrowser )
3070                             ||  !rArguments.getOrDefault( "ShowTreeView", true )  // compatibility name
3071                             ||  !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true );
3072     OSL_ENSURE( !rArguments.has( "ShowTreeView" ),
3073         "SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" );
3074 
3075     if ( bHideTreeView )
3076         hideExplorer();
3077     else
3078         showExplorer();
3079 
3080     if ( m_bPreview )
3081     {
3082         try
3083         {
3084             Sequence< OUString> aProperties(5);
3085             Sequence< Any> aValues(5);
3086 
3087             OUString* pStringIter = aProperties.getArray();
3088             Any* pValueIter = aValues.getArray();
3089             *pStringIter++  = "AlwaysShowCursor";
3090             *pValueIter++   <<= false;
3091             *pStringIter++  = PROPERTY_BORDER;
3092             *pValueIter++   <<= sal_Int16(0);
3093 
3094             *pStringIter++  = "HasNavigationBar";
3095             *pValueIter++   <<= false;
3096             *pStringIter++  = "HasRecordMarker";
3097             *pValueIter++   <<= false;
3098 
3099             *pStringIter++  = "Tabstop";
3100             *pValueIter++   <<= false;
3101 
3102             Reference< XMultiPropertySet >  xFormMultiSet(getFormComponent(), UNO_QUERY);
3103             if ( xFormMultiSet.is() )
3104                 xFormMultiSet->setPropertyValues(aProperties, aValues);
3105         }
3106         catch(const Exception&)
3107         {
3108             DBG_UNHANDLED_EXCEPTION("dbaccess");
3109         }
3110     }
3111 
3112     // are we loaded into a (sub)frame of an embedded document (i.e. a form belonging to a database
3113     // document)?
3114     bool bSubFrameOfEmbeddedDocument = false;
3115     if ( xFrame.is() )
3116     {
3117         Reference<XFramesSupplier> xSup = xFrame->getCreator();
3118         Reference<XController> xCont = xSup.is() ? xSup->getController() : Reference<XController>();
3119 
3120         bSubFrameOfEmbeddedDocument = xCont.is() && ::dbtools::isEmbeddedInDatabase( xCont->getModel(), xForeignConnection );
3121     }
3122 
3123     // if we have a connection at this point, it was either passed from outside, our
3124     // determined from a outer DB document. In both cases, do not dispose it later on.
3125     SharedConnection xConnection( xForeignConnection, SharedConnection::NoTakeOwnership );
3126 
3127     // should we display all registered databases in the left hand side tree?
3128     // or only *one* special?
3129     bool bLimitedTreeEntries = false;
3130     // if we're part of a frame which is a secondary frame of a database document, then only
3131     // display the database for this document, not all registered ones
3132     bLimitedTreeEntries |= bSubFrameOfEmbeddedDocument;
3133     // if the tree view is not to be displayed at all, then only display the data source
3134     // which was given as initial selection
3135     bLimitedTreeEntries |= !m_bEnableBrowser;
3136 
3137     if ( bLimitedTreeEntries )
3138     {
3139         if ( xConnection.is() )
3140         {
3141             startConnectionListening( xConnection );
3142 
3143             // if no initial name was given, try to obtain one from the data source
3144             if ( sInitialDataSourceName.isEmpty() )
3145             {
3146                 Reference< XChild > xChild( xConnection, UNO_QUERY );
3147                 Reference< XPropertySet > xDataSourceProperties;
3148                 if ( xChild.is() )
3149                     xDataSourceProperties.set(xChild->getParent(), css::uno::UNO_QUERY);
3150                 if ( xDataSourceProperties.is() )
3151                 {
3152                     try
3153                     {
3154                         OSL_VERIFY( xDataSourceProperties->getPropertyValue( PROPERTY_NAME ) >>= sInitialDataSourceName );
3155                     }
3156                     catch( const Exception& )
3157                     {
3158                         SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::impl_initialize: a connection parent which does not have a 'Name'!??" );
3159                     }
3160                 }
3161             }
3162         }
3163 
3164         implAddDatasource( sInitialDataSourceName, xConnection );
3165         m_pTreeView->getListBox().Expand( m_pTreeView->getListBox().First() );
3166     }
3167     else
3168         initializeTreeModel();
3169 
3170     if ( m_bEnableBrowser )
3171     {
3172         m_aDocScriptSupport = ::boost::optional< bool >( false );
3173     }
3174     else
3175     {
3176         // we are not used as "browser", but as mere view for a single table/query/command. In particular,
3177         // there is a specific database document which we belong to.
3178         Reference< XOfficeDatabaseDocument > xDocument( getDataSourceOrModel(
3179             lcl_getDataSource( m_xDatabaseContext, sInitialDataSourceName, xConnection ) ), UNO_QUERY );
3180         m_aDocScriptSupport = ::boost::optional< bool >( Reference< XEmbeddedScripts >( xDocument, UNO_QUERY ).is() );
3181     }
3182 
3183     if ( implSelect( sInitialDataSourceName, sInitialCommand, nInitialDisplayCommandType, bEscapeProcessing, xConnection, true ) )
3184     {
3185         try
3186         {
3187             Reference< XPropertySet > xRowSetProps(getRowSet(), UNO_QUERY);
3188             xRowSetProps->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,makeAny(aCatalogName));
3189             xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,makeAny(aSchemaName));
3190             xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,makeAny(aTableName));
3191 
3192         }
3193         catch(const Exception&)
3194         {
3195             SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: could not set the update related names!");
3196         }
3197     }
3198 
3199     InvalidateAll();
3200 }
3201 
3202 bool SbaTableQueryBrowser::haveExplorer() const
3203 {
3204     return m_pTreeView && m_pTreeView->IsVisible();
3205 }
3206 
3207 void SbaTableQueryBrowser::hideExplorer()
3208 {
3209     if (!haveExplorer())
3210         return;
3211     if (!getBrowserView())
3212         return;
3213 
3214     m_pTreeView->Hide();
3215     m_pSplitter->Hide();
3216     getBrowserView()->Resize();
3217 
3218     InvalidateFeature(ID_BROWSER_EXPLORER);
3219 }
3220 
3221 void SbaTableQueryBrowser::showExplorer()
3222 {
3223     if (haveExplorer())
3224         return;
3225 
3226     if (!getBrowserView())
3227         return;
3228 
3229     m_pTreeView->Show();
3230     m_pSplitter->Show();
3231     getBrowserView()->Resize();
3232 
3233     InvalidateFeature(ID_BROWSER_EXPLORER);
3234 }
3235 
3236 bool SbaTableQueryBrowser::ensureConnection(SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection)
3237 {
3238     SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(_pAnyEntry);
3239     DBTreeListUserData* pDSData =
3240                 pDSEntry
3241             ?   static_cast<DBTreeListUserData*>(pDSEntry->GetUserData())
3242             :   nullptr;
3243 
3244     return ensureConnection( pDSEntry, pDSData, _rConnection );
3245 }
3246 
3247 std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor( SvTreeListEntry* _pAnyEntry )
3248 {
3249     std::unique_ptr< ImageProvider > pImageProvider( new ImageProvider );
3250     SharedConnection xConnection;
3251     if ( getExistentConnectionFor( _pAnyEntry, xConnection ) )
3252         pImageProvider.reset( new ImageProvider( xConnection ) );
3253     return pImageProvider;
3254 }
3255 
3256 bool SbaTableQueryBrowser::getExistentConnectionFor( SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection )
3257 {
3258     SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent( _pAnyEntry );
3259     DBTreeListUserData* pDSData =
3260                 pDSEntry
3261             ?   static_cast< DBTreeListUserData* >( pDSEntry->GetUserData() )
3262             :   nullptr;
3263     if ( pDSData )
3264         _rConnection = pDSData->xConnection;
3265     return _rConnection.is();
3266 }
3267 
3268 bool SbaTableQueryBrowser::impl_isDataSourceEntry( SvTreeListEntry* _pEntry ) const
3269 {
3270     return m_pTreeView->GetTreeModel()->GetRootLevelParent( _pEntry ) == _pEntry;
3271 }
3272 
3273 bool SbaTableQueryBrowser::ensureConnection( SvTreeListEntry* _pDSEntry, void* pDSData, SharedConnection& _rConnection )
3274 {
3275     OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" );
3276     if(_pDSEntry)
3277     {
3278         DBTreeListUserData* pTreeListData = static_cast<DBTreeListUserData*>(pDSData);
3279         OUString aDSName = GetEntryText(_pDSEntry);
3280 
3281         if ( pTreeListData )
3282             _rConnection = pTreeListData->xConnection;
3283 
3284         if ( !_rConnection.is() && pTreeListData )
3285         {
3286             // show the "connecting to ..." status
3287             OUString sConnecting(DBA_RES(STR_CONNECTING_DATASOURCE));
3288             sConnecting = sConnecting.replaceFirst("$name$", aDSName);
3289             BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sConnecting);
3290 
3291             // build a string showing context information in case of error
3292             OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE));
3293             sConnectingContext = sConnectingContext.replaceFirst("$name$", aDSName);
3294 
3295             // connect
3296             _rConnection.reset(
3297                 connect( getDataSourceAccessor( _pDSEntry ), sConnectingContext, nullptr ),
3298                 SharedConnection::TakeOwnership
3299             );
3300 
3301             // remember the connection
3302             pTreeListData->xConnection = _rConnection;
3303         }
3304     }
3305 
3306     return _rConnection.is();
3307 }
3308 
3309 IMPL_LINK( SbaTableQueryBrowser, OnTreeEntryCompare, const SvSortData&, _rSortData, sal_Int32 )
3310 {
3311     const SvTreeListEntry* pLHS = _rSortData.pLeft;
3312     const SvTreeListEntry* pRHS = _rSortData.pRight;
3313     OSL_ENSURE(pLHS && pRHS, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid tree entries!");
3314     // we want the table entry and the end so we have to do a check
3315 
3316     if (isContainer(pRHS))
3317     {
3318         // don't use getEntryType (directly or indirecly) for the LHS:
3319         // LHS is currently being inserted, so it is not "completely valid" at the moment
3320 
3321         const EntryType eRight = getEntryType(pRHS);
3322         if (etTableContainer == eRight)
3323             // every other container should be placed _before_ the bookmark container
3324             return -1;
3325 
3326         const OUString sLeft = m_pTreeView->getListBox().GetEntryText(const_cast<SvTreeListEntry*>(pLHS));
3327 
3328         EntryType eLeft = etTableContainer;
3329         if (DBA_RES(RID_STR_TABLES_CONTAINER) == sLeft)
3330             eLeft = etTableContainer;
3331         else if (DBA_RES(RID_STR_QUERIES_CONTAINER) == sLeft)
3332             eLeft = etQueryContainer;
3333 
3334         if ( eLeft == eRight )
3335             return 0;
3336 
3337         if ( ( eLeft == etTableContainer ) && ( eRight == etQueryContainer ) )
3338             return 1;
3339 
3340         if ( ( eLeft == etQueryContainer ) && ( eRight == etTableContainer ) )
3341             return -1;
3342 
3343         SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::OnTreeEntryCompare: unexpected case!" );
3344         return 0;
3345     }
3346 
3347     const SvLBoxString* pLeftTextItem = static_cast<const SvLBoxString*>(pLHS->GetFirstItem(SvLBoxItemType::String));
3348     const SvLBoxString* pRightTextItem = static_cast<const SvLBoxString*>(pRHS->GetFirstItem(SvLBoxItemType::String));
3349     OSL_ENSURE(pLeftTextItem && pRightTextItem, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid text items!");
3350 
3351     OUString sLeftText = pLeftTextItem->GetText();
3352     OUString sRightText = pRightTextItem->GetText();
3353 
3354     sal_Int32 nCompareResult = 0;   // equal by default
3355 
3356     if (m_xCollator.is())
3357     {
3358         try
3359         {
3360             nCompareResult = m_xCollator->compareString(sLeftText, sRightText);
3361         }
3362         catch(const Exception&)
3363         {
3364         }
3365     }
3366     else
3367         // default behaviour if we do not have a collator -> do the simple string compare
3368         nCompareResult = sLeftText.compareTo(sRightText);
3369 
3370     return nCompareResult;
3371 }
3372 
3373 void SbaTableQueryBrowser::implAdministrate( SvTreeListEntry* _pApplyTo )
3374 {
3375     OSL_PRECOND( _pApplyTo, "SbaTableQueryBrowser::implAdministrate: illegal entry!" );
3376     if ( !_pApplyTo )
3377         return;
3378 
3379     try
3380     {
3381         // get the desktop object
3382         Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() );
3383 
3384         // the initial selection
3385         SvTreeListEntry* pTopLevelSelected = _pApplyTo;
3386         while (pTopLevelSelected && m_pTreeView->getListBox().GetParent(pTopLevelSelected))
3387             pTopLevelSelected = m_pTreeView->getListBox().GetParent(pTopLevelSelected);
3388         OUString sInitialSelection;
3389         if (pTopLevelSelected)
3390             sInitialSelection = getDataSourceAccessor( pTopLevelSelected );
3391 
3392         Reference< XDataSource > xDataSource( getDataSourceByName( sInitialSelection, getView(), getORB(), nullptr ) );
3393         Reference< XModel > xDocumentModel( getDataSourceOrModel( xDataSource ), UNO_QUERY );
3394 
3395         if ( xDocumentModel.is() )
3396         {
3397             Reference< XInteractionHandler2 > xInteractionHandler(
3398                 InteractionHandler::createWithParent(getORB(), nullptr) );
3399 
3400             ::comphelper::NamedValueCollection aLoadArgs;
3401             aLoadArgs.put( "Model", xDocumentModel );
3402             aLoadArgs.put( "InteractionHandler", xInteractionHandler );
3403             aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
3404 
3405             Sequence< PropertyValue > aLoadArgPV;
3406             aLoadArgs >>= aLoadArgPV;
3407 
3408             xFrameLoader->loadComponentFromURL(
3409                 xDocumentModel->getURL(),
3410                 "_default",
3411                 FrameSearchFlag::ALL | FrameSearchFlag::GLOBAL,
3412                 aLoadArgPV
3413             );
3414         }
3415     }
3416     catch( const Exception& )
3417     {
3418         DBG_UNHANDLED_EXCEPTION("dbaccess");
3419     }
3420 }
3421 
3422 bool SbaTableQueryBrowser::requestQuickHelp( const SvTreeListEntry* _pEntry, OUString& _rText ) const
3423 {
3424     const DBTreeListUserData* pData = static_cast< const DBTreeListUserData* >( _pEntry->GetUserData() );
3425     if ( ( pData->eType == etDatasource ) && !pData->sAccessor.isEmpty() )
3426     {
3427         _rText = ::svt::OFileNotation( pData->sAccessor ).get( ::svt::OFileNotation::N_SYSTEM );
3428         return true;
3429     }
3430     return false;
3431 }
3432 
3433 OUString SbaTableQueryBrowser::getContextMenuResourceName( Control& _rControl ) const
3434 {
3435     OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl,
3436         "SbaTableQueryBrowser::getContextMenuResourceName: where does this come from?" );
3437     if ( &m_pTreeView->getListBox() != &_rControl )
3438         return OUString();
3439 
3440     return OUString("explorer");
3441 }
3442 
3443 IController& SbaTableQueryBrowser::getCommandController()
3444 {
3445     return *this;
3446 }
3447 
3448 ::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors()
3449 {
3450     return &m_aContextMenuInterceptors;
3451 }
3452 
3453 Any SbaTableQueryBrowser::getCurrentSelection( Control& _rControl ) const
3454 {
3455     OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl,
3456         "SbaTableQueryBrowser::getCurrentSelection: where does this come from?" );
3457 
3458     if ( &m_pTreeView->getListBox() != &_rControl )
3459         return Any();
3460 
3461     SvTreeListEntry* pSelected = m_pTreeView->getListBox().FirstSelected();
3462     if ( !pSelected )
3463         return Any();
3464 
3465     OSL_ENSURE( m_pTreeView->getListBox().NextSelected( pSelected ) == nullptr,
3466         "SbaTableQueryBrowser::getCurrentSelection: single-selection is expected here!" );
3467 
3468     NamedDatabaseObject aSelectedObject;
3469     DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pSelected->GetUserData() );
3470     aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType );
3471 
3472     switch ( aSelectedObject.Type )
3473     {
3474     case DatabaseObject::QUERY:
3475     case DatabaseObject::TABLE:
3476         aSelectedObject.Name = m_pTreeView->getListBox().GetEntryText( pSelected );
3477         break;
3478 
3479     case DatabaseObjectContainer::DATA_SOURCE:
3480     case DatabaseObjectContainer::QUERIES:
3481     case DatabaseObjectContainer::TABLES:
3482         aSelectedObject.Name = getDataSourceAccessor( pSelected );
3483         break;
3484 
3485     default:
3486         SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" );
3487         break;
3488     }
3489 
3490     return makeAny( aSelectedObject );
3491 }
3492 
3493 bool SbaTableQueryBrowser::implGetQuerySignature( OUString& _rCommand, bool& _bEscapeProcessing )
3494 {
3495     _rCommand.clear();
3496     _bEscapeProcessing = false;
3497 
3498     try
3499     {
3500         // contain the dss (data source signature) of the form
3501         OUString sDataSourceName;
3502         OUString sCommand;
3503         sal_Int32       nCommandType = CommandType::COMMAND;
3504         Reference< XPropertySet > xRowsetProps( getRowSet(), UNO_QUERY );
3505         ODataAccessDescriptor aDesc( xRowsetProps );
3506         sDataSourceName = aDesc.getDataSource();
3507         aDesc[ DataAccessDescriptorProperty::Command ]      >>= sCommand;
3508         aDesc[ DataAccessDescriptorProperty::CommandType ]  >>= nCommandType;
3509 
3510         // do we need to do anything?
3511         if ( CommandType::QUERY != nCommandType )
3512             return false;
3513 
3514         // get the query object
3515         Reference< XQueryDefinitionsSupplier > xSuppQueries;
3516         Reference< XNameAccess > xQueries;
3517         Reference< XPropertySet > xQuery;
3518         m_xDatabaseContext->getByName( sDataSourceName ) >>= xSuppQueries;
3519         if ( xSuppQueries.is() )
3520             xQueries = xSuppQueries->getQueryDefinitions();
3521         if ( xQueries.is() )
3522             xQueries->getByName( sCommand ) >>= xQuery;
3523         OSL_ENSURE( xQuery.is(), "SbaTableQueryBrowser::implGetQuerySignature: could not retrieve the query object!" );
3524 
3525         // get the two properties we need
3526         if ( xQuery.is() )
3527         {
3528             xQuery->getPropertyValue( PROPERTY_COMMAND ) >>= _rCommand;
3529             _bEscapeProcessing = ::cppu::any2bool( xQuery->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) );
3530             return true;
3531         }
3532     }
3533     catch( const Exception& )
3534     {
3535         DBG_UNHANDLED_EXCEPTION("dbaccess");
3536     }
3537 
3538     return false;
3539 }
3540 
3541 void SbaTableQueryBrowser::frameAction(const css::frame::FrameActionEvent& aEvent)
3542 {
3543     if (aEvent.Frame == m_xCurrentFrameParent)
3544     {
3545         if(aEvent.Action == FrameAction_COMPONENT_DETACHING)
3546             implRemoveStatusListeners();
3547         else if (aEvent.Action == FrameAction_COMPONENT_REATTACHED)
3548             connectExternalDispatches();
3549     }
3550     else
3551         SbaXDataBrowserController::frameAction(aEvent);
3552 
3553 }
3554 
3555 void SbaTableQueryBrowser::clearGridColumns(const Reference< XNameContainer >& _xColContainer)
3556 {
3557     // first we have to clear the grid
3558     Reference< XInterface > xColumn;
3559     for (const OUString& rName : _xColContainer->getElementNames())
3560     {
3561         _xColContainer->getByName(rName) >>= xColumn;
3562         _xColContainer->removeByName(rName);
3563         ::comphelper::disposeComponent(xColumn);
3564     }
3565 }
3566 
3567 void SbaTableQueryBrowser::loadMenu(const Reference< XFrame >& _xFrame)
3568 {
3569     if ( m_bShowMenu )
3570     {
3571         OGenericUnoController::loadMenu(_xFrame);
3572     }
3573     else if ( !m_bPreview )
3574     {
3575         Reference< css::frame::XLayoutManager > xLayoutManager = getLayoutManager(_xFrame);
3576 
3577         if ( xLayoutManager.is() )
3578         {
3579             xLayoutManager->lock();
3580             xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
3581             xLayoutManager->unlock();
3582             xLayoutManager->doLayout();
3583         }
3584         onLoadedMenu( xLayoutManager );
3585     }
3586 }
3587 
3588 OUString SbaTableQueryBrowser::getPrivateTitle() const
3589 {
3590     OUString sTitle;
3591     if ( m_pCurrentlyDisplayed )
3592     {
3593         SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(m_pCurrentlyDisplayed);
3594         // get the entry for the datasource
3595         SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer);
3596         OUString sName = m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed);
3597         sTitle = GetEntryText( pConnection );
3598         INetURLObject aURL(sTitle);
3599         if ( aURL.GetProtocol() != INetProtocol::NotValid )
3600             sTitle = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
3601         if ( !sName.isEmpty() )
3602         {
3603             sName += " - ";
3604             sName += sTitle;
3605             sTitle = sName;
3606         }
3607     }
3608 
3609     return sTitle;
3610 }
3611 
3612 bool SbaTableQueryBrowser::preReloadForm()
3613 {
3614     bool bIni = false;
3615     if ( !m_pCurrentlyDisplayed )
3616     {
3617         // switch the grid to design mode while loading
3618         getBrowserView()->getGridControl()->setDesignMode(true);
3619         // we had an invalid statement so we need to connect the column models
3620         Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
3621         svx::ODataAccessDescriptor aDesc(xRowSetProps);
3622         // extract the props
3623         OUString sDataSource;
3624         OUString sCommand;
3625         sal_Int32 nCommandType = CommandType::COMMAND;
3626         bool bEscapeProcessing = true;
3627         extractDescriptorProps(aDesc, sDataSource, sCommand, nCommandType, bEscapeProcessing);
3628         if ( !sDataSource.isEmpty() && !sCommand.isEmpty() && (-1 != nCommandType) )
3629         {
3630             SvTreeListEntry* pDataSource = nullptr;
3631             SvTreeListEntry* pCommandType = nullptr;
3632             m_pCurrentlyDisplayed = getObjectEntry( sDataSource, sCommand, nCommandType, &pDataSource, &pCommandType );
3633             bIni = true;
3634         }
3635     }
3636     return bIni;
3637 }
3638 
3639 void SbaTableQueryBrowser::postReloadForm()
3640 {
3641     InitializeGridModel(getFormComponent());
3642     LoadFinished(true);
3643 }
3644 
3645 Reference< XEmbeddedScripts > SAL_CALL SbaTableQueryBrowser::getScriptContainer()
3646 {
3647     // update our database document
3648     Reference< XModel > xDocument;
3649     try
3650     {
3651         Reference< XPropertySet > xCursorProps( getRowSet(), UNO_QUERY_THROW );
3652         Reference< XConnection > xConnection( xCursorProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY );
3653         if ( xConnection.is() )
3654         {
3655             Reference< XChild > xChild( xConnection, UNO_QUERY_THROW );
3656             Reference< XDocumentDataSource > xDataSource( xChild->getParent(), UNO_QUERY_THROW );
3657             xDocument.set( xDataSource->getDatabaseDocument(), UNO_QUERY_THROW );
3658         }
3659     }
3660     catch( const Exception& )
3661     {
3662         DBG_UNHANDLED_EXCEPTION("dbaccess");
3663     }
3664     Reference< XEmbeddedScripts > xScripts( xDocument, UNO_QUERY );
3665     OSL_ENSURE( xScripts.is() || !xDocument.is(),
3666         "SbaTableQueryBrowser::getScriptContainer: invalid database document!" );
3667     return xScripts;
3668 }
3669 
3670 void SAL_CALL SbaTableQueryBrowser::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
3671 {
3672     if ( Interceptor.is() )
3673         m_aContextMenuInterceptors.addInterface( Interceptor );
3674 }
3675 
3676 void SAL_CALL SbaTableQueryBrowser::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
3677 {
3678     if ( Interceptor.is() )
3679         m_aContextMenuInterceptors.removeInterface( Interceptor );
3680 }
3681 
3682 void SAL_CALL SbaTableQueryBrowser::registeredDatabaseLocation( const DatabaseRegistrationEvent& Event )
3683 {
3684     SolarMutexGuard aGuard;
3685     implAddDatasource( Event.Name, SharedConnection() );
3686 }
3687 
3688 void SbaTableQueryBrowser::impl_cleanupDataSourceEntry( const OUString& _rDataSourceName )
3689 {
3690     // get the top-level representing the removed data source
3691     SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().FirstChild( nullptr );
3692     while ( pDataSourceEntry )
3693     {
3694         if ( m_pTreeView->getListBox().GetEntryText( pDataSourceEntry ) == _rDataSourceName )
3695             break;
3696 
3697         pDataSourceEntry = pDataSourceEntry->NextSibling();
3698     }
3699 
3700     OSL_ENSURE( pDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" );
3701     if ( !pDataSourceEntry )
3702         return;
3703 
3704     if ( isSelected( pDataSourceEntry ) )
3705     {   // a table or query belonging to the deleted data source is currently being displayed.
3706         OSL_ENSURE( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) == pDataSourceEntry,
3707             "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (1)!" );
3708         unloadAndCleanup();
3709     }
3710     else
3711         OSL_ENSURE(
3712                 ( nullptr == m_pCurrentlyDisplayed )
3713             ||  ( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) != pDataSourceEntry ),
3714             "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (2)!");
3715 
3716     // delete any user data of the child entries of the to-be-removed entry
3717     std::pair<SvTreeListEntries::const_iterator, SvTreeListEntries::const_iterator> aIters =
3718         m_pTreeView->GetTreeModel()->GetChildIterators(pDataSourceEntry);
3719 
3720     SvTreeListEntries::const_iterator it = aIters.first, itEnd = aIters.second;
3721 
3722     for (; it != itEnd; ++it)
3723     {
3724         SvTreeListEntry* pEntry = (*it).get();
3725         const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pEntry->GetUserData());
3726         pEntry->SetUserData(nullptr);
3727         delete pData;
3728     }
3729 
3730     // remove the entry
3731     DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() );
3732     pDataSourceEntry->SetUserData( nullptr );
3733     delete pData;
3734     m_pTreeView->GetTreeModel()->Remove( pDataSourceEntry );
3735 }
3736 
3737 void SAL_CALL SbaTableQueryBrowser::revokedDatabaseLocation( const DatabaseRegistrationEvent& Event )
3738 {
3739     SolarMutexGuard aGuard;
3740 
3741     impl_cleanupDataSourceEntry( Event.Name );
3742 
3743     // maybe the object which is part of the document data source has been removed
3744     checkDocumentDataSource();
3745 }
3746 
3747 void SAL_CALL SbaTableQueryBrowser::changedDatabaseLocation( const DatabaseRegistrationEvent& Event )
3748 {
3749     SolarMutexGuard aGuard;
3750 
3751     // in case the data source was expanded, and connected, we need to clean it up
3752     // for simplicity, just do as if the data source were completely removed and re-added
3753     impl_cleanupDataSourceEntry( Event.Name );
3754     implAddDatasource( Event.Name, SharedConnection() );
3755 }
3756 
3757 }   // namespace dbaui
3758 
3759 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3760