Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  unodatbr.cxx

  Sprache: C
 

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <browserids.hxx>
#include <core_resource.hxx>
#include <helpids.h>
#include <dbtreelistbox.hxx>
#include "dbtreemodel.hxx"
#include <strings.hrc>
#include <imageprovider.hxx>
#include <sbagrid.hxx>
#include <strings.hxx>
#include <UITools.hxx>
#include <unodatbr.hxx>

#include <com/sun/star/awt/MouseWheelBehavior.hpp>
#include <com/sun/star/awt/TextAlign.hpp>
#include <com/sun/star/awt/VisualEffect.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/form/XGridColumnFactory.hpp>
#include <com/sun/star/form/XLoadable.hpp>
#include <com/sun/star/form/XReset.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#include <com/sun/star/frame/XLayoutManager.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/i18n/Collator.hpp>
#include <com/sun/star/sdb/CommandType.hpp>
#include <com/sun/star/sdb/SQLContext.hpp>
#include <com/sun/star/sdb/XDatabaseContext.hpp>
#include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
#include <com/sun/star/sdb/XDocumentDataSource.hpp>
#include <com/sun/star/sdb/XParametersSupplier.hpp>
#include <com/sun/star/sdb/XQueriesSupplier.hpp>
#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
#include <com/sun/star/sdb/XResultSetAccess.hpp>
#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
#include <com/sun/star/sdbc/ColumnValue.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/FetchDirection.hpp>
#include <com/sun/star/sdbc/SQLWarning.hpp>
#include <com/sun/star/sdbc/XDataSource.hpp>
#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
#include <com/sun/star/task/InteractionHandler.hpp>
#include <com/sun/star/util/XFlushable.hpp>
#include <com/sun/star/util/XNumberFormatter.hpp>
#include <com/sun/star/util/XURLTransformer.hpp>
#include <com/sun/star/document/MacroExecMode.hpp>
#include <com/sun/star/ui/XContextMenuInterceptor.hpp>

#include <comphelper/extract.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/types.hxx>
#include <connectivity/dbexception.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <svl/filenotation.hxx>
#include <svx/dataaccessdescriptor.hxx>
#include <svx/databaseregistrationui.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <tools/multisel.hxx>
#include <tools/urlobj.hxx>
#include <unotools/confignode.hxx>
#include <utility>
#include <vcl/split.hxx>
#include <vcl/svapp.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/settings.hxx>
#include <vcl/weld.hxx>

#include <memory>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::awt;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdb::application;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::ui::dialogs;
using namespace ::com::sun::star::task;
using namespace ::com::sun::star::form;
using namespace ::com::sun::star::i18n;
using namespace ::com::sun::star::view;
using namespace ::com::sun::star::datatransfer;
using namespace ::com::sun::star::document;
using namespace ::com::sun::star::ui;
using namespace ::dbtools;
using namespace ::comphelper;
using namespace ::svx;

// SbaTableQueryBrowser
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
org_openoffice_comp_dbu_ODatasourceBrowser_get_implementation(
    css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
{
    SolarMutexGuard aGuard;
    return cppu::acquire(new ::dbaui::SbaTableQueryBrowser(context));
}

namespace dbaui
{

namespace DatabaseObject = css::sdb::application::DatabaseObject;
namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer;

static void SafeAddPropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
{
    Reference< XPropertySetInfo >  xInfo = xSet->getPropertySetInfo();
    if (xInfo->hasPropertyByName(rPropName))
        xSet->addPropertyChangeListener(rPropName, pListener);
}

static void SafeRemovePropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
{
    Reference< XPropertySetInfo >  xInfo = xSet->getPropertySetInfo();
    if (xInfo->hasPropertyByName(rPropName))
        xSet->removePropertyChangeListener(rPropName, pListener);
}

OUString SAL_CALL SbaTableQueryBrowser::getImplementationName()
{
    return u"org.openoffice.comp.dbu.ODatasourceBrowser"_ustr;
}

css::uno::Sequence<OUString> SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames()
{
    return { u"com.sun.star.sdb.DataSourceBrowser"_ustr };
}

SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM)
    :SbaXDataBrowserController(_rM)
    ,m_aSelectionListeners( getMutex() )
    ,m_aContextMenuInterceptors( getMutex() )
    ,m_aTableCopyHelper(this)
    ,m_pTreeView(nullptr)
    ,m_pSplitter(nullptr)
    ,m_nAsyncDrop(nullptr)
    ,m_bQueryEscapeProcessing( false )
    ,m_bShowMenu(false)
    ,m_bInSuspend(false)
    ,m_bEnableBrowser(true)
{
}

SbaTableQueryBrowser::~SbaTableQueryBrowser()
{
    if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
    {
        SAL_WARN("dbaccess.ui""Please check who doesn't dispose this component!");
        // increment ref count to prevent double call of Dtor
        osl_atomic_increment( &m_refCount );
        dispose();
    }
    SolarMutexGuard g;
    m_pTreeView.reset();
    m_pSplitter.reset();
}

Any SAL_CALL SbaTableQueryBrowser::queryInterface(const Type& _rType)
{
    if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) )
    {
        OSL_PRECOND( m_aDocScriptSupport.has_value(), "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" );
        if ( m_aDocScriptSupport.has_value() && *m_aDocScriptSupport )
            return Any( Reference< XScriptInvocationContext >( this ) );
        return Any();
    }

    Any aReturn = SbaXDataBrowserController::queryInterface(_rType);
    if (!aReturn.hasValue())
        aReturn = SbaTableQueryBrowser_Base::queryInterface(_rType);
    return aReturn;
}

Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes(  )
{
    Sequence< Type > aTypes( ::comphelper::concatSequences(
        SbaXDataBrowserController::getTypes(),
        SbaTableQueryBrowser_Base::getTypes()
    ) );

    OSL_PRECOND( m_aDocScriptSupport.has_value(), "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" );
    if ( !m_aDocScriptSupport.has_value() || !*m_aDocScriptSupport )
    {
        auto [begin, end] = asNonConstRange(aTypes);
        auto newEnd = std::remove_if( begin, end,
                                      [](const Type& type)
                                      { return type == cppu::UnoType<XScriptInvocationContext>::get(); } );
        aTypes.realloc( std::distance(begin, newEnd) );
    }
    return aTypes;
}

Sequence< sal_Int8 > SAL_CALL SbaTableQueryBrowser::getImplementationId(  )
{
    return css::uno::Sequence<sal_Int8>();
}

void SAL_CALL SbaTableQueryBrowser::disposing()
{
    SolarMutexGuard aGuard;
        // doin' a lot of VCL stuff here -> lock the SolarMutex

    // kiss our listeners goodbye
    css::lang::EventObject aEvt(*this);
    m_aSelectionListeners.disposeAndClear(aEvt);
    m_aContextMenuInterceptors.disposeAndClear(aEvt);

    if (getBrowserView())
    {
        // Need to do some cleanup of the data pointed to the tree view entries before we remove the treeview
        clearTreeModel();
        m_pTreeView = nullptr;
        getBrowserView()->setTreeView(nullptr);
    }

    // remove ourself as status listener
    implRemoveStatusListeners();

    // check out from all the objects we are listening
    // the frame
    if (m_xCurrentFrameParent.is())
        m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));

    // remove the container listener from the database context
    try
    {
        Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
        xDatabaseRegistrations->removeDatabaseRegistrationsListener( this );
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }

    SbaXDataBrowserController::disposing();
}

bool SbaTableQueryBrowser::Construct(vcl::Window* pParent)
{
    if ( !SbaXDataBrowserController::Construct( pParent ) )
        return false;

    try
    {
        Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
        xDatabaseRegistrations->addDatabaseRegistrationsListener( this );

        // the collator for the string compares
        m_xCollator = Collator::create( getORB() );
        m_xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
    }
    catch(const Exception&)
    {
        SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::Construct: could not create (or start listening at) the database context!");
    }

    // some help ids
    if (!getBrowserView() || !getBrowserView()->getVclControl())
        return true;

    // create controls and set sizes
    const tools::Long  nFrameWidth = getBrowserView()->LogicToPixel(::Size(3, 0), MapMode(MapUnit::MapAppFont)).Width();

    m_pSplitter = VclPtr<Splitter>::Create(getBrowserView(),WB_HSCROLL);
    m_pSplitter->SetPosSizePixel( ::Point(0,0), ::Size(nFrameWidth,0) );
    m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) );

    m_pTreeView = VclPtr<InterimDBTreeListBox>::Create(getBrowserView());

    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    rTreeView.connect_expanding(LINK(this, SbaTableQueryBrowser, OnExpandEntry));

    m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry));

    m_pTreeView->setContextMenuProvider( this );
    m_pTreeView->setControlActionListener( this );
    m_pTreeView->SetHelpId(HID_CTL_TREEVIEW);

    // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide
    m_pSplitter->SetSplitPosPixel(getBrowserView()->LogicToPixel(::Size(80, 0), MapMode(MapUnit::MapAppFont)).Width());

    getBrowserView()->setSplitter(m_pSplitter);
    getBrowserView()->setTreeView(m_pTreeView);

    // fill view with data
    rTreeView.set_sort_order(true);
    rTreeView.set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter&&nbsp;rRight){
        return OnTreeEntryCompare(rLeft, rRight);
    });
    rTreeView.make_sorted();
    m_pTreeView->SetSelChangeHdl(LINK(this, SbaTableQueryBrowser, OnSelectionChange));
    m_pTreeView->show_container();

    // TODO
    getBrowserView()->getVclControl()->SetHelpId(HID_CTL_TABBROWSER);
    if (getBrowserView()->getVclControl()->GetHeaderBar())
        getBrowserView()->getVclControl()->GetHeaderBar()->SetHelpId(HID_DATABROWSE_HEADER);
    InvalidateFeature(ID_BROWSER_EXPLORER);

    return true;
}

namespace
{
    struct SelectValueByName
    {
        const Any& operator()( OUString const& i_name ) const
        {
            return m_rCollection.get( i_name );
        }

        explicit SelectValueByName( ::comphelper::NamedValueCollection const& i_collection )
            :m_rCollection( i_collection )
        {
        }

        ::comphelper::NamedValueCollection const&   m_rCollection;
    };
}

void SbaTableQueryBrowser::impl_sanitizeRowSetClauses_nothrow()
{
    try
    {
        Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW );
        bool bEscapeProcessing = false;
        OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
        if ( !bEscapeProcessing )
            // don't touch or interpret anything if escape processing is disabled
            return;

        Reference< XSingleSelectQueryComposer > xComposer( createParser_nothrow() );
        if ( !xComposer.is() )
            // can't do anything. Already reported via assertion in createParser_nothrow.
            return;

        // the tables participating in the statement
        const Reference< XTablesSupplier > xSuppTables( xComposer, UNO_QUERY_THROW );
        const Reference< XNameAccess > xTableNames( xSuppTables->getTables(), UNO_SET_THROW );

        // the columns participating in the statement
        const Reference< XColumnsSupplier > xSuppColumns( xComposer, UNO_QUERY_THROW );
        const Reference< XNameAccess > xColumnNames( xSuppColumns->getColumns(), UNO_SET_THROW );

        // check if the order columns apply to tables which really exist in the statement
        const Reference< XIndexAccess > xOrderColumns( xComposer->getOrderColumns(), UNO_SET_THROW );
        const sal_Int32 nOrderColumns( xOrderColumns->getCount() );
        bool invalidColumn = nOrderColumns == 0;
        for ( sal_Int32 c=0; ( c < nOrderColumns ) && !invalidColumn; ++c )
        {
            const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW );
            OUString sTableName;
            OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName );
            OUString sColumnName;
            OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName );

            if ( sTableName.isEmpty() )
            {
                if ( !xColumnNames->hasByName( sColumnName ) )
                {
                    invalidColumn = true;
                    break;
                }
            }
            else
            {
                if ( !xTableNames->hasByName( sTableName ) )
                {
                    invalidColumn = true;
                    break;
                }

                const Reference< XColumnsSupplier > xSuppTableColumns( xTableNames->getByName( sTableName ), UNO_QUERY_THROW );
                const Reference< XNameAccess > xTableColumnNames( xSuppTableColumns->getColumns(), UNO_SET_THROW );
                if ( !xTableColumnNames->hasByName( sColumnName ) )
                {
                    invalidColumn = true;
                    break;
                }
            }
        }

        if ( invalidColumn )
        {
            // reset the complete order statement at both the row set and the parser
            xRowSetProps->setPropertyValue( PROPERTY_ORDER, Any( OUString() ) );
            xComposer->setOrder( u""_ustr );
        }

        // check if the columns participating in the filter refer to existing tables
        // TODO: there's no API at all for this. The method which comes nearest to what we need is
        // "getStructuredFilter", but it returns pure column names only. That is, for a statement like
        // "SELECT * FROM <table> WHERE <other_table>.<column> = <value>", it will return "<column>". But
        // there's no API at all to retrieve the information about  "<other_table>" - which is what would
        // be needed here.
        // That'd be a chance to replace getStructuredFilter with something more reasonable.
        // So, what really would be handy, is some
        //   XNormalizedFilter getNormalizedFilter();
        // with
        //   interface XDisjunctiveFilterExpression
        //   {
        //     XConjunctiveFilterTerm getTerm( int index );
        //   }
        //   interface XConjunctiveFilterTerm
        //   {
        //     ComparisonPredicate getPredicate( int index );
        //   }
        //   struct ComparisonPredicate
        //   {
        //     XComparisonOperand   Lhs;
        //     SQLFilterOperator    Operator;
        //     XComparisonOperand   Rhs;
        //   }
        //   interface XComparisonOperand
        //   {
        //     SQLFilterOperand Type;
        //     XPropertySet     getColumn();
        //     string           getLiteral();
        //     ...
        //   }
        //   enum SQLFilterOperand { Column, Literal, ... }
        // ... or something like this...
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }
}

bool SbaTableQueryBrowser::InitializeForm( const Reference< XPropertySet > & i_formProperties )
{
    if (!m_xCurrentlyDisplayed)
        return true;

    // this method set all format settings from the original table or query
    try
    {
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
        ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" );
        ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" );

        Reference< XPropertySetInfo > xPSI( pData->xObjectProperties->getPropertySetInfo(), UNO_SET_THROW );

        ::comphelper::NamedValueCollection aPropertyValues;

        const OUString aTransferProperties[] =
        {
            PROPERTY_APPLYFILTER,
            PROPERTY_FILTER,
            PROPERTY_HAVING_CLAUSE,
            PROPERTY_ORDER
        };
        for (const auto & aTransferProperty : aTransferProperties)
        {
            if ( !xPSI->hasPropertyByName( aTransferProperty ) )
                continue;
            aPropertyValues.put( aTransferProperty, pData->xObjectProperties->getPropertyValue( aTransferProperty ) );
        }

        std::vector< OUString > aNames( aPropertyValues.getNames() );
        std::sort(aNames.begin(), aNames.end());
        Sequence< OUString > aPropNames( comphelper::containerToSequence(aNames) );

        Sequence< Any > aPropValues( aNames.size() );
        std::transform( aNames.begin(), aNames.end(), aPropValues.getArray(), SelectValueByName( aPropertyValues ) );

        Reference< XMultiPropertySet > xFormMultiSet( i_formProperties, UNO_QUERY_THROW );
        xFormMultiSet->setPropertyValues( aPropNames, aPropValues );

        impl_sanitizeRowSetClauses_nothrow();
    }
    catch ( const Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
        return false;
    }

    return true;
}

