nss: upgrade to release 3.73
[LibreOffice.git] / dbaccess / source / ui / browser / unodatbr.cxx
blob32588dd1e8cc4e4d8e512f33cb05489496d3add8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <browserids.hxx>
21 #include <core_resource.hxx>
22 #include <helpids.h>
23 #include <dbtreelistbox.hxx>
24 #include "dbtreemodel.hxx"
25 #include <strings.hrc>
26 #include <imageprovider.hxx>
27 #include <sbagrid.hxx>
28 #include <strings.hxx>
29 #include <UITools.hxx>
30 #include <unodatbr.hxx>
32 #include <com/sun/star/awt/MouseWheelBehavior.hpp>
33 #include <com/sun/star/awt/TextAlign.hpp>
34 #include <com/sun/star/awt/VisualEffect.hpp>
35 #include <com/sun/star/beans/NamedValue.hpp>
36 #include <com/sun/star/beans/PropertyValue.hpp>
37 #include <com/sun/star/beans/XMultiPropertySet.hpp>
38 #include <com/sun/star/container/XNameContainer.hpp>
39 #include <com/sun/star/form/XGridColumnFactory.hpp>
40 #include <com/sun/star/form/XLoadable.hpp>
41 #include <com/sun/star/form/XReset.hpp>
42 #include <com/sun/star/frame/Desktop.hpp>
43 #include <com/sun/star/frame/FrameSearchFlag.hpp>
44 #include <com/sun/star/frame/XLayoutManager.hpp>
45 #include <com/sun/star/lang/DisposedException.hpp>
46 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
47 #include <com/sun/star/i18n/Collator.hpp>
48 #include <com/sun/star/sdb/CommandType.hpp>
49 #include <com/sun/star/sdb/SQLContext.hpp>
50 #include <com/sun/star/sdb/XDatabaseContext.hpp>
51 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
52 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
53 #include <com/sun/star/sdb/XParametersSupplier.hpp>
54 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
55 #include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
56 #include <com/sun/star/sdb/XResultSetAccess.hpp>
57 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
58 #include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
59 #include <com/sun/star/sdbc/ColumnValue.hpp>
60 #include <com/sun/star/sdbc/DataType.hpp>
61 #include <com/sun/star/sdbc/FetchDirection.hpp>
62 #include <com/sun/star/sdbc/SQLWarning.hpp>
63 #include <com/sun/star/sdbc/XDataSource.hpp>
64 #include <com/sun/star/sdbc/XWarningsSupplier.hpp>
65 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
66 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
67 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
68 #include <com/sun/star/task/InteractionHandler.hpp>
69 #include <com/sun/star/util/XFlushable.hpp>
70 #include <com/sun/star/util/XNumberFormatter.hpp>
71 #include <com/sun/star/util/XURLTransformer.hpp>
72 #include <com/sun/star/document/MacroExecMode.hpp>
73 #include <com/sun/star/ui/XContextMenuInterceptor.hpp>
75 #include <comphelper/extract.hxx>
76 #include <comphelper/sequence.hxx>
77 #include <comphelper/types.hxx>
78 #include <connectivity/dbexception.hxx>
79 #include <cppuhelper/exc_hlp.hxx>
80 #include <i18nlangtag/languagetag.hxx>
81 #include <svl/filenotation.hxx>
82 #include <svx/dataaccessdescriptor.hxx>
83 #include <svx/databaseregistrationui.hxx>
84 #include <toolkit/helper/vclunohelper.hxx>
85 #include <tools/diagnose_ex.h>
86 #include <osl/diagnose.h>
87 #include <sal/log.hxx>
88 #include <tools/multisel.hxx>
89 #include <tools/urlobj.hxx>
90 #include <unotools/confignode.hxx>
91 #include <vcl/split.hxx>
92 #include <vcl/svapp.hxx>
93 #include <vcl/toolbox.hxx>
94 #include <vcl/settings.hxx>
95 #include <vcl/weld.hxx>
97 #include <memory>
99 using namespace ::com::sun::star::uno;
100 using namespace ::com::sun::star::awt;
101 using namespace ::com::sun::star::sdb;
102 using namespace ::com::sun::star::sdb::application;
103 using namespace ::com::sun::star::sdbc;
104 using namespace ::com::sun::star::sdbcx;
105 using namespace ::com::sun::star::beans;
106 using namespace ::com::sun::star::util;
107 using namespace ::com::sun::star::frame;
108 using namespace ::com::sun::star::container;
109 using namespace ::com::sun::star::lang;
110 using namespace ::com::sun::star::ui::dialogs;
111 using namespace ::com::sun::star::task;
112 using namespace ::com::sun::star::form;
113 using namespace ::com::sun::star::io;
114 using namespace ::com::sun::star::i18n;
115 using namespace ::com::sun::star::view;
116 using namespace ::com::sun::star::datatransfer;
117 using namespace ::com::sun::star::document;
118 using namespace ::com::sun::star::ui;
119 using namespace ::dbtools;
120 using namespace ::comphelper;
121 using namespace ::svx;
123 // SbaTableQueryBrowser
124 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
125 org_openoffice_comp_dbu_ODatasourceBrowser_get_implementation(
126 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
128 SolarMutexGuard aGuard;
129 return cppu::acquire(new ::dbaui::SbaTableQueryBrowser(context));
132 namespace dbaui
135 namespace DatabaseObject = css::sdb::application::DatabaseObject;
136 namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer;
138 static void SafeAddPropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
140 Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo();
141 if (xInfo->hasPropertyByName(rPropName))
142 xSet->addPropertyChangeListener(rPropName, pListener);
145 static void SafeRemovePropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener)
147 Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo();
148 if (xInfo->hasPropertyByName(rPropName))
149 xSet->removePropertyChangeListener(rPropName, pListener);
152 OUString SAL_CALL SbaTableQueryBrowser::getImplementationName()
154 return "org.openoffice.comp.dbu.ODatasourceBrowser";
157 css::uno::Sequence<OUString> SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames()
159 return { "com.sun.star.sdb.DataSourceBrowser" };
162 SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM)
163 :SbaXDataBrowserController(_rM)
164 ,m_aSelectionListeners( getMutex() )
165 ,m_aContextMenuInterceptors( getMutex() )
166 ,m_aTableCopyHelper(this)
167 ,m_pTreeView(nullptr)
168 ,m_pSplitter(nullptr)
169 ,m_nAsyncDrop(nullptr)
170 ,m_bQueryEscapeProcessing( false )
171 ,m_bShowMenu(false)
172 ,m_bInSuspend(false)
173 ,m_bEnableBrowser(true)
177 SbaTableQueryBrowser::~SbaTableQueryBrowser()
179 if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
181 SAL_WARN("dbaccess.ui", "Please check who doesn't dispose this component!");
182 // increment ref count to prevent double call of Dtor
183 osl_atomic_increment( &m_refCount );
184 dispose();
186 SolarMutexGuard g;
187 m_pTreeView.reset();
188 m_pSplitter.reset();
191 Any SAL_CALL SbaTableQueryBrowser::queryInterface(const Type& _rType)
193 if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) )
195 OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" );
196 if ( !!m_aDocScriptSupport && *m_aDocScriptSupport )
197 return makeAny( Reference< XScriptInvocationContext >( this ) );
198 return Any();
201 Any aReturn = SbaXDataBrowserController::queryInterface(_rType);
202 if (!aReturn.hasValue())
203 aReturn = SbaTableQueryBrowser_Base::queryInterface(_rType);
204 return aReturn;
207 Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes( )
209 Sequence< Type > aTypes( ::comphelper::concatSequences(
210 SbaXDataBrowserController::getTypes(),
211 SbaTableQueryBrowser_Base::getTypes()
212 ) );
214 OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" );
215 if ( !m_aDocScriptSupport || !*m_aDocScriptSupport )
217 auto newEnd = std::remove_if( aTypes.begin(), aTypes.end(),
218 [](const Type& type)
219 { return type == cppu::UnoType<XScriptInvocationContext>::get(); } );
220 aTypes.realloc( std::distance(aTypes.begin(), newEnd) );
222 return aTypes;
225 Sequence< sal_Int8 > SAL_CALL SbaTableQueryBrowser::getImplementationId( )
227 return css::uno::Sequence<sal_Int8>();
230 void SAL_CALL SbaTableQueryBrowser::disposing()
232 SolarMutexGuard aGuard;
233 // doin' a lot of VCL stuff here -> lock the SolarMutex
235 // kiss our listeners goodbye
236 css::lang::EventObject aEvt(*this);
237 m_aSelectionListeners.disposeAndClear(aEvt);
238 m_aContextMenuInterceptors.disposeAndClear(aEvt);
240 if (getBrowserView())
242 // Need to do some cleanup of the data pointed to the tree view entries before we remove the treeview
243 clearTreeModel();
244 m_pTreeView = nullptr;
245 getBrowserView()->setTreeView(nullptr);
248 // remove ourself as status listener
249 implRemoveStatusListeners();
251 // remove the container listener from the database context
254 Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
255 xDatabaseRegistrations->removeDatabaseRegistrationsListener( this );
257 catch( const Exception& )
259 DBG_UNHANDLED_EXCEPTION("dbaccess");
262 // check out from all the objects we are listening
263 // the frame
264 if (m_xCurrentFrameParent.is())
265 m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
266 SbaXDataBrowserController::disposing();
269 bool SbaTableQueryBrowser::Construct(vcl::Window* pParent)
271 if ( !SbaXDataBrowserController::Construct( pParent ) )
272 return false;
276 Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW );
277 xDatabaseRegistrations->addDatabaseRegistrationsListener( this );
279 // the collator for the string compares
280 m_xCollator = Collator::create( getORB() );
281 m_xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
283 catch(const Exception&)
285 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Construct: could not create (or start listening at) the database context!");
287 // some help ids
288 if (getBrowserView() && getBrowserView()->getVclControl())
291 // create controls and set sizes
292 const tools::Long nFrameWidth = getBrowserView()->LogicToPixel(::Size(3, 0), MapMode(MapUnit::MapAppFont)).Width();
294 m_pSplitter = VclPtr<Splitter>::Create(getBrowserView(),WB_HSCROLL);
295 m_pSplitter->SetPosSizePixel( ::Point(0,0), ::Size(nFrameWidth,0) );
296 m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) );
298 m_pTreeView = VclPtr<InterimDBTreeListBox>::Create(getBrowserView());
300 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
301 rTreeView.connect_expanding(LINK(this, SbaTableQueryBrowser, OnExpandEntry));
303 m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry));
305 m_pTreeView->setContextMenuProvider( this );
306 m_pTreeView->setControlActionListener( this );
307 m_pTreeView->SetHelpId(HID_CTL_TREEVIEW);
309 // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide
310 m_pSplitter->SetSplitPosPixel(getBrowserView()->LogicToPixel(::Size(80, 0), MapMode(MapUnit::MapAppFont)).Width());
312 getBrowserView()->setSplitter(m_pSplitter);
313 getBrowserView()->setTreeView(m_pTreeView);
315 // fill view with data
316 rTreeView.set_sort_order(true);
317 rTreeView.set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){
318 return OnTreeEntryCompare(rLeft, rRight);
320 rTreeView.make_sorted();
321 m_pTreeView->SetSelChangeHdl(LINK(this, SbaTableQueryBrowser, OnSelectionChange));
322 m_pTreeView->show_container();
324 // TODO
325 getBrowserView()->getVclControl()->SetHelpId(HID_CTL_TABBROWSER);
326 if (getBrowserView()->getVclControl()->GetHeaderBar())
327 getBrowserView()->getVclControl()->GetHeaderBar()->SetHelpId(HID_DATABROWSE_HEADER);
328 InvalidateFeature(ID_BROWSER_EXPLORER);
331 return true;
334 namespace
336 struct SelectValueByName
338 const Any& operator()( OUString const& i_name ) const
340 return m_rCollection.get( i_name );
343 explicit SelectValueByName( ::comphelper::NamedValueCollection const& i_collection )
344 :m_rCollection( i_collection )
348 ::comphelper::NamedValueCollection const& m_rCollection;
352 void SbaTableQueryBrowser::impl_sanitizeRowSetClauses_nothrow()
356 Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW );
357 bool bEscapeProcessing = false;
358 OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
359 if ( !bEscapeProcessing )
360 // don't touch or interpret anything if escape processing is disabled
361 return;
363 Reference< XSingleSelectQueryComposer > xComposer( createParser_nothrow() );
364 if ( !xComposer.is() )
365 // can't do anything. Already reported via assertion in createParser_nothrow.
366 return;
368 // the tables participating in the statement
369 const Reference< XTablesSupplier > xSuppTables( xComposer, UNO_QUERY_THROW );
370 const Reference< XNameAccess > xTableNames( xSuppTables->getTables(), UNO_SET_THROW );
372 // the columns participating in the statement
373 const Reference< XColumnsSupplier > xSuppColumns( xComposer, UNO_QUERY_THROW );
374 const Reference< XNameAccess > xColumnNames( xSuppColumns->getColumns(), UNO_SET_THROW );
376 // check if the order columns apply to tables which really exist in the statement
377 const Reference< XIndexAccess > xOrderColumns( xComposer->getOrderColumns(), UNO_SET_THROW );
378 const sal_Int32 nOrderColumns( xOrderColumns->getCount() );
379 bool invalidColumn = nOrderColumns == 0;
380 for ( sal_Int32 c=0; ( c < nOrderColumns ) && !invalidColumn; ++c )
382 const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW );
383 OUString sTableName;
384 OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName );
385 OUString sColumnName;
386 OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName );
388 if ( sTableName.isEmpty() )
390 if ( !xColumnNames->hasByName( sColumnName ) )
392 invalidColumn = true;
393 break;
396 else
398 if ( !xTableNames->hasByName( sTableName ) )
400 invalidColumn = true;
401 break;
404 const Reference< XColumnsSupplier > xSuppTableColumns( xTableNames->getByName( sTableName ), UNO_QUERY_THROW );
405 const Reference< XNameAccess > xTableColumnNames( xSuppTableColumns->getColumns(), UNO_SET_THROW );
406 if ( !xTableColumnNames->hasByName( sColumnName ) )
408 invalidColumn = true;
409 break;
414 if ( invalidColumn )
416 // reset the complete order statement at both the row set and the parser
417 xRowSetProps->setPropertyValue( PROPERTY_ORDER, makeAny( OUString() ) );
418 xComposer->setOrder( "" );
421 // check if the columns participating in the filter refer to existing tables
422 // TODO: there's no API at all for this. The method which comes nearest to what we need is
423 // "getStructuredFilter", but it returns pure column names only. That is, for a statement like
424 // "SELECT * FROM <table> WHERE <other_table>.<column> = <value>", it will return "<column>". But
425 // there's no API at all to retrieve the information about "<other_table>" - which is what would
426 // be needed here.
427 // That'd be a chance to replace getStructuredFilter with something more reasonable.
428 // So, what really would be handy, is some
429 // XNormalizedFilter getNormalizedFilter();
430 // with
431 // interface XDisjunctiveFilterExpression
432 // {
433 // XConjunctiveFilterTerm getTerm( int index );
434 // }
435 // interface XConjunctiveFilterTerm
436 // {
437 // ComparisonPredicate getPredicate( int index );
438 // }
439 // struct ComparisonPredicate
440 // {
441 // XComparisonOperand Lhs;
442 // SQLFilterOperator Operator;
443 // XComparisonOperand Rhs;
444 // }
445 // interface XComparisonOperand
446 // {
447 // SQLFilterOperand Type;
448 // XPropertySet getColumn();
449 // string getLiteral();
450 // ...
451 // }
452 // enum SQLFilterOperand { Column, Literal, ... }
453 // ... or something like this...
455 catch( const Exception& )
457 DBG_UNHANDLED_EXCEPTION("dbaccess");
461 bool SbaTableQueryBrowser::InitializeForm( const Reference< XPropertySet > & i_formProperties )
463 if (!m_xCurrentlyDisplayed)
464 return true;
466 // this method set all format settings from the original table or query
469 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
470 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed).toUInt64());
471 ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" );
472 ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" );
474 Reference< XPropertySetInfo > xPSI( pData->xObjectProperties->getPropertySetInfo(), UNO_SET_THROW );
476 ::comphelper::NamedValueCollection aPropertyValues;
478 const OUString aTransferProperties[] =
480 OUString(PROPERTY_APPLYFILTER),
481 OUString(PROPERTY_FILTER),
482 OUString(PROPERTY_HAVING_CLAUSE),
483 OUString(PROPERTY_ORDER)
485 for (const auto & aTransferPropertie : aTransferProperties)
487 if ( !xPSI->hasPropertyByName( aTransferPropertie ) )
488 continue;
489 aPropertyValues.put( aTransferPropertie, pData->xObjectProperties->getPropertyValue( aTransferPropertie ) );
492 std::vector< OUString > aNames( aPropertyValues.getNames() );
493 std::sort(aNames.begin(), aNames.end());
494 Sequence< OUString > aPropNames( comphelper::containerToSequence(aNames) );
496 Sequence< Any > aPropValues( aNames.size() );
497 std::transform( aNames.begin(), aNames.end(), aPropValues.getArray(), SelectValueByName( aPropertyValues ) );
499 Reference< XMultiPropertySet > xFormMultiSet( i_formProperties, UNO_QUERY_THROW );
500 xFormMultiSet->setPropertyValues( aPropNames, aPropValues );
502 impl_sanitizeRowSetClauses_nothrow();
504 catch ( const Exception& )
506 DBG_UNHANDLED_EXCEPTION("dbaccess");
507 return false;
510 return true;
513 void SbaTableQueryBrowser::initializePreviewMode()
515 if ( getBrowserView() && getBrowserView()->getVclControl() )
517 getBrowserView()->getVclControl()->AlwaysEnableInput( false );
518 getBrowserView()->getVclControl()->EnableInput( false );
519 getBrowserView()->getVclControl()->ForceHideScrollbars();
521 Reference< XPropertySet > xDataSourceSet(getRowSet(), UNO_QUERY);
522 if ( xDataSourceSet.is() )
524 xDataSourceSet->setPropertyValue("AllowInserts",makeAny(false));
525 xDataSourceSet->setPropertyValue("AllowUpdates",makeAny(false));
526 xDataSourceSet->setPropertyValue("AllowDeletes",makeAny(false));
530 void SbaTableQueryBrowser::InitializeGridModel(const Reference< css::form::XFormComponent > & xGrid)
534 Reference< css::form::XGridColumnFactory > xColFactory(xGrid, UNO_QUERY);
535 Reference< XNameContainer > xColContainer(xGrid, UNO_QUERY);
536 clearGridColumns( xColContainer );
538 Reference< XLoadable > xFormAsLoadable;
539 if (xGrid.is())
540 xFormAsLoadable.set(xGrid->getParent(), css::uno::UNO_QUERY);
541 if (xFormAsLoadable.is() && xFormAsLoadable->isLoaded())
543 // set the formats from the table
544 if (m_xCurrentlyDisplayed)
546 Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 ));
547 Sequence< Any> aValues(7 + ( m_bPreview ? 5 : 0 ));
549 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
550 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed).toUInt64());
551 OSL_ENSURE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeGridModel: No table available!" );
552 if ( !pData->xObjectProperties.is() )
553 return;
555 OUString* pStringIter = aProperties.getArray();
556 Any* pValueIter = aValues.getArray();
557 if ( m_bPreview )
559 *pStringIter++ = "AlwaysShowCursor";
560 *pValueIter++ <<= false;
561 *pStringIter++ = PROPERTY_BORDER;
562 *pValueIter++ <<= sal_Int16(0);
565 *pStringIter++ = PROPERTY_FONT;
566 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_FONT);
567 *pStringIter++ = PROPERTY_TEXTEMPHASIS;
568 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTEMPHASIS);
569 *pStringIter++ = PROPERTY_TEXTRELIEF;
570 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTRELIEF);
571 if ( m_bPreview )
573 *pStringIter++ = "HasNavigationBar";
574 *pValueIter++ <<= false;
575 *pStringIter++ = "HasRecordMarker";
576 *pValueIter++ <<= false;
578 *pStringIter++ = PROPERTY_ROW_HEIGHT;
579 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_ROW_HEIGHT);
580 if ( m_bPreview )
582 *pStringIter++ = "Tabstop";
583 *pValueIter++ <<= false;
585 *pStringIter++ = PROPERTY_TEXTCOLOR;
586 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTCOLOR);
587 *pStringIter++ = PROPERTY_TEXTLINECOLOR;
588 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTLINECOLOR);
590 Reference< XMultiPropertySet > xFormMultiSet(xGrid, UNO_QUERY);
591 xFormMultiSet->setPropertyValues(aProperties, aValues);
594 // get the formats supplier of the database we're working with
595 Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormatter()->getNumberFormatsSupplier();
597 Reference<XConnection> xConnection;
598 Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
599 xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
600 OSL_ENSURE(xConnection.is(),"A ActiveConnection should normally exists!");
602 Reference<XChild> xChild(xConnection,UNO_QUERY);
603 Reference<XPropertySet> xDataSourceProp(xChild->getParent(),UNO_QUERY);
604 bool bSuppressVersionCol = false;
605 OSL_VERIFY( xDataSourceProp->getPropertyValue( PROPERTY_SUPPRESSVERSIONCL ) >>= bSuppressVersionCol );
607 // insert the column into the gridcontrol so that we see something :-)
608 OUString aCurrentModelType;
609 Reference<XColumnsSupplier> xSupCols(getRowSet(),UNO_QUERY);
610 Reference<XNameAccess> xColumns = xSupCols->getColumns();
612 OUString sDefaultProperty;
613 Reference< XPropertySet > xColumn;
614 Reference< XPropertySetInfo > xColPSI;
615 const Sequence<OUString> aColNames = xColumns->getElementNames();
616 for (const OUString& rName : aColNames)
618 xColumn.set( xColumns->getByName( rName ), UNO_QUERY_THROW );
619 xColPSI.set( xColumn->getPropertySetInfo(), UNO_SET_THROW );
621 // ignore the column when it is a rowversion one
622 if ( bSuppressVersionCol
623 && xColPSI->hasPropertyByName( PROPERTY_ISROWVERSION )
624 && ::cppu::any2bool( xColumn->getPropertyValue( PROPERTY_ISROWVERSION ) )
626 continue;
628 // use the result set column's type to determine the type of grid column to create
629 bool bFormattedIsNumeric = true;
630 sal_Int32 nType = ::comphelper::getINT32( xColumn->getPropertyValue( PROPERTY_TYPE ) );
632 std::vector< NamedValue > aInitialValues;
633 std::vector< OUString > aCopyProperties;
634 Any aDefault;
636 switch(nType)
638 case DataType::BIT:
639 case DataType::BOOLEAN:
641 aCurrentModelType = "CheckBox";
642 aInitialValues.emplace_back( "VisualEffect", makeAny( VisualEffect::FLAT ) );
643 sDefaultProperty = PROPERTY_DEFAULTSTATE;
645 sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
646 OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
647 aInitialValues.emplace_back(
648 "TriState",
649 makeAny( ColumnValue::NO_NULLS != nNullable )
651 if ( ColumnValue::NO_NULLS == nNullable )
652 aDefault <<= sal_Int16(TRISTATE_FALSE);
654 break;
656 case DataType::LONGVARCHAR:
657 case DataType::CLOB:
658 aInitialValues.emplace_back( "MultiLine", makeAny( true ) );
659 [[fallthrough]];
660 case DataType::BINARY:
661 case DataType::VARBINARY:
662 case DataType::LONGVARBINARY:
663 aCurrentModelType = "TextField";
664 sDefaultProperty = PROPERTY_DEFAULTTEXT;
665 break;
667 case DataType::VARCHAR:
668 case DataType::CHAR:
669 bFormattedIsNumeric = false;
670 [[fallthrough]];
671 default:
672 aCurrentModelType = "FormattedField";
673 sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT;
675 if ( xSupplier.is() )
676 aInitialValues.emplace_back( "FormatsSupplier", makeAny( xSupplier ) );
677 aInitialValues.emplace_back( "TreatAsNumber", makeAny( bFormattedIsNumeric ) );
678 aCopyProperties.emplace_back(PROPERTY_FORMATKEY );
679 break;
682 aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, makeAny( rName ) );
683 OUString sLabel;
684 xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
685 if ( !sLabel.isEmpty() )
686 aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( sLabel ) );
687 else
688 aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( rName ) );
690 Reference< XPropertySet > xGridCol( xColFactory->createColumn( aCurrentModelType ), UNO_SET_THROW );
691 Reference< XPropertySetInfo > xGridColPSI( xGridCol->getPropertySetInfo(), UNO_SET_THROW );
693 // calculate the default
694 if ( xGridColPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) )
696 aDefault = xColumn->getPropertyValue( PROPERTY_CONTROLDEFAULT );
697 // default value
698 if ( nType == DataType::BIT || nType == DataType::BOOLEAN )
700 if ( aDefault.hasValue() )
701 aDefault <<= (comphelper::getString(aDefault).toInt32() == 0) ? sal_Int16(TRISTATE_FALSE) : sal_Int16(TRISTATE_TRUE);
702 else
703 aDefault <<= sal_Int16(TRISTATE_INDET);
707 if ( aDefault.hasValue() )
708 aInitialValues.emplace_back( sDefaultProperty, aDefault );
710 // transfer properties from the definition to the UNO-model :
711 aCopyProperties.emplace_back(PROPERTY_HIDDEN );
712 aCopyProperties.emplace_back(PROPERTY_WIDTH );
714 // help text to display for the column
715 Any aDescription;
716 if ( xColPSI->hasPropertyByName( PROPERTY_HELPTEXT ) )
717 aDescription = xColumn->getPropertyValue( PROPERTY_HELPTEXT );
718 OUString sTemp;
719 aDescription >>= sTemp;
720 if ( sTemp.isEmpty() )
721 xColumn->getPropertyValue( PROPERTY_DESCRIPTION ) >>= sTemp;
723 aDescription <<= sTemp;
724 aInitialValues.emplace_back( PROPERTY_HELPTEXT, aDescription );
726 // ... horizontal justify
727 Any aAlign; aAlign <<= sal_Int16( 0 );
728 Any aColAlign( xColumn->getPropertyValue( PROPERTY_ALIGN ) );
729 if ( aColAlign.hasValue() )
730 aAlign <<= sal_Int16( ::comphelper::getINT32( aColAlign ) );
731 aInitialValues.emplace_back( PROPERTY_ALIGN, aAlign );
733 // don't allow the mouse to scroll in the cells
734 if ( xGridColPSI->hasPropertyByName( PROPERTY_MOUSE_WHEEL_BEHAVIOR ) )
735 aInitialValues.emplace_back( PROPERTY_MOUSE_WHEEL_BEHAVIOR, makeAny( MouseWheelBehavior::SCROLL_DISABLED ) );
737 // now set all those values
738 for (auto const& property : aInitialValues)
740 xGridCol->setPropertyValue( property.Name, property.Value );
742 for (auto const& copyPropertyName : aCopyProperties)
743 xGridCol->setPropertyValue( copyPropertyName, xColumn->getPropertyValue(copyPropertyName) );
745 xColContainer->insertByName(rName, makeAny(xGridCol));
749 catch(const Exception&)
751 DBG_UNHANDLED_EXCEPTION("dbaccess");
755 static Reference<XPropertySet> getColumnHelper(const weld::TreeView& rTreeView,
756 const weld::TreeIter* pCurrentlyDisplayed,
757 const Reference<XPropertySet>& rxSource)
759 Reference<XPropertySet> xRet;
760 if (pCurrentlyDisplayed)
762 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*pCurrentlyDisplayed).toUInt64());
763 Reference<XColumnsSupplier> xColumnsSup(pData->xObjectProperties,UNO_QUERY);
764 Reference<XNameAccess> xNames = xColumnsSup->getColumns();
765 OUString aName;
766 rxSource->getPropertyValue(PROPERTY_NAME) >>= aName;
767 if(xNames.is() && xNames->hasByName(aName))
768 xRet.set(xNames->getByName(aName),UNO_QUERY);
770 return xRet;
773 void SbaTableQueryBrowser::transferChangedControlProperty(const OUString& _rProperty, const Any& _rNewValue)
775 if (m_xCurrentlyDisplayed)
777 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
778 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed).toUInt64());
779 Reference< XPropertySet > xObjectProps = pData->xObjectProperties;
780 OSL_ENSURE(xObjectProps.is(),"SbaTableQueryBrowser::transferChangedControlProperty: no table/query object!");
781 if (xObjectProps.is())
782 xObjectProps->setPropertyValue(_rProperty, _rNewValue);
786 void SbaTableQueryBrowser::propertyChange(const PropertyChangeEvent& evt)
788 SbaXDataBrowserController::propertyChange(evt);
790 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
794 Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
795 if (!xSource.is())
796 return;
797 // one of the many properties which require us to update the definition ?
798 // a column's width ?
799 else if (evt.PropertyName == PROPERTY_WIDTH)
800 { // a column width has changed -> update the model
801 // (the update of the view is done elsewhere)
802 Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
803 if(xProp.is())
805 if(!evt.NewValue.hasValue())
806 xProp->setPropertyValue(PROPERTY_WIDTH,makeAny(sal_Int32(227)));
807 else
808 xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue);
812 // a column's 'visible' state ?
813 else if (evt.PropertyName == PROPERTY_HIDDEN)
815 Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
816 if(xProp.is())
817 xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue);
820 // a columns alignment ?
821 else if (evt.PropertyName == PROPERTY_ALIGN)
823 Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
826 if(xProp.is())
828 if(evt.NewValue.hasValue())
830 sal_Int16 nAlign = 0;
831 if(evt.NewValue >>= nAlign)
832 xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(sal_Int32(nAlign)));
833 else
834 xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue);
836 else
837 xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(css::awt::TextAlign::LEFT));
840 catch( const Exception& )
842 DBG_UNHANDLED_EXCEPTION("dbaccess");
846 // a column's format ?
847 else if ( evt.PropertyName == PROPERTY_FORMATKEY
848 && (TypeClass_LONG == evt.NewValue.getValueTypeClass())
851 // update the model (means the definition object)
852 Reference<XPropertySet> xProp = getColumnHelper(rTreeView, m_xCurrentlyDisplayed.get(), xSource);
853 if(xProp.is())
854 xProp->setPropertyValue(PROPERTY_FORMATKEY,evt.NewValue);
857 // some table definition properties ?
858 // the height of the rows in the grid ?
859 else if (evt.PropertyName == PROPERTY_ROW_HEIGHT)
861 if (m_xCurrentlyDisplayed)
863 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*m_xCurrentlyDisplayed).toUInt64());
864 OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" );
866 bool bDefault = !evt.NewValue.hasValue();
867 if (bDefault)
868 pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,makeAny(sal_Int32(45)));
869 else
870 pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,evt.NewValue);
874 else if ( evt.PropertyName == PROPERTY_FONT // the font ?
875 || evt.PropertyName == PROPERTY_TEXTCOLOR // the text color ?
876 || evt.PropertyName == PROPERTY_FILTER // the filter ?
877 || evt.PropertyName == PROPERTY_HAVING_CLAUSE // the having clause ?
878 || evt.PropertyName == PROPERTY_ORDER // the sort ?
879 || evt.PropertyName == PROPERTY_APPLYFILTER // the appliance of the filter ?
880 || evt.PropertyName == PROPERTY_TEXTLINECOLOR // the text line color ?
881 || evt.PropertyName == PROPERTY_TEXTEMPHASIS // the text emphasis ?
882 || evt.PropertyName == PROPERTY_TEXTRELIEF // the text relief ?
885 transferChangedControlProperty(evt.PropertyName, evt.NewValue);
888 catch( const Exception& )
890 DBG_UNHANDLED_EXCEPTION("dbaccess");
894 sal_Bool SbaTableQueryBrowser::suspend(sal_Bool bSuspend)
896 SolarMutexGuard aSolarGuard;
897 ::osl::MutexGuard aGuard( getMutex() );
898 if ( getView() && getView()->IsInModalMode() )
899 return false;
900 bool bRet = false;
901 if ( !m_bInSuspend )
903 m_bInSuspend = true;
904 if ( rBHelper.bDisposed )
905 throw DisposedException( OUString(), *this );
907 bRet = SbaXDataBrowserController::suspend(bSuspend);
908 if ( bRet && getView() )
909 getView()->Hide();
911 m_bInSuspend = false;
914 return bRet;
917 void SAL_CALL SbaTableQueryBrowser::statusChanged( const FeatureStateEvent& _rEvent )
919 // search the external dispatcher causing this call
920 Reference< XDispatch > xSource(_rEvent.Source, UNO_QUERY);
921 bool bFound = false;
922 for (auto & externalFeature : m_aExternalFeatures)
924 if ( _rEvent.FeatureURL.Complete == externalFeature.second.aURL.Complete)
926 bFound = true;
927 OSL_ENSURE( xSource.get() == externalFeature.second.xDispatcher.get(), "SbaTableQueryBrowser::statusChanged: inconsistent!" );
928 // update the enabled state
929 externalFeature.second.bEnabled = _rEvent.IsEnabled;
931 switch ( externalFeature.first )
933 case ID_BROWSER_DOCUMENT_DATASOURCE:
935 // if it's the slot for the document data source, remember the state
936 Sequence< PropertyValue > aDescriptor;
937 bool bProperFormat = _rEvent.State >>= aDescriptor;
938 OSL_ENSURE(bProperFormat, "SbaTableQueryBrowser::statusChanged: need a data access descriptor here!");
939 m_aDocumentDataSource.initializeFrom(aDescriptor);
941 OSL_ENSURE( ( m_aDocumentDataSource.has(DataAccessDescriptorProperty::DataSource)
942 || m_aDocumentDataSource.has(DataAccessDescriptorProperty::DatabaseLocation)
944 && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command)
945 && m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType),
946 "SbaTableQueryBrowser::statusChanged: incomplete descriptor!");
948 // check if we know the object which is set as document data source
949 checkDocumentDataSource();
951 break;
953 default:
954 // update the toolbox
955 implCheckExternalSlot( externalFeature.first );
956 break;
958 break;
962 OSL_ENSURE(bFound, "SbaTableQueryBrowser::statusChanged: don't know who sent this!");
965 void SbaTableQueryBrowser::checkDocumentDataSource()
967 std::unique_ptr<weld::TreeIter> xDataSourceEntry;
968 std::unique_ptr<weld::TreeIter> xContainerEntry;
969 std::unique_ptr<weld::TreeIter> xObjectEntry = getObjectEntry(m_aDocumentDataSource, &xDataSourceEntry, &xContainerEntry);
970 bool bKnownDocDataSource = static_cast<bool>(xObjectEntry);
971 if (!bKnownDocDataSource)
973 if (xDataSourceEntry)
975 // at least the data source is known
976 if (xContainerEntry)
978 bKnownDocDataSource = true; // assume we know it.
979 // TODO: should we expand the object container? This may be too expensive just for checking...
981 else
983 if (m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType)
984 && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command))
985 { // maybe we have a command to be displayed ?
986 sal_Int32 nCommandType = CommandType::TABLE;
987 m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
989 OUString sCommand;
990 m_aDocumentDataSource[DataAccessDescriptorProperty::Command] >>= sCommand;
992 bKnownDocDataSource = (CommandType::COMMAND == nCommandType) && (!sCommand.isEmpty());
998 if ( !bKnownDocDataSource )
999 m_aExternalFeatures[ ID_BROWSER_DOCUMENT_DATASOURCE ].bEnabled = false;
1001 // update the toolbox
1002 implCheckExternalSlot(ID_BROWSER_DOCUMENT_DATASOURCE);
1005 void SbaTableQueryBrowser::extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor, OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing)
1007 _rDataSource = _rDescriptor.getDataSource();
1008 if ( _rDescriptor.has(DataAccessDescriptorProperty::Command) )
1009 _rDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand;
1010 if ( _rDescriptor.has(DataAccessDescriptorProperty::CommandType) )
1011 _rDescriptor[DataAccessDescriptorProperty::CommandType] >>= _rCommandType;
1013 // escape processing is the only one allowed not to be present
1014 _rEscapeProcessing = true;
1015 if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing))
1016 _rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]);
1019 namespace
1021 bool getDataSourceDisplayName_isURL( const OUString& _rDS, OUString& _rDisplayName, OUString& _rUniqueId )
1023 INetURLObject aURL( _rDS );
1024 if ( aURL.GetProtocol() != INetProtocol::NotValid )
1026 _rDisplayName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
1027 _rUniqueId = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1028 return true;
1030 _rDisplayName = _rDS;
1031 _rUniqueId.clear();
1032 return false;
1035 struct FilterByEntryDataId : public IEntryFilter
1037 OUString sId;
1038 explicit FilterByEntryDataId( const OUString& _rId ) : sId( _rId ) { }
1040 virtual ~FilterByEntryDataId() {}
1042 virtual bool includeEntry(const void* pEntry) const override;
1045 bool FilterByEntryDataId::includeEntry(const void* pUserData) const
1047 const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData);
1048 return ( !pData || ( pData->sAccessor == sId ) );
1052 OUString SbaTableQueryBrowser::getDataSourceAccessor(const weld::TreeIter& rDataSourceEntry) const
1054 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1055 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(rDataSourceEntry).toUInt64());
1056 OSL_ENSURE( pData, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry data!" );
1057 OSL_ENSURE( pData->eType == etDatasource, "SbaTableQueryBrowser::getDataSourceAccessor: entry does not denote a data source!" );
1058 return !pData->sAccessor.isEmpty() ? pData->sAccessor : GetEntryText(rDataSourceEntry);
1061 std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 nCommandType,
1062 std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry, bool bExpandAncestors,
1063 const SharedConnection& _rxConnection )
1065 if (ppDataSourceEntry)
1066 ppDataSourceEntry->reset();
1067 if (ppContainerEntry)
1068 ppContainerEntry->reset();
1070 std::unique_ptr<weld::TreeIter> xObject;
1071 if ( m_pTreeView )
1073 // look for the data source entry
1074 OUString sDisplayName, sDataSourceId;
1075 bool bIsDataSourceURL = getDataSourceDisplayName_isURL( _rDataSource, sDisplayName, sDataSourceId );
1076 // the display name may differ from the URL for readability reasons
1077 // #i33699#
1079 FilterByEntryDataId aFilter( sDataSourceId );
1080 std::unique_ptr<weld::TreeIter> xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter );
1081 if (!xDataSource) // check if the data source name is a file location
1083 if ( bIsDataSourceURL )
1085 // special case, the data source is a URL
1086 // add new entries to the list box model
1087 implAddDatasource( _rDataSource, _rxConnection );
1088 xDataSource = m_pTreeView->GetEntryPosByName( sDisplayName, nullptr, &aFilter );
1089 OSL_ENSURE( xDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" );
1093 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1095 if (xDataSource)
1097 if (ppDataSourceEntry)
1099 // (caller wants to have it...)
1100 *ppDataSourceEntry = rTreeView.make_iterator(xDataSource.get());
1103 // expand if required so
1104 if (bExpandAncestors)
1105 rTreeView.expand_row(*xDataSource);
1107 // look for the object container
1108 std::unique_ptr<weld::TreeIter> xCommandType;
1109 if (nCommandType == CommandType::QUERY || nCommandType == CommandType::TABLE)
1111 xCommandType = rTreeView.make_iterator(xDataSource.get());
1112 if (!rTreeView.iter_children(*xCommandType))
1113 xCommandType.reset();
1114 else
1116 // 1st child is queries, so we're already done if looking for CommandType::QUERY
1118 // 2nd child is tables
1119 if (nCommandType == CommandType::TABLE && !rTreeView.iter_next_sibling(*xCommandType))
1120 xCommandType.reset();
1124 if (xCommandType)
1126 if (ppContainerEntry)
1128 // (caller wants to have it...)
1129 *ppContainerEntry = rTreeView.make_iterator(xCommandType.get());
1132 rTreeView.make_unsorted();
1134 // expand if required so
1135 if (bExpandAncestors)
1137 rTreeView.expand_row(*xCommandType);
1140 // look for the object
1141 sal_Int32 nIndex = 0;
1144 OUString sPath;
1145 switch (nCommandType)
1147 case CommandType::TABLE:
1148 sPath = _rCommand;
1149 nIndex = -1;
1150 break;
1152 case CommandType::QUERY:
1153 sPath = _rCommand.getToken( 0, '/', nIndex );
1154 break;
1156 default:
1157 assert(false);
1159 xObject = m_pTreeView->GetEntryPosByName(sPath, xCommandType.get());
1160 if (xObject)
1161 rTreeView.copy_iterator(*xObject, *xCommandType);
1162 else
1163 xCommandType.reset();
1164 if ( nIndex >= 0 )
1166 if (ensureEntryObject(*xObject))
1168 DBTreeListUserData* pParentData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xObject).toUInt64());
1169 Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
1170 sal_Int32 nIndex2 = nIndex;
1171 sPath = _rCommand.getToken( 0, '/', nIndex2 );
1174 if ( xCollection->hasByName(sPath) )
1176 if(!m_pTreeView->GetEntryPosByName(sPath, xObject.get()))
1178 Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY);
1179 DBTreeListUserData* pEntryData = new DBTreeListUserData;
1180 pEntryData->eType = etQuery;
1181 if ( xChild.is() )
1183 pEntryData->eType = etQueryContainer;
1185 implAppendEntry(xObject.get(), sPath, pEntryData);
1189 catch(const Exception&)
1191 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
1196 while ( nIndex >= 0 );
1198 rTreeView.make_sorted();
1202 return xObject;
1205 std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor,
1206 std::unique_ptr<weld::TreeIter>* ppDataSourceEntry, std::unique_ptr<weld::TreeIter>* ppContainerEntry)
1208 // extract the props from the descriptor
1209 OUString sDataSource;
1210 OUString sCommand;
1211 sal_Int32 nCommandType = CommandType::COMMAND;
1212 bool bEscapeProcessing = true;
1213 extractDescriptorProps(rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);
1215 return getObjectEntry(sDataSource, sCommand, nCommandType, ppDataSourceEntry, ppContainerEntry, false /*bExpandAncestors*/);
1218 void SbaTableQueryBrowser::connectExternalDispatches()
1220 Reference< XDispatchProvider > xProvider( getFrame(), UNO_QUERY );
1221 OSL_ENSURE(xProvider.is(), "SbaTableQueryBrowser::connectExternalDispatches: no DispatchProvider !");
1222 if (!xProvider.is())
1223 return;
1225 if ( m_aExternalFeatures.empty() )
1227 const char* pURLs[] = {
1228 ".uno:DataSourceBrowser/DocumentDataSource",
1229 ".uno:DataSourceBrowser/FormLetter",
1230 ".uno:DataSourceBrowser/InsertColumns",
1231 ".uno:DataSourceBrowser/InsertContent",
1233 const sal_uInt16 nIds[] = {
1234 ID_BROWSER_DOCUMENT_DATASOURCE,
1235 ID_BROWSER_FORMLETTER,
1236 ID_BROWSER_INSERTCOLUMNS,
1237 ID_BROWSER_INSERTCONTENT
1240 for ( size_t i=0; i < SAL_N_ELEMENTS( pURLs ); ++i )
1242 URL aURL;
1243 aURL.Complete = OUString::createFromAscii( pURLs[i] );
1244 if ( m_xUrlTransformer.is() )
1245 m_xUrlTransformer->parseStrict( aURL );
1246 m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( aURL );
1250 for (auto & externalFeature : m_aExternalFeatures)
1252 externalFeature.second.xDispatcher = xProvider->queryDispatch(
1253 externalFeature.second.aURL, "_parent", FrameSearchFlag::PARENT
1256 if ( externalFeature.second.xDispatcher.get() == static_cast< XDispatch* >( this ) )
1258 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::connectExternalDispatches: this should not happen anymore!" );
1259 // (nowadays, the URLs aren't in our SupportedFeatures list anymore, so we should
1260 // not supply a dispatcher for this)
1261 externalFeature.second.xDispatcher.clear();
1264 if ( externalFeature.second.xDispatcher.is() )
1268 externalFeature.second.xDispatcher->addStatusListener( this, externalFeature.second.aURL );
1270 catch( const Exception& )
1272 DBG_UNHANDLED_EXCEPTION("dbaccess");
1276 implCheckExternalSlot( externalFeature.first );
1280 void SbaTableQueryBrowser::implCheckExternalSlot( sal_uInt16 _nId )
1282 if ( !m_xMainToolbar.is() )
1283 return;
1285 VclPtr<vcl::Window> pToolboxWindow = VCLUnoHelper::GetWindow( m_xMainToolbar );
1286 ToolBox* pToolbox = dynamic_cast< ToolBox* >( pToolboxWindow.get() );
1287 OSL_ENSURE( pToolbox, "SbaTableQueryBrowser::implCheckExternalSlot: cannot obtain the toolbox window!" );
1289 // check if we have to hide this item from the toolbox
1290 if ( pToolbox )
1292 bool bHaveDispatcher = m_aExternalFeatures[ _nId ].xDispatcher.is();
1293 if ( bHaveDispatcher != pToolbox->IsItemVisible( _nId ) )
1294 bHaveDispatcher ? pToolbox->ShowItem( _nId ) : pToolbox->HideItem( _nId );
1297 // and invalidate this feature in general
1298 InvalidateFeature( _nId );
1301 void SAL_CALL SbaTableQueryBrowser::disposing( const css::lang::EventObject& _rSource )
1303 // our frame ?
1304 Reference< css::frame::XFrame > xSourceFrame(_rSource.Source, UNO_QUERY);
1305 if (m_xCurrentFrameParent.is() && (xSourceFrame == m_xCurrentFrameParent))
1306 m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
1307 else
1309 // search the external dispatcher causing this call in our map
1310 Reference< XDispatch > xSource(_rSource.Source, UNO_QUERY);
1311 if(xSource.is())
1313 ExternalFeaturesMap::const_iterator aLoop = m_aExternalFeatures.begin();
1314 ExternalFeaturesMap::const_iterator aEnd = m_aExternalFeatures.end();
1315 while (aLoop != aEnd)
1317 if ( aLoop->second.xDispatcher.get() == xSource.get() )
1319 sal_uInt16 nSlot = aLoop->first;
1321 // remove it
1322 aLoop = m_aExternalFeatures.erase(aLoop);
1324 // maybe update the UI
1325 implCheckExternalSlot(nSlot);
1327 // continue, the same XDispatch may be responsible for more than one URL
1329 ++aLoop;
1332 else
1334 Reference<XConnection> xCon(_rSource.Source, UNO_QUERY);
1335 if ( xCon.is() && m_pTreeView )
1337 // our connection is in dispose so we have to find the entry equal with this connection
1338 // and close it what means to collapse the entry
1339 // get the top-level representing the removed data source
1340 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1341 std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator());
1342 if (rTreeView.get_iter_first(*xDSLoop))
1346 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xDSLoop).toUInt64());
1347 if ( pData && pData->xConnection == xCon )
1349 // we set the connection to null to avoid a second disposing of the connection
1350 pData->xConnection.clear();
1351 closeConnection(*xDSLoop, false);
1352 break;
1355 while (rTreeView.iter_next_sibling(*xDSLoop));
1358 else
1359 SbaXDataBrowserController::disposing(_rSource);
1364 void SbaTableQueryBrowser::implRemoveStatusListeners()
1366 // clear all old dispatches
1367 for (auto const& externalFeature : m_aExternalFeatures)
1369 if ( externalFeature.second.xDispatcher.is() )
1373 externalFeature.second.xDispatcher->removeStatusListener( this, externalFeature.second.aURL );
1375 catch (Exception&)
1377 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implRemoveStatusListeners: could not remove a status listener!");
1381 m_aExternalFeatures.clear();
1384 sal_Bool SAL_CALL SbaTableQueryBrowser::select( const Any& _rSelection )
1386 SolarMutexGuard aGuard;
1387 // doin' a lot of VCL stuff here -> lock the SolarMutex
1389 Sequence< PropertyValue > aDescriptorSequence;
1390 if (!(_rSelection >>= aDescriptorSequence))
1391 throw IllegalArgumentException(OUString(), *this, 1);
1392 // TODO: error message
1394 ODataAccessDescriptor aDescriptor;
1397 aDescriptor = ODataAccessDescriptor(aDescriptorSequence);
1399 catch(const Exception&)
1401 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::select: could not extract the descriptor!");
1404 // check the presence of the props we need
1405 if ( !(aDescriptor.has(DataAccessDescriptorProperty::DataSource) || aDescriptor.has(DataAccessDescriptorProperty::DatabaseLocation)) || !aDescriptor.has(DataAccessDescriptorProperty::Command) || !aDescriptor.has(DataAccessDescriptorProperty::CommandType))
1406 throw IllegalArgumentException(OUString(), *this, 1);
1407 // TODO: error message
1409 return implSelect(aDescriptor,true);
1412 Any SAL_CALL SbaTableQueryBrowser::getSelection( )
1414 Any aReturn;
1418 Reference< XLoadable > xLoadable(getRowSet(), UNO_QUERY);
1419 if (xLoadable.is() && xLoadable->isLoaded())
1421 Reference< XPropertySet > aFormProps(getRowSet(), UNO_QUERY);
1422 ODataAccessDescriptor aDescriptor(aFormProps);
1423 // remove properties which are not part of our "selection"
1424 aDescriptor.erase(DataAccessDescriptorProperty::Connection);
1425 aDescriptor.erase(DataAccessDescriptorProperty::Cursor);
1427 aReturn <<= aDescriptor.createPropertyValueSequence();
1430 catch( const Exception& )
1432 DBG_UNHANDLED_EXCEPTION("dbaccess");
1435 return aReturn;
1438 void SAL_CALL SbaTableQueryBrowser::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
1440 m_aSelectionListeners.addInterface(_rxListener);
1443 void SAL_CALL SbaTableQueryBrowser::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
1445 m_aSelectionListeners.removeInterface(_rxListener);
1448 void SbaTableQueryBrowser::attachFrame(const Reference< css::frame::XFrame > & _xFrame)
1450 implRemoveStatusListeners();
1452 if (m_xCurrentFrameParent.is())
1453 m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
1455 SbaXDataBrowserController::attachFrame(_xFrame);
1457 Reference< XFrame > xCurrentFrame( getFrame() );
1458 if ( xCurrentFrame.is() )
1460 m_xCurrentFrameParent = xCurrentFrame->findFrame("_parent",FrameSearchFlag::PARENT);
1461 if ( m_xCurrentFrameParent.is() )
1462 m_xCurrentFrameParent->addFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this));
1464 // obtain our toolbox
1467 Reference< XPropertySet > xFrameProps( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW );
1468 Reference< XLayoutManager > xLayouter(
1469 xFrameProps->getPropertyValue("LayoutManager"),
1470 UNO_QUERY );
1472 if ( xLayouter.is() )
1474 Reference< XUIElement > xUI(
1475 xLayouter->getElement( "private:resource/toolbar/toolbar" ),
1476 UNO_SET_THROW );
1477 m_xMainToolbar.set(xUI->getRealInterface(), css::uno::UNO_QUERY);
1478 OSL_ENSURE( m_xMainToolbar.is(), "SbaTableQueryBrowser::attachFrame: where's my toolbox?" );
1481 catch( const Exception& )
1483 DBG_UNHANDLED_EXCEPTION("dbaccess");
1487 // get the dispatchers for the external slots
1488 connectExternalDispatches();
1491 void SbaTableQueryBrowser::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
1493 SbaXDataBrowserController::addModelListeners(_xGridControlModel);
1494 Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY);
1495 if (xSourceSet.is())
1497 xSourceSet->addPropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
1498 xSourceSet->addPropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
1499 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
1500 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
1501 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
1502 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
1507 void SbaTableQueryBrowser::removeModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel)
1509 SbaXDataBrowserController::removeModelListeners(_xGridControlModel);
1510 Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY);
1511 if (xSourceSet.is())
1513 xSourceSet->removePropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this));
1514 xSourceSet->removePropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this));
1515 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this));
1516 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this));
1517 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this));
1518 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this));
1522 void SbaTableQueryBrowser::RowChanged()
1524 if(getBrowserView())
1526 SbaGridControl* pControl = getBrowserView()->getVclControl();
1527 if (!pControl->IsEditing())
1528 InvalidateFeature(ID_BROWSER_COPY);
1530 SbaXDataBrowserController::RowChanged();
1533 void SbaTableQueryBrowser::ColumnChanged()
1535 if(getBrowserView())
1537 SbaGridControl* pControl = getBrowserView()->getVclControl();
1538 if (!pControl->IsEditing())
1539 InvalidateFeature(ID_BROWSER_COPY);
1541 SbaXDataBrowserController::ColumnChanged();
1544 void SbaTableQueryBrowser::AddColumnListener(const Reference< XPropertySet > & xCol)
1546 SbaXDataBrowserController::AddColumnListener(xCol);
1547 SafeAddPropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
1548 SafeAddPropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
1549 SafeAddPropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
1550 SafeAddPropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
1553 void SbaTableQueryBrowser::RemoveColumnListener(const Reference< XPropertySet > & xCol)
1555 SbaXDataBrowserController::RemoveColumnListener(xCol);
1556 SafeRemovePropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this));
1557 SafeRemovePropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this));
1558 SafeRemovePropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this));
1559 SafeRemovePropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this));
1562 void SbaTableQueryBrowser::criticalFail()
1564 SbaXDataBrowserController::criticalFail();
1565 unloadAndCleanup( false );
1568 void SbaTableQueryBrowser::LoadFinished(bool _bWasSynch)
1570 SbaXDataBrowserController::LoadFinished(_bWasSynch);
1572 m_sQueryCommand.clear();
1573 m_bQueryEscapeProcessing = false;
1575 if (isValid() && !loadingCancelled())
1577 // did we load a query?
1578 bool bTemporary; // needed because we m_bQueryEscapeProcessing is only one bit wide (and we want to pass it by reference)
1579 if ( implGetQuerySignature( m_sQueryCommand, bTemporary ) )
1580 m_bQueryEscapeProcessing = bTemporary;
1583 // if the form has been loaded, this means that our "selection" has changed
1584 css::lang::EventObject aEvent( *this );
1585 m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent );
1588 bool SbaTableQueryBrowser::getExternalSlotState( sal_uInt16 _nId ) const
1590 bool bEnabled = false;
1591 ExternalFeaturesMap::const_iterator aPos = m_aExternalFeatures.find( _nId );
1592 if ( ( m_aExternalFeatures.end() != aPos ) && aPos->second.xDispatcher.is() )
1593 bEnabled = aPos->second.bEnabled;
1594 return bEnabled;
1597 FeatureState SbaTableQueryBrowser::GetState(sal_uInt16 nId) const
1599 FeatureState aReturn;
1600 // (disabled automatically)
1602 // no chance without a view
1603 if (!getBrowserView() || !getBrowserView()->getVclControl())
1604 return aReturn;
1606 switch ( nId )
1608 case ID_TREE_ADMINISTRATE:
1609 aReturn.bEnabled = true;
1610 return aReturn;
1612 case ID_BROWSER_CLOSE:
1613 // the close button should always be enabled
1614 aReturn.bEnabled = !m_bEnableBrowser;
1615 return aReturn;
1617 // "toggle explorer" is always enabled (if we have an explorer)
1618 case ID_BROWSER_EXPLORER:
1619 aReturn.bEnabled = m_bEnableBrowser;
1620 aReturn.bChecked = haveExplorer();
1621 return aReturn;
1623 case ID_BROWSER_REMOVEFILTER:
1624 return SbaXDataBrowserController::GetState( nId );
1626 case ID_BROWSER_COPY:
1627 if ( !m_pTreeView->HasChildPathFocus() )
1628 // handled below
1629 break;
1630 [[fallthrough]];
1631 case ID_TREE_CLOSE_CONN:
1632 case ID_TREE_EDIT_DATABASE:
1634 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1635 std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator());
1636 if (!rTreeView.get_cursor(xCurrentEntry.get()))
1637 return aReturn;
1639 EntryType eType = getEntryType(*xCurrentEntry);
1640 if ( eType == etUnknown )
1641 return aReturn;
1643 std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(xCurrentEntry.get());
1644 DBTreeListUserData* pDSData
1645 = xDataSourceEntry
1646 ? reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry).toUInt64())
1647 : nullptr;
1649 if ( nId == ID_TREE_CLOSE_CONN )
1651 aReturn.bEnabled = ( pDSData != nullptr ) && pDSData->xConnection.is();
1653 else if ( nId == ID_TREE_EDIT_DATABASE )
1655 ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( getORB(),
1656 "/org.openoffice.Office.DataAccess/Policies/Features/Common" ) );
1657 bool bHaveEditDatabase( true );
1658 OSL_VERIFY( aConfig.getNodeValue( "EditDatabaseFromDataSourceView" ) >>= bHaveEditDatabase );
1659 aReturn.bEnabled = getORB().is() && xDataSourceEntry && bHaveEditDatabase;
1661 else if ( nId == ID_BROWSER_COPY )
1663 aReturn.bEnabled = isEntryCopyAllowed(*xCurrentEntry);
1666 return aReturn;
1670 // all slots not handled above are not available if no form is loaded
1671 if (!isLoaded())
1672 return aReturn;
1676 bool bHandled = false;
1677 switch (nId)
1679 case ID_BROWSER_DOCUMENT_DATASOURCE:
1680 // the slot is enabled if we have an external dispatcher able to handle it,
1681 // and the dispatcher must have enabled the slot in general
1682 aReturn.bEnabled = getExternalSlotState( ID_BROWSER_DOCUMENT_DATASOURCE );
1683 bHandled = true;
1684 break;
1685 case ID_BROWSER_REFRESH:
1686 aReturn.bEnabled = true;
1687 bHandled = true;
1688 break;
1691 if (bHandled)
1692 return aReturn;
1694 // no chance without valid models
1695 if (isValid() && !isValidCursor() && nId != ID_BROWSER_CLOSE)
1696 return aReturn;
1698 switch (nId)
1700 case ID_BROWSER_INSERTCOLUMNS:
1701 case ID_BROWSER_INSERTCONTENT:
1702 case ID_BROWSER_FORMLETTER:
1704 // the slot is enabled if we have an external dispatcher able to handle it,
1705 // and the dispatcher must have enabled the slot in general
1706 aReturn.bEnabled = getExternalSlotState( nId );
1708 // for the Insert* slots, we need at least one selected row
1709 if (ID_BROWSER_FORMLETTER != nId)
1710 aReturn.bEnabled = aReturn.bEnabled && getBrowserView()->getVclControl()->GetSelectRowCount();
1712 // disabled for native queries which are not saved within the database
1713 Reference< XPropertySet > xDataSource(getRowSet(), UNO_QUERY);
1716 aReturn.bEnabled = aReturn.bEnabled && xDataSource.is();
1718 if (xDataSource.is())
1720 sal_Int32 nType = ::comphelper::getINT32(xDataSource->getPropertyValue(PROPERTY_COMMAND_TYPE));
1721 aReturn.bEnabled = aReturn.bEnabled &&
1722 ( ::comphelper::getBOOL(xDataSource->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) ||
1723 (nType == css::sdb::CommandType::QUERY) );
1726 catch(DisposedException&)
1728 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: object already disposed!");
1730 catch( const Exception& )
1732 DBG_UNHANDLED_EXCEPTION("dbaccess");
1735 break;
1737 case ID_BROWSER_TITLE:
1739 Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
1740 sal_Int32 nCommandType = CommandType::TABLE;
1741 xProp->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nCommandType;
1742 OUString sTitle;
1743 switch (nCommandType)
1745 case CommandType::TABLE:
1746 sTitle = DBA_RES(STR_TBL_TITLE); break;
1747 case CommandType::QUERY:
1748 case CommandType::COMMAND:
1749 sTitle = DBA_RES(STR_QRY_TITLE); break;
1750 default:
1751 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: unknown command type!");
1753 OUString aName;
1754 xProp->getPropertyValue(PROPERTY_COMMAND) >>= aName;
1755 OUString sObject(aName);
1757 aReturn.sTitle = sTitle.replaceFirst("#", sObject);
1758 aReturn.bEnabled = true;
1760 break;
1761 case ID_BROWSER_TABLEATTR:
1762 case ID_BROWSER_ROWHEIGHT:
1763 case ID_BROWSER_COLATTRSET:
1764 case ID_BROWSER_COLWIDTH:
1765 aReturn.bEnabled = getBrowserView()->getVclControl() && isValid() && isValidCursor();
1766 // aReturn.bEnabled &= getDefinition() && !getDefinition()->GetDatabase()->IsReadOnly();
1767 break;
1769 case ID_BROWSER_COPY:
1770 OSL_ENSURE( !m_pTreeView->HasChildPathFocus(), "SbaTableQueryBrowser::GetState( ID_BROWSER_COPY ): this should have been handled above!" );
1771 if (getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing())
1773 SbaGridControl* pControl = getBrowserView()->getVclControl();
1774 if ( pControl->GetSelectRowCount() )
1776 aReturn.bEnabled = m_aCurrentFrame.isActive();
1777 break;
1779 else
1780 aReturn.bEnabled = pControl->canCopyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
1781 break;
1783 [[fallthrough]];
1784 default:
1785 return SbaXDataBrowserController::GetState(nId);
1788 catch(const Exception&)
1790 DBG_UNHANDLED_EXCEPTION("dbaccess");
1793 return aReturn;
1797 void SbaTableQueryBrowser::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& aArgs)
1799 switch (nId)
1801 default:
1802 SbaXDataBrowserController::Execute(nId,aArgs);
1803 break;
1805 case ID_TREE_EDIT_DATABASE:
1807 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1808 std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
1809 if (rTreeView.get_cursor(xIter.get()))
1810 implAdministrate(*xIter);
1811 break;
1813 case ID_TREE_CLOSE_CONN:
1815 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1816 std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
1817 if (rTreeView.get_cursor(xIter.get()))
1819 xIter = m_pTreeView->GetRootLevelParent(xIter.get());
1820 closeConnection(*xIter);
1822 break;
1824 case ID_TREE_ADMINISTRATE:
1825 svx::administrateDatabaseRegistration( getFrameWeld() );
1826 break;
1828 case ID_BROWSER_REFRESH:
1830 if ( !SaveModified( ) )
1831 // nothing to do
1832 break;
1834 bool bFullReinit = false;
1835 // check if the query signature (if the form is based on a query) has changed
1836 if ( !m_sQueryCommand.isEmpty() )
1838 OUString sNewQueryCommand;
1839 bool bNewQueryEP;
1841 bool bIsQuery =
1842 implGetQuerySignature( sNewQueryCommand, bNewQueryEP );
1843 OSL_ENSURE( bIsQuery, "SbaTableQueryBrowser::Execute: was a query before, but is not anymore?" );
1845 bFullReinit = ( sNewQueryCommand != m_sQueryCommand ) || ( m_bQueryEscapeProcessing != bNewQueryEP );
1847 if ( !bFullReinit )
1849 // let the base class do a simple reload
1850 SbaXDataBrowserController::Execute(nId,aArgs);
1851 break;
1853 [[fallthrough]];
1856 case ID_BROWSER_REFRESH_REBUILD:
1858 if ( !SaveModified() )
1859 // nothing to do
1860 break;
1862 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1863 std::unique_ptr<weld::TreeIter> xSelected = m_xCurrentlyDisplayed ?
1864 rTreeView.make_iterator(m_xCurrentlyDisplayed.get()) : nullptr;
1866 // unload
1867 unloadAndCleanup( false );
1869 // reselect the entry
1870 if ( xSelected )
1872 implSelect(xSelected.get());
1874 else
1876 Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
1877 implSelect(svx::ODataAccessDescriptor(xProp));
1880 break;
1882 case ID_BROWSER_EXPLORER:
1883 toggleExplorer();
1884 break;
1886 case ID_BROWSER_DOCUMENT_DATASOURCE:
1887 implSelect(m_aDocumentDataSource);
1888 break;
1890 case ID_BROWSER_INSERTCOLUMNS:
1891 case ID_BROWSER_INSERTCONTENT:
1892 case ID_BROWSER_FORMLETTER:
1893 if (getBrowserView() && isValidCursor())
1895 // the URL the slot id is assigned to
1896 OSL_ENSURE( m_aExternalFeatures.find( nId ) != m_aExternalFeatures.end(),
1897 "SbaTableQueryBrowser::Execute( ID_BROWSER_?): how could this ever be enabled?" );
1898 URL aParentUrl = m_aExternalFeatures[ nId ].aURL;
1900 // let the dispatcher execute the slot
1901 Reference< XDispatch > xDispatch( m_aExternalFeatures[ nId ].xDispatcher );
1902 if (xDispatch.is())
1904 // set the properties for the dispatch
1906 // first fill the selection
1907 SbaGridControl* pGrid = getBrowserView()->getVclControl();
1908 MultiSelection* pSelection = const_cast<MultiSelection*>(pGrid->GetSelection());
1909 Sequence< Any > aSelection;
1910 if ( !pGrid->IsAllSelected() )
1911 { // transfer the selected rows only if not all rows are selected
1912 // (all rows means the whole table)
1913 // #i3832#
1914 if (pSelection != nullptr)
1916 aSelection.realloc(pSelection->GetSelectCount());
1917 tools::Long nIdx = pSelection->FirstSelected();
1918 Any* pSelectionNos = aSelection.getArray();
1919 while (nIdx != SFX_ENDOFSELECTION)
1921 *pSelectionNos++ <<= static_cast<sal_Int32>(nIdx + 1);
1922 nIdx = pSelection->NextSelected();
1927 Reference< XResultSet > xCursorClone;
1930 Reference< XResultSetAccess > xResultSetAccess(getRowSet(),UNO_QUERY);
1931 if (xResultSetAccess.is())
1932 xCursorClone = xResultSetAccess->createResultSet();
1934 catch(DisposedException&)
1936 SAL_WARN("dbaccess.ui", "Object already disposed!");
1938 catch(const Exception&)
1940 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Execute(ID_BROWSER_?): could not clone the cursor!");
1943 Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY);
1947 ODataAccessDescriptor aDescriptor;
1948 OUString sDataSourceName;
1949 xProp->getPropertyValue(PROPERTY_DATASOURCENAME) >>= sDataSourceName;
1951 aDescriptor.setDataSource(sDataSourceName);
1952 aDescriptor[DataAccessDescriptorProperty::Command] = xProp->getPropertyValue(PROPERTY_COMMAND);
1953 aDescriptor[DataAccessDescriptorProperty::CommandType] = xProp->getPropertyValue(PROPERTY_COMMAND_TYPE);
1954 aDescriptor[DataAccessDescriptorProperty::Connection] = xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION);
1955 aDescriptor[DataAccessDescriptorProperty::Cursor] <<= xCursorClone;
1956 if ( aSelection.hasElements() )
1958 aDescriptor[DataAccessDescriptorProperty::Selection] <<= aSelection;
1959 aDescriptor[DataAccessDescriptorProperty::BookmarkSelection] <<= false;
1960 // these are selection indices
1961 // before we change this, all clients have to be adjusted
1962 // so that they recognize the new BookmarkSelection property!
1965 xDispatch->dispatch(aParentUrl, aDescriptor.createPropertyValueSequence());
1967 catch( const Exception& )
1969 DBG_UNHANDLED_EXCEPTION("dbaccess");
1973 break;
1975 case ID_BROWSER_CLOSE:
1976 closeTask();
1977 // if it's not 0, such an async close is already pending
1978 break;
1980 case ID_BROWSER_COPY:
1981 if(m_pTreeView->HasChildPathFocus())
1983 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
1984 std::unique_ptr<weld::TreeIter> xCursor(rTreeView.make_iterator());
1985 if (rTreeView.get_cursor(xCursor.get()))
1986 copyEntry(*xCursor);
1988 else if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing() && getBrowserView()->getVclControl()->GetSelectRowCount() < 1)
1990 SbaGridControl* pControl = getBrowserView()->getVclControl();
1991 pControl->copyCellText(pControl->GetCurRow(), pControl->GetCurColumnId());
1993 else
1994 SbaXDataBrowserController::Execute(nId,aArgs);
1995 break;
1999 void SbaTableQueryBrowser::implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection )
2001 OUString a, b, c, d, e;
2002 implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection );
2005 void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, OUString& _rDbImage,
2006 OUString& _rQueryName, OUString& _rQueryImage, OUString& _rTableName, OUString& _rTableImage,
2007 const SharedConnection& _rxConnection)
2009 SolarMutexGuard aGuard;
2010 // initialize the names/images if necessary
2011 if (_rQueryName.isEmpty())
2012 _rQueryName = DBA_RES(RID_STR_QUERIES_CONTAINER);
2013 if (_rTableName.isEmpty())
2014 _rTableName = DBA_RES(RID_STR_TABLES_CONTAINER);
2016 if (_rQueryImage.isEmpty())
2017 _rQueryImage = ImageProvider::getFolderImageId(DatabaseObject::QUERY);
2018 if (_rTableImage.isEmpty())
2019 _rTableImage = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
2021 if (_rDbImage.isEmpty())
2022 _rDbImage = ImageProvider::getDatabaseImage();
2024 // add the entry for the data source
2025 // special handling for data sources denoted by URLs - we do not want to display this ugly URL, do we?
2026 // #i33699#
2027 OUString sDSDisplayName, sDataSourceId;
2028 getDataSourceDisplayName_isURL( _rDbName, sDSDisplayName, sDataSourceId );
2030 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2031 DBTreeListUserData* pDSData = new DBTreeListUserData;
2032 pDSData->eType = etDatasource;
2033 pDSData->sAccessor = sDataSourceId;
2034 pDSData->xConnection = _rxConnection;
2035 OUString sId(OUString::number(reinterpret_cast<sal_uInt64>(pDSData)));
2037 std::unique_ptr<weld::TreeIter> xDatasourceEntry(rTreeView.make_iterator());
2038 rTreeView.insert(nullptr, -1, &sDSDisplayName, &sId, nullptr, nullptr, false, xDatasourceEntry.get());
2039 rTreeView.set_image(*xDatasourceEntry, _rDbImage);
2040 rTreeView.set_text_emphasis(*xDatasourceEntry, false, 0);
2042 // the child for the queries container
2044 DBTreeListUserData* pQueriesData = new DBTreeListUserData;
2045 pQueriesData->eType = etQueryContainer;
2046 sId = OUString::number(reinterpret_cast<sal_uInt64>(pQueriesData));
2048 std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator());
2049 rTreeView.insert(xDatasourceEntry.get(), -1, &_rQueryName, &sId,
2050 nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get());
2051 rTreeView.set_image(*xRet, _rQueryImage);
2052 rTreeView.set_text_emphasis(*xRet, false, 0);
2055 // the child for the tables container
2057 DBTreeListUserData* pTablesData = new DBTreeListUserData;
2058 pTablesData->eType = etTableContainer;
2059 sId = OUString::number(reinterpret_cast<sal_uInt64>(pTablesData));
2061 std::unique_ptr<weld::TreeIter> xRet(rTreeView.make_iterator());
2062 rTreeView.insert(xDatasourceEntry.get(), -1, &_rTableName, &sId,
2063 nullptr, nullptr, true /*ChildrenOnDemand*/, xRet.get());
2064 rTreeView.set_image(*xRet, _rTableImage);
2065 rTreeView.set_text_emphasis(*xRet, false, 0);
2069 void SbaTableQueryBrowser::initializeTreeModel()
2071 if (m_xDatabaseContext.is())
2073 OUString aDBImage, aQueriesImage, aTablesImage;
2074 OUString sQueriesName, sTablesName;
2076 // fill the model with the names of the registered datasources
2077 const Sequence<OUString> aDatasourceNames = m_xDatabaseContext->getElementNames();
2078 for (const OUString& rDatasource : aDatasourceNames)
2079 implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() );
2083 void SbaTableQueryBrowser::populateTree(const Reference<XNameAccess>& _xNameAccess,
2084 const weld::TreeIter& rParent,
2085 EntryType eEntryType)
2087 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2088 rTreeView.make_unsorted();
2090 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(rParent).toUInt64());
2091 if (pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables
2092 pData->xContainer = _xNameAccess;
2096 const Sequence<OUString> aNames = _xNameAccess->getElementNames();
2097 for (const OUString& rName : aNames)
2099 if( !m_pTreeView->GetEntryPosByName(rName, &rParent))
2101 DBTreeListUserData* pEntryData = new DBTreeListUserData;
2102 pEntryData->eType = eEntryType;
2103 if ( eEntryType == etQuery )
2105 Reference<XNameAccess> xChild(_xNameAccess->getByName(rName),UNO_QUERY);
2106 if ( xChild.is() )
2107 pEntryData->eType = etQueryContainer;
2109 implAppendEntry(&rParent, rName, pEntryData);
2113 catch(const Exception&)
2115 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree");
2118 rTreeView.make_sorted();
2121 std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implAppendEntry(const weld::TreeIter* pParent, const OUString& rName, DBTreeListUserData* pUserData)
2123 EntryType eEntryType = pUserData->eType;
2125 std::unique_ptr<ImageProvider> xImageProvider(getImageProviderFor(pParent));
2127 OUString aImage = xImageProvider->getImageId(rName, getDatabaseObjectType(eEntryType));
2129 OUString sId(OUString::number(reinterpret_cast<sal_uInt64>(pUserData)));
2130 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2131 std::unique_ptr<weld::TreeIter> xNewEntry(rTreeView.make_iterator());
2132 rTreeView.insert(pParent, -1, &rName, &sId, nullptr, nullptr, eEntryType == etQueryContainer, xNewEntry.get());
2133 rTreeView.set_image(*xNewEntry, aImage);
2134 rTreeView.set_text_emphasis(*xNewEntry, false, 0);
2136 return xNewEntry;
2139 IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, const weld::TreeIter&, rParent, bool)
2141 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2142 if (rTreeView.iter_has_child(rParent))
2144 // nothing to do...
2145 return true;
2148 std::unique_ptr<weld::TreeIter> xFirstParent = m_pTreeView->GetRootLevelParent(&rParent);
2149 OSL_ENSURE(xFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!");
2151 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(rParent).toInt64());
2152 assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!");
2154 if (etTableContainer == pData->eType)
2156 weld::WaitObject aWaitCursor(getFrameWeld());
2158 // it could be that we already have a connection
2159 SharedConnection xConnection;
2160 ensureConnection(xFirstParent.get(), xConnection);
2162 if ( xConnection.is() )
2164 SQLExceptionInfo aInfo;
2167 Reference< XWarningsSupplier > xWarnings(xConnection, UNO_QUERY);
2168 if (xWarnings.is())
2169 xWarnings->clearWarnings();
2171 // first insert the views because the tables can also include
2172 // views but that time the bitmap is the wrong one
2173 // the nameaccess will be overwritten in populateTree
2174 Reference<XViewsSupplier> xViewSup(xConnection,UNO_QUERY);
2175 if(xViewSup.is())
2176 populateTree( xViewSup->getViews(), rParent, etTableOrView );
2178 Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY);
2179 if(xTabSup.is())
2181 populateTree( xTabSup->getTables(), rParent, etTableOrView );
2182 Reference<XContainer> xCont(xTabSup->getTables(),UNO_QUERY);
2183 if(xCont.is())
2184 // add as listener to know when elements are inserted or removed
2185 xCont->addContainerListener(this);
2188 if (xWarnings.is())
2190 #if 0
2191 SQLExceptionInfo aWarnings(xWarnings->getWarnings());
2192 // Obviously this if test is always false. So to avoid a Clang warning
2193 // "use of logical '&&' with constant operand" I put this in #if
2194 // 0. Yeah, I know it is fairly likely nobody will ever read this
2195 // comment and make a decision what to do here, so I could as well
2196 // have just binned this...
2197 if (aWarnings.isValid() && sal_False)
2199 SQLContext aContext;
2200 aContext.Message = DBA_RES(STR_OPENTABLES_WARNINGS);
2201 aContext.Details = DBA_RES(STR_OPENTABLES_WARNINGS_DETAILS);
2202 aContext.NextException = aWarnings.get();
2203 aWarnings = aContext;
2204 showError(aWarnings);
2206 #endif
2207 // TODO: we need a better concept for these warnings:
2208 // something like "don't show any warnings for this datasource, again" would be nice
2209 // But this requires an extension of the InteractionHandler and an additional property on the data source
2212 catch(const SQLContext& e) { aInfo = e; }
2213 catch(const SQLWarning& e) { aInfo = e; }
2214 catch(const SQLException& e) { aInfo = e; }
2215 catch(const WrappedTargetException& e)
2217 SQLException aSql;
2218 if(e.TargetException >>= aSql)
2219 aInfo = aSql;
2220 else
2221 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: something strange happened!");
2223 catch( const Exception& )
2225 DBG_UNHANDLED_EXCEPTION("dbaccess");
2227 if (aInfo.isValid())
2228 showError(aInfo);
2230 else
2231 return false;
2232 // 0 indicates that an error occurred
2234 else
2236 // we have to expand the queries or bookmarks
2237 if (ensureEntryObject(rParent))
2239 DBTreeListUserData* pParentData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(rParent).toUInt64());
2240 Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY );
2241 populateTree(xCollection, rParent, etQuery);
2244 return true;
2247 bool SbaTableQueryBrowser::ensureEntryObject(const weld::TreeIter& rEntry)
2249 EntryType eType = getEntryType(rEntry);
2251 // the user data of the entry
2252 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2253 DBTreeListUserData* pEntryData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(rEntry).toUInt64());
2254 OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!");
2256 std::unique_ptr<weld::TreeIter> xDataSourceEntry = m_pTreeView->GetRootLevelParent(&rEntry);
2258 bool bSuccess = false;
2259 switch (eType)
2261 case etQueryContainer:
2263 if ( pEntryData->xContainer.is() )
2265 // nothing to do
2266 bSuccess = true;
2267 break;
2270 std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
2271 if (rTreeView.iter_parent(*xParent))
2273 if (rTreeView.iter_compare(*xParent, *xDataSourceEntry) != 0)
2275 OUString aName(rTreeView.get_text(rEntry));
2276 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xParent).toUInt64());
2279 Reference< XNameAccess > xNameAccess(pData->xContainer,UNO_QUERY);
2280 if ( xNameAccess.is() )
2281 pEntryData->xContainer.set(xNameAccess->getByName(aName),UNO_QUERY);
2283 catch(const Exception& )
2285 DBG_UNHANDLED_EXCEPTION("dbaccess");
2288 bSuccess = pEntryData->xContainer.is();
2290 else
2294 Reference< XQueryDefinitionsSupplier > xQuerySup;
2295 m_xDatabaseContext->getByName(getDataSourceAccessor(*xDataSourceEntry)) >>= xQuerySup;
2296 if (xQuerySup.is())
2298 Reference< XNameAccess > xQueryDefs = xQuerySup->getQueryDefinitions();
2299 Reference< XContainer > xCont(xQueryDefs, UNO_QUERY);
2300 if (xCont.is())
2301 // add as listener to get notified if elements are inserted or removed
2302 xCont->addContainerListener(this);
2304 pEntryData->xContainer = xQueryDefs;
2305 bSuccess = pEntryData->xContainer.is();
2307 else {
2308 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: no XQueryDefinitionsSupplier interface!");
2311 catch( const Exception& )
2313 DBG_UNHANDLED_EXCEPTION("dbaccess");
2317 break;
2319 default:
2320 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: ooops ... missing some implementation here!");
2321 // TODO ...
2322 break;
2324 return bSuccess;
2327 bool SbaTableQueryBrowser::implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect)
2329 // extract the props
2330 OUString sDataSource;
2331 OUString sCommand;
2332 sal_Int32 nCommandType = CommandType::COMMAND;
2333 bool bEscapeProcessing = true;
2334 extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing);
2336 // select it
2337 return implSelect( sDataSource, sCommand, nCommandType, bEscapeProcessing, SharedConnection(), _bSelectDirect );
2340 bool SbaTableQueryBrowser::implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand,
2341 const sal_Int32 nCommandType, const bool _bEscapeProcessing, const SharedConnection& _rxConnection)
2345 Reference<XPropertySet> xProp( getRowSet(), UNO_QUERY_THROW );
2346 Reference< XLoadable > xLoadable( xProp, UNO_QUERY_THROW );
2347 // the values allowing the RowSet to re-execute
2348 xProp->setPropertyValue(PROPERTY_DATASOURCENAME, makeAny(_rDataSourceName));
2349 if(_rxConnection.is())
2350 xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( _rxConnection.getTyped() ) );
2352 // set this _before_ setting the connection, else the rowset would rebuild it ...
2353 xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, makeAny(nCommandType));
2354 xProp->setPropertyValue(PROPERTY_COMMAND, makeAny(_rCommand));
2355 xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny(_bEscapeProcessing));
2356 if ( m_bPreview )
2358 xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, makeAny(FetchDirection::FORWARD));
2361 // the formatter depends on the data source we're working on, so rebuild it here ...
2362 initFormatter();
2364 // switch the grid to design mode while loading
2365 getBrowserView()->getGridControl()->setDesignMode(true);
2366 InitializeForm( xProp );
2368 bool bSuccess = true;
2372 Reference< XNameContainer > xColContainer(getFormComponent(), UNO_QUERY);
2373 // first we have to clear the grid
2374 clearGridColumns(xColContainer);
2376 FormErrorHelper aHelper(this);
2377 // load the form
2378 bSuccess = reloadForm(xLoadable);
2380 // initialize the model
2381 InitializeGridModel(getFormComponent());
2383 Any aVal = xProp->getPropertyValue(PROPERTY_ISNEW);
2384 if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
2386 // then set the default values and the parameters given from the parent
2387 Reference< XReset> xReset(xProp, UNO_QUERY);
2388 xReset->reset();
2391 if ( m_bPreview )
2392 initializePreviewMode();
2394 LoadFinished(true);
2397 InvalidateAll();
2398 return bSuccess;
2400 catch( const SQLException& )
2402 Any aException( ::cppu::getCaughtException() );
2403 showError( SQLExceptionInfo( aException ) );
2405 catch( const WrappedTargetException& e )
2407 if ( e.TargetException.isExtractableTo( ::cppu::UnoType< SQLException >::get() ) )
2408 showError( SQLExceptionInfo( e.TargetException ) );
2409 else
2411 TOOLS_WARN_EXCEPTION("dbaccess", "");
2414 catch(const Exception&)
2416 DBG_UNHANDLED_EXCEPTION("dbaccess");
2419 InvalidateAll();
2420 return false;
2423 bool SbaTableQueryBrowser::implSelect(const OUString& _rDataSourceName, const OUString& _rCommand,
2424 const sal_Int32 nCommandType, const bool _bEscapeProcessing,
2425 const SharedConnection& _rxConnection,
2426 bool _bSelectDirect)
2428 if (_rDataSourceName.getLength() && _rCommand.getLength() && (-1 != nCommandType))
2430 std::unique_ptr<weld::TreeIter> xDataSource;
2431 std::unique_ptr<weld::TreeIter> xCommandType;
2432 std::unique_ptr<weld::TreeIter> xCommand = getObjectEntry( _rDataSourceName, _rCommand, nCommandType, &xDataSource, &xCommandType, true, _rxConnection );
2434 if (xCommand)
2436 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2438 bool bSuccess = true;
2439 if ( _bSelectDirect )
2441 bSuccess = implSelect(xCommand.get());
2443 else
2445 rTreeView.select(*xCommand);
2448 if ( bSuccess )
2450 rTreeView.scroll_to_row(*xCommand);
2451 rTreeView.set_cursor(*xCommand);
2454 else if (!xCommandType)
2456 if (m_xCurrentlyDisplayed)
2458 // tell the old entry (if any) it has been deselected
2459 selectPath(m_xCurrentlyDisplayed.get(), false);
2460 m_xCurrentlyDisplayed.reset();
2463 // we have a command and need to display this in the rowset
2464 return implLoadAnything(_rDataSourceName, _rCommand, nCommandType, _bEscapeProcessing, _rxConnection);
2467 return false;
2470 IMPL_LINK_NOARG(SbaTableQueryBrowser, OnSelectionChange, LinkParamNone*, void)
2472 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2473 std::unique_ptr<weld::TreeIter> xSelection(rTreeView.make_iterator());
2474 if (!rTreeView.get_selected(xSelection.get()))
2475 xSelection.reset();
2476 implSelect(xSelection.get());
2479 std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::implGetConnectionEntry(weld::TreeIter& rEntry) const
2481 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2482 std::unique_ptr<weld::TreeIter> xCurrentEntry(rTreeView.make_iterator(&rEntry));
2483 DBTreeListUserData* pEntryData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry).toInt64());
2484 while (pEntryData->eType != etDatasource)
2486 rTreeView.iter_parent(*xCurrentEntry);
2487 pEntryData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xCurrentEntry).toInt64());
2489 return xCurrentEntry;
2492 bool SbaTableQueryBrowser::implSelect(const weld::TreeIter* pEntry)
2494 if ( !pEntry )
2495 return false;
2497 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2498 DBTreeListUserData* pEntryData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*pEntry).toUInt64());
2499 switch (pEntryData->eType)
2501 case etTableOrView:
2502 case etQuery:
2503 break;
2504 default:
2505 // nothing to do
2506 return false;
2509 OSL_ENSURE(rTreeView.get_iter_depth(*pEntry) >= 2, "SbaTableQueryBrowser::implSelect: invalid entry!");
2511 // get the entry for the tables or queries
2512 std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(pEntry);
2513 rTreeView.iter_parent(*xContainer);
2514 DBTreeListUserData* pContainerData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xContainer).toUInt64());
2516 // get the entry for the datasource
2517 std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer);
2518 DBTreeListUserData* pConData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xConnection).toUInt64());
2520 // reinitialize the rowset
2521 // but first check if it is necessary
2522 // get all old properties
2523 Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
2524 OUString aOldName;
2525 xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName;
2526 sal_Int32 nOldType = 0;
2527 xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType;
2528 Reference<XConnection> xOldConnection(xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY);
2530 // the name of the table or query
2531 const OUString sSimpleName = rTreeView.get_text(*pEntry);
2532 OUStringBuffer sNameBuffer(sSimpleName);
2533 if ( etQueryContainer == pContainerData->eType )
2535 std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(xContainer.get());
2536 std::unique_ptr<weld::TreeIter> xNextTemp = rTreeView.make_iterator(xTemp.get());
2537 if (rTreeView.iter_parent(*xNextTemp))
2539 while (rTreeView.iter_compare(*xNextTemp, *xConnection) != 0)
2541 sNameBuffer.insert(0,'/');
2542 sNameBuffer.insert(0, rTreeView.get_text(*xTemp));
2543 rTreeView.copy_iterator(*xNextTemp, *xTemp);
2544 if (!rTreeView.iter_parent(*xNextTemp))
2545 break;
2549 OUString aName = sNameBuffer.makeStringAndClear();
2551 sal_Int32 nCommandType = ( etTableContainer == pContainerData->eType)
2552 ? CommandType::TABLE
2553 : CommandType::QUERY;
2555 // check if need to rebuild the rowset
2556 bool bRebuild = ( xOldConnection != pConData->xConnection )
2557 || ( nOldType != nCommandType )
2558 || ( aName != aOldName );
2560 Reference< css::form::XLoadable > xLoadable = getLoadable();
2561 bRebuild |= !xLoadable->isLoaded();
2562 bool bSuccess = true;
2563 if ( bRebuild )
2567 weld::WaitObject aWaitCursor(getFrameWeld());
2569 // tell the old entry it has been deselected
2570 selectPath(m_xCurrentlyDisplayed.get(), false);
2571 m_xCurrentlyDisplayed.reset();
2573 // not really loaded
2574 m_xCurrentlyDisplayed = rTreeView.make_iterator(pEntry);
2575 // tell the new entry it has been selected
2576 selectPath(m_xCurrentlyDisplayed.get());
2578 // get the name of the data source currently selected
2579 ensureConnection(m_xCurrentlyDisplayed.get(), pConData->xConnection);
2581 if ( !pConData->xConnection.is() )
2583 unloadAndCleanup( false );
2584 return false;
2587 Reference<XNameAccess> xNameAccess;
2588 switch(nCommandType)
2590 case CommandType::TABLE:
2592 // only for tables
2593 if ( !pContainerData->xContainer.is() )
2595 Reference<XTablesSupplier> xSup( pConData->xConnection, UNO_QUERY );
2596 if(xSup.is())
2597 xNameAccess = xSup->getTables();
2599 pContainerData->xContainer = xNameAccess;
2601 else
2602 xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
2604 break;
2605 case CommandType::QUERY:
2607 if ( pContainerData->xContainer.is() )
2608 xNameAccess.set( pContainerData->xContainer, UNO_QUERY );
2609 else
2611 Reference<XQueriesSupplier> xSup( pConData->xConnection, UNO_QUERY );
2612 if(xSup.is())
2613 xNameAccess = xSup->getQueries();
2616 break;
2618 OUString sStatus(DBA_RES(CommandType::TABLE == nCommandType ? STR_LOADING_TABLE : STR_LOADING_QUERY));
2619 sStatus = sStatus.replaceFirst("$name$", aName);
2620 BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sStatus);
2622 bool bEscapeProcessing = true;
2623 if(xNameAccess.is() && xNameAccess->hasByName(sSimpleName))
2625 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*pEntry).toUInt64());
2626 if ( !pData->xObjectProperties.is() )
2628 Reference<XInterface> xObject;
2629 if(xNameAccess->getByName(sSimpleName) >>= xObject) // remember the table or query object
2631 pData->xObjectProperties.set(xObject, css::uno::UNO_QUERY);
2632 // if the query contains a parameterized statement and preview is enabled we won't get any data.
2633 if ( nCommandType == CommandType::QUERY && xObject.is() )
2635 Reference<XPropertySet> xObjectProps(xObject,UNO_QUERY);
2636 xObjectProps->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bEscapeProcessing;
2637 if ( m_bPreview )
2639 OUString sSql;
2640 xObjectProps->getPropertyValue(PROPERTY_COMMAND) >>= sSql;
2641 Reference< XMultiServiceFactory > xFactory( pConData->xConnection, UNO_QUERY );
2642 if (xFactory.is())
2646 Reference<XSingleSelectQueryAnalyzer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
2647 if ( xAnalyzer.is() )
2649 xAnalyzer->setQuery(sSql);
2650 Reference<XParametersSupplier> xParSup(xAnalyzer,UNO_QUERY);
2651 if ( xParSup->getParameters()->getCount() > 0 )
2653 OUString sFilter = " WHERE " + xAnalyzer->getFilter();
2654 OUString sReplace = sSql.replaceFirst(sFilter, "");
2655 xAnalyzer->setQuery(sReplace);
2656 Reference<XSingleSelectQueryComposer> xComposer(xAnalyzer,UNO_QUERY);
2657 xComposer->setFilter("0=1");
2658 aName = xAnalyzer->getQuery();
2659 nCommandType = CommandType::COMMAND;
2663 catch (Exception&)
2665 DBG_UNHANDLED_EXCEPTION("dbaccess");
2674 OUString sDataSourceName(getDataSourceAccessor(*xConnection));
2675 bSuccess = implLoadAnything( sDataSourceName, aName, nCommandType, bEscapeProcessing, pConData->xConnection );
2676 if ( !bSuccess )
2677 { // clean up
2678 criticalFail();
2681 catch(const SQLException& e)
2683 showError(SQLExceptionInfo(e));
2684 // reset the values
2685 xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
2686 xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
2687 bSuccess = false;
2689 catch(WrappedTargetException& e)
2691 SQLException aSql;
2692 if(e.TargetException >>= aSql)
2693 showError(SQLExceptionInfo(aSql));
2694 else
2695 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implSelect: something strange happened!");
2696 // reset the values
2697 xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
2698 xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
2699 bSuccess = false;
2701 catch(const Exception&)
2703 // reset the values
2704 xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any());
2705 xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any());
2706 bSuccess = false;
2709 return bSuccess;
2712 std::unique_ptr<weld::TreeIter> SbaTableQueryBrowser::getEntryFromContainer(const Reference<XNameAccess>& rxNameAccess)
2714 std::unique_ptr<weld::TreeIter> xContainer;
2716 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2717 std::unique_ptr<weld::TreeIter> xDSLoop(rTreeView.make_iterator(xContainer.get()));
2718 if (rTreeView.get_iter_first(*xDSLoop))
2722 xContainer = rTreeView.make_iterator(xDSLoop.get());
2723 if (rTreeView.iter_children(*xContainer))
2725 // 1st child is queries
2726 DBTreeListUserData* pQueriesData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xContainer).toUInt64());
2727 if (pQueriesData && pQueriesData->xContainer == rxNameAccess)
2728 break;
2730 if (rTreeView.iter_next_sibling(*xContainer))
2732 // 2nd child is tables
2733 DBTreeListUserData* pTablesData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xContainer).toUInt64());
2734 if (pTablesData && pTablesData->xContainer == rxNameAccess)
2735 break;
2738 xContainer.reset();
2740 while (rTreeView.iter_next_sibling(*xDSLoop));
2743 return xContainer;
2746 void SAL_CALL SbaTableQueryBrowser::elementInserted(const ContainerEvent& rEvent)
2748 SolarMutexGuard aSolarGuard;
2750 Reference< XNameAccess > xNames(rEvent.Source, UNO_QUERY);
2751 // first search for a definition container where we can insert this element
2753 std::unique_ptr<weld::TreeIter> xEntry = getEntryFromContainer(xNames);
2754 if (xEntry) // found one
2756 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2757 rTreeView.make_unsorted();
2759 // insert the new entry into the tree
2760 DBTreeListUserData* pContainerData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xEntry).toUInt64());
2761 OSL_ENSURE(pContainerData, "elementInserted: There must be user data for this type!");
2763 DBTreeListUserData* pNewData = new DBTreeListUserData;
2764 bool bIsTable = etTableContainer == pContainerData->eType;
2765 if ( bIsTable )
2767 rEvent.Element >>= pNewData->xObjectProperties;// remember the new element
2768 pNewData->eType = etTableOrView;
2770 else
2772 if (rTreeView.iter_n_children(*xEntry) < xNames->getElementNames().getLength() - 1)
2774 // the item inserts its children on demand, but it has not been expanded yet. So ensure here and
2775 // now that it has all items
2776 populateTree(xNames, *xEntry, etQuery);
2778 pNewData->eType = etQuery;
2780 implAppendEntry(xEntry.get(), ::comphelper::getString(rEvent.Accessor), pNewData);
2782 rTreeView.make_sorted();
2784 else
2785 SbaXDataBrowserController::elementInserted(rEvent);
2788 bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(const OUString& rName, const weld::TreeIter& rContainer)
2790 if (!m_xCurrentlyDisplayed)
2791 return false;
2792 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2793 if (getEntryType(*m_xCurrentlyDisplayed) != getChildType(rContainer))
2794 return false;
2795 if (rTreeView.get_text(*m_xCurrentlyDisplayed) != rName)
2796 return false;
2797 std::unique_ptr<weld::TreeIter> xParent = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
2798 return rTreeView.iter_parent(*xParent) && rTreeView.iter_compare(*xParent, rContainer) == 0;
2801 void SAL_CALL SbaTableQueryBrowser::elementRemoved( const ContainerEvent& _rEvent )
2803 SolarMutexGuard aSolarGuard;
2805 Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
2806 // get the top-level representing the removed data source
2807 // and search for the queries and tables
2808 std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames);
2809 if (xContainer)
2811 // a query or table has been removed
2812 OUString aName = ::comphelper::getString(_rEvent.Accessor);
2814 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2815 if (isCurrentlyDisplayedChanged(aName, *xContainer))
2817 // the element displayed currently has been replaced
2819 // we need to remember the old value
2820 std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
2822 // unload
2823 unloadAndCleanup( false ); // don't dispose the connection
2825 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xTemp).toUInt64());
2826 rTreeView.set_id(*xTemp, OUString());
2827 delete pData; // the data could be null because we have a table which isn't correct
2828 rTreeView.remove(*xTemp);
2830 else
2832 // remove the entry from the model
2833 std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get()));
2834 if (rTreeView.get_iter_first(*xChild))
2838 if (rTreeView.get_text(*xChild) == aName)
2840 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xChild).toUInt64());
2841 rTreeView.set_id(*xChild, OUString());
2842 delete pData;
2843 rTreeView.remove(*xChild);
2844 break;
2846 } while (rTreeView.iter_next_sibling(*xChild));
2850 // maybe the object which is part of the document data source has been removed
2851 checkDocumentDataSource();
2853 else
2854 SbaXDataBrowserController::elementRemoved(_rEvent);
2857 void SAL_CALL SbaTableQueryBrowser::elementReplaced( const ContainerEvent& _rEvent )
2859 SolarMutexGuard aSolarGuard;
2861 Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY);
2862 std::unique_ptr<weld::TreeIter> xContainer = getEntryFromContainer(xNames);
2863 if (xContainer)
2865 // a table or query as been replaced
2866 OUString aName = ::comphelper::getString(_rEvent.Accessor);
2868 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2869 if (isCurrentlyDisplayedChanged(aName, *xContainer))
2870 { // the element displayed currently has been replaced
2872 // we need to remember the old value
2873 std::unique_ptr<weld::TreeIter> xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
2874 unloadAndCleanup( false ); // don't dispose the connection
2876 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xTemp).toUInt64());
2877 if (pData)
2879 if ( etTableOrView == pData->eType )
2881 // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
2882 _rEvent.Element >>= pData->xObjectProperties; // remember the new element
2884 else
2886 rTreeView.set_id(*xTemp, OUString());
2887 delete pData;
2891 else
2893 // find the entry for this name
2894 std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xContainer.get()));
2895 if (rTreeView.get_iter_first(*xChild))
2899 if (rTreeView.get_text(*xChild) == aName)
2901 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xChild).toUInt64());
2902 if (pData)
2904 if ( etTableOrView == pData->eType )
2906 // only insert userdata when we have a table because the query is only a commanddefinition object and not a query
2907 _rEvent.Element >>= pData->xObjectProperties; // remember the new element
2909 else
2911 rTreeView.set_id(*xChild, OUString());
2912 delete pData;
2915 break;
2917 } while (rTreeView.iter_next_sibling(*xChild));
2921 // maybe the object which is part of the document data source has been removed
2922 checkDocumentDataSource();
2924 else if (xNames.get() == m_xDatabaseContext.get())
2925 { // a datasource has been replaced in the context
2926 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::elementReplaced: no support for replaced data sources!");
2927 // very suspicious: the database context should not allow to replace data source, only to register
2928 // and revoke them
2930 else
2931 SbaXDataBrowserController::elementReplaced(_rEvent);
2934 void SbaTableQueryBrowser::impl_releaseConnection( SharedConnection& _rxConnection )
2936 // remove as event listener
2937 Reference< XComponent > xComponent( _rxConnection, UNO_QUERY );
2938 if ( xComponent.is() )
2940 Reference< XEventListener > xListener( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY );
2941 xComponent->removeEventListener( xListener );
2946 // temporary (hopefully!) hack for #i55274#
2947 Reference< XFlushable > xFlush( _rxConnection, UNO_QUERY );
2948 if ( xFlush.is() )
2949 xFlush->flush();
2951 catch( const Exception& )
2953 DBG_UNHANDLED_EXCEPTION("dbaccess");
2956 // clear
2957 _rxConnection.clear();
2958 // will implicitly dispose if we have the ownership, since xConnection is a SharedConnection
2961 void SbaTableQueryBrowser::disposeConnection(const weld::TreeIter* pDSEntry)
2963 OSL_ENSURE( pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" );
2964 OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" );
2966 if (pDSEntry)
2968 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2969 DBTreeListUserData* pTreeListData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*pDSEntry).toUInt64());
2970 if (pTreeListData)
2971 impl_releaseConnection(pTreeListData->xConnection);
2975 void SbaTableQueryBrowser::closeConnection(weld::TreeIter& rDSEntry, bool _bDisposeConnection)
2977 OSL_ENSURE(impl_isDataSourceEntry(&rDSEntry), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!");
2979 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
2981 // if one of the entries of the given DS is displayed currently, unload the form
2982 if (m_xCurrentlyDisplayed)
2984 std::unique_ptr<weld::TreeIter> xRoot = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get());
2985 if (rTreeView.iter_compare(*xRoot, rDSEntry) == 0)
2986 unloadAndCleanup(_bDisposeConnection);
2989 // collapse the query/table container
2990 std::unique_ptr<weld::TreeIter> xContainers(rTreeView.make_iterator(&rDSEntry));
2991 if (rTreeView.iter_children(*xContainers))
2995 std::unique_ptr<weld::TreeIter> xElements(rTreeView.make_iterator(xContainers.get()));
2996 if (rTreeView.iter_children(*xElements))
2998 rTreeView.collapse_row(*xContainers);
2999 // and delete their children (they are connection-relative)
3000 bool bElements = true;
3001 while (bElements)
3003 std::unique_ptr<weld::TreeIter> xRemove(rTreeView.make_iterator(xElements.get()));
3004 bElements = rTreeView.iter_next_sibling(*xElements);
3005 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xRemove).toUInt64());
3006 rTreeView.set_id(*xRemove, OUString());
3007 delete pData;
3008 rTreeView.remove(*xRemove);
3012 while (rTreeView.iter_next_sibling(*xContainers));
3015 // collapse the entry itself
3016 rTreeView.collapse_row(rDSEntry);
3018 // dispose/reset the connection
3019 if ( _bDisposeConnection )
3020 disposeConnection(&rDSEntry);
3023 void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection )
3025 if (!m_xCurrentlyDisplayed)
3026 // nothing to do
3027 return;
3029 std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get());
3031 // de-select the path for the currently displayed table/query
3032 selectPath(m_xCurrentlyDisplayed.get(), false);
3033 m_xCurrentlyDisplayed.reset();
3037 // get the active connection. We need to dispose it.
3039 // unload the form
3040 Reference< XLoadable > xLoadable = getLoadable();
3041 if (xLoadable->isLoaded())
3042 xLoadable->unload();
3044 // clear the grid control
3045 Reference< XNameContainer > xConta(getControlModel(),UNO_QUERY);
3046 clearGridColumns(xConta);
3048 // dispose the connection
3049 if(_bDisposeConnection)
3050 disposeConnection(xDSEntry.get());
3052 catch(SQLException& e)
3054 showError(SQLExceptionInfo(e));
3056 catch(WrappedTargetException& e)
3058 SQLException aSql;
3059 if(e.TargetException >>= aSql)
3060 showError(SQLExceptionInfo(aSql));
3061 else
3062 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: something strange happened!");
3064 catch(const Exception&)
3066 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: could not reset the form");
3070 namespace
3072 Reference< XInterface > lcl_getDataSource( const Reference< XDatabaseContext >& _rxDatabaseContext,
3073 const OUString& _rDataSourceName, const Reference< XConnection >& _rxConnection )
3075 Reference< XDataSource > xDataSource;
3078 if ( !_rDataSourceName.isEmpty() && _rxDatabaseContext->hasByName( _rDataSourceName ) )
3079 xDataSource.set( _rxDatabaseContext->getByName( _rDataSourceName ), UNO_QUERY_THROW );
3081 if ( !xDataSource.is() )
3083 Reference< XChild > xConnAsChild( _rxConnection, UNO_QUERY );
3084 if ( xConnAsChild.is() )
3085 xDataSource.set( xConnAsChild->getParent(), UNO_QUERY_THROW );
3088 catch( const Exception& )
3090 DBG_UNHANDLED_EXCEPTION("dbaccess");
3092 return xDataSource.get();
3096 void SbaTableQueryBrowser::impl_initialize()
3098 SolarMutexGuard aGuard;
3099 // doin' a lot of VCL stuff here -> lock the SolarMutex
3101 // first initialize the parent
3102 SbaXDataBrowserController::impl_initialize();
3104 Reference<XConnection> xForeignConnection;
3105 Reference< XFrame > xFrame;
3107 OUString aTableName, aCatalogName, aSchemaName;
3109 bool bEscapeProcessing = true;
3110 sal_Int32 nInitialDisplayCommandType = CommandType::COMMAND;
3111 OUString sInitialDataSourceName;
3112 OUString sInitialCommand;
3114 const NamedValueCollection& rArguments( getInitParams() );
3116 rArguments.get_ensureType( PROPERTY_DATASOURCENAME, sInitialDataSourceName );
3117 rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, nInitialDisplayCommandType );
3118 rArguments.get_ensureType( PROPERTY_COMMAND, sInitialCommand );
3119 rArguments.get_ensureType( PROPERTY_ACTIVE_CONNECTION, xForeignConnection );
3120 rArguments.get_ensureType( PROPERTY_UPDATE_CATALOGNAME, aCatalogName );
3121 rArguments.get_ensureType( PROPERTY_UPDATE_SCHEMANAME, aSchemaName );
3122 rArguments.get_ensureType( PROPERTY_UPDATE_TABLENAME, aTableName );
3123 rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing );
3124 rArguments.get_ensureType( "Frame", xFrame );
3125 rArguments.get_ensureType( PROPERTY_SHOWMENU, m_bShowMenu );
3127 // disable the browser if either of ShowTreeViewButton (compatibility name) or EnableBrowser
3128 // is present and set to FALSE
3129 bool bDisableBrowser = !rArguments.getOrDefault( "ShowTreeViewButton", true ) // compatibility name
3130 || !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true );
3131 OSL_ENSURE( !rArguments.has( "ShowTreeViewButton" ),
3132 "SbaTableQueryBrowser::impl_initialize: ShowTreeViewButton is superseded by EnableBrowser!" );
3133 m_bEnableBrowser = !bDisableBrowser;
3135 // hide the tree view it is disabled in general, or if the settings tell to hide it initially
3136 bool bHideTreeView = ( !m_bEnableBrowser )
3137 || !rArguments.getOrDefault( "ShowTreeView", true ) // compatibility name
3138 || !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true );
3139 OSL_ENSURE( !rArguments.has( "ShowTreeView" ),
3140 "SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" );
3142 if ( bHideTreeView )
3143 hideExplorer();
3144 else
3145 showExplorer();
3147 if ( m_bPreview )
3151 Sequence< OUString> aProperties(5);
3152 Sequence< Any> aValues(5);
3154 OUString* pStringIter = aProperties.getArray();
3155 Any* pValueIter = aValues.getArray();
3156 *pStringIter++ = "AlwaysShowCursor";
3157 *pValueIter++ <<= false;
3158 *pStringIter++ = PROPERTY_BORDER;
3159 *pValueIter++ <<= sal_Int16(0);
3161 *pStringIter++ = "HasNavigationBar";
3162 *pValueIter++ <<= false;
3163 *pStringIter++ = "HasRecordMarker";
3164 *pValueIter++ <<= false;
3166 *pStringIter++ = "Tabstop";
3167 *pValueIter++ <<= false;
3169 Reference< XMultiPropertySet > xFormMultiSet(getFormComponent(), UNO_QUERY);
3170 if ( xFormMultiSet.is() )
3171 xFormMultiSet->setPropertyValues(aProperties, aValues);
3173 catch(const Exception&)
3175 DBG_UNHANDLED_EXCEPTION("dbaccess");
3179 // are we loaded into a (sub)frame of an embedded document (i.e. a form belonging to a database
3180 // document)?
3181 bool bSubFrameOfEmbeddedDocument = false;
3182 if ( xFrame.is() )
3184 Reference<XFramesSupplier> xSup = xFrame->getCreator();
3185 Reference<XController> xCont = xSup.is() ? xSup->getController() : Reference<XController>();
3187 bSubFrameOfEmbeddedDocument = xCont.is() && ::dbtools::isEmbeddedInDatabase( xCont->getModel(), xForeignConnection );
3190 // if we have a connection at this point, it was either passed from outside, our
3191 // determined from an outer DB document. In both cases, do not dispose it later on.
3192 SharedConnection xConnection( xForeignConnection, SharedConnection::NoTakeOwnership );
3194 // should we display all registered databases in the left hand side tree?
3195 // or only *one* special?
3196 bool bLimitedTreeEntries = false;
3197 // if we're part of a frame which is a secondary frame of a database document, then only
3198 // display the database for this document, not all registered ones
3199 bLimitedTreeEntries |= bSubFrameOfEmbeddedDocument;
3200 // if the tree view is not to be displayed at all, then only display the data source
3201 // which was given as initial selection
3202 bLimitedTreeEntries |= !m_bEnableBrowser;
3204 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3205 rTreeView.make_unsorted();
3207 if ( bLimitedTreeEntries )
3209 if ( xConnection.is() )
3211 startConnectionListening( xConnection );
3213 // if no initial name was given, try to obtain one from the data source
3214 if ( sInitialDataSourceName.isEmpty() )
3216 Reference< XChild > xChild( xConnection, UNO_QUERY );
3217 Reference< XPropertySet > xDataSourceProperties;
3218 if ( xChild.is() )
3219 xDataSourceProperties.set(xChild->getParent(), css::uno::UNO_QUERY);
3220 if ( xDataSourceProperties.is() )
3224 OSL_VERIFY( xDataSourceProperties->getPropertyValue( PROPERTY_NAME ) >>= sInitialDataSourceName );
3226 catch( const Exception& )
3228 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: a connection parent which does not have a 'Name'!??" );
3234 implAddDatasource( sInitialDataSourceName, xConnection );
3236 std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator());
3237 if (rTreeView.get_iter_first(*xFirst))
3238 rTreeView.expand_row(*xFirst);
3240 else
3241 initializeTreeModel();
3243 rTreeView.make_sorted();
3245 if ( m_bEnableBrowser )
3247 m_aDocScriptSupport = ::std::optional< bool >( false );
3249 else
3251 // we are not used as "browser", but as mere view for a single table/query/command. In particular,
3252 // there is a specific database document which we belong to.
3253 Reference< XOfficeDatabaseDocument > xDocument( getDataSourceOrModel(
3254 lcl_getDataSource( m_xDatabaseContext, sInitialDataSourceName, xConnection ) ), UNO_QUERY );
3255 m_aDocScriptSupport = ::std::optional< bool >( Reference< XEmbeddedScripts >( xDocument, UNO_QUERY ).is() );
3258 if ( implSelect( sInitialDataSourceName, sInitialCommand, nInitialDisplayCommandType, bEscapeProcessing, xConnection, true ) )
3262 Reference< XPropertySet > xRowSetProps(getRowSet(), UNO_QUERY);
3263 xRowSetProps->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,makeAny(aCatalogName));
3264 xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,makeAny(aSchemaName));
3265 xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,makeAny(aTableName));
3268 catch(const Exception&)
3270 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: could not set the update related names!");
3274 InvalidateAll();
3277 bool SbaTableQueryBrowser::haveExplorer() const
3279 return m_pTreeView && m_pTreeView->IsVisible();
3282 void SbaTableQueryBrowser::hideExplorer()
3284 if (!haveExplorer())
3285 return;
3286 if (!getBrowserView())
3287 return;
3289 m_pTreeView->Hide();
3290 m_pSplitter->Hide();
3291 getBrowserView()->Resize();
3293 InvalidateFeature(ID_BROWSER_EXPLORER);
3296 void SbaTableQueryBrowser::showExplorer()
3298 if (haveExplorer())
3299 return;
3301 if (!getBrowserView())
3302 return;
3304 m_pTreeView->Show();
3305 m_pSplitter->Show();
3306 getBrowserView()->Resize();
3308 InvalidateFeature(ID_BROWSER_EXPLORER);
3311 bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection)
3313 std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry);
3314 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3315 DBTreeListUserData* pDSData =
3316 xDSEntry
3317 ? reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry).toUInt64())
3318 : nullptr;
3320 return ensureConnection(xDSEntry.get(), pDSData, rConnection);
3323 std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor(const weld::TreeIter* pAnyEntry)
3325 std::unique_ptr<ImageProvider> xImageProvider(new ImageProvider);
3326 SharedConnection xConnection;
3327 if (getExistentConnectionFor(pAnyEntry, xConnection))
3328 xImageProvider.reset(new ImageProvider(xConnection));
3329 return xImageProvider;
3332 bool SbaTableQueryBrowser::getExistentConnectionFor(const weld::TreeIter* pAnyEntry, SharedConnection& rConnection)
3334 std::unique_ptr<weld::TreeIter> xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry);
3335 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3336 DBTreeListUserData* pDSData =
3337 xDSEntry
3338 ? reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xDSEntry).toUInt64())
3339 : nullptr;
3340 if (pDSData)
3341 rConnection = pDSData->xConnection;
3342 return rConnection.is();
3345 bool SbaTableQueryBrowser::impl_isDataSourceEntry(const weld::TreeIter* pEntry) const
3347 if (!pEntry)
3348 return false;
3349 std::unique_ptr<weld::TreeIter> xRoot(m_pTreeView->GetRootLevelParent(pEntry));
3350 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3351 return rTreeView.iter_compare(*xRoot, *pEntry) == 0;
3354 bool SbaTableQueryBrowser::ensureConnection(const weld::TreeIter* pDSEntry, void* pDSData, SharedConnection& rConnection)
3356 OSL_ENSURE( impl_isDataSourceEntry( pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" );
3357 if (pDSEntry)
3359 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3360 OUString aDSName = rTreeView.get_text(*pDSEntry);
3362 DBTreeListUserData* pTreeListData = static_cast<DBTreeListUserData*>(pDSData);
3363 if ( pTreeListData )
3364 rConnection = pTreeListData->xConnection;
3366 if ( !rConnection.is() && pTreeListData )
3368 // show the "connecting to ..." status
3369 OUString sConnecting(DBA_RES(STR_CONNECTING_DATASOURCE));
3370 sConnecting = sConnecting.replaceFirst("$name$", aDSName);
3371 BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sConnecting);
3373 // build a string showing context information in case of error
3374 OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE));
3375 sConnectingContext = sConnectingContext.replaceFirst("$name$", aDSName);
3377 // connect
3378 rConnection.reset(
3379 connect(getDataSourceAccessor(*pDSEntry), sConnectingContext, nullptr),
3380 SharedConnection::TakeOwnership);
3382 // remember the connection
3383 pTreeListData->xConnection = rConnection;
3386 return rConnection.is();
3389 int SbaTableQueryBrowser::OnTreeEntryCompare(const weld::TreeIter& rLHS, const weld::TreeIter& rRHS)
3391 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3393 // we want the table entry and the end so we have to do a check
3394 if (isContainer(rRHS))
3396 // don't use getEntryType (directly or indirectly) for the LHS:
3397 // LHS is currently being inserted, so it is not "completely valid" at the moment
3399 const EntryType eRight = getEntryType(rRHS);
3400 if (etTableContainer == eRight)
3401 // every other container should be placed _before_ the bookmark container
3402 return -1;
3404 const OUString sLeft = rTreeView.get_text(rLHS);
3406 EntryType eLeft = etTableContainer;
3407 if (DBA_RES(RID_STR_TABLES_CONTAINER) == sLeft)
3408 eLeft = etTableContainer;
3409 else if (DBA_RES(RID_STR_QUERIES_CONTAINER) == sLeft)
3410 eLeft = etQueryContainer;
3412 if ( eLeft == eRight )
3413 return 0;
3415 if ( ( eLeft == etTableContainer ) && ( eRight == etQueryContainer ) )
3416 return 1;
3418 if ( ( eLeft == etQueryContainer ) && ( eRight == etTableContainer ) )
3419 return -1;
3421 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnTreeEntryCompare: unexpected case!" );
3422 return 0;
3425 OUString sLeftText = rTreeView.get_text(rLHS);
3426 OUString sRightText = rTreeView.get_text(rRHS);
3428 sal_Int32 nCompareResult = 0; // equal by default
3430 if (m_xCollator.is())
3434 nCompareResult = m_xCollator->compareString(sLeftText, sRightText);
3436 catch(const Exception&)
3440 else
3441 // default behaviour if we do not have a collator -> do the simple string compare
3442 nCompareResult = sLeftText.compareTo(sRightText);
3444 return nCompareResult;
3447 void SbaTableQueryBrowser::implAdministrate(weld::TreeIter& rApplyTo)
3451 // get the desktop object
3452 Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() );
3454 // the initial selection
3455 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3456 std::unique_ptr<weld::TreeIter> xTopLevelSelected(rTreeView.make_iterator(&rApplyTo));
3458 while (rTreeView.get_iter_depth(*xTopLevelSelected))
3459 rTreeView.iter_parent(*xTopLevelSelected);
3461 OUString sInitialSelection = getDataSourceAccessor(*xTopLevelSelected);
3463 Reference< XDataSource > xDataSource( getDataSourceByName( sInitialSelection, getFrameWeld(), getORB(), nullptr ) );
3464 Reference< XModel > xDocumentModel( getDataSourceOrModel( xDataSource ), UNO_QUERY );
3466 if ( xDocumentModel.is() )
3468 Reference< XInteractionHandler2 > xInteractionHandler(
3469 InteractionHandler::createWithParent(getORB(), nullptr) );
3471 ::comphelper::NamedValueCollection aLoadArgs;
3472 aLoadArgs.put( "Model", xDocumentModel );
3473 aLoadArgs.put( "InteractionHandler", xInteractionHandler );
3474 aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
3476 Sequence< PropertyValue > aLoadArgPV;
3477 aLoadArgs >>= aLoadArgPV;
3479 xFrameLoader->loadComponentFromURL(
3480 xDocumentModel->getURL(),
3481 "_default",
3482 FrameSearchFlag::ALL | FrameSearchFlag::GLOBAL,
3483 aLoadArgPV
3487 catch( const Exception& )
3489 DBG_UNHANDLED_EXCEPTION("dbaccess");
3493 bool SbaTableQueryBrowser::requestQuickHelp(const void* pUserData, OUString& rText) const
3495 const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pUserData);
3496 if (pData->eType == etDatasource && !pData->sAccessor.isEmpty())
3498 rText = ::svt::OFileNotation(pData->sAccessor).get( ::svt::OFileNotation::N_SYSTEM);
3499 return true;
3501 return false;
3504 OUString SbaTableQueryBrowser::getContextMenuResourceName() const
3506 return "explorer";
3509 IController& SbaTableQueryBrowser::getCommandController()
3511 return *this;
3514 ::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors()
3516 return &m_aContextMenuInterceptors;
3519 Any SbaTableQueryBrowser::getCurrentSelection(weld::TreeView& rControl) const
3521 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3523 OSL_PRECOND( &rTreeView == &rControl,
3524 "SbaTableQueryBrowser::getCurrentSelection: where does this come from?" );
3526 if (&rTreeView != &rControl)
3527 return Any();
3529 std::unique_ptr<weld::TreeIter> xSelected(rTreeView.make_iterator());
3530 if (!rTreeView.get_selected(xSelected.get()))
3531 return Any();
3533 NamedDatabaseObject aSelectedObject;
3534 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xSelected).toUInt64());
3535 aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType );
3537 switch ( aSelectedObject.Type )
3539 case DatabaseObject::QUERY:
3540 case DatabaseObject::TABLE:
3541 aSelectedObject.Name = rTreeView.get_text(*xSelected);
3542 break;
3544 case DatabaseObjectContainer::DATA_SOURCE:
3545 case DatabaseObjectContainer::QUERIES:
3546 case DatabaseObjectContainer::TABLES:
3547 aSelectedObject.Name = getDataSourceAccessor(*xSelected);
3548 break;
3550 default:
3551 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" );
3552 break;
3555 return makeAny( aSelectedObject );
3558 vcl::Window* SbaTableQueryBrowser::getMenuParent() const
3560 return m_pTreeView;
3563 void SbaTableQueryBrowser::adjustMenuPosition(const weld::TreeView&, ::Point&) const
3567 bool SbaTableQueryBrowser::implGetQuerySignature( OUString& _rCommand, bool& _bEscapeProcessing )
3569 _rCommand.clear();
3570 _bEscapeProcessing = false;
3574 // contain the dss (data source signature) of the form
3575 OUString sDataSourceName;
3576 OUString sCommand;
3577 sal_Int32 nCommandType = CommandType::COMMAND;
3578 Reference< XPropertySet > xRowsetProps( getRowSet(), UNO_QUERY );
3579 ODataAccessDescriptor aDesc( xRowsetProps );
3580 sDataSourceName = aDesc.getDataSource();
3581 aDesc[ DataAccessDescriptorProperty::Command ] >>= sCommand;
3582 aDesc[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
3584 // do we need to do anything?
3585 if ( CommandType::QUERY != nCommandType )
3586 return false;
3588 // get the query object
3589 Reference< XQueryDefinitionsSupplier > xSuppQueries;
3590 Reference< XNameAccess > xQueries;
3591 Reference< XPropertySet > xQuery;
3592 m_xDatabaseContext->getByName( sDataSourceName ) >>= xSuppQueries;
3593 if ( xSuppQueries.is() )
3594 xQueries = xSuppQueries->getQueryDefinitions();
3595 if ( xQueries.is() )
3596 xQueries->getByName( sCommand ) >>= xQuery;
3597 OSL_ENSURE( xQuery.is(), "SbaTableQueryBrowser::implGetQuerySignature: could not retrieve the query object!" );
3599 // get the two properties we need
3600 if ( xQuery.is() )
3602 xQuery->getPropertyValue( PROPERTY_COMMAND ) >>= _rCommand;
3603 _bEscapeProcessing = ::cppu::any2bool( xQuery->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) );
3604 return true;
3607 catch( const Exception& )
3609 DBG_UNHANDLED_EXCEPTION("dbaccess");
3612 return false;
3615 void SbaTableQueryBrowser::frameAction(const css::frame::FrameActionEvent& aEvent)
3617 if (aEvent.Frame == m_xCurrentFrameParent)
3619 if(aEvent.Action == FrameAction_COMPONENT_DETACHING)
3620 implRemoveStatusListeners();
3621 else if (aEvent.Action == FrameAction_COMPONENT_REATTACHED)
3622 connectExternalDispatches();
3624 else
3625 SbaXDataBrowserController::frameAction(aEvent);
3629 void SbaTableQueryBrowser::clearGridColumns(const Reference< XNameContainer >& _xColContainer)
3631 // first we have to clear the grid
3632 Reference< XInterface > xColumn;
3633 const Sequence<OUString> aColNames = _xColContainer->getElementNames();
3634 for (const OUString& rName : aColNames)
3636 _xColContainer->getByName(rName) >>= xColumn;
3637 _xColContainer->removeByName(rName);
3638 ::comphelper::disposeComponent(xColumn);
3642 void SbaTableQueryBrowser::loadMenu(const Reference< XFrame >& _xFrame)
3644 if ( m_bShowMenu )
3646 OGenericUnoController::loadMenu(_xFrame);
3648 else if ( !m_bPreview )
3650 Reference< css::frame::XLayoutManager > xLayoutManager = getLayoutManager(_xFrame);
3652 if ( xLayoutManager.is() )
3654 xLayoutManager->lock();
3655 xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
3656 xLayoutManager->unlock();
3657 xLayoutManager->doLayout();
3659 onLoadedMenu( xLayoutManager );
3663 OUString SbaTableQueryBrowser::getPrivateTitle() const
3665 OUString sTitle;
3666 if (m_xCurrentlyDisplayed)
3668 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3669 std::unique_ptr<weld::TreeIter> xContainer = rTreeView.make_iterator(m_xCurrentlyDisplayed.get());
3670 if (!rTreeView.iter_parent(*xContainer))
3671 return OUString();
3672 // get the entry for the datasource
3673 std::unique_ptr<weld::TreeIter> xConnection = implGetConnectionEntry(*xContainer);
3674 OUString sName = rTreeView.get_text(*m_xCurrentlyDisplayed);
3675 sTitle = GetEntryText(*xConnection);
3676 INetURLObject aURL(sTitle);
3677 if ( aURL.GetProtocol() != INetProtocol::NotValid )
3678 sTitle = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset);
3679 if ( !sName.isEmpty() )
3681 sName += " - " + sTitle;
3682 sTitle = sName;
3686 return sTitle;
3689 bool SbaTableQueryBrowser::preReloadForm()
3691 bool bIni = false;
3692 if (!m_xCurrentlyDisplayed)
3694 // switch the grid to design mode while loading
3695 getBrowserView()->getGridControl()->setDesignMode(true);
3696 // we had an invalid statement so we need to connect the column models
3697 Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY);
3698 svx::ODataAccessDescriptor aDesc(xRowSetProps);
3699 // extract the props
3700 OUString sDataSource;
3701 OUString sCommand;
3702 sal_Int32 nCommandType = CommandType::COMMAND;
3703 bool bEscapeProcessing = true;
3704 extractDescriptorProps(aDesc, sDataSource, sCommand, nCommandType, bEscapeProcessing);
3705 if ( !sDataSource.isEmpty() && !sCommand.isEmpty() && (-1 != nCommandType) )
3707 m_xCurrentlyDisplayed = getObjectEntry(sDataSource, sCommand, nCommandType, nullptr, nullptr);
3708 bIni = true;
3711 return bIni;
3714 void SbaTableQueryBrowser::postReloadForm()
3716 InitializeGridModel(getFormComponent());
3717 LoadFinished(true);
3720 Reference< XEmbeddedScripts > SAL_CALL SbaTableQueryBrowser::getScriptContainer()
3722 // update our database document
3723 Reference< XModel > xDocument;
3726 Reference< XPropertySet > xCursorProps( getRowSet(), UNO_QUERY_THROW );
3727 Reference< XConnection > xConnection( xCursorProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY );
3728 if ( xConnection.is() )
3730 Reference< XChild > xChild( xConnection, UNO_QUERY_THROW );
3731 Reference< XDocumentDataSource > xDataSource( xChild->getParent(), UNO_QUERY_THROW );
3732 xDocument.set( xDataSource->getDatabaseDocument(), UNO_QUERY_THROW );
3735 catch( const Exception& )
3737 DBG_UNHANDLED_EXCEPTION("dbaccess");
3739 Reference< XEmbeddedScripts > xScripts( xDocument, UNO_QUERY );
3740 OSL_ENSURE( xScripts.is() || !xDocument.is(),
3741 "SbaTableQueryBrowser::getScriptContainer: invalid database document!" );
3742 return xScripts;
3745 void SAL_CALL SbaTableQueryBrowser::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
3747 if ( Interceptor.is() )
3748 m_aContextMenuInterceptors.addInterface( Interceptor );
3751 void SAL_CALL SbaTableQueryBrowser::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
3753 if ( Interceptor.is() )
3754 m_aContextMenuInterceptors.removeInterface( Interceptor );
3757 void SAL_CALL SbaTableQueryBrowser::registeredDatabaseLocation( const DatabaseRegistrationEvent& Event )
3759 SolarMutexGuard aGuard;
3760 implAddDatasource( Event.Name, SharedConnection() );
3763 void SbaTableQueryBrowser::impl_cleanupDataSourceEntry(const OUString& rDataSourceName)
3765 // get the top-level representing the removed data source
3766 weld::TreeView& rTreeView = m_pTreeView->GetWidget();
3767 std::unique_ptr<weld::TreeIter> xDataSourceEntry(rTreeView.make_iterator());
3768 bool bDataSourceEntry = rTreeView.get_iter_first(*xDataSourceEntry);
3769 while (bDataSourceEntry)
3771 if (rTreeView.get_text(*xDataSourceEntry) == rDataSourceName)
3772 break;
3773 bDataSourceEntry = rTreeView.iter_next_sibling(*xDataSourceEntry);
3776 OSL_ENSURE( bDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" );
3777 if (!bDataSourceEntry)
3778 return;
3780 if (isSelected(*xDataSourceEntry))
3782 // a table or query belonging to the deleted data source is currently being displayed.
3783 unloadAndCleanup();
3786 std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(xDataSourceEntry.get()));
3787 if (rTreeView.iter_children(*xChild))
3791 // delete any user data of the child entries of the to-be-removed entry
3792 const DBTreeListUserData* pData = reinterpret_cast<const DBTreeListUserData*>(rTreeView.get_id(*xChild).toUInt64());
3793 rTreeView.set_id(*xChild, OUString());
3794 delete pData;
3795 } while (rTreeView.iter_next_sibling(*xChild));
3798 // remove the entry
3799 DBTreeListUserData* pData = reinterpret_cast<DBTreeListUserData*>(rTreeView.get_id(*xDataSourceEntry).toUInt64());
3800 rTreeView.set_id(*xDataSourceEntry, OUString());
3801 delete pData;
3802 rTreeView.remove(*xDataSourceEntry);
3805 void SAL_CALL SbaTableQueryBrowser::revokedDatabaseLocation( const DatabaseRegistrationEvent& Event )
3807 SolarMutexGuard aGuard;
3809 impl_cleanupDataSourceEntry( Event.Name );
3811 // maybe the object which is part of the document data source has been removed
3812 checkDocumentDataSource();
3815 void SAL_CALL SbaTableQueryBrowser::changedDatabaseLocation( const DatabaseRegistrationEvent& Event )
3817 SolarMutexGuard aGuard;
3819 // in case the data source was expanded, and connected, we need to clean it up
3820 // for simplicity, just do as if the data source were completely removed and re-added
3821 impl_cleanupDataSourceEntry( Event.Name );
3822 implAddDatasource( Event.Name, SharedConnection() );
3825 } // namespace dbaui
3827 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */