/* -*- 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 );
}
// no chance without a view if (!getBrowserView() || !getBrowserView()->getVclControl()) return aReturn;
switch ( nId )
{ case ID_TREE_ADMINISTRATE:
aReturn.bEnabled = true; return aReturn;
case ID_BROWSER_CLOSE: // the close button should always be enabled
aReturn.bEnabled = !m_bEnableBrowser; return aReturn;
// "toggle explorer" is always enabled (if we have an explorer) case ID_BROWSER_EXPLORER:
aReturn.bEnabled = m_bEnableBrowser;
aReturn.bChecked = haveExplorer(); return aReturn;
case ID_BROWSER_REMOVEFILTER: return SbaXDataBrowserController::GetState( nId );
case ID_BROWSER_COPY: if ( !m_pTreeView->HasChildPathFocus() ) // handled below break;
[[fallthrough]]; case ID_TREE_CLOSE_CONN: case ID_TREE_EDIT_DATABASE:
{
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator()); if (!rTreeView.get_cursor(xCurrentEntry.get())) return aReturn;
// 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();
case ID_TREE_EDIT_DATABASE:
{
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); if (rTreeView.get_cursor(xIter.get()))
implAdministrate(*xIter); break;
} case ID_TREE_CLOSE_CONN:
{
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator()); if (rTreeView.get_cursor(xIter.get()))
{
xIter = m_pTreeView->GetRootLevelParent(xIter.get());
closeConnection(*xIter);
} break;
} case ID_TREE_ADMINISTRATE:
svx::administrateDatabaseRegistration( getFrameWeld() ); break;
case ID_BROWSER_REFRESH:
{ if ( !SaveModified( ) ) // nothing to do break;
bool bFullReinit = false; // check if the query signature (if the form is based on a query) has changed if ( !m_sQueryCommand.isEmpty() )
{
OUString sNewQueryCommand; bool bNewQueryEP;
bool bIsQuery =
implGetQuerySignature( sNewQueryCommand, bNewQueryEP );
OSL_ENSURE( bIsQuery, "SbaTableQueryBrowser::Execute: was a query before, but is not anymore?" );
bFullReinit = ( sNewQueryCommand != m_sQueryCommand ) || ( m_bQueryEscapeProcessing != bNewQueryEP );
} if ( !bFullReinit )
{ // let the base class do a simple reload
SbaXDataBrowserController::Execute(nId,aArgs); break;
}
[[fallthrough]];
}
case ID_BROWSER_REFRESH_REBUILD:
{ if ( !SaveModified() ) // nothing to do break;
// reselect the entry if ( xSelected )
{
implSelect(xSelected.get());
} else
{
Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
implSelect(svx::ODataAccessDescriptor(xProp));
}
} break;
case ID_BROWSER_EXPLORER:
toggleExplorer(); break;
case ID_BROWSER_DOCUMENT_DATASOURCE:
implSelect(m_aDocumentDataSource); break;
case ID_BROWSER_INSERTCOLUMNS: case ID_BROWSER_INSERTCONTENT: case ID_BROWSER_FORMLETTER: if (getBrowserView() && isValidCursor())
{ // the URL the slot id is assigned to
OSL_ENSURE( m_aExternalFeatures.find( nId ) != m_aExternalFeatures.end(), "SbaTableQueryBrowser::Execute( ID_BROWSER_?): how could this ever be enabled?" );
URL aParentUrl = m_aExternalFeatures[ nId ].aURL;
// let the dispatcher execute the slot
Reference< XDispatch > xDispatch( m_aExternalFeatures[ nId ].xDispatcher ); if (xDispatch.is())
{ // set the properties for the dispatch
// first fill the selection
SbaGridControl* pGrid = getBrowserView()->getVclControl();
MultiSelection* pSelection = const_cast<MultiSelection*>(pGrid->GetSelection());
Sequence< Any > aSelection; if ( !pGrid->IsAllSelected() )
{ // transfer the selected rows only if not all rows are selected // (all rows means the whole table) // #i3832# if (pSelection != nullptr)
{
aSelection.realloc(pSelection->GetSelectCount());
tools::Long nIdx = pSelection->FirstSelected();
Any* pSelectionNos = aSelection.getArray(); while (nIdx != SFX_ENDOFSELECTION)
{
*pSelectionNos++ <<= static_cast<sal_Int32>(nIdx + 1);
nIdx = pSelection->NextSelected();
}
}
}
Reference< XResultSet > xCursorClone; try
{
Reference< XResultSetAccess > xResultSetAccess(getRowSet(),UNO_QUERY); if (xResultSetAccess.is())
xCursorClone = xResultSetAccess->createResultSet();
} catch(DisposedException&)
{
SAL_WARN("dbaccess.ui", "Object already disposed!");
} catch(const Exception&)
{
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Execute(ID_BROWSER_?): could not clone the cursor!");
}
aDescriptor.setDataSource(sDataSourceName);
aDescriptor[DataAccessDescriptorProperty::Command] = xProp->getPropertyValue(PROPERTY_COMMAND);
aDescriptor[DataAccessDescriptorProperty::CommandType] = xProp->getPropertyValue(PROPERTY_COMMAND_TYPE);
aDescriptor[DataAccessDescriptorProperty::Connection] = xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION);
aDescriptor[DataAccessDescriptorProperty::Cursor] <<= xCursorClone; if ( aSelection.hasElements() )
{
aDescriptor[DataAccessDescriptorProperty::Selection] <<= aSelection;
aDescriptor[DataAccessDescriptorProperty::BookmarkSelection] <<= false; // these are selection indices // before we change this, all clients have to be adjusted // so that they recognize the new BookmarkSelection property!
}
void SbaTableQueryBrowser::implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection )
{
OUString a, b, c, d, e;
implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection );
}
void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, OUString& _rDbImage,
OUString& _rQueryName, OUString& _rQueryImage, OUString& _rTableName, OUString& _rTableImage, const SharedConnection& _rxConnection)
{
SolarMutexGuard aGuard; // initialize the names/images if necessary if (_rQueryName.isEmpty())
_rQueryName = DBA_RES(RID_STR_QUERIES_CONTAINER); if (_rTableName.isEmpty())
_rTableName = DBA_RES(RID_STR_TABLES_CONTAINER);
if (_rQueryImage.isEmpty())
_rQueryImage = ImageProvider::getFolderImageId(DatabaseObject::QUERY); if (_rTableImage.isEmpty())
_rTableImage = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
if (_rDbImage.isEmpty())
_rDbImage = ImageProvider::getDatabaseImage();
// add the entry for the data source // special handling for data sources denoted by URLs - we do not want to display this ugly URL, do we? // #i33699#
OUString sDSDisplayName, sDataSourceId;
getDataSourceDisplayName_isURL( _rDbName, sDSDisplayName, sDataSourceId );
// the child for the queries container
{
DBTreeListUserData* pQueriesData = new DBTreeListUserData;
pQueriesData->eType = etQueryContainer;
sId = weld::toId(pQueriesData);
// the child for the tables container
{
DBTreeListUserData* pTablesData = new DBTreeListUserData;
pTablesData->eType = etTableContainer;
sId = weld::toId(pTablesData);
// fill the model with the names of the registered datasources const Sequence<OUString> aDatasourceNames = m_xDatabaseContext->getElementNames(); for (const OUString& rDatasource : aDatasourceNames)
implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() );
}
}
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent)); if (pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables
pData->xContainer = _xNameAccess;
try
{ const Sequence<OUString> aNames = _xNameAccess->getElementNames(); for (const OUString& rName : aNames)
{ if( !m_pTreeView->GetEntryPosByName(rName, &rParent))
{
DBTreeListUserData* pEntryData = new DBTreeListUserData;
pEntryData->eType = eEntryType; if ( eEntryType == etQuery )
{
Reference<XNameAccess> xChild(_xNameAccess->getByName(rName),UNO_QUERY); if ( xChild.is() )
pEntryData->eType = etQueryContainer;
}
implAppendEntry(&rParent, rName, pEntryData);
}
}
} catch(const Exception&)
{
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
}
IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, const weld::TreeIter&, rParent, bool)
{
weld::TreeView& rTreeView = m_pTreeView->GetWidget(); if (rTreeView.iter_has_child(rParent))
{ // nothing to do... returntrue;
}
std::unique_ptr<weld::TreeIter> xFirstParent = m_pTreeView->GetRootLevelParent(&rParent);
OSL_ENSURE(xFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!");
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!");
if (etTableContainer == pData->eType)
{
weld::WaitObject aWaitCursor(getFrameWeld());
// it could be that we already have a connection
SharedConnection xConnection; if (ensureConnection(xFirstParent.get(), xConnection) && xConnection.is())
{
SQLExceptionInfo aInfo; try
{
Reference< XWarningsSupplier > xWarnings(xConnection, UNO_QUERY); if (xWarnings.is())
xWarnings->clearWarnings();
// first insert the views because the tables can also include // views but that time the bitmap is the wrong one // the nameaccess will be overwritten in populateTree
Reference<XViewsSupplier> xViewSup(xConnection,UNO_QUERY); if(xViewSup.is())
populateTree( xViewSup->getViews(), rParent, etTableOrView );
Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY); if(xTabSup.is())
{
populateTree( xTabSup->getTables(), rParent, etTableOrView );
Reference<XContainer> xCont(xTabSup->getTables(),UNO_QUERY); if(xCont.is()) // add as listener to know when elements are inserted or removed
xCont->addContainerListener(this);
}
if (xWarnings.is())
{ #if 0
SQLExceptionInfo aWarnings(xWarnings->getWarnings()); // Obviously this if test is always false. So to avoid a Clang warning // "use of logical '&&' with constant operand" I put this in #if // 0. Yeah, I know it is fairly likely nobody will ever read this // comment and make a decision what to do here, so I could as well // have just binned this... if (aWarnings.isValid() && sal_False)
{
SQLContext aContext;
aContext.Message = DBA_RES(STR_OPENTABLES_WARNINGS);
aContext.Details = DBA_RES(STR_OPENTABLES_WARNINGS_DETAILS);
aContext.NextException = aWarnings.get();
aWarnings = aContext;
showError(aWarnings);
} #endif // TODO: we need a better concept for these warnings: // something like "don't show any warnings for this datasource, again" would be nice // But this requires an extension of the InteractionHandler and an additional property on the data source
}
} catch(const SQLContext& e) { aInfo = e; } catch(const SQLWarning& e) { aInfo = e; } catch(const SQLException& e) { aInfo = e; } catch(const WrappedTargetException& e)
{
SQLException aSql; if(e.TargetException >>= aSql)
aInfo = aSql; else
SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: something strange happened!");
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("dbaccess");
} if (aInfo.isValid())
showError(aInfo);
} else returnfalse; // 0 indicates that an error occurred
} else
{ // we have to expand the queries or bookmarks if (ensureEntryObject(rParent))
{
DBTreeListUserData* pParentData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rParent));
Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
populateTree(xCollection, rParent, etQuery);
}
} returntrue;
}
// the user data of the entry
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
DBTreeListUserData* pEntryData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(rEntry));
assert(pEntryData && "ensureEntryObject: user data should already be set!");
bSuccess = pEntryData->xContainer.is();
} else
{ try
{
Reference< XQueryDefinitionsSupplier > xQuerySup;
m_xDatabaseContext->getByName(getDataSourceAccessor(*xDataSourceEntry)) >>= xQuerySup; if (xQuerySup.is())
{
Reference< XNameAccess > xQueryDefs = xQuerySup->getQueryDefinitions();
Reference< XContainer > xCont(xQueryDefs, UNO_QUERY); if (xCont.is()) // add as listener to get notified if elements are inserted or removed
xCont->addContainerListener(this);
// set this _before_ setting the connection, else the rowset would rebuild it ...
xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, Any(nCommandType));
xProp->setPropertyValue(PROPERTY_COMMAND, Any(_rCommand));
xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::Any(_bEscapeProcessing)); if ( m_bPreview )
{
xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, Any(FetchDirection::FORWARD));
}
// the formatter depends on the data source we're working on, so rebuild it here ...
initFormatter();
// switch the grid to design mode while loading
getBrowserView()->getGridControl()->setDesignMode(true);
InitializeForm( xProp );
bool bSuccess = true;
{
{
Reference< XNameContainer > xColContainer(getFormComponent(), UNO_QUERY); // first we have to clear the grid
clearGridColumns(xColContainer);
}
FormErrorHelper aHelper(this); // load the form
bSuccess = reloadForm(xLoadable);
// initialize the model
InitializeGridModel(getFormComponent());
Any aVal = xProp->getPropertyValue(PROPERTY_ISNEW); if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
{ // then set the default values and the parameters given from the parent
Reference< XReset> xReset(xProp, UNO_QUERY);
xReset->reset();
}
if ( bSuccess )
{
rTreeView.scroll_to_row(*xCommand);
rTreeView.set_cursor(*xCommand);
}
} elseif (!xCommandType)
{ if (m_xCurrentlyDisplayed)
{ // tell the old entry (if any) it has been deselected
selectPath(m_xCurrentlyDisplayed.get(), false);
m_xCurrentlyDisplayed.reset();
}
// we have a command and need to display this in the rowset return implLoadAnything(_rDataSourceName, _rCommand, nCommandType, _bEscapeProcessing, _rxConnection);
} returnfalse;
}
// get the entry for the tables or queries
std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(pEntry);
rTreeView.iter_parent(*xContainer);
DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xContainer));
// get the entry for the datasource
std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer);
DBTreeListUserData* pConData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xConnection));
// reinitialize the rowset // but first check if it is necessary // get all old properties
Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
OUString aOldName;
xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName;
sal_Int32 nOldType = 0;
xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType;
Reference<XConnection> xOldConnection(xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
// the name of the table or query const OUString sSimpleName = rTreeView.get_text(*pEntry);
OUStringBuffer sNameBuffer(sSimpleName); if ( etQueryContainer == pContainerData->eType )
{
std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(xContainer.get());
std::unique_ptr<weld::TreeIter> xNextTemp = rTreeView.make_iterator(xTemp.get()); if (rTreeView.iter_parent(*xNextTemp))
{ while (rTreeView.iter_compare(*xNextTemp, *xConnection) != 0)
{
sNameBuffer.insert(0, rTreeView.get_text(*xTemp) + "/");
rTreeView.copy_iterator(*xNextTemp, *xTemp); if (!rTreeView.iter_parent(*xNextTemp)) break;
}
}
}
OUString aName = sNameBuffer.makeStringAndClear();
// tell the old entry it has been deselected
selectPath(m_xCurrentlyDisplayed.get(), false);
m_xCurrentlyDisplayed.reset();
// not really loaded
m_xCurrentlyDisplayed = rTreeView.make_iterator(pEntry); // tell the new entry it has been selected
selectPath(m_xCurrentlyDisplayed.get());
// get the name of the data source currently selected
(void)ensureConnection(m_xCurrentlyDisplayed.get(), pConData->xConnection);
if ( !pConData->xConnection.is() )
{
unloadAndCleanup( false ); returnfalse;
}
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();
Reference< XNameAccess > xNames(rEvent.Source, UNO_QUERY); // first search for a definition container where we can insert this element
std::unique_ptr<weld::TreeIter> xEntry = getEntryFromContainer(xNames); if (xEntry) // found one
{
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
rTreeView.make_unsorted();
// insert the new entry into the tree
DBTreeListUserData* pContainerData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xEntry));
assert(pContainerData && "elementInserted: There must be user data for this type!");
DBTreeListUserData* pNewData = new DBTreeListUserData; bool bIsTable = etTableContainer == pContainerData->eType; if ( bIsTable )
{
rEvent.Element >>= pNewData->xObjectProperties;// remember the new element
pNewData->eType = etTableOrView;
} else
{ if (rTreeView.iter_n_children(*xEntry) < xNames->getElementNames().getLength() - 1)
{ // the item inserts its children on demand, but it has not been expanded yet. So ensure here and // now that it has all items
populateTree(xNames, *xEntry, etQuery);
}
pNewData->eType = etQuery;
}
implAppendEntry(xEntry.get(), ::comphelper::getString(rEvent.Accessor), pNewData);
Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY); // get the top-level representing the removed data source // and search for the queries and tables
std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames); if (xContainer)
{ // a query or table has been removed
OUString aName = ::comphelper::getString(_rEvent.Accessor);
weld::TreeView& rTreeView = m_pTreeView->GetWidget(); if (isCurrentlyDisplayedChanged(aName, *xContainer))
{ // the element displayed currently has been replaced
// we need to remember the old value
std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
// unload
unloadAndCleanup( false ); // don't dispose the connection
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp));
rTreeView.set_id(*xTemp, OUString()); delete pData; // the data could be null because we have a table which isn't correct
rTreeView.remove(*xTemp);
} else
{ // remove the entry from the model
std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get())); if (rTreeView.get_iter_first(*xChild))
{ do
{ if (rTreeView.get_text(*xChild) == aName)
{
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild));
rTreeView.set_id(*xChild, OUString()); delete pData;
rTreeView.remove(*xChild); break;
}
} while (rTreeView.iter_next_sibling(*xChild));
}
}
// maybe the object which is part of the document data source has been removed
checkDocumentDataSource();
} else
SbaXDataBrowserController::elementRemoved(_rEvent);
}
Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames); if (xContainer)
{ // a table or query has been replaced
OUString aName = ::comphelper::getString(_rEvent.Accessor);
weld::TreeView& rTreeView = m_pTreeView->GetWidget(); if (isCurrentlyDisplayedChanged(aName, *xContainer))
{ // the element displayed currently has been replaced
// we need to remember the old value
std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
unloadAndCleanup( false ); // don't dispose the connection
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xTemp)); if (pData)
{ if ( etTableOrView == pData->eType )
{ // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
_rEvent.Element >>= pData->xObjectProperties; // remember the new element
} else
{
rTreeView.set_id(*xTemp, OUString()); delete pData;
}
}
} else
{ // find the entry for this name
std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get())); if (rTreeView.get_iter_first(*xChild))
{ do
{ if (rTreeView.get_text(*xChild) == aName)
{
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xChild)); if (pData)
{ if ( etTableOrView == pData->eType )
{ // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
_rEvent.Element >>= pData->xObjectProperties; // remember the new element
} else
{
rTreeView.set_id(*xChild, OUString()); delete pData;
}
} break;
}
} while (rTreeView.iter_next_sibling(*xChild));
}
}
// maybe the object which is part of the document data source has been removed
checkDocumentDataSource();
} elseif (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);
}
// if one of the entries of the given DS is displayed currently, unload the form if (m_xCurrentlyDisplayed)
{
std::unique_ptr<weld::TreeIter> xRoot = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get()); if (rTreeView.iter_compare(*xRoot, rDSEntry) == 0)
unloadAndCleanup(_bDisposeConnection);
}
// collapse the query/table container
std::unique_ptr<weld::TreeIter> xContainers(rTreeView.make_iterator(&rDSEntry)); if (rTreeView.iter_children(*xContainers))
{ do
{
std::unique_ptr<weld::TreeIter> xElements(rTreeView.make_iterator(xContainers.get())); if (rTreeView.iter_children(*xElements))
{
rTreeView.collapse_row(*xContainers); // and delete their children (they are connection-relative) bool bElements = true; while (bElements)
{
std::unique_ptr<weld::TreeIter> xRemove(rTreeView.make_iterator(xElements.get()));
bElements = rTreeView.iter_next_sibling(*xElements);
DBTreeListUserData* pData = weld::fromId<DBTreeListUserData*>(rTreeView.get_id(*xRemove));
rTreeView.set_id(*xRemove, OUString()); delete pData;
rTreeView.remove(*xRemove);
}
}
} while (rTreeView.iter_next_sibling(*xContainers));
}
// collapse the entry itself
rTreeView.collapse_row(rDSEntry);
// dispose/reset the connection if ( _bDisposeConnection )
disposeConnection(&rDSEntry);
}
void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection )
{ if (!m_xCurrentlyDisplayed) // nothing to do return;
void SbaTableQueryBrowser::impl_initialize(const ::comphelper::NamedValueCollection& rArguments)
{
SolarMutexGuard aGuard; // doin' a lot of VCL stuff here -> lock the SolarMutex
// first initialize the parent
SbaXDataBrowserController::impl_initialize(rArguments);
// disable the browser if either of ShowTreeViewButton (compatibility name) or EnableBrowser // is present and set to FALSE bool bDisableBrowser = !rArguments.getOrDefault( u"ShowTreeViewButton"_ustr, true ) // compatibility name
|| !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true );
OSL_ENSURE( !rArguments.has( u"ShowTreeViewButton"_ustr ), "SbaTableQueryBrowser::impl_initialize: ShowTreeViewButton is superseded by EnableBrowser!" );
m_bEnableBrowser = !bDisableBrowser;
// hide the tree view it is disabled in general, or if the settings tell to hide it initially bool bHideTreeView = ( !m_bEnableBrowser )
|| !rArguments.getOrDefault( u"ShowTreeView"_ustr, true ) // compatibility name
|| !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true );
OSL_ENSURE( !rArguments.has( u"ShowTreeView"_ustr ), "SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" );
if ( bHideTreeView )
hideExplorer(); else
showExplorer();
// 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>();
// if we have a connection at this point, it was either passed from outside, our // determined from an outer DB document. In both cases, do not dispose it later on.
SharedConnection xConnection( xForeignConnection, SharedConnection::NoTakeOwnership );
// should we display all registered databases in the left hand side tree? // or only *one* special? bool bLimitedTreeEntries = false; // if we're part of a frame which is a secondary frame of a database document, then only // display the database for this document, not all registered ones
bLimitedTreeEntries |= bSubFrameOfEmbeddedDocument; // if the tree view is not to be displayed at all, then only display the data source // which was given as initial selection
bLimitedTreeEntries |= !m_bEnableBrowser;
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'!??" );
}
}
}
}
std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator()); if (rTreeView.get_iter_first(*xFirst))
rTreeView.expand_row(*xFirst);
} else
initializeTreeModel();
rTreeView.make_sorted();
if ( m_bEnableBrowser )
{
m_aDocScriptSupport = ::std::optional< bool >( false );
} else
{ // we are not used as "browser", but as mere view for a single table/query/command. In particular, // there is a specific database document which we belong to.
Reference< XOfficeDatabaseDocument > xDocument( getDataSourceOrModel(
lcl_getDataSource( m_xDatabaseContext, sInitialDataSourceName, xConnection ) ), UNO_QUERY );
m_aDocScriptSupport = ::std::optional< bool >( Reference< XEmbeddedScripts >( xDocument, UNO_QUERY ).is() );
}
if ( !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);
// we want the table entry and the end so we have to do a check if (isContainer(rRHS))
{ // don't use getEntryType (directly or indirectly) for the LHS: // LHS is currently being inserted, so it is not "completely valid" at the moment
const EntryType eRight = getEntryType(rRHS); if (etTableContainer == eRight) // every other container should be placed _before_ the bookmark container return -1;
if (m_xCollator.is())
{ try
{
nCompareResult = m_xCollator->compareString(sLeftText, sRightText);
} catch(const Exception&)
{
}
} else // default behaviour if we do not have a collator -> do the simple string compare
nCompareResult = sLeftText.compareTo(sRightText);
return nCompareResult;
}
void SbaTableQueryBrowser::implAdministrate(const weld::TreeIter& rApplyTo)
{ try
{ // get the desktop object
Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() );
// the initial selection
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
std::unique_ptr<weld::TreeIter> xTopLevelSelected(rTreeView.make_iterator(&rApplyTo));
while (rTreeView.get_iter_depth(*xTopLevelSelected))
rTreeView.iter_parent(*xTopLevelSelected);
switch ( aSelectedObject.Type )
{ case DatabaseObject::QUERY: case DatabaseObject::TABLE:
aSelectedObject.Name = rTreeView.get_text(*xSelected); break;
case DatabaseObjectContainer::DATA_SOURCE: case DatabaseObjectContainer::QUERIES: case DatabaseObjectContainer::TABLES:
aSelectedObject.Name = getDataSourceAccessor(*xSelected); break;
void SbaTableQueryBrowser::impl_cleanupDataSourceEntry(std::u16string_view rDataSourceName)
{ // get the top-level representing the removed data source
weld::TreeView& rTreeView = m_pTreeView->GetWidget();
std::unique_ptr<weld::TreeIter> xDataSourceEntry(rTreeView.make_iterator()); bool bDataSourceEntry = rTreeView.get_iter_first(*xDataSourceEntry); while (bDataSourceEntry)
{ if (rTreeView.get_text(*xDataSourceEntry) == rDataSourceName) break;
bDataSourceEntry = rTreeView.iter_next_sibling(*xDataSourceEntry);
}
OSL_ENSURE( bDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" ); if (!bDataSourceEntry) return;
if (isSelected(*xDataSourceEntry))
{ // a table or query belonging to the deleted data source is currently being displayed.
unloadAndCleanup();
}
std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xDataSourceEntry.get())); if (rTreeView.iter_children(*xChild))
{ do
{ // delete any user data of the child entries of the to-be-removed entry const DBTreeListUserData* pData = weld::fromId<const DBTreeListUserData*>(rTreeView.get_id(*xChild));
rTreeView.set_id(*xChild, OUString()); delete pData;
} while (rTreeView.iter_next_sibling(*xChild));
}
// 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() );
}
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.