void SbaTableQueryBrowser::initializePreviewMode()
{
    if ( getBrowserView() && getBrowserView()->getVclControl() )
    {
        getBrowserView()->getVclControl()->AlwaysEnableInput( false );
        getBrowserView()->getVclControl()->EnableInput( false );
        getBrowserView()->getVclControl()->ForceHideScrollbars();
    }
    Reference< XPropertySet >  xDataSourceSet(getRowSet(), UNO_QUERY);
    if ( xDataSourceSet.is() )
    {
        xDataSourceSet->setPropertyValue(u"AllowInserts"_ustr,Any(false));
        xDataSourceSet->setPropertyValue(u"AllowUpdates"_ustr,Any(false));
        xDataSourceSet->setPropertyValue(u"AllowDeletes"_ustr,Any(false));
    }
}

void SbaTableQueryBrowser::InitializeGridModel(const Reference< css::form::XFormComponent > & xGrid)
{
    try
    {
        Reference< css::form::XGridColumnFactory >  xColFactory(xGrid, UNO_QUERY);
        Reference< XNameContainer >  xColContainer(xGrid, UNO_QUERY);
        clearGridColumns( xColContainer );

        Reference< XLoadable > xFormAsLoadable;
        if (xGrid.is())
            xFormAsLoadable.set(xGrid->getParent(), css::uno::UNO_QUERY);
        if (xFormAsLoadable.is() && xFormAsLoadable->isLoaded())
        {
            // set the formats from the table
            if (m_xCurrentlyDisplayed)
            {
                Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 ));
                Sequence< Any> aValues(6 + ( m_bPreview ? 5 : 0 ));

                weld::TreeView& rTreeView = m_pTreeView->GetWidget();
                DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
                OSL_ENSURE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeGridModel: No table available!" );
                if ( !pData->xObjectProperties.is() )
                    return;

                OUString* pStringIter = aProperties.getArray();
                Any* pValueIter = aValues.getArray();
                if ( m_bPreview )
                {
                    *pStringIter++  = "AlwaysShowCursor";
                    *pValueIter++   <<= false;
                    *pStringIter++  = PROPERTY_BORDER;
                    *pValueIter++   <<= sal_Int16(0);
                }

                *pStringIter++  = PROPERTY_FONT;
                *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_FONT);
                *pStringIter++  = PROPERTY_TEXTEMPHASIS;
                *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTEMPHASIS);
                *pStringIter++  = PROPERTY_TEXTRELIEF;
                *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTRELIEF);
                if ( m_bPreview )
                {
                    *pStringIter++  = "HasNavigationBar";
                    *pValueIter++       <<= false;
                    *pStringIter++  = "HasRecordMarker";
                    *pValueIter++       <<= false;
                }
                *pStringIter++  = PROPERTY_ROW_HEIGHT;
                *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_ROW_HEIGHT);
                if ( m_bPreview )
                {
                    *pStringIter++  = "Tabstop";
                    *pValueIter++       <<= false;
                }
                *pStringIter++  = PROPERTY_TEXTCOLOR;
                *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTCOLOR);
                *pStringIter++  = PROPERTY_TEXTLINECOLOR;
                *pValueIter++   = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTLINECOLOR);

                Reference< XMultiPropertySet >  xFormMultiSet(xGrid, UNO_QUERY);
                xFormMultiSet->setPropertyValues(aProperties, aValues);
            }

            // get the formats supplier of the database we're working with
            Reference< css::util::XNumberFormatsSupplier >  xSupplier = getNumberFormatter()->getNumberFormatsSupplier();

            Reference<XConnection> xConnection;
            Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
            xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
            OSL_ENSURE(xConnection.is(),"A ActiveConnection should normally exists!");

            Reference<XChild> xChild(xConnection,UNO_QUERY);
            Reference<XPropertySet> xDataSourceProp(xChild->getParent(),UNO_QUERY);
            bool bSuppressVersionCol = false;
            OSL_VERIFY( xDataSourceProp->getPropertyValue( PROPERTY_SUPPRESSVERSIONCL ) >>= bSuppressVersionCol );

            // insert the column into the gridcontrol so that we see something :-)
            OUString aCurrentModelType;
            Reference<XColumnsSupplier> xSupCols(getRowSet(),UNO_QUERY);
            Reference<XNameAccess> xColumns     = xSupCols->getColumns();

            OUString sDefaultProperty;
            Reference< XPropertySet > xColumn;
            Reference< XPropertySetInfo > xColPSI;
            const Sequence<OUString> aColNames = xColumns->getElementNames();
            for (const OUString& rName : aColNames)
            {
                xColumn.set( xColumns->getByName( rName ), UNO_QUERY_THROW );
                xColPSI.set( xColumn->getPropertySetInfo(), UNO_SET_THROW );

                // ignore the column when it is a rowversion one
                if  (   bSuppressVersionCol
                    &&  xColPSI->hasPropertyByName( PROPERTY_ISROWVERSION )
                    &&  ::cppu::any2bool( xColumn->getPropertyValue( PROPERTY_ISROWVERSION ) )
                    )
                    continue;

                // use the result set column's type to determine the type of grid column to create
                bool bFormattedIsNumeric    = true;
                sal_Int32 nType = ::comphelper::getINT32( xColumn->getPropertyValue( PROPERTY_TYPE ) );

                std::vector< NamedValue > aInitialValues;
                std::vector< OUString > aCopyProperties;
                Any aDefault;

                switch(nType)
                {
                    case DataType::BIT:
                    case DataType::BOOLEAN:
                    {
                        aCurrentModelType = "CheckBox";
                        aInitialValues.emplace_back( "VisualEffect", Any( VisualEffect::FLAT ) );
                        sDefaultProperty = PROPERTY_DEFAULTSTATE;

                        sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
                        OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
                        aInitialValues.emplace_back(
                            "TriState",
                            Any( ColumnValue::NO_NULLS != nNullable )
                        );
                        if ( ColumnValue::NO_NULLS == nNullable )
                            aDefault <<= sal_Int16(TRISTATE_FALSE);
                    }
                    break;

                    case DataType::LONGVARCHAR:
                    case DataType::CLOB:
                        aInitialValues.emplace_back( "MultiLine", Any( true ) );
                        [[fallthrough]];
                    case DataType::BINARY:
                    case DataType::VARBINARY:
                    case DataType::LONGVARBINARY:
                        aCurrentModelType = "TextField";
                        sDefaultProperty = PROPERTY_DEFAULTTEXT;
                        break;

                    case DataType::VARCHAR:
                    case DataType::CHAR:
                        bFormattedIsNumeric = false;
                        [[fallthrough]];
                    default:
                        aCurrentModelType = "FormattedField";
                        sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT;

                        if ( xSupplier.is() )
                            aInitialValues.emplace_back( "FormatsSupplier", Any( xSupplier ) );
                        aInitialValues.emplace_back( "TreatAsNumber", Any( bFormattedIsNumeric ) );
                        aCopyProperties.emplace_back(PROPERTY_FORMATKEY );
                        break;
                }

                aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, Any( rName ) );
                OUString sLabel;
                xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
                if ( !sLabel.isEmpty() )
                    aInitialValues.emplace_back( PROPERTY_LABEL, Any( sLabel ) );
                else
                    aInitialValues.emplace_back( PROPERTY_LABEL, Any( rName ) );

                Reference< XPropertySet > xGridCol( xColFactory->createColumn( aCurrentModelType ), UNO_SET_THROW );
                Reference< XPropertySetInfo > xGridColPSI( xGridCol->getPropertySetInfo(), UNO_SET_THROW );

                // calculate the default
                if ( xGridColPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) )
                {
                    aDefault = xColumn->getPropertyValue( PROPERTY_CONTROLDEFAULT );
                    // default value
                    if ( nType == DataType::BIT || nType == DataType::BOOLEAN )
                    {
                        if ( aDefault.hasValue() )
                            aDefault <<= (comphelper::getString(aDefault).toInt32() == 0) ? sal_Int16(TRISTATE_FALSE) : sal_Int16(TRISTATE_TRUE);
                        else
                            aDefault <<= sal_Int16(TRISTATE_INDET);
                    }
                }

                if ( aDefault.hasValue() )
                    aInitialValues.emplace_back( sDefaultProperty, aDefault );

                // transfer properties from the definition to the UNO-model :
                aCopyProperties.emplace_back(PROPERTY_HIDDEN );
                aCopyProperties.emplace_back(PROPERTY_WIDTH );

                // help text to display for the column
                Any aDescription;
                if ( xColPSI->hasPropertyByName( PROPERTY_HELPTEXT ) )
                    aDescription = xColumn->getPropertyValue( PROPERTY_HELPTEXT );
                OUString sTemp;
                aDescription >>= sTemp;
                if ( sTemp.isEmpty() )
                    xColumn->getPropertyValue( PROPERTY_DESCRIPTION ) >>= sTemp;

                aDescription <<= sTemp;
                aInitialValues.emplace_back( PROPERTY_HELPTEXT, aDescription );

                // ... horizontal justify
                Any aAlign; aAlign <<= sal_Int16( 0 );
                Any aColAlign( xColumn->getPropertyValue( PROPERTY_ALIGN ) );
                if ( aColAlign.hasValue() )
                    aAlign <<= sal_Int16( ::comphelper::getINT32( aColAlign ) );
                aInitialValues.emplace_back( PROPERTY_ALIGN, aAlign );

                // don't allow the mouse to scroll in the cells
                if ( xGridColPSI->hasPropertyByName( PROPERTY_MOUSE_WHEEL_BEHAVIOR ) )
                    aInitialValues.emplace_back( PROPERTY_MOUSE_WHEEL_BEHAVIOR, Any( MouseWheelBehavior::SCROLL_DISABLED ) );

                // now set all those values
                for (auto const& property : aInitialValues)
                {
                    xGridCol->setPropertyValue( property.Name, property.Value );
                }
                for (auto const& copyPropertyName : aCopyProperties)
                    xGridCol->setPropertyValue( copyPropertyName, xColumn->getPropertyValue(copyPropertyName) );

                xColContainer->insertByName(rName, Any(xGridCol));
            }
        }
    }
    catch(const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }
}

static Reference<XPropertySet> getColumnHelper(const weld::TreeView& rTreeView,
                                               const weld::TreeIter* pCurrentlyDisplayed,
                                               const Reference<XPropertySet>& rxSource)
{
    Reference<XPropertySet> xRet;
    if (pCurrentlyDisplayed)
    {
        DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pCurrentlyDisplayed));
        Reference<XColumnsSupplier> xColumnsSup(pData->xObjectProperties,UNO_QUERY);
        Reference<XNameAccess> xNames = xColumnsSup->getColumns();
        OUString aName;
        rxSource->getPropertyValue(PROPERTY_NAME) >>= aName;
        if(xNames.is() && xNames->hasByName(aName))
            xRet.set(xNames->getByName(aName),UNO_QUERY);
    }
    return xRet;
}

void SbaTableQueryBrowser::transferChangedControlProperty(const OUString& _rProperty, const Any& _rNewValue)
{
    if (m_xCurrentlyDisplayed)
    {
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
        Reference< XPropertySet > xObjectProps = pData->xObjectProperties;
        OSL_ENSURE(xObjectProps.is(),"SbaTableQueryBrowser::transferChangedControlProperty: no table/query object!");
        if (xObjectProps.is())
            xObjectProps->setPropertyValue(_rProperty, _rNewValue);
    }
}

void SbaTableQueryBrowser::propertyChange(const PropertyChangeEvent& evt)
{
    SbaXDataBrowserController::propertyChange(evt);

    weld::TreeView& rTreeView = m_pTreeView->GetWidget();

    try
    {
        Reference< XPropertySet >  xSource(evt.Source, UNO_QUERY);
        if (!xSource.is())
            return;
        // one of the many properties which require us to update the definition ?
        // a column's width ?
        else if (evt.PropertyName == PROPERTY_WIDTH)
        {   // a column width has changed -> update the model
            // (the update of the view is done elsewhere)
            Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
            if(xProp.is())
            {
                if(!evt.NewValue.hasValue())
                    xProp->setPropertyValue(PROPERTY_WIDTH,Any(sal_Int32(227)));
                else
                    xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue);
            }
        }

        // a column's 'visible' state ?
        else if (evt.PropertyName == PROPERTY_HIDDEN)
        {
            Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
            if(xProp.is())
                xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue);
        }

        // a columns alignment ?
        else if (evt.PropertyName == PROPERTY_ALIGN)
        {
            Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
            try
            {
                if(xProp.is())
                {
                    if(evt.NewValue.hasValue())
                    {
                        sal_Int16 nAlign = 0;
                        if(evt.NewValue >>= nAlign)
                            xProp->setPropertyValue(PROPERTY_ALIGN,Any(sal_Int32(nAlign)));
                        else
                            xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue);
                    }
                    else
                        xProp->setPropertyValue(PROPERTY_ALIGN,Any(css::awt::TextAlign::LEFT));
                }
            }
            catchconst Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("dbaccess");
            }
        }

        // a column's format ?
        else if (   evt.PropertyName == PROPERTY_FORMATKEY
            &&  (TypeClass_LONG == evt.NewValue.getValueTypeClass())
            )
        {
            // update the model (means the definition object)
            Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
            if(xProp.is())
                xProp->setPropertyValue(PROPERTY_FORMATKEY,evt.NewValue);
        }

        // some table definition properties ?
        // the height of the rows in the grid ?
        else if (evt.PropertyName == PROPERTY_ROW_HEIGHT)
        {
            if (m_xCurrentlyDisplayed)
            {
                DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
                OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" );

                bool bDefault = !evt.NewValue.hasValue();
                if (bDefault)
                    pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,Any(sal_Int32(45)));
                else
                    pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,evt.NewValue);
            }
        }

        else if (   evt.PropertyName == PROPERTY_FONT          // the font ?
                ||  evt.PropertyName == PROPERTY_TEXTCOLOR     // the text color ?
                ||  evt.PropertyName == PROPERTY_FILTER        // the filter ?
                ||  evt.PropertyName == PROPERTY_HAVING_CLAUSE // the having clause ?
                ||  evt.PropertyName == PROPERTY_ORDER         // the sort ?
                ||  evt.PropertyName == PROPERTY_APPLYFILTER   // the appliance of the filter ?
                ||  evt.PropertyName == PROPERTY_TEXTLINECOLOR // the text line color ?
                ||  evt.PropertyName == PROPERTY_TEXTEMPHASIS  // the text emphasis ?
                ||  evt.PropertyName == PROPERTY_TEXTRELIEF    // the text relief ?
                )
        {
            transferChangedControlProperty(evt.PropertyName, evt.NewValue);
        }
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }
}

sal_Bool SbaTableQueryBrowser::suspend(sal_Bool bSuspend)
{
    SolarMutexGuard aSolarGuard;
    ::osl::MutexGuard aGuard( getMutex() );
    if ( getView() && getView()->IsInModalMode() )
        return false;
    bool bRet = false;
    if ( !m_bInSuspend )
    {
        m_bInSuspend = true;
        if ( rBHelper.bDisposed )
            throw DisposedException( OUString(), *this );

        bRet = SbaXDataBrowserController::suspend(bSuspend);
        if ( bRet && getView() )
            getView()->Hide();

        m_bInSuspend = false;
    }

    return bRet;
}

