/* -*- 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 <dbexchange.hxx>
#include <dbtreelistbox.hxx>
#include "dbtreemodel.hxx"
#include "dbtreeview.hxx"
#include <dbu_reghelper.hxx>
#include <stringconstants.hxx>
#include <strings.hrc>
#include <dlgsave.hxx>
#include <uiservices.hxx>
#include <HtmlReader.hxx>
#include <imageprovider.hxx>
#include <listviewitems.hxx>
#include <QEnumTypes.hxx>
#include <RtfReader.hxx>
#include <sbagrid.hrc>
#include <sbagrid.hxx>
#include <sqlmessage.hxx>
#include <TokenWriter.hxx>
#include <UITools.hxx>
#include <unodatbr.hxx>
#include <WColumnSelect.hxx>
#include <WCopyTable.hxx>
#include <WCPage.hxx>
#include <WExtendPages.hxx>
#include <WNameMatch.hxx>
#include <com/sun/star/awt/LineEndFormat.hpp>
#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/container/XNameContainer.hpp>
#include <com/sun/star/form/XForm.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/i18n/Collator.hpp>
#include <com/sun/star/sdb/CommandType.hpp>
#include <com/sun/star/sdb/SQLContext.hpp>
#include <com/sun/star/sdb/XBookmarksSupplier.hpp>
#include <com/sun/star/sdb/XCompletedConnection.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/XResultSetMetaDataSupplier.hpp>
#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
#include <com/sun/star/sdbcx/Privilege.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
#include <com/sun/star/sdbcx/XDrop.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/ui/dialogs/XExecutableDialog.hpp>
#include <com/sun/star/util/XFlushable.hpp>
#include <com/sun/star/document/MacroExecMode.hpp>
#include <com/sun/star/ui/XContextMenuInterceptor.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/extract.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/types.hxx>
#include <connectivity/dbexception.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/typeprovider.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sot/storage.hxx>
#include <svl/filenotation.hxx>
#include <svl/intitem.hxx>
#include <unotools/moduleoptions.hxx>
#include <svtools/svlbitm.hxx>
#include <svtools/treelistbox.hxx>
#include <svtools/treelistentry.hxx>
#include <svx/algitem.hxx>
#include <svx/dataaccessdescriptor.hxx>
#include <svx/databaseregistrationui.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <tools/diagnose_ex.h>
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <tools/multisel.hxx>
#include <tools/urlobj.hxx>
#include <unotools/confignode.hxx>
#include <vcl/split.hxx>
#include <vcl/stdtext.hxx>
#include <vcl/svapp.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/waitobj.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/settings.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::io;
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" void createRegistryInfo_OBrowser()
{
static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::SbaTableQueryBrowser > aAutoRegistration;
}
namespace dbaui
{
namespace DatabaseObject = css::sdb::application::DatabaseObject;
namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer;
void SafeAddPropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
{
Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo();
if (xInfo->hasPropertyByName(rPropName))
xSet->addPropertyChangeListener(rPropName, pListener);
}
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 getImplementationName_Static();
}
css::uno::Sequence<OUString> SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames()
{
return getSupportedServiceNames_Static();
}
OUString SbaTableQueryBrowser::getImplementationName_Static()
{
return OUString("org.openoffice.comp.dbu.ODatasourceBrowser");
}
css::uno::Sequence<OUString> SbaTableQueryBrowser::getSupportedServiceNames_Static()
{
css::uno::Sequence<OUString> aSupported { "com.sun.star.sdb.DataSourceBrowser" };
return aSupported;
}
Reference< XInterface > SbaTableQueryBrowser::Create(const Reference<XMultiServiceFactory >& _rxFactory)
{
SolarMutexGuard aGuard;
return *(new SbaTableQueryBrowser(comphelper::getComponentContext(_rxFactory)));
}
SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM)
:SbaXDataBrowserController(_rM)
,m_aSelectionListeners( getMutex() )
,m_aContextMenuInterceptors( getMutex() )
,m_aTableCopyHelper(this)
,m_pTreeView(nullptr)
,m_pSplitter(nullptr)
,m_pCurrentlyDisplayed(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, "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" );
if ( !!m_aDocScriptSupport && *m_aDocScriptSupport )
return makeAny( 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, "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" );
if ( !m_aDocScriptSupport || !*m_aDocScriptSupport )
{
auto newEnd = std::remove_if( aTypes.begin(), aTypes.end(),
[](const Type& type)
{ return type == cppu::UnoType<XScriptInvocationContext>::get(); } );
aTypes.realloc( std::distance(aTypes.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 cleaup 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();
// remove the container listener from the database context
try
{
Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
xDatabaseRegistrations->removeDatabaseRegistrationsListener( this );
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
// check out from all the objects we are listening
// the frame
if (m_xCurrentFrameParent.is())
m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
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())
{
// create controls and set sizes
const 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<DBTreeView>::Create(getBrowserView(), WB_TABSTOP | WB_BORDER);
m_pTreeView->SetPreExpandHandler(LINK(this, SbaTableQueryBrowser, OnExpandEntry));
m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry));
m_pTreeView->getListBox().setContextMenuProvider( this );
m_pTreeView->getListBox().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
auto pTreeModel = m_pTreeView->GetTreeModel();
pTreeModel->SetSortMode(SortAscending);
pTreeModel->SetCompareHdl(LINK(this, SbaTableQueryBrowser, OnTreeEntryCompare));
m_pTreeView->setSelChangeHdl( LINK( this, SbaTableQueryBrowser, OnSelectionChange ) );
// 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_QUERY_THROW );
// the columns participating in the statement
const Reference< XColumnsSupplier > xSuppColumns( xComposer, UNO_QUERY_THROW );
const Reference< XNameAccess > xColumnNames( xSuppColumns->getColumns(), UNO_QUERY_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_QUERY_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, makeAny( OUString() ) );
xComposer->setOrder( "" );
}
// 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 ....
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
}
bool SbaTableQueryBrowser::InitializeForm( const Reference< XPropertySet > & i_formProperties )
{
if(!m_pCurrentlyDisplayed)
return true;
// this method set all format settings from the original table or query
try
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
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[] =
{
OUString(PROPERTY_APPLYFILTER),
OUString(PROPERTY_FILTER),
OUString(PROPERTY_HAVING_CLAUSE),
OUString(PROPERTY_ORDER)
};
for (const auto & aTransferPropertie : aTransferProperties)
{
if ( !xPSI->hasPropertyByName( aTransferPropertie ) )
continue;
aPropertyValues.put( aTransferPropertie, pData->xObjectProperties->getPropertyValue( aTransferPropertie ) );
}
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("AllowInserts",makeAny(false));
xDataSourceSet->setPropertyValue("AllowUpdates",makeAny(false));
xDataSourceSet->setPropertyValue("AllowDeletes",makeAny(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< XChild > xGridAsChild(xGrid, UNO_QUERY);
Reference< XLoadable > xFormAsLoadable;
if (xGridAsChild.is())
xFormAsLoadable.set(xGridAsChild->getParent(), css::uno::UNO_QUERY);
if (xFormAsLoadable.is() && xFormAsLoadable->isLoaded())
{
// set the formats from the table
if(m_pCurrentlyDisplayed)
{
Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 ));
Sequence< Any> aValues(7 + ( m_bPreview ? 5 : 0 ));
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
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;
for (const OUString& rName : xColumns->getElementNames())
{
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", makeAny( VisualEffect::FLAT ) );
sDefaultProperty = PROPERTY_DEFAULTSTATE;
sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
aInitialValues.emplace_back(
"TriState",
makeAny( 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", makeAny( true ) );
SAL_FALLTHROUGH;
case DataType::BINARY:
case DataType::VARBINARY:
case DataType::LONGVARBINARY:
aCurrentModelType = "TextField";
sDefaultProperty = PROPERTY_DEFAULTTEXT;
break;
case DataType::VARCHAR:
case DataType::CHAR:
bFormattedIsNumeric = false;
SAL_FALLTHROUGH;
default:
aCurrentModelType = "FormattedField";
sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT;
if ( xSupplier.is() )
aInitialValues.emplace_back( "FormatsSupplier", makeAny( xSupplier ) );
aInitialValues.emplace_back( "TreatAsNumber", makeAny( bFormattedIsNumeric ) );
aCopyProperties.emplace_back(PROPERTY_FORMATKEY );
break;
}
aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, makeAny( rName ) );
OUString sLabel;
xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
if ( !sLabel.isEmpty() )
aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( sLabel ) );
else
aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( 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, makeAny( 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, makeAny(xGridCol));
}
}
}
catch(const Exception&)
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
}
Reference<XPropertySet> getColumnHelper(SvTreeListEntry const * _pCurrentlyDisplayed, const Reference<XPropertySet>& _rxSource)
{
Reference<XPropertySet> xRet;
if(_pCurrentlyDisplayed)
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pCurrentlyDisplayed->GetUserData());
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_pCurrentlyDisplayed)
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
Reference< XPropertySet > xObjectProps(pData->xObjectProperties, UNO_QUERY);
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);
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(m_pCurrentlyDisplayed,xSource);
if(xProp.is())
{
if(!evt.NewValue.hasValue())
xProp->setPropertyValue(PROPERTY_WIDTH,makeAny(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(m_pCurrentlyDisplayed,xSource);
if(xProp.is())
xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue);
}
// a columns alignment ?
else if (evt.PropertyName == PROPERTY_ALIGN)
{
Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource);
try
{
if(xProp.is())
{
if(evt.NewValue.hasValue())
{
sal_Int16 nAlign = 0;
if(evt.NewValue >>= nAlign)
xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(sal_Int32(nAlign)));
else
xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue);
}
else
xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(css::awt::TextAlign::LEFT));
}
}
catch( const 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(m_pCurrentlyDisplayed,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_pCurrentlyDisplayed)
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData());
OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" );
bool bDefault = !evt.NewValue.hasValue();
if (bDefault)
pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,makeAny(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);
}
}
catch( const 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()
{
SvTreeListEntry* pDataSourceEntry = nullptr;
SvTreeListEntry* pContainerEntry = nullptr;
SvTreeListEntry* pObjectEntry = getObjectEntry( m_aDocumentDataSource, &pDataSourceEntry, &pContainerEntry );
bool bKnownDocDataSource = (nullptr != pObjectEntry);
if (!bKnownDocDataSource)
{
if (nullptr != pDataSourceEntry)
{ // at least the data source is known
if (nullptr != pContainerEntry)
bKnownDocDataSource = true; // assume we know it.
// TODO: should we expand the object container? This may be too expensive just for checking ....
else
{
if ((nullptr == pObjectEntry) && 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& _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( const OUString& _rId ) : sId( _rId ) { }
virtual ~FilterByEntryDataId() {}
virtual bool includeEntry( SvTreeListEntry* _pEntry ) const override;
};
bool FilterByEntryDataId::includeEntry( SvTreeListEntry* _pEntry ) const
{
DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( _pEntry->GetUserData() );
return ( !pData || ( pData->sAccessor == sId ) );
}
}
OUString SbaTableQueryBrowser::getDataSourceAccessor( SvTreeListEntry* _pDataSourceEntry ) const
{
OSL_ENSURE( _pDataSourceEntry, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry!" );
DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( _pDataSourceEntry->GetUserData() );
OSL_ENSURE( 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( _pDataSourceEntry );
}
SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 _nCommandType,
SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _ppContainerEntry, bool _bExpandAncestors,
const SharedConnection& _rxConnection )
{
if (_ppDataSourceEntry)
*_ppDataSourceEntry = nullptr;
if (_ppContainerEntry)
*_ppContainerEntry = nullptr;
SvTreeListEntry* pObject = nullptr;
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 );
SvTreeListEntry* pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter );
if ( !pDataSource ) // 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 );
pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter );
OSL_ENSURE( pDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" );
}
}
if (_ppDataSourceEntry)
// (caller wants to have it ...)
*_ppDataSourceEntry = pDataSource;
if (pDataSource)
{
// expand if required so
if (_bExpandAncestors)
m_pTreeView->getListBox().Expand(pDataSource);
// look for the object container
SvTreeListEntry* pCommandType = nullptr;
switch (_nCommandType)
{
case CommandType::TABLE:
pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_TABLES);
break;
case CommandType::QUERY:
pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_QUERIES);
break;
}
if (_ppContainerEntry)
*_ppContainerEntry = pCommandType;
if (pCommandType)
{
// expand if required so
if (_bExpandAncestors)
{
m_pTreeView->getListBox().Expand(pCommandType);
}
// 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);
}
pObject = m_pTreeView->getListBox().GetEntryPosByName(sPath, pCommandType);
pCommandType = pObject;
if ( nIndex >= 0 )
{
if (ensureEntryObject(pObject))
{
DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( pObject->GetUserData() );
Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
sal_Int32 nIndex2 = nIndex;
sPath = _rCommand.getToken( 0, '/', nIndex2 );
try
{
if ( xCollection->hasByName(sPath) )
{
if(!m_pTreeView->getListBox().GetEntryPosByName(sPath,pObject))
{
Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY);
DBTreeListUserData* pEntryData = new DBTreeListUserData;
pEntryData->eType = etQuery;
if ( xChild.is() )
{
pEntryData->eType = etQueryContainer;
}
implAppendEntry( pObject, sPath, pEntryData, pEntryData->eType );
}
}
}
catch(const Exception&)
{
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
}
}
}
}
while ( nIndex >= 0 );
}
}
}
return pObject;
}
SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& _rDescriptor,
SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _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())
{
if ( m_aExternalFeatures.empty() )
{
const sal_Char* pURLs[] = {
".uno:DataSourceBrowser/DocumentDataSource",
".uno:DataSourceBrowser/FormLetter",
".uno:DataSourceBrowser/InsertColumns",
".uno:DataSourceBrowser/InsertContent",
};
const sal_uInt16 nIds[] = {
ID_BROWSER_DOCUMENT_DATASOURCE,
ID_BROWSER_FORMLETTER,
ID_BROWSER_INSERTCOLUMNS,
ID_BROWSER_INSERTCONTENT
};
for ( size_t i=0; i < SAL_N_ELEMENTS( pURLs ); ++i )
{
URL aURL;
aURL.Complete = OUString::createFromAscii( pURLs[i] );
if ( m_xUrlTransformer.is() )
m_xUrlTransformer->parseStrict( aURL );
m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( aURL );
}
}
for (auto & externalFeature : m_aExternalFeatures)
{
externalFeature.second.xDispatcher = xProvider->queryDispatch(
externalFeature.second.aURL, "_parent", 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 );
}
catch( const 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( _nId ) )
bHaveDispatcher ? pToolbox->ShowItem( _nId ) : pToolbox->HideItem( _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
SvTreeListEntry* pDSLoop = m_pTreeView->getListBox().FirstChild(nullptr);
while (pDSLoop)
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pDSLoop->GetUserData());
if ( pData && pData->xConnection == xCon )
{
// we set the connection to null to avoid a second disposing of the connection
pData->xConnection.clear();
closeConnection(pDSLoop,false);
break;
}
pDSLoop = pDSLoop->NextSibling();
}
}
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();
}
}
catch( const 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("_parent",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("LayoutManager"),
UNO_QUERY );
if ( xLayouter.is() )
{
Reference< XUIElement > xUI(
xLayouter->getElement( "private:resource/toolbar/toolbar" ),
UNO_SET_THROW );
m_xMainToolbar.set(xUI->getRealInterface(), css::uno::UNO_QUERY);
OSL_ENSURE( m_xMainToolbar.is(), "SbaTableQueryBrowser::attachFrame: where's my toolbox?" );
}
}
catch( const 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 a 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;
SAL_FALLTHROUGH;
case ID_TREE_CLOSE_CONN:
case ID_TREE_EDIT_DATABASE:
{
SvTreeListEntry* pCurrentEntry( m_pTreeView->getListBox().GetCurEntry() );
EntryType eType = getEntryType( pCurrentEntry );
if ( eType == etUnknown )
return aReturn;
SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent( pCurrentEntry );
DBTreeListUserData* pDSData
= pDataSourceEntry
? static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() )
: 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(),
"/org.openoffice.Office.DataAccess/Policies/Features/Common" ) );
bool bHaveEditDatabase( true );
OSL_VERIFY( aConfig.getNodeValue( "EditDatabaseFromDataSourceView" ) >>= bHaveEditDatabase );
aReturn.bEnabled = getORB().is() && ( pDataSourceEntry != nullptr ) && bHaveEditDatabase;
}
else if ( nId == ID_BROWSER_COPY )
{
aReturn.bEnabled = isEntryCopyAllowed( pCurrentEntry );
}
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!");
}
catch( const 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() && 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() && 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;
}
SAL_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:
implAdministrate( m_pTreeView->getListBox().GetCurEntry() );
break;
case ID_TREE_CLOSE_CONN:
closeConnection( m_pTreeView->getListBox().GetRootLevelParent( m_pTreeView->getListBox().GetCurEntry() ) );
break;
case ID_TREE_ADMINISTRATE:
svx::administrateDatabaseRegistration( getView() );
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;
}
SAL_FALLTHROUGH;
}
case ID_BROWSER_REFRESH_REBUILD:
{
if ( !SaveModified() )
// nothing to do
break;
SvTreeListEntry* pSelected = m_pCurrentlyDisplayed;
// unload
unloadAndCleanup( false );
// reselect the entry
if ( pSelected )
{
implSelect( pSelected );
}
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());
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.getLength() )
{
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());
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
}
}
break;
case ID_BROWSER_CLOSE:
closeTask();
// if it's not 0, such a async close is already pending
break;
case ID_BROWSER_COPY:
if(m_pTreeView->HasChildPathFocus())
{
copyEntry(m_pTreeView->getListBox().GetCurEntry());
}
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 )
{
Image a, b, c;
OUString d, e;
implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection );
}
void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, Image& _rDbImage,
OUString& _rQueryName, Image& _rQueryImage, OUString& _rTableName, Image& _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)
_rQueryImage = ImageProvider::getFolderImage( DatabaseObject::QUERY );
if (!_rTableImage)
_rTableImage = ImageProvider::getFolderImage( DatabaseObject::TABLE );
if (!_rDbImage)
_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 );
SvTreeListEntry* pDatasourceEntry = m_pTreeView->getListBox().InsertEntry( sDSDisplayName, _rDbImage, _rDbImage );
DBTreeListUserData* pDSData = new DBTreeListUserData;
pDSData->eType = etDatasource;
pDSData->sAccessor = sDataSourceId;
pDSData->xConnection = _rxConnection;
pDatasourceEntry->SetUserData(pDSData);
// the child for the queries container
{
DBTreeListUserData* pQueriesData = new DBTreeListUserData;
pQueriesData->eType = etQueryContainer;
m_pTreeView->getListBox().InsertEntry(
_rQueryName, _rQueryImage, _rQueryImage, pDatasourceEntry,
true /*ChildrenOnDemand*/, TREELIST_APPEND, pQueriesData );
}
// the child for the tables container
{
DBTreeListUserData* pTablesData = new DBTreeListUserData;
pTablesData->eType = etTableContainer;
m_pTreeView->getListBox().InsertEntry(
_rTableName, _rTableImage, _rTableImage, pDatasourceEntry,
true /*ChildrenOnDemand*/, TREELIST_APPEND, pTablesData );
}
}
void SbaTableQueryBrowser::initializeTreeModel()
{
if (m_xDatabaseContext.is())
{
Image aDBImage, aQueriesImage, aTablesImage;
OUString sQueriesName, sTablesName;
// fill the model with the names of the registered datasources
for (const OUString& rDatasource : m_xDatabaseContext->getElementNames())
implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() );
}
}
void SbaTableQueryBrowser::populateTree(const Reference<XNameAccess>& _xNameAccess,
SvTreeListEntry* _pParent,
EntryType _eEntryType)
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pParent->GetUserData());
if(pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables
pData->xContainer = _xNameAccess;
try
{
for (const OUString& rName : _xNameAccess->getElementNames())
{
if( !m_pTreeView->getListBox().GetEntryPosByName(rName,_pParent))
{
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( _pParent, rName, pEntryData, pEntryData->eType );
}
}
}
catch(const Exception&)
{
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
}
}
SvTreeListEntry* SbaTableQueryBrowser::implAppendEntry( SvTreeListEntry* _pParent, const OUString& _rName, void* _pUserData, EntryType _eEntryType )
{
std::unique_ptr< ImageProvider > pImageProvider( getImageProviderFor( _pParent ) );
Image aImage;
pImageProvider->getImages( _rName, getDatabaseObjectType( _eEntryType ), aImage );
SvTreeListEntry* pNewEntry = m_pTreeView->getListBox().InsertEntry( _rName, _pParent, _eEntryType == etQueryContainer , TREELIST_APPEND, _pUserData );
m_pTreeView->getListBox().SetExpandedEntryBmp( pNewEntry, aImage );
m_pTreeView->getListBox().SetCollapsedEntryBmp( pNewEntry, aImage );
return pNewEntry;
}
IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, SvTreeListEntry*, _pParent, bool)
{
if (_pParent->HasChildren())
// nothing to do...
return true;
SvTreeListEntry* pFirstParent = m_pTreeView->getListBox().GetRootLevelParent(_pParent);
OSL_ENSURE(pFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!");
DBTreeListUserData* pData = static_cast< DBTreeListUserData* >(_pParent->GetUserData());
assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!");
#if OSL_DEBUG_LEVEL > 0
SvLBoxString* pString = static_cast<SvLBoxString*>(pFirstParent->GetFirstItem(SvLBoxItemType::String));
OSL_ENSURE(pString,"SbaTableQueryBrowser::OnExpandEntry: No string item!");
#endif
if (etTableContainer == pData->eType)
{
WaitObject aWaitCursor(getBrowserView());
// it could be that we already have a connection
SharedConnection xConnection;
ensureConnection( pFirstParent, xConnection );
if ( 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(), _pParent, etTableOrView );
Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY);
if(xTabSup.is())
{
populateTree( xTabSup->getTables(), _pParent, 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())
{
SQLExceptionInfo aWarnings(xWarnings->getWarnings());
#if 0
// 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!");
}
catch( const 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(_pParent))
{
DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( _pParent->GetUserData() );
Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
populateTree( xCollection, _pParent, etQuery );
}
}
return true;
}
bool SbaTableQueryBrowser::ensureEntryObject( SvTreeListEntry* _pEntry )
{
OSL_ENSURE(_pEntry, "SbaTableQueryBrowser::ensureEntryObject: invalid argument!");
if (!_pEntry)
return false;
EntryType eType = getEntryType( _pEntry );
// the user data of the entry
DBTreeListUserData* pEntryData = static_cast<DBTreeListUserData*>(_pEntry->GetUserData());
OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!");
SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent(_pEntry);
bool bSuccess = false;
switch (eType)
{
case etQueryContainer:
if ( pEntryData->xContainer.is() )
{
// nothing to do
bSuccess = true;
break;
}
{
SvTreeListEntry* pParent = m_pTreeView->getListBox().GetParent(_pEntry);
if ( pParent != pDataSourceEntry )
{
SvLBoxString* pString = static_cast<SvLBoxString*>(_pEntry->GetFirstItem(SvLBoxItemType::String));
OSL_ENSURE(pString,"There must be a string item!");
OUString aName(pString->GetText());
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pParent->GetUserData());
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( pDataSourceEntry ) ) >>= 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!");
}
}
catch( const 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, makeAny(_rDataSourceName));
if(_rxConnection.is())
xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( _rxConnection.getTyped() ) );
// set this _before_ setting the connection, else the rowset would rebuild it ...
xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, makeAny(_nCommandType));
xProp->setPropertyValue(PROPERTY_COMMAND, makeAny(_rCommand));
xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny(_bEscapeProcessing));
if ( m_bPreview )
{
xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, makeAny(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;
}
catch( const SQLException& )
{
Any aException( ::cppu::getCaughtException() );
showError( SQLExceptionInfo( aException ) );
}
catch( const WrappedTargetException& e )
{
if ( e.TargetException.isExtractableTo( ::cppu::UnoType< SQLException >::get() ) )
showError( SQLExceptionInfo( e.TargetException ) );
else
SAL_WARN("dbaccess", e);
}
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))
{
SvTreeListEntry* pDataSource = nullptr;
SvTreeListEntry* pCommandType = nullptr;
SvTreeListEntry* pCommand = getObjectEntry( _rDataSourceName, _rCommand, _nCommandType, &pDataSource, &pCommandType, true, _rxConnection );
if (pCommand)
{
bool bSuccess = true;
if ( _bSelectDirect )
{
bSuccess = implSelect( pCommand );
}
else
{
m_pTreeView->getListBox().Select( pCommand );
}
if ( bSuccess )
{
m_pTreeView->getListBox().MakeVisible(pCommand);
m_pTreeView->getListBox().SetCursor(pCommand);
}
}
else if (!pCommandType)
{
if ( m_pCurrentlyDisplayed )
{ // tell the old entry (if any) it has been deselected
selectPath(m_pCurrentlyDisplayed, false);
m_pCurrentlyDisplayed = nullptr;
}
// 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)
{
implSelect( m_pTreeView->getListBox().FirstSelected() );
}
SvTreeListEntry* SbaTableQueryBrowser::implGetConnectionEntry(SvTreeListEntry* _pEntry) const
{
SvTreeListEntry* pCurrentEntry = _pEntry;
DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() );
while(pEntryData->eType != etDatasource )
{
pCurrentEntry = m_pTreeView->GetTreeModel()->GetParent(pCurrentEntry);
pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() );
}
return pCurrentEntry;
}
bool SbaTableQueryBrowser::implSelect( SvTreeListEntry* _pEntry )
{
if ( !_pEntry )
return false;
DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( _pEntry->GetUserData() );
switch (pEntryData->eType)
{
case etTableOrView:
case etQuery:
break;
default:
// nothing to do
return false;
}
OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(_pEntry), "SbaTableQueryBrowser::implSelect: invalid entry (1)!");
OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(m_pTreeView->GetTreeModel()->GetParent(_pEntry)), "SbaTableQueryBrowser::implSelect: invalid entry (2)!");
// get the entry for the tables or queries
SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(_pEntry);
DBTreeListUserData* pContainerData = static_cast<DBTreeListUserData*>(pContainer->GetUserData());
// get the entry for the datasource
SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer);
DBTreeListUserData* pConData = static_cast<DBTreeListUserData*>(pConnection->GetUserData());
// 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
SvLBoxString* pString = static_cast<SvLBoxString*>(_pEntry->GetFirstItem(SvLBoxItemType::String));
OSL_ENSURE(pString,"There must be a string item!");
const OUString sSimpleName = pString->GetText();
OUStringBuffer sNameBuffer(sSimpleName);
if ( etQueryContainer == pContainerData->eType )
{
SvTreeListEntry* pTemp = pContainer;
while( m_pTreeView->GetTreeModel()->GetParent(pTemp) != pConnection )
{
sNameBuffer.insert(0,'/');
pString = static_cast<SvLBoxString*>(pTemp->GetFirstItem(SvLBoxItemType::String));
OSL_ENSURE(pString,"There must be a string item!");
sNameBuffer.insert(0,pString->GetText());
pTemp = m_pTreeView->GetTreeModel()->GetParent(pTemp);
}
}
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
{
WaitObject aWaitCursor(getBrowserView());
// tell the old entry it has been deselected
selectPath(m_pCurrentlyDisplayed, false);
m_pCurrentlyDisplayed = nullptr;
// not really loaded
m_pCurrentlyDisplayed = _pEntry;
// tell the new entry it has been selected
selectPath(m_pCurrentlyDisplayed);
// get the name of the data source currently selected
ensureConnection( m_pCurrentlyDisplayed, 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 = static_cast<DBTreeListUserData*>(_pEntry->GetUserData());
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 ";
sFilter = sFilter + xAnalyzer->getFilter();
OUString sReplace(sSql);
sReplace = sReplace.replaceFirst(sFilter, "");
xAnalyzer->setQuery(sReplace);
Reference<XSingleSelectQueryComposer> xComposer(xAnalyzer,UNO_QUERY);
xComposer->setFilter("0=1");
aName = xAnalyzer->getQuery();
nCommandType = CommandType::COMMAND;
}
}
}
catch (Exception&)
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
}
}
}
}
}
}
OUString sDataSourceName( getDataSourceAccessor( pConnection ) );
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;
}
SvTreeListEntry* SbaTableQueryBrowser::getEntryFromContainer(const Reference<XNameAccess>& _rxNameAccess)
{
DBTreeListBox& rListBox = m_pTreeView->getListBox();
SvTreeListEntry* pContainer = nullptr;
SvTreeListEntry* pDSLoop = rListBox.FirstChild(nullptr);
while (pDSLoop)
{
pContainer = rListBox.GetEntry(pDSLoop, CONTAINER_QUERIES);
DBTreeListUserData* pQueriesData = static_cast<DBTreeListUserData*>(pContainer->GetUserData());
if ( pQueriesData && pQueriesData->xContainer == _rxNameAccess )
break;
pContainer = rListBox.GetEntry(pDSLoop, CONTAINER_TABLES);
DBTreeListUserData* pTablesData = static_cast<DBTreeListUserData*>(pContainer->GetUserData());
if ( pTablesData && pTablesData->xContainer == _rxNameAccess )
break;
pDSLoop = pDSLoop->NextSibling();
pContainer = nullptr;
}
return pContainer;
}
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
SvTreeListEntry* pEntry = getEntryFromContainer(xNames);
if(pEntry) // found one
{
// insert the new entry into the tree
DBTreeListUserData* pContainerData = static_cast<DBTreeListUserData*>(pEntry->GetUserData());
OSL_ENSURE(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 (static_cast<sal_Int32>(m_pTreeView->getListBox().GetChildCount(pEntry)) < ( 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, pEntry, etQuery );
}
pNewData->eType = etQuery;
}
implAppendEntry( pEntry, ::comphelper::getString( _rEvent.Accessor ), pNewData, pNewData->eType );
}
else
SbaXDataBrowserController::elementInserted(_rEvent);
}
bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(const OUString& _sName, SvTreeListEntry const * _pContainer)
{
return m_pCurrentlyDisplayed
&& getEntryType(m_pCurrentlyDisplayed) == getChildType(_pContainer)
&& m_pTreeView->getListBox().GetParent(m_pCurrentlyDisplayed) == _pContainer
&& m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed) == _sName;
}
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
SvTreeListEntry* pContainer = getEntryFromContainer(xNames);
if ( pContainer )
{ // a query or table has been removed
OUString aName = ::comphelper::getString(_rEvent.Accessor);
if ( isCurrentlyDisplayedChanged( aName, pContainer) )
{ // the element displayed currently has been replaced
// we need to remember the old value
SvTreeListEntry* pTemp = m_pCurrentlyDisplayed;
// unload
unloadAndCleanup( false ); // don't dispose the connection
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pTemp->GetUserData());
pTemp->SetUserData(nullptr);
delete pData;
// the data could be null because we have a table which isn't correct
m_pTreeView->GetTreeModel()->Remove(pTemp);
}
else
{
// remove the entry from the model
SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer);
while(pChild)
{
if (m_pTreeView->getListBox().GetEntryText(pChild) == aName)
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pChild->GetUserData());
pChild->SetUserData(nullptr);
delete pData;
m_pTreeView->GetTreeModel()->Remove(pChild);
break;
}
pChild = pChild->NextSibling();
}
}
// 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);
SvTreeListEntry* pContainer = getEntryFromContainer(xNames);
if ( pContainer )
{ // a table or query as been replaced
OUString aName = ::comphelper::getString(_rEvent.Accessor);
if ( isCurrentlyDisplayedChanged( aName, pContainer) )
{ // the element displayed currently has been replaced
// we need to remember the old value
SvTreeListEntry* pTemp = m_pCurrentlyDisplayed;
unloadAndCleanup( false ); // don't dispose the connection
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pTemp->GetUserData());
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
{
pTemp->SetUserData(nullptr);
delete pData;
}
}
}
else
{
// find the entry for this name
SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer);
while(pChild)
{
if (m_pTreeView->getListBox().GetEntryText(pChild) == aName)
{
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pChild->GetUserData());
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
{
pChild->SetUserData(nullptr);
delete pData;
}
}
break;
}
pChild = pChild->NextSibling();
}
}
// 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();
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
// clear
_rxConnection.clear();
// will implicitly dispose if we have the ownership, since xConnection is a SharedConnection
}
void SbaTableQueryBrowser::disposeConnection( SvTreeListEntry* _pDSEntry )
{
OSL_ENSURE( _pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" );
OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" );
if ( _pDSEntry )
{
DBTreeListUserData* pTreeListData = static_cast< DBTreeListUserData* >( _pDSEntry->GetUserData() );
if ( pTreeListData )
impl_releaseConnection( pTreeListData->xConnection );
}
}
void SbaTableQueryBrowser::closeConnection(SvTreeListEntry* _pDSEntry, bool _bDisposeConnection)
{
OSL_ENSURE(_pDSEntry, "SbaTableQueryBrowser::closeConnection: invalid entry (NULL)!");
OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!");
// if one of the entries of the given DS is displayed currently, unload the form
if (m_pCurrentlyDisplayed && (m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed) == _pDSEntry))
unloadAndCleanup(_bDisposeConnection);
// collapse the query/table container
for (SvTreeListEntry* pContainers = m_pTreeView->GetTreeModel()->FirstChild(_pDSEntry); pContainers; pContainers = pContainers->NextSibling())
{
SvTreeListEntry* pElements = m_pTreeView->GetTreeModel()->FirstChild(pContainers);
if ( pElements )
m_pTreeView->getListBox().Collapse(pContainers);
m_pTreeView->getListBox().EnableExpandHandler(pContainers);
// and delete their children (they are connection-relative)
for (; pElements; )
{
SvTreeListEntry* pRemove = pElements;
pElements = pElements->NextSibling();
DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pRemove->GetUserData());
pRemove->SetUserData(nullptr);
delete pData;
m_pTreeView->GetTreeModel()->Remove(pRemove);
}
}
// collapse the entry itself
m_pTreeView->getListBox().Collapse(_pDSEntry);
// dispose/reset the connection
if ( _bDisposeConnection )
disposeConnection( _pDSEntry );
}
void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection )
{
if (!m_pCurrentlyDisplayed)
// nothing to do
return;
SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed);
// de-select the path for the currently displayed table/query
if (m_pCurrentlyDisplayed)
{
selectPath(m_pCurrentlyDisplayed, false);
}
m_pCurrentlyDisplayed = nullptr;
try
{
// get the active connection. We need to dispose it.
Reference< XPropertySet > xRowSetProps(getRowSet(),UNO_QUERY);
Reference< XConnection > xConn;
xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION) >>= xConn;
#if OSL_DEBUG_LEVEL > 0
{
Reference< XComponent > xComp(
xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),
css::uno::UNO_QUERY);
}
#endif
// 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( pDSEntry );
}
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 );
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
return xDataSource.get();
}
}
void SbaTableQueryBrowser::impl_initialize()
{
SolarMutexGuard aGuard;
// doin' a lot of VCL stuff here -> lock the SolarMutex
// first initialize the parent
SbaXDataBrowserController::impl_initialize();
Reference<XConnection> xForeignConnection;
Reference< XFrame > xFrame;
OUString aTableName, aCatalogName, aSchemaName;
bool bEscapeProcessing = true;
sal_Int32 nInitialDisplayCommandType = CommandType::COMMAND;
OUString sInitialDataSourceName;
OUString sInitialCommand;
const NamedValueCollection& rArguments( getInitParams() );
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( "Frame", 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( "ShowTreeViewButton", true ) // compatibility name
|| !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true );
OSL_ENSURE( !rArguments.has( "ShowTreeViewButton" ),
"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( "ShowTreeView", true ) // compatibility name
|| !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true );
OSL_ENSURE( !rArguments.has( "ShowTreeView" ),
"SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" );
if ( bHideTreeView )
hideExplorer();
else
showExplorer();
if ( m_bPreview )
{
try
{
Sequence< OUString> aProperties(5);
Sequence< Any> aValues(5);
OUString* pStringIter = aProperties.getArray();
Any* pValueIter = aValues.getArray();
*pStringIter++ = "AlwaysShowCursor";
*pValueIter++ <<= false;
*pStringIter++ = PROPERTY_BORDER;
*pValueIter++ <<= sal_Int16(0);
*pStringIter++ = "HasNavigationBar";
*pValueIter++ <<= false;
*pStringIter++ = "HasRecordMarker";
*pValueIter++ <<= false;
*pStringIter++ = "Tabstop";
*pValueIter++ <<= 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 a 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;
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 );
}
catch( const Exception& )
{
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: a connection parent which does not have a 'Name'!??" );
}
}
}
}
implAddDatasource( sInitialDataSourceName, xConnection );
m_pTreeView->getListBox().Expand( m_pTreeView->getListBox().First() );
}
else
initializeTreeModel();
if ( m_bEnableBrowser )
{
m_aDocScriptSupport = ::boost::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 = ::boost::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,makeAny(aCatalogName));
xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,makeAny(aSchemaName));
xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,makeAny(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(SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection)
{
SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(_pAnyEntry);
DBTreeListUserData* pDSData =
pDSEntry
? static_cast<DBTreeListUserData*>(pDSEntry->GetUserData())
: nullptr;
return ensureConnection( pDSEntry, pDSData, _rConnection );
}
std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor( SvTreeListEntry* _pAnyEntry )
{
std::unique_ptr< ImageProvider > pImageProvider( new ImageProvider );
SharedConnection xConnection;
if ( getExistentConnectionFor( _pAnyEntry, xConnection ) )
pImageProvider.reset( new ImageProvider( xConnection ) );
return pImageProvider;
}
bool SbaTableQueryBrowser::getExistentConnectionFor( SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection )
{
SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent( _pAnyEntry );
DBTreeListUserData* pDSData =
pDSEntry
? static_cast< DBTreeListUserData* >( pDSEntry->GetUserData() )
: nullptr;
if ( pDSData )
_rConnection = pDSData->xConnection;
return _rConnection.is();
}
bool SbaTableQueryBrowser::impl_isDataSourceEntry( SvTreeListEntry* _pEntry ) const
{
return m_pTreeView->GetTreeModel()->GetRootLevelParent( _pEntry ) == _pEntry;
}
bool SbaTableQueryBrowser::ensureConnection( SvTreeListEntry* _pDSEntry, void* pDSData, SharedConnection& _rConnection )
{
OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" );
if(_pDSEntry)
{
DBTreeListUserData* pTreeListData = static_cast<DBTreeListUserData*>(pDSData);
OUString aDSName = GetEntryText(_pDSEntry);
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();
}
IMPL_LINK( SbaTableQueryBrowser, OnTreeEntryCompare, const SvSortData&, _rSortData, sal_Int32 )
{
const SvTreeListEntry* pLHS = _rSortData.pLeft;
const SvTreeListEntry* pRHS = _rSortData.pRight;
OSL_ENSURE(pLHS && pRHS, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid tree entries!");
// we want the table entry and the end so we have to do a check
if (isContainer(pRHS))
{
// don't use getEntryType (directly or indirecly) for the LHS:
// LHS is currently being inserted, so it is not "completely valid" at the moment
const EntryType eRight = getEntryType(pRHS);
if (etTableContainer == eRight)
// every other container should be placed _before_ the bookmark container
return -1;
const OUString sLeft = m_pTreeView->getListBox().GetEntryText(const_cast<SvTreeListEntry*>(pLHS));
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;
}
const SvLBoxString* pLeftTextItem = static_cast<const SvLBoxString*>(pLHS->GetFirstItem(SvLBoxItemType::String));
const SvLBoxString* pRightTextItem = static_cast<const SvLBoxString*>(pRHS->GetFirstItem(SvLBoxItemType::String));
OSL_ENSURE(pLeftTextItem && pRightTextItem, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid text items!");
OUString sLeftText = pLeftTextItem->GetText();
OUString sRightText = pRightTextItem->GetText();
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( SvTreeListEntry* _pApplyTo )
{
OSL_PRECOND( _pApplyTo, "SbaTableQueryBrowser::implAdministrate: illegal entry!" );
if ( !_pApplyTo )
return;
try
{
// get the desktop object
Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() );
// the initial selection
SvTreeListEntry* pTopLevelSelected = _pApplyTo;
while (pTopLevelSelected && m_pTreeView->getListBox().GetParent(pTopLevelSelected))
pTopLevelSelected = m_pTreeView->getListBox().GetParent(pTopLevelSelected);
OUString sInitialSelection;
if (pTopLevelSelected)
sInitialSelection = getDataSourceAccessor( pTopLevelSelected );
Reference< XDataSource > xDataSource( getDataSourceByName( sInitialSelection, getView(), getORB(), nullptr ) );
Reference< XModel > xDocumentModel( getDataSourceOrModel( xDataSource ), UNO_QUERY );
if ( xDocumentModel.is() )
{
Reference< XInteractionHandler2 > xInteractionHandler(
InteractionHandler::createWithParent(getORB(), nullptr) );
::comphelper::NamedValueCollection aLoadArgs;
aLoadArgs.put( "Model", xDocumentModel );
aLoadArgs.put( "InteractionHandler", xInteractionHandler );
aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
Sequence< PropertyValue > aLoadArgPV;
aLoadArgs >>= aLoadArgPV;
xFrameLoader->loadComponentFromURL(
xDocumentModel->getURL(),
"_default",
FrameSearchFlag::ALL | FrameSearchFlag::GLOBAL,
aLoadArgPV
);
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
}
bool SbaTableQueryBrowser::requestQuickHelp( const SvTreeListEntry* _pEntry, OUString& _rText ) const
{
const DBTreeListUserData* pData = static_cast< const DBTreeListUserData* >( _pEntry->GetUserData() );
if ( ( pData->eType == etDatasource ) && !pData->sAccessor.isEmpty() )
{
_rText = ::svt::OFileNotation( pData->sAccessor ).get( ::svt::OFileNotation::N_SYSTEM );
return true;
}
return false;
}
OUString SbaTableQueryBrowser::getContextMenuResourceName( Control& _rControl ) const
{
OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl,
"SbaTableQueryBrowser::getContextMenuResourceName: where does this come from?" );
if ( &m_pTreeView->getListBox() != &_rControl )
return OUString();
return OUString("explorer");
}
IController& SbaTableQueryBrowser::getCommandController()
{
return *this;
}
::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors()
{
return &m_aContextMenuInterceptors;
}
Any SbaTableQueryBrowser::getCurrentSelection( Control& _rControl ) const
{
OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl,
"SbaTableQueryBrowser::getCurrentSelection: where does this come from?" );
if ( &m_pTreeView->getListBox() != &_rControl )
return Any();
SvTreeListEntry* pSelected = m_pTreeView->getListBox().FirstSelected();
if ( !pSelected )
return Any();
OSL_ENSURE( m_pTreeView->getListBox().NextSelected( pSelected ) == nullptr,
"SbaTableQueryBrowser::getCurrentSelection: single-selection is expected here!" );
NamedDatabaseObject aSelectedObject;
DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pSelected->GetUserData() );
aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType );
switch ( aSelectedObject.Type )
{
case DatabaseObject::QUERY:
case DatabaseObject::TABLE:
aSelectedObject.Name = m_pTreeView->getListBox().GetEntryText( pSelected );
break;
case DatabaseObjectContainer::DATA_SOURCE:
case DatabaseObjectContainer::QUERIES:
case DatabaseObjectContainer::TABLES:
aSelectedObject.Name = getDataSourceAccessor( pSelected );
break;
default:
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" );
break;
}
return makeAny( aSelectedObject );
}
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;
}
}
catch( const 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;
for (const OUString& rName : _xColContainer->getElementNames())
{
_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( "private:resource/toolbar/toolbar" );
xLayoutManager->unlock();
xLayoutManager->doLayout();
}
onLoadedMenu( xLayoutManager );
}
}
OUString SbaTableQueryBrowser::getPrivateTitle() const
{
OUString sTitle;
if ( m_pCurrentlyDisplayed )
{
SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(m_pCurrentlyDisplayed);
// get the entry for the datasource
SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer);
OUString sName = m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed);
sTitle = GetEntryText( pConnection );
INetURLObject aURL(sTitle);
if ( aURL.GetProtocol() != INetProtocol::NotValid )
sTitle = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
if ( !sName.isEmpty() )
{
sName += " - ";
sName += sTitle;
sTitle = sName;
}
}
return sTitle;
}
bool SbaTableQueryBrowser::preReloadForm()
{
bool bIni = false;
if ( !m_pCurrentlyDisplayed )
{
// 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) )
{
SvTreeListEntry* pDataSource = nullptr;
SvTreeListEntry* pCommandType = nullptr;
m_pCurrentlyDisplayed = getObjectEntry( sDataSource, sCommand, nCommandType, &pDataSource, &pCommandType );
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 );
}
}
catch( const 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( const OUString& _rDataSourceName )
{
// get the top-level representing the removed data source
SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().FirstChild( nullptr );
while ( pDataSourceEntry )
{
if ( m_pTreeView->getListBox().GetEntryText( pDataSourceEntry ) == _rDataSourceName )
break;
pDataSourceEntry = pDataSourceEntry->NextSibling();
}
OSL_ENSURE( pDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" );
if ( !pDataSourceEntry )
return;
if ( isSelected( pDataSourceEntry ) )
{ // a table or query belonging to the deleted data source is currently being displayed.
OSL_ENSURE( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) == pDataSourceEntry,
"SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (1)!" );
unloadAndCleanup();
}
else
OSL_ENSURE(
( nullptr == m_pCurrentlyDisplayed )
|| ( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) != pDataSourceEntry ),
"SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (2)!");
// delete any user data of the child entries of the to-be-removed entry
std::pair<SvTreeListEntries::const_iterator, SvTreeListEntries::const_iterator> aIters =
m_pTreeView->GetTreeModel()->GetChildIterators(pDataSourceEntry);
SvTreeListEntries::const_iterator it = aIters.first, itEnd = aIters.second;
for (; it != itEnd; ++it)
{
SvTreeListEntry* pEntry = (*it).get();
const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pEntry->GetUserData());
pEntry->SetUserData(nullptr);
delete pData;
}
// remove the entry
DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() );
pDataSourceEntry->SetUserData( nullptr );
delete pData;
m_pTreeView->GetTreeModel()->Remove( pDataSourceEntry );
}
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: */
↑ V560 A part of conditional expression is always true: getBrowserView().
↑ V560 A part of conditional expression is always true: getBrowserView().
↑ V560 A part of conditional expression is always true: (nullptr == pObjectEntry).