/* -*- 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 .
*/
void SAL_CALL SbaTableQueryBrowser::disposing()
{
SolarMutexGuard aGuard; // doin' a lot of VCL stuff here -> lock the SolarMutex
// kiss our listeners goodbye
css::lang::EventObject aEvt(*this);
m_aSelectionListeners.disposeAndClear(aEvt);
m_aContextMenuInterceptors.disposeAndClear(aEvt);
if (getBrowserView())
{ // Need to do some cleanup of the data pointed to the tree view entries before we remove the treeview
clearTreeModel();
m_pTreeView = nullptr;
getBrowserView()->setTreeView(nullptr);
}
// remove ourself as status listener
implRemoveStatusListeners();
// check out from all the objects we are listening // the frame if (m_xCurrentFrameParent.is())
m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
// remove the container listener from the database context try
{
Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
xDatabaseRegistrations->removeDatabaseRegistrationsListener( this );
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
m_pTreeView->setContextMenuProvider( this );
m_pTreeView->setControlActionListener( this );
m_pTreeView->SetHelpId(HID_CTL_TREEVIEW);
// a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide
m_pSplitter->SetSplitPosPixel(getBrowserView()->LogicToPixel(::Size(80, 0), MapMode(MapUnit::MapAppFont)).Width());
// fill view with data
rTreeView.set_sort_order(true);
rTreeView.set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){ return OnTreeEntryCompare(rLeft, rRight);
});
rTreeView.make_sorted();
m_pTreeView->SetSelChangeHdl(LINK(this, SbaTableQueryBrowser, OnSelectionChange));
m_pTreeView->show_container();
// TODO
getBrowserView()->getVclControl()->SetHelpId(HID_CTL_TABBROWSER); if (getBrowserView()->getVclControl()->GetHeaderBar())
getBrowserView()->getVclControl()->GetHeaderBar()->SetHelpId(HID_DATABROWSE_HEADER);
InvalidateFeature(ID_BROWSER_EXPLORER);
if ( invalidColumn )
{ // reset the complete order statement at both the row set and the parser
xRowSetProps->setPropertyValue( PROPERTY_ORDER, Any( OUString() ) );
xComposer->setOrder( u""_ustr );
}
// check if the columns participating in the filter refer to existing tables // TODO: there's no API at all for this. The method which comes nearest to what we need is // "getStructuredFilter", but it returns pure column names only. That is, for a statement like // "SELECT * FROM <table> WHERE <other_table>.<column> = <value>", it will return "<column>". But // there's no API at all to retrieve the information about "<other_table>" - which is what would // be needed here. // That'd be a chance to replace getStructuredFilter with something more reasonable. // So, what really would be handy, is some // XNormalizedFilter getNormalizedFilter(); // with // interface XDisjunctiveFilterExpression // { // XConjunctiveFilterTerm getTerm( int index ); // } // interface XConjunctiveFilterTerm // { // ComparisonPredicate getPredicate( int index ); // } // struct ComparisonPredicate // { // XComparisonOperand Lhs; // SQLFilterOperator Operator; // XComparisonOperand Rhs; // } // interface XComparisonOperand // { // SQLFilterOperand Type; // XPropertySet getColumn(); // string getLiteral(); // ... // } // enum SQLFilterOperand { Column, Literal, ... } // ... or something like this...
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
}
}
// this method set all format settings from the original table or query try
{
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" );
ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" );
// get the formats supplier of the database we're working with
Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormatter()->getNumberFormatsSupplier();
// insert the column into the gridcontrol so that we see something :-)
OUString aCurrentModelType;
Reference<XColumnsSupplier> xSupCols(getRowSet(),UNO_QUERY);
Reference<XNameAccess> xColumns = xSupCols->getColumns();
// ignore the column when it is a rowversion one if ( bSuppressVersionCol
&& xColPSI->hasPropertyByName( PROPERTY_ISROWVERSION )
&& ::cppu::any2bool( xColumn->getPropertyValue( PROPERTY_ISROWVERSION ) )
) continue;
// use the result set column's type to determine the type of grid column to create bool bFormattedIsNumeric = true;
sal_Int32 nType = ::comphelper::getINT32( xColumn->getPropertyValue( PROPERTY_TYPE ) );
std::vector< NamedValue > aInitialValues;
std::vector< OUString > aCopyProperties;
Any aDefault;
switch(nType)
{ case DataType::BIT: case DataType::BOOLEAN:
{
aCurrentModelType = "CheckBox";
aInitialValues.emplace_back( "VisualEffect", Any( VisualEffect::FLAT ) );
sDefaultProperty = PROPERTY_DEFAULTSTATE;
case DataType::LONGVARCHAR: case DataType::CLOB:
aInitialValues.emplace_back( "MultiLine", Any( true ) );
[[fallthrough]]; case DataType::BINARY: case DataType::VARBINARY: case DataType::LONGVARBINARY:
aCurrentModelType = "TextField";
sDefaultProperty = PROPERTY_DEFAULTTEXT; break;
case DataType::VARCHAR: case DataType::CHAR:
bFormattedIsNumeric = false;
[[fallthrough]]; default:
aCurrentModelType = "FormattedField";
sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT;
// 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;
// don't allow the mouse to scroll in the cells if ( xGridColPSI->hasPropertyByName( PROPERTY_MOUSE_WHEEL_BEHAVIOR ) )
aInitialValues.emplace_back( PROPERTY_MOUSE_WHEEL_BEHAVIOR, Any( MouseWheelBehavior::SCROLL_DISABLED ) );
// now set all those values for (autoconst& property : aInitialValues)
{
xGridCol->setPropertyValue( property.Name, property.Value );
} for (autoconst& copyPropertyName : aCopyProperties)
xGridCol->setPropertyValue( copyPropertyName, xColumn->getPropertyValue(copyPropertyName) );
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 ? elseif (evt.PropertyName == PROPERTY_WIDTH)
{ // a column width has changed -> update the model // (the update of the view is done elsewhere)
Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource); if(xProp.is())
{ if(!evt.NewValue.hasValue())
xProp->setPropertyValue(PROPERTY_WIDTH,Any(sal_Int32(227))); else
xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue);
}
}
// a column's 'visible' state ? elseif (evt.PropertyName == PROPERTY_HIDDEN)
{
Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource); if(xProp.is())
xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue);
}
// a column's format ? elseif ( evt.PropertyName == PROPERTY_FORMATKEY
&& (TypeClass_LONG == evt.NewValue.getValueTypeClass())
)
{ // update the model (means the definition object)
Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource); if(xProp.is())
xProp->setPropertyValue(PROPERTY_FORMATKEY,evt.NewValue);
}
// some table definition properties ? // the height of the rows in the grid ? elseif (evt.PropertyName == PROPERTY_ROW_HEIGHT)
{ if (m_xCurrentlyDisplayed)
{
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed));
OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" );
elseif ( 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");
}
}
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(bFound, "SbaTableQueryBrowser::statusChanged: don't know who sent this!");
}
void SbaTableQueryBrowser::checkDocumentDataSource()
{
std::unique_ptr<weld::TreeIter> xDataSourceEntry;
std::unique_ptr<weld::TreeIter> xContainerEntry;
std::unique_ptr<weld::TreeIter> xObjectEntry = getObjectEntry(m_aDocumentDataSource, &xDataSourceEntry, &xContainerEntry); bool bKnownDocDataSource = static_cast<bool>(xObjectEntry); if (!bKnownDocDataSource)
{ if (xDataSourceEntry)
{ // at least the data source is known if (xContainerEntry)
{
bKnownDocDataSource = true; // assume we know it. // TODO: should we expand the object container? This may be too expensive just for checking...
} else
{ if (m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType)
&& m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command))
{ // maybe we have a command to be displayed ?
sal_Int32 nCommandType = CommandType::TABLE;
m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
// escape processing is the only one allowed not to be present
_rEscapeProcessing = true; if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing))
_rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]);
}
std::unique_ptr<weld::TreeIter> xObject; if ( m_pTreeView )
{ // look for the data source entry
OUString sDisplayName, sDataSourceId; bool bIsDataSourceURL = getDataSourceDisplayName_isURL( _rDataSource, sDisplayName, sDataSourceId ); // the display name may differ from the URL for readability reasons // #i33699#
FilterByEntryDataId aFilter( sDataSourceId );
std::unique_ptr<weld::TreeIter> xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter ); if (!xDataSource) // check if the data source name is a file location
{ if ( bIsDataSourceURL )
{ // special case, the data source is a URL // add new entries to the list box model
implAddDatasource( _rDataSource, _rxConnection );
xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter );
OSL_ENSURE( xDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" );
}
}
if (xDataSource)
{ if (ppDataSourceEntry)
{ // (caller wants to have it...)
*ppDataSourceEntry = rTreeView.make_iterator(xDataSource.get());
}
// expand if required so if (bExpandAncestors)
rTreeView.expand_row(*xDataSource);
// look for the object container
std::unique_ptr<weld::TreeIter> xCommandType; if (nCommandType == CommandType::QUERY || nCommandType == CommandType::TABLE)
{
xCommandType = rTreeView.make_iterator(xDataSource.get()); if (!rTreeView.iter_children(*xCommandType))
xCommandType.reset(); else
{ // 1st child is queries, so we're already done if looking for CommandType::QUERY
// 2nd child is tables if (nCommandType == CommandType::TABLE && !rTreeView.iter_next_sibling(*xCommandType))
xCommandType.reset();
}
}
if (xCommandType)
{ if (ppContainerEntry)
{ // (caller wants to have it...)
*ppContainerEntry = rTreeView.make_iterator(xCommandType.get());
}
rTreeView.make_unsorted();
// expand if required so if (bExpandAncestors)
{
rTreeView.expand_row(*xCommandType);
}
// look for the object
sal_Int32 nIndex = 0; do
{
OUString sPath; switch (nCommandType)
{ case CommandType::TABLE:
sPath = _rCommand;
nIndex = -1; break;
case CommandType::QUERY:
sPath = _rCommand.getToken( 0, '/', nIndex ); break;
default:
assert(false);
}
xObject = m_pTreeView->GetEntryPosByName(sPath, xCommandType.get()); if (xObject)
rTreeView.copy_iterator(*xObject, *xCommandType); else
xCommandType.reset(); if ( nIndex >= 0 )
{ if (ensureEntryObject(*xObject))
{
DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xObject));
Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
sal_Int32 nIndex2 = nIndex;
sPath = _rCommand.getToken( 0, '/', nIndex2 ); try
{ if ( xCollection->hasByName(sPath) )
{ if(!m_pTreeView->GetEntryPosByName(sPath, xObject.get()))
{
Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY);
DBTreeListUserData* pEntryData = new DBTreeListUserData;
pEntryData->eType = etQuery; if ( xChild.is() )
{
pEntryData->eType = etQueryContainer;
}
implAppendEntry(xObject.get(), sPath, pEntryData);
}
}
} catch(const Exception&)
{
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
}
}
}
} while ( nIndex >= 0 );
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();
}
// check if we have to hide this item from the toolbox if ( pToolbox )
{ bool bHaveDispatcher = m_aExternalFeatures[ _nId ].xDispatcher.is(); if ( bHaveDispatcher != pToolbox->IsItemVisible( ToolBoxItemId(_nId) ) )
bHaveDispatcher ? pToolbox->ShowItem( ToolBoxItemId(_nId) ) : pToolbox->HideItem( ToolBoxItemId(_nId) );
}
// and invalidate this feature in general
InvalidateFeature( _nId );
}
// remove it
aLoop = m_aExternalFeatures.erase(aLoop);
// maybe update the UI
implCheckExternalSlot(nSlot);
// continue, the same XDispatch may be responsible for more than one URL
}
++aLoop;
}
} else
{
Reference<XConnection> xCon(_rSource.Source, UNO_QUERY); if ( xCon.is() && m_pTreeView )
{ // our connection is in dispose so we have to find the entry equal with this connection // and close it what means to collapse the entry // get the top-level representing the removed data source
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator()); if (rTreeView.get_iter_first(*xDSLoop))
{ do
{
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xDSLoop)); if ( pData && pData->xConnection == xCon )
{ // we set the connection to null to avoid a second disposing of the connection
pData->xConnection.clear();
closeConnection(*xDSLoop, false); break;
}
} while (rTreeView.iter_next_sibling(*xDSLoop));
}
} else
SbaXDataBrowserController::disposing(_rSource);
}
}
}
void SbaTableQueryBrowser::implRemoveStatusListeners()
{ // clear all old dispatches for (autoconst& 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
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);
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 );
}
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.