void SAL_CALL SbaTableQueryBrowser::statusChanged( const FeatureStateEvent& _rEvent )
{
    // search the external dispatcher causing this call
    Reference< XDispatch > xSource(_rEvent.Source, UNO_QUERY);
    bool bFound = false;
    for (auto & externalFeature : m_aExternalFeatures)
    {
        if ( _rEvent.FeatureURL.Complete == externalFeature.second.aURL.Complete)
        {
            bFound = true;
            OSL_ENSURE( xSource.get() == externalFeature.second.xDispatcher.get(), "SbaTableQueryBrowser::statusChanged: inconsistent!" );
            // update the enabled state
            externalFeature.second.bEnabled = _rEvent.IsEnabled;

            switch ( externalFeature.first )
            {
                case ID_BROWSER_DOCUMENT_DATASOURCE:
                {
                    // if it's the slot for the document data source, remember the state
                    Sequence< PropertyValue > aDescriptor;
                    bool bProperFormat = _rEvent.State >>= aDescriptor;
                    OSL_ENSURE(bProperFormat, "SbaTableQueryBrowser::statusChanged: need a data access descriptor here!");
                    m_aDocumentDataSource.initializeFrom(aDescriptor);

                    OSL_ENSURE( (   m_aDocumentDataSource.has(DataAccessDescriptorProperty::DataSource)
                                ||  m_aDocumentDataSource.has(DataAccessDescriptorProperty::DatabaseLocation)
                                )
                                &&  m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command)
                                &&  m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType),
                        "SbaTableQueryBrowser::statusChanged: incomplete descriptor!");

                    // check if we know the object which is set as document data source
                    checkDocumentDataSource();
                }
                break;

                default:
                    // update the toolbox
                    implCheckExternalSlot( externalFeature.first );
                    break;
            }
            break;
        }
    }

    OSL_ENSURE(bFound, "SbaTableQueryBrowser::statusChanged: don't know who sent this!");
}

void SbaTableQueryBrowser::checkDocumentDataSource()
{
    std::unique_ptr<weld::TreeIter> xDataSourceEntry;
    std::unique_ptr<weld::TreeIter> xContainerEntry;
    std::unique_ptr<weld::TreeIter> xObjectEntry = getObjectEntry(m_aDocumentDataSource, &xDataSourceEntry,&nbsp;&xContainerEntry);
    bool bKnownDocDataSource = static_cast<bool>(xObjectEntry);
    if (!bKnownDocDataSource)
    {
        if (xDataSourceEntry)
        {
            // at least the data source is known
            if (xContainerEntry)
            {
                bKnownDocDataSource = true// assume we know it.
                // TODO: should we expand the object container? This may be too expensive just for checking...
            }
            else
            {
                if (m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType)
                    && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command))
                {   // maybe we have a command to be displayed ?
                    sal_Int32 nCommandType = CommandType::TABLE;
                    m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType;

                    OUString sCommand;
                    m_aDocumentDataSource[DataAccessDescriptorProperty::Command] >>= sCommand;

                    bKnownDocDataSource = (CommandType::COMMAND == nCommandType) && (!sCommand.isEmpty());
                }
            }
        }
    }

    if ( !bKnownDocDataSource )
        m_aExternalFeatures[ ID_BROWSER_DOCUMENT_DATASOURCE ].bEnabled = false;

    // update the toolbox
    implCheckExternalSlot(ID_BROWSER_DOCUMENT_DATASOURCE);
}

void SbaTableQueryBrowser::extractDescriptorProps(const svx::ODataAccessDescriptor&&nbsp;_rDescriptor, OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing)
{
    _rDataSource = _rDescriptor.getDataSource();
    if ( _rDescriptor.has(DataAccessDescriptorProperty::Command) )
        _rDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand;
    if ( _rDescriptor.has(DataAccessDescriptorProperty::CommandType) )
        _rDescriptor[DataAccessDescriptorProperty::CommandType] >>= _rCommandType;

    // escape processing is the only one allowed not to be present
    _rEscapeProcessing = true;
    if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing))
        _rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]);
}

namespace
{
    bool getDataSourceDisplayName_isURL( const OUString& _rDS, OUString& _rDisplayName, OUString& _rUniqueId )
    {
        INetURLObject aURL( _rDS );
        if ( aURL.GetProtocol() != INetProtocol::NotValid )
        {
            _rDisplayName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
            _rUniqueId = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
            return true;
        }
        _rDisplayName = _rDS;
        _rUniqueId.clear();
        return false;
    }

    struct FilterByEntryDataId : public IEntryFilter
    {
        OUString sId;
        explicit FilterByEntryDataId( OUString _aId ) : sId(std::move( _aId )) { }

        virtual ~FilterByEntryDataId() {}

        virtual bool    includeEntry(const void* pEntry) const override;
    };

    bool FilterByEntryDataId::includeEntry(const void* pUserData) const
    {
        const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData);
        return ( !pData || ( pData->sAccessor == sId ) );
    }
}

OUString SbaTableQueryBrowser::getDataSourceAccessor(const weld::TreeIter& rDataSourceEntry) const
{
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rDataSourceEntry));
    assert(pData && "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry data!");
    OSL_ENSURE( pData->eType == etDatasource, "SbaTableQueryBrowser::getDataSourceAccessor: entry does not denote a data source!" );
    return !pData->sAccessor.isEmpty() ? pData->sAccessor : GetEntryText(rDataSourceEntry);
}

std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const OUString&&nbsp;_rDataSource, const OUString& _rCommand, sal_Int32 nCommandType,
        std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry, bool bExpandAncestors,
        const SharedConnection& _rxConnection )
{
    if (ppDataSourceEntry)
        ppDataSourceEntry->reset();
    if (ppContainerEntry)
        ppContainerEntry->reset();

    std::unique_ptr<weld::TreeIter> xObject;
    if ( m_pTreeView )
    {
        // look for the data source entry
        OUString sDisplayName, sDataSourceId;
        bool bIsDataSourceURL = getDataSourceDisplayName_isURL( _rDataSource, sDisplayName, sDataSourceId );
            // the display name may differ from the URL for readability reasons
            // #i33699#

        FilterByEntryDataId aFilter( sDataSourceId );
        std::unique_ptr<weld::TreeIter> xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter );
        if (!xDataSource) // check if the data source name is a file location
        {
            if ( bIsDataSourceURL )
            {
                // special case, the data source is a URL
                // add new entries to the list box model
                implAddDatasource( _rDataSource, _rxConnection );
                xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter );
                OSL_ENSURE( xDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" );
            }
        }

        weld::TreeView& rTreeView = m_pTreeView->GetWidget();

        if (xDataSource)
        {
            if (ppDataSourceEntry)
            {
                // (caller wants to have it...)
                *ppDataSourceEntry = rTreeView.make_iterator(xDataSource.get());
            }

            // expand if required so
            if (bExpandAncestors)
                rTreeView.expand_row(*xDataSource);

            // look for the object container
            std::unique_ptr<weld::TreeIter> xCommandType;
            if (nCommandType == CommandType::QUERY || nCommandType == CommandType::TABLE)
            {
                xCommandType = rTreeView.make_iterator(xDataSource.get());
                if (!rTreeView.iter_children(*xCommandType))
                    xCommandType.reset();
                else
                {
                    // 1st child is queries, so we're already done if looking for CommandType::QUERY

                    // 2nd child is tables
                    if (nCommandType == CommandType::TABLE && !rTreeView.iter_next_sibling(*xCommandType))
                        xCommandType.reset();
                }
            }

            if (xCommandType)
            {
                if (ppContainerEntry)
                {
                    // (caller wants to have it...)
                    *ppContainerEntry = rTreeView.make_iterator(xCommandType.get());
                }

                rTreeView.make_unsorted();

                // expand if required so
                if (bExpandAncestors)
                {
                    rTreeView.expand_row(*xCommandType);
                }

                // look for the object
                sal_Int32 nIndex = 0;
                do
                {
                    OUString sPath;
                    switch (nCommandType)
                    {
                    case CommandType::TABLE:
                        sPath = _rCommand;
                        nIndex = -1;
                        break;

                    case CommandType::QUERY:
                        sPath = _rCommand.getToken( 0, '/', nIndex );
                        break;

                    default:
                        assert(false);
                    }
                    xObject = m_pTreeView->GetEntryPosByName(sPath, xCommandType.get());
                    if (xObject)
                        rTreeView.copy_iterator(*xObject, *xCommandType);
                    else
                        xCommandType.reset();
                    if ( nIndex >= 0 )
                    {
                        if (ensureEntryObject(*xObject))
                        {
                            DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xObject));
                            Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
                            sal_Int32 nIndex2 = nIndex;
                            sPath = _rCommand.getToken( 0, '/', nIndex2 );
                            try
                            {
                                if ( xCollection->hasByName(sPath) )
                                {
                                    if(!m_pTreeView->GetEntryPosByName(sPath, xObject.get()))
                                    {
                                        Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY);
                                        DBTreeListUserData* pEntryData = new DBTreeListUserData;
                                        pEntryData->eType = etQuery;
                                        if ( xChild.is() )
                                        {
                                            pEntryData->eType = etQueryContainer;
                                        }
                                        implAppendEntry(xObject.get(), sPath, pEntryData);
                                    }
                                }
                            }
                            catch(const Exception&)
                            {
                                SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::populateTree: could not fill the tree");
                            }
                        }
                    }
                }
                while ( nIndex >= 0 );

                rTreeView.make_sorted();
            }
        }
    }
    return xObject;
}

std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor,
        std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry)
{
    // extract the props from the descriptor
    OUString sDataSource;
    OUString sCommand;
    sal_Int32 nCommandType = CommandType::COMMAND;
    bool bEscapeProcessing = true;
    extractDescriptorProps(rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);

    return getObjectEntry(sDataSource, sCommand, nCommandType, ppDataSourceEntry, ppContainerEntry, false /*bExpandAncestors*/);
}

void SbaTableQueryBrowser::connectExternalDispatches()
{
    Reference< XDispatchProvider >  xProvider( getFrame(), UNO_QUERY );
    OSL_ENSURE(xProvider.is(), "SbaTableQueryBrowser::connectExternalDispatches: no DispatchProvider !");
    if (!xProvider.is())
        return;

    if ( m_aExternalFeatures.empty() )
    {
        static constexpr OUString aURLs[] {
            u".uno:DataSourceBrowser/DocumentDataSource"_ustr,
            u".uno:DataSourceBrowser/FormLetter"_ustr,
            u".uno:DataSourceBrowser/InsertColumns"_ustr,
            u".uno:DataSourceBrowser/InsertContent"_ustr,
        };
        static constexpr sal_uInt16 nIds[] = {
            ID_BROWSER_DOCUMENT_DATASOURCE,
            ID_BROWSER_FORMLETTER,
            ID_BROWSER_INSERTCOLUMNS,
            ID_BROWSER_INSERTCONTENT
        };

        for ( size_t i=0; i < std::size( aURLs ); ++i )
        {
            URL aURL;
            aURL.Complete = aURLs[i];
            if ( m_xUrlTransformer.is() )
                m_xUrlTransformer->parseStrict( aURL );
            m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( std::move(aURL) );
        }
    }

    for (auto & externalFeature : m_aExternalFeatures)
    {
        externalFeature.second.xDispatcher = xProvider->queryDispatch(
            externalFeature.second.aURL, u"_parent"_ustr, FrameSearchFlag::PARENT
        );

        if ( externalFeature.second.xDispatcher.get() == static_cast< XDispatch* >( this ) )
        {
            SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::connectExternalDispatches: this should not happen anymore!" );
                // (nowadays, the URLs aren't in our SupportedFeatures list anymore, so we should
                // not supply a dispatcher for this)
            externalFeature.second.xDispatcher.clear();
        }

        if ( externalFeature.second.xDispatcher.is() )
        {
            try
            {
                externalFeature.second.xDispatcher->addStatusListener( this, externalFeature.second.aURL );
            }
            catchconst Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("dbaccess");
            }
        }

        implCheckExternalSlot( externalFeature.first );
    }
}

void SbaTableQueryBrowser::implCheckExternalSlot( sal_uInt16 _nId )
{
    if ( !m_xMainToolbar.is() )
        return;

    VclPtr<vcl::Window> pToolboxWindow = VCLUnoHelper::GetWindow( m_xMainToolbar );
    ToolBox* pToolbox = dynamic_cast< ToolBox* >( pToolboxWindow.get() );
    OSL_ENSURE( pToolbox, "SbaTableQueryBrowser::implCheckExternalSlot: cannot obtain the toolbox window!" );

    // check if we have to hide this item from the toolbox
    if ( pToolbox )
    {
        bool bHaveDispatcher = m_aExternalFeatures[ _nId ].xDispatcher.is();
        if ( bHaveDispatcher != pToolbox->IsItemVisible( ToolBoxItemId(_nId) ) )
            bHaveDispatcher ? pToolbox->ShowItem( ToolBoxItemId(_nId) ) : pToolbox->HideItem( ToolBoxItemId(_nId) );
    }

    // and invalidate this feature in general
    InvalidateFeature( _nId );
}

void SAL_CALL SbaTableQueryBrowser::disposing( const css::lang::EventObject& _rSource )
{
    // our frame ?
    Reference< css::frame::XFrame >  xSourceFrame(_rSource.Source, UNO_QUERY);
    if (m_xCurrentFrameParent.is() && (xSourceFrame == m_xCurrentFrameParent))
        m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
    else
    {
        // search the external dispatcher causing this call in our map
        Reference< XDispatch > xSource(_rSource.Source, UNO_QUERY);
        if(xSource.is())
        {
            ExternalFeaturesMap::const_iterator aLoop = m_aExternalFeatures.begin();
            ExternalFeaturesMap::const_iterator aEnd = m_aExternalFeatures.end();
            while (aLoop != aEnd)
            {
                if ( aLoop->second.xDispatcher.get() == xSource.get() )
                {
                    sal_uInt16 nSlot = aLoop->first;

                    // remove it
                    aLoop = m_aExternalFeatures.erase(aLoop);

                    // maybe update the UI
                    implCheckExternalSlot(nSlot);

                    // continue, the same XDispatch may be responsible for more than one URL
                }
                ++aLoop;
            }
        }
        else
        {
            Reference<XConnection> xCon(_rSource.Source, UNO_QUERY);
            if ( xCon.is() && m_pTreeView )
            {
                // our connection is in dispose so we have to find the entry equal with this connection
                // and close it what means to collapse the entry
                // get the top-level representing the removed data source
                weld::TreeView& rTreeView = m_pTreeView->GetWidget();
                std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator());
                if (rTreeView.get_iter_first(*xDSLoop))
                {
                    do
                    {
                        DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSLoop));
                        if ( pData && pData->xConnection == xCon )
                        {
                            // we set the connection to null to avoid a second disposing of the connection
                            pData->xConnection.clear();
                            closeConnection(*xDSLoop, false);
                            break;
                        }
                    }
                    while (rTreeView.iter_next_sibling(*xDSLoop));
                }
            }
            else
                SbaXDataBrowserController::disposing(_rSource);
        }
    }
}

void SbaTableQueryBrowser::implRemoveStatusListeners()
{
    // clear all old dispatches
    for (auto const& externalFeature : m_aExternalFeatures)
    {
        if ( externalFeature.second.xDispatcher.is() )
        {
            try
            {
                externalFeature.second.xDispatcher->removeStatusListener( this, externalFeature.second.aURL );
            }
            catch (Exception&)
            {
                SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::implRemoveStatusListeners: could not remove a status listener!");
            }
        }
    }
    m_aExternalFeatures.clear();
}

sal_Bool SAL_CALL SbaTableQueryBrowser::select( const Any& _rSelection )
{
    SolarMutexGuard aGuard;
        // doin' a lot of VCL stuff here -> lock the SolarMutex

    Sequence< PropertyValue > aDescriptorSequence;
    if (!(_rSelection >>= aDescriptorSequence))
        throw IllegalArgumentException(OUString(), *this, 1);
        // TODO: error message

    ODataAccessDescriptor aDescriptor;
    try
    {
        aDescriptor = ODataAccessDescriptor(aDescriptorSequence);
    }
    catch(const Exception&)
    {
        SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::select: could not extract the descriptor!");
    }

    // check the presence of the props we need
    if ( !(aDescriptor.has(DataAccessDescriptorProperty::DataSource) || aDescriptor.has(DataAccessDescriptorProperty::DatabaseLocation)) || !aDescriptor.has(DataAccessDescriptorProperty::Command) || !aDescriptor.has(DataAccessDescriptorProperty::CommandType))
        throw IllegalArgumentException(OUString(), *this, 1);
        // TODO: error message

    return implSelect(aDescriptor,true);
}

Any SAL_CALL SbaTableQueryBrowser::getSelection(  )
{
    Any aReturn;

    try
    {
        Reference< XLoadable > xLoadable(getRowSet(), UNO_QUERY);
        if (xLoadable.is() && xLoadable->isLoaded())
        {
            Reference< XPropertySet > aFormProps(getRowSet(), UNO_QUERY);
            ODataAccessDescriptor aDescriptor(aFormProps);
            // remove properties which are not part of our "selection"
            aDescriptor.erase(DataAccessDescriptorProperty::Connection);
            aDescriptor.erase(DataAccessDescriptorProperty::Cursor);

            aReturn <<= aDescriptor.createPropertyValueSequence();
        }
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }

    return aReturn;
}

void SAL_CALL SbaTableQueryBrowser::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
{
    m_aSelectionListeners.addInterface(_rxListener);
}

void SAL_CALL SbaTableQueryBrowser::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
{
    m_aSelectionListeners.removeInterface(_rxListener);
}

void SbaTableQueryBrowser::attachFrame(const Reference< css::frame::XFrame > & _xFrame)
{
    implRemoveStatusListeners();

    if (m_xCurrentFrameParent.is())
        m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));

    SbaXDataBrowserController::attachFrame(_xFrame);

    Reference< XFrame > xCurrentFrame( getFrame() );
    if ( xCurrentFrame.is() )
    {
        m_xCurrentFrameParent = xCurrentFrame->findFrame(u"_parent"_ustr,FrameSearchFlag::PARENT);
        if ( m_xCurrentFrameParent.is() )
            m_xCurrentFrameParent->addFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));

        // obtain our toolbox
        try
        {
            Reference< XPropertySet > xFrameProps( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW );
            Reference< XLayoutManager > xLayouter(
                xFrameProps->getPropertyValue(u"LayoutManager"_ustr),
                UNO_QUERY );

            if ( xLayouter.is() )
            {
                Reference< XUIElement > xUI(
                    xLayouter->getElement( u"private:resource/toolbar/toolbar"_ustr ),
                    UNO_SET_THROW );
                m_xMainToolbar.set(xUI->getRealInterface(), css::uno::UNO_QUERY);
                OSL_ENSURE( m_xMainToolbar.is(), "SbaTableQueryBrowser::attachFrame: where's my toolbox?" );
            }
        }
        catchconst Exception& )
        {
            DBG_UNHANDLED_EXCEPTION("dbaccess");
        }
    }

    // get the dispatchers for the external slots
    connectExternalDispatches();
}

void SbaTableQueryBrowser::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
{
    SbaXDataBrowserController::addModelListeners(_xGridControlModel);
    Reference< XPropertySet >  xSourceSet(_xGridControlModel, UNO_QUERY);
    if (xSourceSet.is())
    {
        xSourceSet->addPropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->addPropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->addPropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->addPropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->addPropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->addPropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
    }

}

void SbaTableQueryBrowser::removeModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
{
    SbaXDataBrowserController::removeModelListeners(_xGridControlModel);
    Reference< XPropertySet >  xSourceSet(_xGridControlModel, UNO_QUERY);
    if (xSourceSet.is())
    {
        xSourceSet->removePropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->removePropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->removePropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->removePropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->removePropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
        xSourceSet->removePropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
    }
}

void SbaTableQueryBrowser::RowChanged()
{
    if(getBrowserView())
    {
        SbaGridControl* pControl = getBrowserView()->getVclControl();
        if (!pControl->IsEditing())
            InvalidateFeature(ID_BROWSER_COPY);
    }
    SbaXDataBrowserController::RowChanged();
}

void SbaTableQueryBrowser::ColumnChanged()
{
    if(getBrowserView())
    {
        SbaGridControl* pControl = getBrowserView()->getVclControl();
        if (!pControl->IsEditing())
            InvalidateFeature(ID_BROWSER_COPY);
    }
    SbaXDataBrowserController::ColumnChanged();
}

void SbaTableQueryBrowser::AddColumnListener(const Reference< XPropertySet > & xCol)
{
    SbaXDataBrowserController::AddColumnListener(xCol);
    SafeAddPropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
    SafeAddPropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
    SafeAddPropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
    SafeAddPropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
}

void SbaTableQueryBrowser::RemoveColumnListener(const Reference< XPropertySet > & xCol)
{
    SbaXDataBrowserController::RemoveColumnListener(xCol);
    SafeRemovePropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
    SafeRemovePropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
    SafeRemovePropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
    SafeRemovePropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
}

void SbaTableQueryBrowser::criticalFail()
{
    SbaXDataBrowserController::criticalFail();
    unloadAndCleanup( false );
}

void SbaTableQueryBrowser::LoadFinished(bool _bWasSynch)
{
    SbaXDataBrowserController::LoadFinished(_bWasSynch);

    m_sQueryCommand.clear();
    m_bQueryEscapeProcessing = false;

    if (isValid() && !loadingCancelled())
    {
        // did we load a query?
        bool bTemporary;    // needed because we m_bQueryEscapeProcessing is only one bit wide (and we want to pass it by reference)
        if ( implGetQuerySignature( m_sQueryCommand, bTemporary ) )
            m_bQueryEscapeProcessing = bTemporary;
    }

    // if the form has been loaded, this means that our "selection" has changed
    css::lang::EventObject aEvent( *this );
    m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent );
}

bool SbaTableQueryBrowser::getExternalSlotState( sal_uInt16 _nId ) const
{
    bool bEnabled = false;
    ExternalFeaturesMap::const_iterator aPos = m_aExternalFeatures.find( _nId );
    if ( ( m_aExternalFeatures.end() != aPos ) && aPos->second.xDispatcher.is() )
        bEnabled = aPos->second.bEnabled;
    return bEnabled;
}

FeatureState SbaTableQueryBrowser::GetState(sal_uInt16 nId) const
{
    FeatureState aReturn;
        // (disabled automatically)

    // no chance without a view
    if (!getBrowserView() || !getBrowserView()->getVclControl())
        return aReturn;

    switch ( nId )
    {
        case ID_TREE_ADMINISTRATE:
            aReturn.bEnabled = true;
            return aReturn;

        case ID_BROWSER_CLOSE:
            // the close button should always be enabled
            aReturn.bEnabled = !m_bEnableBrowser;
            return aReturn;

            // "toggle explorer" is always enabled (if we have an explorer)
        case ID_BROWSER_EXPLORER:
            aReturn.bEnabled = m_bEnableBrowser;
            aReturn.bChecked = haveExplorer();
            return aReturn;

        case ID_BROWSER_REMOVEFILTER:
            return SbaXDataBrowserController::GetState( nId );

        case ID_BROWSER_COPY:
            if ( !m_pTreeView->HasChildPathFocus() )
                // handled below
                break;
            [[fallthrough]];
        case ID_TREE_CLOSE_CONN:
        case ID_TREE_EDIT_DATABASE:
        {
            weld::TreeView& rTreeView = m_pTreeView->GetWidget();
            std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator());
            if (!rTreeView.get_cursor(xCurrentEntry.get()))
                return aReturn;

            EntryType eType = getEntryType(*xCurrentEntry);
            if ( eType == etUnknown )
                return aReturn;

            std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(xCurrentEntry.get());
            DBTreeListUserData* pDSData
                =   xDataSourceEntry
                ?   weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry))
                :   nullptr;

            if ( nId == ID_TREE_CLOSE_CONN )
            {
                aReturn.bEnabled = ( pDSData != nullptr ) && pDSData->xConnection.is();
            }
            else if ( nId == ID_TREE_EDIT_DATABASE )
            {
                ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( getORB(),
                    u"/org.openoffice.Office.DataAccess/Policies/Features/Common"_ustr ) );
                bool bHaveEditDatabase( true );
                OSL_VERIFY( aConfig.getNodeValue( u"EditDatabaseFromDataSourceView"_ustr ) >>= bHaveEditDatabase );
                aReturn.bEnabled = getORB().is() && xDataSourceEntry && bHaveEditDatabase;
            }
            else if ( nId == ID_BROWSER_COPY )
            {
                aReturn.bEnabled = isEntryCopyAllowed(*xCurrentEntry);
            }

            return aReturn;
        }
    }

    // all slots not handled above are not available if no form is loaded
    if (!isLoaded())
        return aReturn;

    try
    {
        bool bHandled = false;
        switch (nId)
        {
            case ID_BROWSER_DOCUMENT_DATASOURCE:
                // the slot is enabled if we have an external dispatcher able to handle it,
                // and the dispatcher must have enabled the slot in general
                aReturn.bEnabled = getExternalSlotState( ID_BROWSER_DOCUMENT_DATASOURCE );
                bHandled = true;
                break;
            case ID_BROWSER_REFRESH:
                aReturn.bEnabled = true;
                bHandled = true;
                break;
        }

        if (bHandled)
            return aReturn;

        // no chance without valid models
        if (isValid() && !isValidCursor() && nId != ID_BROWSER_CLOSE)
            return aReturn;

        switch (nId)
        {
            case ID_BROWSER_INSERTCOLUMNS:
            case ID_BROWSER_INSERTCONTENT:
            case ID_BROWSER_FORMLETTER:
            {
                // the slot is enabled if we have an external dispatcher able to handle it,
                // and the dispatcher must have enabled the slot in general
                aReturn.bEnabled = getExternalSlotState( nId );

                // for the Insert* slots, we need at least one selected row
                if (ID_BROWSER_FORMLETTER != nId)
                    aReturn.bEnabled = aReturn.bEnabled && getBrowserView()->getVclControl()->GetSelectRowCount();

                // disabled for native queries which are not saved within the database
                Reference< XPropertySet >  xDataSource(getRowSet(), UNO_QUERY);
                try
                {
                    aReturn.bEnabled = aReturn.bEnabled && xDataSource.is();

                    if (xDataSource.is())
                    {
                        sal_Int32 nType = ::comphelper::getINT32(xDataSource->getPropertyValue(PROPERTY_COMMAND_TYPE));
                        aReturn.bEnabled = aReturn.bEnabled &&
                                           ( ::comphelper::getBOOL(xDataSource->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) ||
                                             (nType == css::sdb::CommandType::QUERY) );
                    }
                }
                catch(DisposedException&)
                {
                    SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::GetState: object already disposed!");
                }
                catchconst Exception& )
                {
                    DBG_UNHANDLED_EXCEPTION("dbaccess");
                }
            }
            break;

            case ID_BROWSER_TITLE:
                {
                    Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
                    sal_Int32 nCommandType = CommandType::TABLE;
                    xProp->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nCommandType;
                    OUString sTitle;
                    switch (nCommandType)
                    {
                        case CommandType::TABLE:
                            sTitle = DBA_RES(STR_TBL_TITLE); break;
                        case CommandType::QUERY:
                        case CommandType::COMMAND:
                            sTitle = DBA_RES(STR_QRY_TITLE); break;
                        default:
                            SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::GetState: unknown command type!");
                    }
                    OUString aName;
                    xProp->getPropertyValue(PROPERTY_COMMAND) >>= aName;
                    OUString sObject(aName);

                    aReturn.sTitle = sTitle.replaceFirst("#", sObject);
                    aReturn.bEnabled = true;
                }
                break;
            case ID_BROWSER_TABLEATTR:
            case ID_BROWSER_ROWHEIGHT:
            case ID_BROWSER_COLATTRSET:
            case ID_BROWSER_COLWIDTH:
                aReturn.bEnabled = getBrowserView()->getVclControl() && isValid() && isValidCursor();
                //  aReturn.bEnabled &= getDefinition() && !getDefinition()->GetDatabase()->IsReadOnly();
                break;

            case ID_BROWSER_COPY:
                OSL_ENSURE( !m_pTreeView->HasChildPathFocus(), "SbaTableQueryBrowser::GetState( ID_BROWSER_COPY ): this should have been handled above!" );
                if (getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing())
                {
                    SbaGridControl* pControl = getBrowserView()->getVclControl();
                    if ( pControl->GetSelectRowCount() )
                    {
                        aReturn.bEnabled = m_aCurrentFrame.isActive();
                        break;
                    }
                    else
                        aReturn.bEnabled = pControl->canCopyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
                    break;
                }
                [[fallthrough]];
            default:
                return SbaXDataBrowserController::GetState(nId);
        }
    }
    catch(const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }

    return aReturn;

}

void SbaTableQueryBrowser::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& aArgs)
{
    switch (nId)
    {
        default:
            SbaXDataBrowserController::Execute(nId,aArgs);
            break;

        case ID_TREE_EDIT_DATABASE:
        {
            weld::TreeView& rTreeView = m_pTreeView->GetWidget();
            std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
            if (rTreeView.get_cursor(xIter.get()))
                implAdministrate(*xIter);
            break;
        }
        case ID_TREE_CLOSE_CONN:
        {
            weld::TreeView& rTreeView = m_pTreeView->GetWidget();
            std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
            if (rTreeView.get_cursor(xIter.get()))
            {
                xIter = m_pTreeView->GetRootLevelParent(xIter.get());
                closeConnection(*xIter);
            }
            break;
        }
        case ID_TREE_ADMINISTRATE:
            svx::administrateDatabaseRegistration( getFrameWeld() );
            break;

        case ID_BROWSER_REFRESH:
        {
            if ( !SaveModified( ) )
                // nothing to do
                break;

            bool bFullReinit = false;
            // check if the query signature (if the form is based on a query) has changed
            if ( !m_sQueryCommand.isEmpty() )
            {
                OUString sNewQueryCommand;
                bool bNewQueryEP;

                bool bIsQuery =
                    implGetQuerySignature( sNewQueryCommand, bNewQueryEP );
                OSL_ENSURE( bIsQuery, "SbaTableQueryBrowser::Execute: was a query before, but is not anymore?" );

                bFullReinit = ( sNewQueryCommand != m_sQueryCommand ) || ( m_bQueryEscapeProcessing != bNewQueryEP );
            }
            if ( !bFullReinit )
            {
                // let the base class do a simple reload
                SbaXDataBrowserController::Execute(nId,aArgs);
                break;
            }
            [[fallthrough]];
        }

        case ID_BROWSER_REFRESH_REBUILD:
        {
            if ( !SaveModified() )
                // nothing to do
                break;

            weld::TreeView& rTreeView = m_pTreeView->GetWidget();
            std::unique_ptr<weld::TreeIter> xSelected = m_xCurrentlyDisplayed ?
                rTreeView.make_iterator(m_xCurrentlyDisplayed.get()) : nullptr;

            // unload
            unloadAndCleanup( false );

            // reselect the entry
            if ( xSelected )
            {
                implSelect(xSelected.get());
            }
            else
            {
                Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
                implSelect(svx::ODataAccessDescriptor(xProp));
            }
        }
        break;

        case ID_BROWSER_EXPLORER:
            toggleExplorer();
            break;

        case ID_BROWSER_DOCUMENT_DATASOURCE:
            implSelect(m_aDocumentDataSource);
            break;

        case ID_BROWSER_INSERTCOLUMNS:
        case ID_BROWSER_INSERTCONTENT:
        case ID_BROWSER_FORMLETTER:
            if (getBrowserView() && isValidCursor())
            {
                // the URL the slot id is assigned to
                OSL_ENSURE( m_aExternalFeatures.find( nId ) != m_aExternalFeatures.end(),
                    "SbaTableQueryBrowser::Execute( ID_BROWSER_?): how could this ever be enabled?" );
                URL aParentUrl = m_aExternalFeatures[ nId ].aURL;

                // let the dispatcher execute the slot
                Reference< XDispatch > xDispatch( m_aExternalFeatures[ nId ].xDispatcher );
                if (xDispatch.is())
                {
                    // set the properties for the dispatch

                    // first fill the selection
                    SbaGridControl* pGrid = getBrowserView()->getVclControl();
                    MultiSelection* pSelection = const_cast<MultiSelection*>(pGrid->GetSelection());
                    Sequence< Any > aSelection;
                    if ( !pGrid->IsAllSelected() )
                    {   // transfer the selected rows only if not all rows are selected
                        // (all rows means the whole table)
                        // #i3832#
                        if (pSelection != nullptr)
                        {
                            aSelection.realloc(pSelection->GetSelectCount());
                            tools::Long nIdx = pSelection->FirstSelected();
                            Any* pSelectionNos = aSelection.getArray();
                            while (nIdx != SFX_ENDOFSELECTION)
                            {
                                *pSelectionNos++ <<= static_cast<sal_Int32>(nIdx + 1);
                                nIdx = pSelection->NextSelected();
                            }
                        }
                    }

                    Reference< XResultSet > xCursorClone;
                    try
                    {
                        Reference< XResultSetAccess > xResultSetAccess(getRowSet(),UNO_QUERY);
                        if (xResultSetAccess.is())
                            xCursorClone = xResultSetAccess->createResultSet();
                    }
                    catch(DisposedException&)
                    {
                        SAL_WARN("dbaccess.ui""Object already disposed!");
                    }
                    catch(const Exception&)
                    {
                        SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::Execute(ID_BROWSER_?): could not clone the cursor!");
                    }

                    Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);

                    try
                    {
                        ODataAccessDescriptor aDescriptor;
                        OUString sDataSourceName;
                        xProp->getPropertyValue(PROPERTY_DATASOURCENAME) >>= sDataSourceName;

                        aDescriptor.setDataSource(sDataSourceName);
                        aDescriptor[DataAccessDescriptorProperty::Command]      =   xProp->getPropertyValue(PROPERTY_COMMAND);
                        aDescriptor[DataAccessDescriptorProperty::CommandType]  =   xProp->getPropertyValue(PROPERTY_COMMAND_TYPE);
                        aDescriptor[DataAccessDescriptorProperty::Connection]   =   xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION);
                        aDescriptor[DataAccessDescriptorProperty::Cursor]       <<= xCursorClone;
                        if ( aSelection.hasElements() )
                        {
                            aDescriptor[DataAccessDescriptorProperty::Selection]            <<= aSelection;
                            aDescriptor[DataAccessDescriptorProperty::BookmarkSelection]    <<= false;
                                // these are selection indices
                                // before we change this, all clients have to be adjusted
                                // so that they recognize the new BookmarkSelection property!
                        }

                        xDispatch->dispatch(aParentUrl, aDescriptor.createPropertyValueSequence());
                    }
                    catchconst Exception& )
                    {
                        DBG_UNHANDLED_EXCEPTION("dbaccess");
                    }
                }
            }
            break;

        case ID_BROWSER_CLOSE:
            closeTask();
            // if it's not 0, such an async close is already pending
            break;

        case ID_BROWSER_COPY:
            if(m_pTreeView->HasChildPathFocus())
            {
                weld::TreeView& rTreeView = m_pTreeView->GetWidget();
                std::unique_ptr<weld::TreeIter> xCursor(rTreeView.make_iterator());
                if (rTreeView.get_cursor(xCursor.get()))
                    copyEntry(*xCursor);
            }
            else if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing() && getBrowserView()->getVclControl()->GetSelectRowCount() < 1)
            {
                SbaGridControl* pControl = getBrowserView()->getVclControl();
                pControl->copyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
            }
            else
                SbaXDataBrowserController::Execute(nId,aArgs);
            break;
    }
}

void SbaTableQueryBrowser::implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection )
{
    OUString a, b, c, d, e;
    implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection );
}

void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, OUString&&nbsp;_rDbImage,
        OUString& _rQueryName, OUString& _rQueryImage, OUString& _rTableName, OUString& _rTableImage,
        const SharedConnection& _rxConnection)
{
    SolarMutexGuard aGuard;
    // initialize the names/images if necessary
    if (_rQueryName.isEmpty())
        _rQueryName = DBA_RES(RID_STR_QUERIES_CONTAINER);
    if (_rTableName.isEmpty())
        _rTableName = DBA_RES(RID_STR_TABLES_CONTAINER);

    if (_rQueryImage.isEmpty())
        _rQueryImage = ImageProvider::getFolderImageId(DatabaseObject::QUERY);
    if (_rTableImage.isEmpty())
        _rTableImage = ImageProvider::getFolderImageId(DatabaseObject::TABLE);

    if (_rDbImage.isEmpty())
        _rDbImage = ImageProvider::getDatabaseImage();

    // add the entry for the data source
    // special handling for data sources denoted by URLs - we do not want to display this ugly URL, do we?
    // #i33699#
    OUString sDSDisplayName, sDataSourceId;
    getDataSourceDisplayName_isURL( _rDbName, sDSDisplayName, sDataSourceId );

    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    DBTreeListUserData* pDSData = new DBTreeListUserData;
    pDSData->eType = etDatasource;
    pDSData->sAccessor = sDataSourceId;
    pDSData->xConnection = _rxConnection;
    OUString sId(weld::toId(pDSData));

    std::unique_ptr<weld::TreeIter> xDatasourceEntry(rTreeView.make_iterator());
    rTreeView.insert(nullptr, -1, &sDSDisplayName, &sId, nullptr, nullptr, false, xDatasourceEntry.get());
    rTreeView.set_image(*xDatasourceEntry, _rDbImage);
    rTreeView.set_text_emphasis(*xDatasourceEntry, false, 0);

    // the child for the queries container
    {
        DBTreeListUserData* pQueriesData = new DBTreeListUserData;
        pQueriesData->eType = etQueryContainer;
        sId = weld::toId(pQueriesData);

        std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator());
        rTreeView.insert(xDatasourceEntry.get(), -1, &_rQueryName, &sId,
                         nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get());
        rTreeView.set_image(*xRet, _rQueryImage);
        rTreeView.set_text_emphasis(*xRet, false, 0);
    }

    // the child for the tables container
    {
        DBTreeListUserData* pTablesData = new DBTreeListUserData;
        pTablesData->eType = etTableContainer;
        sId = weld::toId(pTablesData);

        std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator());
        rTreeView.insert(xDatasourceEntry.get(), -1, &_rTableName, &sId,
                         nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get());
        rTreeView.set_image(*xRet, _rTableImage);
        rTreeView.set_text_emphasis(*xRet, false, 0);
    }
}

void SbaTableQueryBrowser::initializeTreeModel()
{
    if (m_xDatabaseContext.is())
    {
        OUString aDBImage, aQueriesImage, aTablesImage;
        OUString sQueriesName, sTablesName;

        // fill the model with the names of the registered datasources
        const Sequence<OUString> aDatasourceNames = m_xDatabaseContext->getElementNames();
        for (const OUString& rDatasource : aDatasourceNames)
            implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() );
    }
}

void SbaTableQueryBrowser::populateTree(const Reference<XNameAccess>& _xNameAccess,
                                        const weld::TreeIter& rParent,
                                        EntryType eEntryType)
{
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    rTreeView.make_unsorted();

    DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
    if (pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables
        pData->xContainer = _xNameAccess;

    try
    {
        const Sequence<OUString> aNames = _xNameAccess->getElementNames();
        for (const OUString& rName : aNames)
        {
            if( !m_pTreeView->GetEntryPosByName(rName, &rParent))
            {
                DBTreeListUserData* pEntryData = new DBTreeListUserData;
                pEntryData->eType = eEntryType;
                if ( eEntryType == etQuery )
                {
                    Reference<XNameAccess> xChild(_xNameAccess->getByName(rName),UNO_QUERY);
                    if ( xChild.is() )
                        pEntryData->eType = etQueryContainer;
                }
                implAppendEntry(&rParent, rName, pEntryData);
            }
        }
    }
    catch(const Exception&)
    {
        SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::populateTree: could not fill the tree");
    }

    rTreeView.make_sorted();
}

std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implAppendEntry(const weld::TreeIter* pParent, const OUString& rName, const DBTreeListUserData* pUserData)
{
    EntryType eEntryType = pUserData->eType;

    std::unique_ptr<ImageProvider> xImageProvider(getImageProviderFor(pParent));

    OUString aImage = xImageProvider->getImageId(rName, getDatabaseObjectType(eEntryType));

    OUString sId(weld::toId(pUserData));
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    std::unique_ptr<weld::TreeIter> xNewEntry(rTreeView.make_iterator());
    rTreeView.insert(pParent, -1, &rName, &sId, nullptr, nullptr, eEntryType == etQueryContainer, xNewEntry.get());
    rTreeView.set_image(*xNewEntry, aImage);
    rTreeView.set_text_emphasis(*xNewEntry, false, 0);

    return xNewEntry;
}

IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, const weld::TreeIter&, rParent, bool)
{
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    if (rTreeView.iter_has_child(rParent))
    {
        // nothing to do...
        return true;
    }

    std::unique_ptr<weld::TreeIter> xFirstParent = m_pTreeView->GetRootLevelParent(&rParent);
    OSL_ENSURE(xFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!");

    DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
    assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!");

    if (etTableContainer == pData->eType)
    {
        weld::WaitObject aWaitCursor(getFrameWeld());

        // it could be that we already have a connection
        SharedConnection xConnection;
        if (ensureConnection(xFirstParent.get(), xConnection) && xConnection.is())
        {
            SQLExceptionInfo aInfo;
            try
            {
                Reference< XWarningsSupplier > xWarnings(xConnection, UNO_QUERY);
                if (xWarnings.is())
                    xWarnings->clearWarnings();

                // first insert the views because the tables can also include
                // views but that time the bitmap is the wrong one
                // the nameaccess will be overwritten in populateTree
                Reference<XViewsSupplier> xViewSup(xConnection,UNO_QUERY);
                if(xViewSup.is())
                    populateTree( xViewSup->getViews(), rParent, etTableOrView );

                Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY);
                if(xTabSup.is())
                {
                    populateTree( xTabSup->getTables(), rParent, etTableOrView );
                    Reference<XContainer> xCont(xTabSup->getTables(),UNO_QUERY);
                    if(xCont.is())
                        // add as listener to know when elements are inserted or removed
                        xCont->addContainerListener(this);
                }

                if (xWarnings.is())
                {
#if 0
                    SQLExceptionInfo aWarnings(xWarnings->getWarnings());
// Obviously this if test is always false. So to avoid a Clang warning
// "use of logical '&&' with constant operand" I put this in #if
// 0. Yeah, I know it is fairly likely nobody will ever read this
// comment and make a decision what to do here, so I could as well
// have just binned this...
                    if (aWarnings.isValid() && sal_False)
                    {
                        SQLContext aContext;
                        aContext.Message = DBA_RES(STR_OPENTABLES_WARNINGS);
                        aContext.Details = DBA_RES(STR_OPENTABLES_WARNINGS_DETAILS);
                        aContext.NextException = aWarnings.get();
                        aWarnings = aContext;
                        showError(aWarnings);
                    }
#endif
                    // TODO: we need a better concept for these warnings:
                    // something like "don't show any warnings for this datasource, again" would be nice
                    // But this requires an extension of the InteractionHandler and an additional property on the data source
                }
            }
            catch(const SQLContext& e) { aInfo = e; }
            catch(const SQLWarning& e) { aInfo = e; }
            catch(const SQLException& e) { aInfo = e; }
            catch(const WrappedTargetException& e)
            {
                SQLException aSql;
                if(e.TargetException >>= aSql)
                    aInfo = aSql;
                else
                    SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::OnExpandEntry: something strange happened!");
            }
            catchconst Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("dbaccess");
            }
            if (aInfo.isValid())
                showError(aInfo);
        }
        else
            return false;
                // 0 indicates that an error occurred
    }
    else
    {
        // we have to expand the queries or bookmarks
        if (ensureEntryObject(rParent))
        {
            DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
            Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
            populateTree(xCollection, rParent, etQuery);
        }
    }
    return true;
}

bool SbaTableQueryBrowser::ensureEntryObject(const weld::TreeIter& rEntry)
{
    EntryType eType = getEntryType(rEntry);

    // the user data of the entry
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntry));
    assert(pEntryData && "ensureEntryObject: user data should already be set!");

    std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(&rEntry);

    bool bSuccess = false;
    switch (eType)
    {
        case etQueryContainer:
        {
            if ( pEntryData->xContainer.is() )
            {
                // nothing to do
                bSuccess = true;
                break;
            }

            std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
            if (rTreeView.iter_parent(*xParent))
            {
                if (rTreeView.iter_compare(*xParent, *xDataSourceEntry) != 0)
                {
                    OUString aName(rTreeView.get_text(rEntry));
                    DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xParent));
                    try
                    {
                        Reference< XNameAccess > xNameAccess(pData->xContainer,UNO_QUERY);
                        if ( xNameAccess.is() )
                            pEntryData->xContainer.set(xNameAccess->getByName(aName),UNO_QUERY);
                    }
                    catch(const Exception& )
                    {
                        DBG_UNHANDLED_EXCEPTION("dbaccess");
                    }

                    bSuccess = pEntryData->xContainer.is();
                }
                else
                {
                    try
                    {
                        Reference< XQueryDefinitionsSupplier > xQuerySup;
                        m_xDatabaseContext->getByName(getDataSourceAccessor(*xDataSourceEntry)) >>= xQuerySup;
                        if (xQuerySup.is())
                        {
                            Reference< XNameAccess > xQueryDefs = xQuerySup->getQueryDefinitions();
                            Reference< XContainer > xCont(xQueryDefs, UNO_QUERY);
                            if (xCont.is())
                                // add as listener to get notified if elements are inserted or removed
                                xCont->addContainerListener(this);

                            pEntryData->xContainer = xQueryDefs;
                            bSuccess = pEntryData->xContainer.is();
                        }
                        else {
                            SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::ensureEntryObject: no XQueryDefinitionsSupplier interface!");
                        }
                    }
                    catchconst Exception& )
                    {
                        DBG_UNHANDLED_EXCEPTION("dbaccess");
                    }
                }
            }
            break;
        }
        default:
            SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::ensureEntryObject: ooops ... missing some implementation here!");
            // TODO ...
            break;
    }
    return bSuccess;
}

bool SbaTableQueryBrowser::implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect)
{
    // extract the props
    OUString sDataSource;
    OUString sCommand;
    sal_Int32 nCommandType = CommandType::COMMAND;
    bool bEscapeProcessing = true;
    extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);

    // select it
    return implSelect( sDataSource, sCommand, nCommandType, bEscapeProcessing, SharedConnection(), _bSelectDirect );
}

bool SbaTableQueryBrowser::implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand,
    const sal_Int32 nCommandType, const bool _bEscapeProcessing, const SharedConnection& ;_rxConnection)
{
    try
    {
        Reference<XPropertySet> xProp( getRowSet(), UNO_QUERY_THROW );
        Reference< XLoadable >  xLoadable( xProp, UNO_QUERY_THROW );
        // the values allowing the RowSet to re-execute
        xProp->setPropertyValue(PROPERTY_DATASOURCENAME, Any(_rDataSourceName));
        if(_rxConnection.is())
            xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( _rxConnection.getTyped() ) );

            // set this _before_ setting the connection, else the rowset would rebuild it ...
        xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, Any(nCommandType));
        xProp->setPropertyValue(PROPERTY_COMMAND, Any(_rCommand));
        xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::Any(_bEscapeProcessing));
        if ( m_bPreview )
        {
            xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, Any(FetchDirection::FORWARD));
        }

        // the formatter depends on the data source we're working on, so rebuild it here ...
        initFormatter();

        // switch the grid to design mode while loading
        getBrowserView()->getGridControl()->setDesignMode(true);
        InitializeForm( xProp );

        bool bSuccess = true;

        {
            {
                Reference< XNameContainer >  xColContainer(getFormComponent(), UNO_QUERY);
                // first we have to clear the grid
                clearGridColumns(xColContainer);
            }
            FormErrorHelper aHelper(this);
            // load the form
            bSuccess = reloadForm(xLoadable);

            // initialize the model
            InitializeGridModel(getFormComponent());

            Any aVal = xProp->getPropertyValue(PROPERTY_ISNEW);
            if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
            {
                // then set the default values and the parameters given from the parent
                Reference< XReset> xReset(xProp, UNO_QUERY);
                xReset->reset();
            }

            if ( m_bPreview )
                initializePreviewMode();

            LoadFinished(true);
        }

        InvalidateAll();
        return bSuccess;
    }
    catchconst SQLException& )
    {
        Any aException( ::cppu::getCaughtException() );
        showError( SQLExceptionInfo( aException ) );
    }
    catchconst WrappedTargetException& e )
    {
        if  ( e.TargetException.isExtractableTo( ::cppu::UnoType< SQLException >::get() ) )
            showError( SQLExceptionInfo( e.TargetException ) );
        else
        {
            TOOLS_WARN_EXCEPTION("dbaccess""");
        }
    }
    catch(const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }

    InvalidateAll();
    return false;
}

bool SbaTableQueryBrowser::implSelect(const OUString& _rDataSourceName, const OUString& _rCommand,
                                      const sal_Int32 nCommandType, const bool _bEscapeProcessing,
                                      const SharedConnection& _rxConnection,
                                      bool _bSelectDirect)
{
    if (!_rDataSourceName.getLength() || !_rCommand.getLength() || (-1 == nCommandType))
        return false;

    std::unique_ptr<weld::TreeIter> xDataSource;
    std::unique_ptr<weld::TreeIter> xCommandType;
    std::unique_ptr<weld::TreeIter> xCommand = getObjectEntry( _rDataSourceName, _rCommand, nCommandType, &xDataSource, &xCommandType, true, _rxConnection );

    if (xCommand)
    {
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();

        bool bSuccess = true;
        if ( _bSelectDirect )
        {
            bSuccess = implSelect(xCommand.get());
        }
        else
        {
            rTreeView.select(*xCommand);
        }

        if ( bSuccess )
        {
            rTreeView.scroll_to_row(*xCommand);
            rTreeView.set_cursor(*xCommand);
        }
    }
    else if (!xCommandType)
    {
        if (m_xCurrentlyDisplayed)
        {
            // tell the old entry (if any) it has been deselected
            selectPath(m_xCurrentlyDisplayed.get(), false);
            m_xCurrentlyDisplayed.reset();
        }

        // we have a command and need to display this in the rowset
        return implLoadAnything(_rDataSourceName, _rCommand, nCommandType, _bEscapeProcessing, _rxConnection);
    }
    return false;
}

IMPL_LINK_NOARG(SbaTableQueryBrowser, OnSelectionChange, LinkParamNone*, void)
{
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    std::unique_ptr<weld::TreeIter> xSelection(rTreeView.make_iterator());
    if (!rTreeView.get_selected(xSelection.get()))
        xSelection.reset();
    implSelect(xSelection.get());
}

std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implGetConnectionEntry(const weld::TreeIter& rEntry) const
{
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator(&rEntry));
    DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry));
    while (pEntryData->eType != etDatasource)
    {
        rTreeView.iter_parent(*xCurrentEntry);
        pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry));
    }
    return xCurrentEntry;
}

bool SbaTableQueryBrowser::implSelect(const weld::TreeIter* pEntry)
{
    if ( !pEntry )
        return false;

    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pEntry));
    switch (pEntryData->eType)
    {
        case etTableOrView:
        case etQuery:
            break;
        default:
            // nothing to do
            return false;
    }

    OSL_ENSURE(rTreeView.get_iter_depth(*pEntry) >= 2, "SbaTableQueryBrowser::implSelect: invalid entry!");

    // get the entry for the tables or queries
    std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(pEntry);
    rTreeView.iter_parent(*xContainer);
    DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer));

    // get the entry for the datasource
    std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer);
    DBTreeListUserData* pConData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xConnection));

    // reinitialize the rowset
    // but first check if it is necessary
    // get all old properties
    Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
    OUString aOldName;
    xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName;
    sal_Int32 nOldType = 0;
    xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType;
    Reference<XConnection> xOldConnection(xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);

    // the name of the table or query
    const OUString sSimpleName = rTreeView.get_text(*pEntry);
    OUStringBuffer sNameBuffer(sSimpleName);
    if ( etQueryContainer == pContainerData->eType )
    {
        std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(xContainer.get());
        std::unique_ptr<weld::TreeIter> xNextTemp = rTreeView.make_iterator(xTemp.get());
        if (rTreeView.iter_parent(*xNextTemp))
        {
            while (rTreeView.iter_compare(*xNextTemp, *xConnection) != 0)
            {
                sNameBuffer.insert(0, rTreeView.get_text(*xTemp) + "/");
                rTreeView.copy_iterator(*xNextTemp, *xTemp);
                if (!rTreeView.iter_parent(*xNextTemp))
                    break;
            }
        }
    }
    OUString aName = sNameBuffer.makeStringAndClear();

    sal_Int32 nCommandType =    ( etTableContainer == pContainerData->eType)
                            ?   CommandType::TABLE
                            :   CommandType::QUERY;

    // check if need to rebuild the rowset
    bool bRebuild = ( xOldConnection != pConData->xConnection )
                     || ( nOldType != nCommandType )
                     || ( aName != aOldName );

    Reference< css::form::XLoadable >  xLoadable = getLoadable();
    bRebuild |= !xLoadable->isLoaded();
    bool bSuccess = true;
    if ( bRebuild )
    {
        try
        {
            weld::WaitObject aWaitCursor(getFrameWeld());

            // tell the old entry it has been deselected
            selectPath(m_xCurrentlyDisplayed.get(), false);
            m_xCurrentlyDisplayed.reset();

            // not really loaded
            m_xCurrentlyDisplayed = rTreeView.make_iterator(pEntry);
            // tell the new entry it has been selected
            selectPath(m_xCurrentlyDisplayed.get());

            // get the name of the data source currently selected
            (void)ensureConnection(m_xCurrentlyDisplayed.get(), pConData->xConnection);

            if ( !pConData->xConnection.is() )
            {
                unloadAndCleanup( false );
                return false;
            }

            Reference<XNameAccess> xNameAccess;
            switch(nCommandType)
            {
                case CommandType::TABLE:
                    {
                        // only for tables
                        if ( !pContainerData->xContainer.is() )
                        {
                            Reference<XTablesSupplier> xSup( pConData->xConnection, UNO_QUERY );
                            if(xSup.is())
                                xNameAccess = xSup->getTables();

                            pContainerData->xContainer = xNameAccess;
                        }
                        else
                            xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
                    }
                    break;
                case CommandType::QUERY:
                    {
                        if ( pContainerData->xContainer.is() )
                            xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
                        else
                        {
                            Reference<XQueriesSupplier> xSup( pConData->xConnection, UNO_QUERY );
                            if(xSup.is())
                                xNameAccess = xSup->getQueries();
                        }
                    }
                    break;
            }
            OUString sStatus(DBA_RES(CommandType::TABLE == nCommandType ? STR_LOADING_TABLE : STR_LOADING_QUERY));
            sStatus = sStatus.replaceFirst("$name$", aName);
            BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sStatus);

            bool bEscapeProcessing = true;
            if(xNameAccess.is() && xNameAccess->hasByName(sSimpleName))
            {
                DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pEntry));
                if ( !pData->xObjectProperties.is() )
                {
                    Reference<XInterface> xObject;
                    if(xNameAccess->getByName(sSimpleName) >>= xObject) // remember the table or query object
                    {
                        pData->xObjectProperties.set(xObject, css::uno::UNO_QUERY);
                        // if the query contains a parameterized statement and preview is enabled we won't get any data.
                        if ( nCommandType == CommandType::QUERY && xObject.is() )
                        {
                            Reference<XPropertySet> xObjectProps(xObject,UNO_QUERY);
                            xObjectProps->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bEscapeProcessing;
                            if ( m_bPreview )
                            {
                                OUString sSql;
                                xObjectProps->getPropertyValue(PROPERTY_COMMAND) >>= sSql;
                                Reference< XMultiServiceFactory >  xFactory( pConData->xConnection, UNO_QUERY );
                                if (xFactory.is())
                                {
                                    try
                                    {
                                        Reference<XSingleSelectQueryAnalyzer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
                                        if ( xAnalyzer.is() )
                                        {
                                            xAnalyzer->setQuery(sSql);
                                            Reference<XParametersSupplier> xParSup(xAnalyzer,UNO_QUERY);
                                            if ( xParSup->getParameters()->getCount() > 0 )
                                            {
                                                OUString sFilter = " WHERE " + xAnalyzer->getFilter();
                                                OUString sReplace = sSql.replaceFirst(sFilter, "");
                                                xAnalyzer->setQuery(sReplace);
                                                Reference<XSingleSelectQueryComposer> xComposer(xAnalyzer,UNO_QUERY);
                                                xComposer->setFilter(u"0=1"_ustr);
                                                aName = xAnalyzer->getQuery();
                                                nCommandType = CommandType::COMMAND;
                                            }
                                        }
                                    }
                                    catch (Exception&)
                                    {
                                        DBG_UNHANDLED_EXCEPTION("dbaccess");
                                    }
                                }
                            }
                        }
                    }
                }
            }

            OUString sDataSourceName(getDataSourceAccessor(*xConnection));
            bSuccess = implLoadAnything( sDataSourceName, aName, nCommandType, bEscapeProcessing, pConData->xConnection );
            if ( !bSuccess )
            {   // clean up
                criticalFail();
            }
        }
        catch(const SQLException& e)
        {
            showError(SQLExceptionInfo(e));
            // reset the values
            xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
            xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
            bSuccess = false;
        }
        catch(WrappedTargetException& e)
        {
            SQLException aSql;
            if(e.TargetException >>= aSql)
                showError(SQLExceptionInfo(aSql));
            else
                SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::implSelect: something strange happened!");
            // reset the values
            xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
            xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
            bSuccess = false;
        }
        catch(const Exception&)
        {
            // reset the values
            xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
            xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
            bSuccess = false;
        }
    }
    return bSuccess;
}

std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getEntryFromContainer(const Reference<XNameAccess>& rxNameAccess)
{
    std::unique_ptr<weld::TreeIter> xContainer;

    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator(xContainer.get()));
    if (rTreeView.get_iter_first(*xDSLoop))
    {
        do
        {
            xContainer = rTreeView.make_iterator(xDSLoop.get());
            if (rTreeView.iter_children(*xContainer))
            {
                // 1st child is queries
                DBTreeListUserData* pQueriesData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer));
                if (pQueriesData && pQueriesData->xContainer == rxNameAccess)
                    break;

                if (rTreeView.iter_next_sibling(*xContainer))
                {
                    // 2nd child is tables
                    DBTreeListUserData* pTablesData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer));
                    if (pTablesData && pTablesData->xContainer == rxNameAccess)
                        break;
                }
            }
            xContainer.reset();
        }
        while (rTreeView.iter_next_sibling(*xDSLoop));
    }

    return xContainer;
}

void SAL_CALL SbaTableQueryBrowser::elementInserted(const ContainerEvent& rEvent)
{
    SolarMutexGuard aSolarGuard;

    Reference< XNameAccess > xNames(rEvent.Source, UNO_QUERY);
    // first search for a definition container where we can insert this element

    std::unique_ptr<weld::TreeIter> xEntry = getEntryFromContainer(xNames);
    if (xEntry)  // found one
    {
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        rTreeView.make_unsorted();

        // insert the new entry into the tree
        DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xEntry));
        assert(pContainerData && "elementInserted: There must be user data for this type!");

        DBTreeListUserData* pNewData = new DBTreeListUserData;
        bool bIsTable = etTableContainer == pContainerData->eType;
        if ( bIsTable )
        {
            rEvent.Element >>= pNewData->xObjectProperties;// remember the new element
            pNewData->eType = etTableOrView;
        }
        else
        {
            if (rTreeView.iter_n_children(*xEntry) < xNames->getElementNames().getLength() - 1)
            {
                // the item inserts its children on demand, but it has not been expanded yet. So ensure here and
                // now that it has all items
                populateTree(xNames, *xEntry, etQuery);
            }
            pNewData->eType = etQuery;
        }
        implAppendEntry(xEntry.get(), ::comphelper::getString(rEvent.Accessor), pNewData);

        rTreeView.make_sorted();
    }
    else
        SbaXDataBrowserController::elementInserted(rEvent);
}

bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(std::u16string_view rName, const weld::TreeIter& rContainer)
{
    if (!m_xCurrentlyDisplayed)
        return false;
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    if (getEntryType(*m_xCurrentlyDisplayed) != getChildType(rContainer))
        return false;
    if (rTreeView.get_text(*m_xCurrentlyDisplayed) != rName)
        return false;
    std::unique_ptr<weld::TreeIter> xParent = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
    return rTreeView.iter_parent(*xParent) && rTreeView.iter_compare(*xParent, rContainer) == 0;
}

void SAL_CALL SbaTableQueryBrowser::elementRemoved( const ContainerEvent& _rEvent )
{
    SolarMutexGuard aSolarGuard;

    Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
    // get the top-level representing the removed data source
    // and search for the queries and tables
    std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames);
    if (xContainer)
    {
        // a query or table has been removed
        OUString aName = ::comphelper::getString(_rEvent.Accessor);

        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        if (isCurrentlyDisplayedChanged(aName, *xContainer))
        {
            // the element displayed currently has been replaced

            // we need to remember the old value
            std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());

            // unload
            unloadAndCleanup( false ); // don't dispose the connection

            DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp));
            rTreeView.set_id(*xTemp, OUString());
            delete pData; // the data could be null because we have a table which isn't correct
            rTreeView.remove(*xTemp);
        }
        else
        {
            // remove the entry from the model
            std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get()));
            if (rTreeView.get_iter_first(*xChild))
            {
                do
                {
                    if (rTreeView.get_text(*xChild) == aName)
                    {
                        DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild));
                        rTreeView.set_id(*xChild, OUString());
                        delete pData;
                        rTreeView.remove(*xChild);
                        break;
                    }
                } while (rTreeView.iter_next_sibling(*xChild));
            }
        }

        // maybe the object which is part of the document data source has been removed
        checkDocumentDataSource();
    }
    else
        SbaXDataBrowserController::elementRemoved(_rEvent);
}

void SAL_CALL SbaTableQueryBrowser::elementReplaced( const ContainerEvent& _rEvent )
{
    SolarMutexGuard aSolarGuard;

    Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
    std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames);
    if (xContainer)
    {
        // a table or query has been replaced
        OUString aName = ::comphelper::getString(_rEvent.Accessor);

        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        if (isCurrentlyDisplayedChanged(aName, *xContainer))
        {   // the element displayed currently has been replaced

            // we need to remember the old value
            std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
            unloadAndCleanup( false ); // don't dispose the connection

            DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp));
            if (pData)
            {
                if ( etTableOrView == pData->eType )
                {
                    // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
                    _rEvent.Element >>= pData->xObjectProperties;  // remember the new element
                }
                else
                {
                    rTreeView.set_id(*xTemp, OUString());
                    delete pData;
                }
            }
        }
        else
        {
            // find the entry for this name
            std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get()));
            if (rTreeView.get_iter_first(*xChild))
            {
                do
                {
                    if (rTreeView.get_text(*xChild) == aName)
                    {
                        DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild));
                        if (pData)
                        {
                            if ( etTableOrView == pData->eType )
                            {
                                // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
                                _rEvent.Element >>= pData->xObjectProperties;   // remember the new element
                            }
                            else
                            {
                                rTreeView.set_id(*xChild, OUString());
                                delete pData;
                            }
                        }
                        break;
                    }
                } while (rTreeView.iter_next_sibling(*xChild));
            }
        }

        // maybe the object which is part of the document data source has been removed
        checkDocumentDataSource();
    }
    else if (xNames.get() == m_xDatabaseContext.get())
    {   // a datasource has been replaced in the context
        SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::elementReplaced: no support for replaced data sources!");
            // very suspicious: the database context should not allow to replace data source, only to register
            // and revoke them
    }
    else
        SbaXDataBrowserController::elementReplaced(_rEvent);
}

void SbaTableQueryBrowser::impl_releaseConnection( SharedConnection& _rxConnection )
{
    // remove as event listener
    Reference< XComponent > xComponent( _rxConnection, UNO_QUERY );
    if ( xComponent.is() )
    {
        Reference< XEventListener > xListener( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY );
        xComponent->removeEventListener( xListener );
    }

    try
    {
        // temporary (hopefully!) hack for #i55274#
        Reference< XFlushable > xFlush( _rxConnection, UNO_QUERY );
        if ( xFlush.is() )
            xFlush->flush();
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }

    // clear
    _rxConnection.clear();
        // will implicitly dispose if we have the ownership, since xConnection is a SharedConnection
}

void SbaTableQueryBrowser::disposeConnection(const weld::TreeIter* pDSEntry)
{
    OSL_ENSURE( pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" );
    OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" );

    if (pDSEntry)
    {
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        DBTreeListUserData* pTreeListData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*pDSEntry));
        if (pTreeListData)
            impl_releaseConnection(pTreeListData->xConnection);
    }
}

void SbaTableQueryBrowser::closeConnection(const weld::TreeIter& rDSEntry, bool _bDisposeConnection)
{
    OSL_ENSURE(impl_isDataSourceEntry(&rDSEntry), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!");

    weld::TreeView& rTreeView = m_pTreeView->GetWidget();

    // if one of the entries of the given DS is displayed currently, unload the form
    if (m_xCurrentlyDisplayed)
    {
        std::unique_ptr<weld::TreeIter> xRoot = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get());
        if (rTreeView.iter_compare(*xRoot, rDSEntry) == 0)
            unloadAndCleanup(_bDisposeConnection);
    }

    // collapse the query/table container
    std::unique_ptr<weld::TreeIter> xContainers(rTreeView.make_iterator(&rDSEntry));
    if (rTreeView.iter_children(*xContainers))
    {
        do
        {
            std::unique_ptr<weld::TreeIter> xElements(rTreeView.make_iterator(xContainers.get()));
            if (rTreeView.iter_children(*xElements))
            {
                rTreeView.collapse_row(*xContainers);
                // and delete their children (they are connection-relative)
                bool bElements = true;
                while (bElements)
                {
                    std::unique_ptr<weld::TreeIter> xRemove(rTreeView.make_iterator(xElements.get()));
                    bElements = rTreeView.iter_next_sibling(*xElements);
                    DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xRemove));
                    rTreeView.set_id(*xRemove, OUString());
                    delete pData;
                    rTreeView.remove(*xRemove);
                }
            }
        }
        while (rTreeView.iter_next_sibling(*xContainers));
    }

    // collapse the entry itself
    rTreeView.collapse_row(rDSEntry);

    // dispose/reset the connection
    if ( _bDisposeConnection )
        disposeConnection(&rDSEntry);
}

void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection )
{
    if (!m_xCurrentlyDisplayed)
        // nothing to do
        return;

    std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get());

    // de-select the path for the currently displayed table/query
    selectPath(m_xCurrentlyDisplayed.get(), false);
    m_xCurrentlyDisplayed.reset();

    try
    {
        // get the active connection. We need to dispose it.

        // unload the form
        Reference< XLoadable > xLoadable = getLoadable();
        if (xLoadable->isLoaded())
            xLoadable->unload();

        // clear the grid control
        Reference< XNameContainer > xConta(getControlModel(),UNO_QUERY);
        clearGridColumns(xConta);

        // dispose the connection
        if(_bDisposeConnection)
            disposeConnection(xDSEntry.get());
    }
    catch(SQLException& e)
    {
        showError(SQLExceptionInfo(e));
    }
    catch(WrappedTargetException& e)
    {
        SQLException aSql;
        if(e.TargetException >>= aSql)
            showError(SQLExceptionInfo(aSql));
        else
            SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::unloadAndCleanup: something strange happened!");
    }
    catch(const Exception&)
    {
        SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::unloadAndCleanup: could not reset the form");
    }
}

namespace
{
    Reference< XInterface > lcl_getDataSource( const Reference< XDatabaseContext >& _rxDatabaseContext,
        const OUString& _rDataSourceName, const Reference< XConnection >& _rxConnection )
    {
        Reference< XDataSource > xDataSource;
        try
        {
            if ( !_rDataSourceName.isEmpty() && _rxDatabaseContext->hasByName( _rDataSourceName ) )
                xDataSource.set( _rxDatabaseContext->getByName( _rDataSourceName ), UNO_QUERY_THROW );

            if ( !xDataSource.is() )
            {
                Reference< XChild > xConnAsChild( _rxConnection, UNO_QUERY );
                if ( xConnAsChild.is() )
                    xDataSource.set( xConnAsChild->getParent(), UNO_QUERY_THROW );
            }
        }
        catchconst Exception& )
        {
            DBG_UNHANDLED_EXCEPTION("dbaccess");
        }
        return xDataSource;
    }
}

void SbaTableQueryBrowser::impl_initialize(const ::comphelper::NamedValueCollection& rArguments)
{
    SolarMutexGuard aGuard;
        // doin' a lot of VCL stuff here -> lock the SolarMutex

    // first initialize the parent
    SbaXDataBrowserController::impl_initialize(rArguments);

    Reference<XConnection> xForeignConnection;
    Reference< XFrame > xFrame;

    OUString aTableName, aCatalogName, aSchemaName;

    bool bEscapeProcessing = true;
    sal_Int32 nInitialDisplayCommandType = CommandType::COMMAND;
    OUString sInitialDataSourceName;
    OUString sInitialCommand;

    rArguments.get_ensureType( PROPERTY_DATASOURCENAME, sInitialDataSourceName );
    rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, nInitialDisplayCommandType );
    rArguments.get_ensureType( PROPERTY_COMMAND, sInitialCommand );
    rArguments.get_ensureType( PROPERTY_ACTIVE_CONNECTION, xForeignConnection );
    rArguments.get_ensureType( PROPERTY_UPDATE_CATALOGNAME, aCatalogName );
    rArguments.get_ensureType( PROPERTY_UPDATE_SCHEMANAME, aSchemaName );
    rArguments.get_ensureType( PROPERTY_UPDATE_TABLENAME, aTableName );
    rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing );
    rArguments.get_ensureType( u"Frame"_ustr, xFrame );
    rArguments.get_ensureType( PROPERTY_SHOWMENU, m_bShowMenu );

    // disable the browser if either of ShowTreeViewButton (compatibility name) or EnableBrowser
    // is present and set to FALSE
    bool bDisableBrowser =  !rArguments.getOrDefault( u"ShowTreeViewButton"_ustr, true )   // compatibility name
                            ||  !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true );
    OSL_ENSURE( !rArguments.has( u"ShowTreeViewButton"_ustr ),
        "SbaTableQueryBrowser::impl_initialize: ShowTreeViewButton is superseded by EnableBrowser!" );
    m_bEnableBrowser = !bDisableBrowser;

    // hide the tree view it is disabled in general, or if the settings tell to hide it initially
    bool bHideTreeView =    ( !m_bEnableBrowser )
                            ||  !rArguments.getOrDefault( u"ShowTreeView"_ustr, true )  // compatibility name
                            ||  !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true );
    OSL_ENSURE( !rArguments.has( u"ShowTreeView"_ustr ),
        "SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" );

    if ( bHideTreeView )
        hideExplorer();
    else
        showExplorer();

    if ( m_bPreview )
    {
        try
        {
            Sequence< OUString> aProperties
            {
                u"AlwaysShowCursor"_ustr, PROPERTY_BORDER, u"HasNavigationBar"_ustr, u"HasRecordMarker"_ustr, u"Tabstop"_ustr
            };
            Sequence< Any> aValues
            {
                Any(false), Any(sal_Int16(0)), Any(false), Any(false), Any(false)
            };
            Reference< XMultiPropertySet >  xFormMultiSet(getFormComponent(), UNO_QUERY);
            if ( xFormMultiSet.is() )
                xFormMultiSet->setPropertyValues(aProperties, aValues);
        }
        catch(const Exception&)
        {
            DBG_UNHANDLED_EXCEPTION("dbaccess");
        }
    }

    // are we loaded into a (sub)frame of an embedded document (i.e. a form belonging to a database
    // document)?
    bool bSubFrameOfEmbeddedDocument = false;
    if ( xFrame.is() )
    {
        Reference<XFramesSupplier> xSup = xFrame->getCreator();
        Reference<XController> xCont = xSup.is() ? xSup->getController() : Reference<XController>();

        bSubFrameOfEmbeddedDocument = xCont.is() && ::dbtools::isEmbeddedInDatabase( xCont->getModel(), xForeignConnection );
    }

    // if we have a connection at this point, it was either passed from outside, our
    // determined from an outer DB document. In both cases, do not dispose it later on.
    SharedConnection xConnection( xForeignConnection, SharedConnection::NoTakeOwnership );

    // should we display all registered databases in the left hand side tree?
    // or only *one* special?
    bool bLimitedTreeEntries = false;
    // if we're part of a frame which is a secondary frame of a database document, then only
    // display the database for this document, not all registered ones
    bLimitedTreeEntries |= bSubFrameOfEmbeddedDocument;
    // if the tree view is not to be displayed at all, then only display the data source
    // which was given as initial selection
    bLimitedTreeEntries |= !m_bEnableBrowser;

    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    rTreeView.make_unsorted();

    if ( bLimitedTreeEntries )
    {
        if ( xConnection.is() )
        {
            startConnectionListening( xConnection );

            // if no initial name was given, try to obtain one from the data source
            if ( sInitialDataSourceName.isEmpty() )
            {
                Reference< XChild > xChild( xConnection, UNO_QUERY );
                Reference< XPropertySet > xDataSourceProperties;
                if ( xChild.is() )
                    xDataSourceProperties.set(xChild->getParent(), css::uno::UNO_QUERY);
                if ( xDataSourceProperties.is() )
                {
                    try
                    {
                        OSL_VERIFY( xDataSourceProperties->getPropertyValue( PROPERTY_NAME ) >>= sInitialDataSourceName );
                    }
                    catchconst Exception& )
                    {
                        SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::impl_initialize: a connection parent which does not have a 'Name'!??" );
                    }
                }
            }
        }

        implAddDatasource( sInitialDataSourceName, xConnection );

        std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator());
        if (rTreeView.get_iter_first(*xFirst))
            rTreeView.expand_row(*xFirst);
    }
    else
        initializeTreeModel();

    rTreeView.make_sorted();

    if ( m_bEnableBrowser )
    {
        m_aDocScriptSupport = ::std::optional< bool >( false );
    }
    else
    {
        // we are not used as "browser", but as mere view for a single table/query/command. In particular,
        // there is a specific database document which we belong to.
        Reference< XOfficeDatabaseDocument > xDocument( getDataSourceOrModel(
            lcl_getDataSource( m_xDatabaseContext, sInitialDataSourceName, xConnection ) ), UNO_QUERY );
        m_aDocScriptSupport = ::std::optional< bool >( Reference< XEmbeddedScripts >( xDocument, UNO_QUERY ).is() );
    }

    if ( implSelect( sInitialDataSourceName, sInitialCommand, nInitialDisplayCommandType, bEscapeProcessing, xConnection, true ) )
    {
        try
        {
            Reference< XPropertySet > xRowSetProps(getRowSet(), UNO_QUERY);
            xRowSetProps->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,Any(aCatalogName));
            xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,Any(aSchemaName));
            xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,Any(aTableName));

        }
        catch(const Exception&)
        {
            SAL_WARN("dbaccess.ui""SbaTableQueryBrowser::impl_initialize: could not set the update related names!");
        }
    }

    InvalidateAll();
}

bool SbaTableQueryBrowser::haveExplorer() const
{
    return m_pTreeView && m_pTreeView->IsVisible();
}

void SbaTableQueryBrowser::hideExplorer()
{
    if (!haveExplorer())
        return;
    if (!getBrowserView())
        return;

    m_pTreeView->Hide();
    m_pSplitter->Hide();
    getBrowserView()->Resize();

    InvalidateFeature(ID_BROWSER_EXPLORER);
}

void SbaTableQueryBrowser::showExplorer()
{
    if (haveExplorer())
        return;

    if (!getBrowserView())
        return;

    m_pTreeView->Show();
    m_pSplitter->Show();
    getBrowserView()->Resize();

    InvalidateFeature(ID_BROWSER_EXPLORER);
}

bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection)
{
    std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry);
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    DBTreeListUserData* pDSData =
                xDSEntry
            ?   weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry))
            :   nullptr;

    return ensureConnection(xDSEntry.get(), pDSData, rConnection);
}

std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor(const weld::TreeIter* pAnyEntry)
{
    std::unique_ptr<ImageProvider> xImageProvider(new ImageProvider);
    SharedConnection xConnection;
    if (getExistentConnectionFor(pAnyEntry, xConnection))
        xImageProvider.reset(new ImageProvider(xConnection));
    return xImageProvider;
}

bool SbaTableQueryBrowser::getExistentConnectionFor(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection)
{
    std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry);
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    DBTreeListUserData* pDSData =
                xDSEntry
            ?   weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry))
            :   nullptr;
    if (pDSData)
        rConnection = pDSData->xConnection;
    return rConnection.is();
}

bool SbaTableQueryBrowser::impl_isDataSourceEntry(const weld::TreeIter* pEntry) const
{
    if (!pEntry)
        return false;
    std::unique_ptr<weld::TreeIter> xRoot(m_pTreeView->GetRootLevelParent(pEntry));
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    return rTreeView.iter_compare(*xRoot, *pEntry) == 0;
}

bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pDSEntry, void* pDSData, SharedConnection& rConnection)
{
    OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" );
    if (pDSEntry)
    {
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        OUString aDSName = rTreeView.get_text(*pDSEntry);

        DBTreeListUserData* pTreeListData = static_cast<DBTreeListUserData*>(pDSData);
        if ( pTreeListData )
            rConnection = pTreeListData->xConnection;

        if ( !rConnection.is() && pTreeListData )
        {
            // show the "connecting to ..." status
            OUString sConnecting(DBA_RES(STR_CONNECTING_DATASOURCE));
            sConnecting = sConnecting.replaceFirst("$name$", aDSName);
            BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sConnecting);

            // build a string showing context information in case of error
            OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE));
            sConnectingContext = sConnectingContext.replaceFirst("$name$", aDSName);

            // connect
            rConnection.reset(
                connect(getDataSourceAccessor(*pDSEntry), sConnectingContext, nullptr),
                SharedConnection::TakeOwnership);

            // remember the connection
            pTreeListData->xConnection = rConnection;
        }
    }
    return rConnection.is();
}

int SbaTableQueryBrowser::OnTreeEntryCompare(const weld::TreeIter& rLHS, const weld::TreeIter& rRHS)
{
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();

    // we want the table entry and the end so we have to do a check
    if (isContainer(rRHS))
    {
        // don't use getEntryType (directly or indirectly) for the LHS:
        // LHS is currently being inserted, so it is not "completely valid" at the moment

        const EntryType eRight = getEntryType(rRHS);
        if (etTableContainer == eRight)
            // every other container should be placed _before_ the bookmark container
            return -1;

        const OUString sLeft = rTreeView.get_text(rLHS);

        EntryType eLeft = etTableContainer;
        if (DBA_RES(RID_STR_TABLES_CONTAINER) == sLeft)
            eLeft = etTableContainer;
        else if (DBA_RES(RID_STR_QUERIES_CONTAINER) == sLeft)
            eLeft = etQueryContainer;

        if ( eLeft == eRight )
            return 0;

        if ( ( eLeft == etTableContainer ) && ( eRight == etQueryContainer ) )
            return 1;

        if ( ( eLeft == etQueryContainer ) && ( eRight == etTableContainer ) )
            return -1;

        SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::OnTreeEntryCompare: unexpected case!" );
        return 0;
    }

    OUString sLeftText = rTreeView.get_text(rLHS);
    OUString sRightText = rTreeView.get_text(rRHS);

    sal_Int32 nCompareResult = 0;   // equal by default

    if (m_xCollator.is())
    {
        try
        {
            nCompareResult = m_xCollator->compareString(sLeftText, sRightText);
        }
        catch(const Exception&)
        {
        }
    }
    else
        // default behaviour if we do not have a collator -> do the simple string compare
        nCompareResult = sLeftText.compareTo(sRightText);

    return nCompareResult;
}

void SbaTableQueryBrowser::implAdministrate(const weld::TreeIter& rApplyTo)
{
    try
    {
        // get the desktop object
        Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() );

        // the initial selection
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        std::unique_ptr<weld::TreeIter> xTopLevelSelected(rTreeView.make_iterator(&rApplyTo));

        while (rTreeView.get_iter_depth(*xTopLevelSelected))
            rTreeView.iter_parent(*xTopLevelSelected);

        OUString sInitialSelection = getDataSourceAccessor(*xTopLevelSelected);

        Reference< XDataSource > xDataSource( getDataSourceByName( sInitialSelection, getFrameWeld(), getORB(), nullptr ) );
        Reference< XModel > xDocumentModel( getDataSourceOrModel( xDataSource ), UNO_QUERY );

        if ( xDocumentModel.is() )
        {
            Reference< XInteractionHandler2 > xInteractionHandler(
                InteractionHandler::createWithParent(getORB(), nullptr) );

            ::comphelper::NamedValueCollection aLoadArgs;
            aLoadArgs.put( u"Model"_ustr, xDocumentModel );
            aLoadArgs.put( u"InteractionHandler"_ustr, xInteractionHandler );
            aLoadArgs.put( u"MacroExecutionMode"_ustr, MacroExecMode::USE_CONFIG );

            Sequence< PropertyValue > aLoadArgPV;
            aLoadArgs >>= aLoadArgPV;

            xFrameLoader->loadComponentFromURL(
                xDocumentModel->getURL(),
                u"_default"_ustr,
                FrameSearchFlag::ALL | FrameSearchFlag::GLOBAL,
                aLoadArgPV
            );
        }
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }
}

bool SbaTableQueryBrowser::requestQuickHelp(const void* pUserData, OUString& rText) const
{
    const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData);
    if (pData->eType == etDatasource && !pData->sAccessor.isEmpty())
    {
        rText = ::svt::OFileNotation(pData->sAccessor).get( ::svt::OFileNotation::N_SYSTEM);
        return true;
    }
    return false;
}

OUString SbaTableQueryBrowser::getContextMenuResourceName() const
{
    return u"explorer"_ustr;
}

IController& SbaTableQueryBrowser::getCommandController()
{
    return *this;
}

::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors()
{
    return &m_aContextMenuInterceptors;
}

Any SbaTableQueryBrowser::getCurrentSelection(weld::TreeView& rControl) const
{
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();

    OSL_PRECOND( &rTreeView == &rControl,
        "SbaTableQueryBrowser::getCurrentSelection: where does this come from?" );

    if (&rTreeView != &rControl)
        return Any();

    std::unique_ptr<weld::TreeIter> xSelected(rTreeView.make_iterator());
    if (!rTreeView.get_selected(xSelected.get()))
        return Any();

    NamedDatabaseObject aSelectedObject;
    DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xSelected));
    aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType );

    switch ( aSelectedObject.Type )
    {
    case DatabaseObject::QUERY:
    case DatabaseObject::TABLE:
        aSelectedObject.Name = rTreeView.get_text(*xSelected);
        break;

    case DatabaseObjectContainer::DATA_SOURCE:
    case DatabaseObjectContainer::QUERIES:
    case DatabaseObjectContainer::TABLES:
        aSelectedObject.Name = getDataSourceAccessor(*xSelected);
        break;

    default:
        SAL_WARN("dbaccess.ui",  "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" );
        break;
    }

    return Any( aSelectedObject );
}

vcl::Window* SbaTableQueryBrowser::getMenuParent() const
{
    return m_pTreeView;
}

void SbaTableQueryBrowser::adjustMenuPosition(const weld::TreeView&, ::Point&) ;const
{
}

bool SbaTableQueryBrowser::implGetQuerySignature( OUString& _rCommand, bool_bEscapeProcessing )
{
    _rCommand.clear();
    _bEscapeProcessing = false;

    try
    {
        // contain the dss (data source signature) of the form
        OUString sDataSourceName;
        OUString sCommand;
        sal_Int32       nCommandType = CommandType::COMMAND;
        Reference< XPropertySet > xRowsetProps( getRowSet(), UNO_QUERY );
        ODataAccessDescriptor aDesc( xRowsetProps );
        sDataSourceName = aDesc.getDataSource();
        aDesc[ DataAccessDescriptorProperty::Command ]      >>= sCommand;
        aDesc[ DataAccessDescriptorProperty::CommandType ]  >>= nCommandType;

        // do we need to do anything?
        if ( CommandType::QUERY != nCommandType )
            return false;

        // get the query object
        Reference< XQueryDefinitionsSupplier > xSuppQueries;
        Reference< XNameAccess > xQueries;
        Reference< XPropertySet > xQuery;
        m_xDatabaseContext->getByName( sDataSourceName ) >>= xSuppQueries;
        if ( xSuppQueries.is() )
            xQueries = xSuppQueries->getQueryDefinitions();
        if ( xQueries.is() )
            xQueries->getByName( sCommand ) >>= xQuery;
        OSL_ENSURE( xQuery.is(), "SbaTableQueryBrowser::implGetQuerySignature: could not retrieve the query object!" );

        // get the two properties we need
        if ( xQuery.is() )
        {
            xQuery->getPropertyValue( PROPERTY_COMMAND ) >>= _rCommand;
            _bEscapeProcessing = ::cppu::any2bool( xQuery->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) );
            return true;
        }
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }

    return false;
}

void SbaTableQueryBrowser::frameAction(const css::frame::FrameActionEvent& aEvent)
{
    if (aEvent.Frame == m_xCurrentFrameParent)
    {
        if(aEvent.Action == FrameAction_COMPONENT_DETACHING)
            implRemoveStatusListeners();
        else if (aEvent.Action == FrameAction_COMPONENT_REATTACHED)
            connectExternalDispatches();
    }
    else
        SbaXDataBrowserController::frameAction(aEvent);

}

void SbaTableQueryBrowser::clearGridColumns(const Reference< XNameContainer >& _xColContainer)
{
    // first we have to clear the grid
    Reference< XInterface > xColumn;
    const Sequence<OUString> aColNames = _xColContainer->getElementNames();
    for (const OUString& rName : aColNames)
    {
        _xColContainer->getByName(rName) >>= xColumn;
        _xColContainer->removeByName(rName);
        ::comphelper::disposeComponent(xColumn);
    }
}

void SbaTableQueryBrowser::loadMenu(const Reference< XFrame >& _xFrame)
{
    if ( m_bShowMenu )
    {
        OGenericUnoController::loadMenu(_xFrame);
    }
    else if ( !m_bPreview )
    {
        Reference< css::frame::XLayoutManager > xLayoutManager = getLayoutManager(_xFrame);

        if ( xLayoutManager.is() )
        {
            xLayoutManager->lock();
            xLayoutManager->createElement( u"private:resource/toolbar/toolbar"_ustr );
            xLayoutManager->unlock();
            xLayoutManager->doLayout();
        }
        onLoadedMenu( xLayoutManager );
    }
}

OUString SbaTableQueryBrowser::getPrivateTitle() const
{
    OUString sTitle;
    if (m_xCurrentlyDisplayed)
    {
        weld::TreeView& rTreeView = m_pTreeView->GetWidget();
        std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
        if (!rTreeView.iter_parent(*xContainer))
            return OUString();
        // get the entry for the datasource
        std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer);
        OUString sName = rTreeView.get_text(*m_xCurrentlyDisplayed);
        sTitle = GetEntryText(*xConnection);
        INetURLObject aURL(sTitle);
        if ( aURL.GetProtocol() != INetProtocol::NotValid )
            sTitle = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
        if ( !sName.isEmpty() )
        {
            sName += " - " + sTitle;
            sTitle = sName;
        }
    }

    return sTitle;
}

bool SbaTableQueryBrowser::preReloadForm()
{
    bool bIni = false;
    if (!m_xCurrentlyDisplayed)
    {
        // switch the grid to design mode while loading
        getBrowserView()->getGridControl()->setDesignMode(true);
        // we had an invalid statement so we need to connect the column models
        Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
        svx::ODataAccessDescriptor aDesc(xRowSetProps);
        // extract the props
        OUString sDataSource;
        OUString sCommand;
        sal_Int32 nCommandType = CommandType::COMMAND;
        bool bEscapeProcessing = true;
        extractDescriptorProps(aDesc, sDataSource, sCommand, nCommandType, bEscapeProcessing);
        if ( !sDataSource.isEmpty() && !sCommand.isEmpty() && (-1 != nCommandType) )
        {
            m_xCurrentlyDisplayed = getObjectEntry(sDataSource, sCommand, nCommandType, nullptr, nullptr);
            bIni = true;
        }
    }
    return bIni;
}

void SbaTableQueryBrowser::postReloadForm()
{
    InitializeGridModel(getFormComponent());
    LoadFinished(true);
}

Reference< XEmbeddedScripts > SAL_CALL SbaTableQueryBrowser::getScriptContainer()
{
    // update our database document
    Reference< XModel > xDocument;
    try
    {
        Reference< XPropertySet > xCursorProps( getRowSet(), UNO_QUERY_THROW );
        Reference< XConnection > xConnection( xCursorProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY );
        if ( xConnection.is() )
        {
            Reference< XChild > xChild( xConnection, UNO_QUERY_THROW );
            Reference< XDocumentDataSource > xDataSource( xChild->getParent(), UNO_QUERY_THROW );
            xDocument.set( xDataSource->getDatabaseDocument(), UNO_QUERY_THROW );
        }
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("dbaccess");
    }
    Reference< XEmbeddedScripts > xScripts( xDocument, UNO_QUERY );
    OSL_ENSURE( xScripts.is() || !xDocument.is(),
        "SbaTableQueryBrowser::getScriptContainer: invalid database document!" );
    return xScripts;
}

void SAL_CALL SbaTableQueryBrowser::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
{
    if ( Interceptor.is() )
        m_aContextMenuInterceptors.addInterface( Interceptor );
}

void SAL_CALL SbaTableQueryBrowser::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
{
    if ( Interceptor.is() )
        m_aContextMenuInterceptors.removeInterface( Interceptor );
}

void SAL_CALL SbaTableQueryBrowser::registeredDatabaseLocation( const DatabaseRegistrationEvent& Event )
{
    SolarMutexGuard aGuard;
    implAddDatasource( Event.Name, SharedConnection() );
}

void SbaTableQueryBrowser::impl_cleanupDataSourceEntry(std::u16string_view rDataSourceName)
{
    // get the top-level representing the removed data source
    weld::TreeView& rTreeView = m_pTreeView->GetWidget();
    std::unique_ptr<weld::TreeIter> xDataSourceEntry(rTreeView.make_iterator());
    bool bDataSourceEntry = rTreeView.get_iter_first(*xDataSourceEntry);
    while (bDataSourceEntry)
    {
        if (rTreeView.get_text(*xDataSourceEntry) == rDataSourceName)
            break;
        bDataSourceEntry = rTreeView.iter_next_sibling(*xDataSourceEntry);
    }

    OSL_ENSURE( bDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" );
    if (!bDataSourceEntry)
        return;

    if (isSelected(*xDataSourceEntry))
    {
        // a table or query belonging to the deleted data source is currently being displayed.
        unloadAndCleanup();
    }

    std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xDataSourceEntry.get()));
    if (rTreeView.iter_children(*xChild))
    {
        do
        {
            // delete any user data of the child entries of the to-be-removed entry
            const DBTreeListUserData* pData = weld::fromId<const DBTreeListUserData*>(rTreeView.get_id(*xChild));
            rTreeView.set_id(*xChild, OUString());
            delete pData;
        } while (rTreeView.iter_next_sibling(*xChild));
    }

    // remove the entry
    DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry));
    rTreeView.set_id(*xDataSourceEntry, OUString());
    delete pData;
    rTreeView.remove(*xDataSourceEntry);
}

void SAL_CALL SbaTableQueryBrowser::revokedDatabaseLocation( const DatabaseRegistrationEvent& Event )
{
    SolarMutexGuard aGuard;

    impl_cleanupDataSourceEntry( Event.Name );

    // maybe the object which is part of the document data source has been removed
    checkDocumentDataSource();
}

void SAL_CALL SbaTableQueryBrowser::changedDatabaseLocation( const DatabaseRegistrationEvent& Event )
{
    SolarMutexGuard aGuard;

    // in case the data source was expanded, and connected, we need to clean it up
    // for simplicity, just do as if the data source were completely removed and re-added
    impl_cleanupDataSourceEntry( Event.Name );
    implAddDatasource( Event.Name, SharedConnection() );
}

}   // namespace dbaui

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5 in Prozent
C=92 H=96 G=93

¤ Dauer der Verarbeitung: 0.77 Sekunden  (vorverarbeitet am  2026-05-08) ¤

*© Formatika GbR, Deutschland






Versionsinformation zu Columbo

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge