1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <browserids.hxx> 21 #include <core_resource.hxx> 22 #include <helpids.h> 23 #include <dbexchange.hxx> 24 #include <dbtreelistbox.hxx> 25 #include "dbtreemodel.hxx" 26 #include "dbtreeview.hxx" 27 #include <dbu_reghelper.hxx> 28 #include <stringconstants.hxx> 29 #include <strings.hrc> 30 #include <dlgsave.hxx> 31 #include <uiservices.hxx> 32 #include <HtmlReader.hxx> 33 #include <imageprovider.hxx> 34 #include <listviewitems.hxx> 35 #include <QEnumTypes.hxx> 36 #include <RtfReader.hxx> 37 #include <sbagrid.hrc> 38 #include <sbagrid.hxx> 39 #include <sqlmessage.hxx> 40 #include <TokenWriter.hxx> 41 #include <UITools.hxx> 42 #include <unodatbr.hxx> 43 #include <WColumnSelect.hxx> 44 #include <WCopyTable.hxx> 45 #include <WCPage.hxx> 46 #include <WExtendPages.hxx> 47 #include <WNameMatch.hxx> 48 49 #include <com/sun/star/awt/LineEndFormat.hpp> 50 #include <com/sun/star/awt/MouseWheelBehavior.hpp> 51 #include <com/sun/star/awt/TextAlign.hpp> 52 #include <com/sun/star/awt/VisualEffect.hpp> 53 #include <com/sun/star/beans/NamedValue.hpp> 54 #include <com/sun/star/beans/PropertyValue.hpp> 55 #include <com/sun/star/container/XNameContainer.hpp> 56 #include <com/sun/star/form/XForm.hpp> 57 #include <com/sun/star/form/XGridColumnFactory.hpp> 58 #include <com/sun/star/form/XLoadable.hpp> 59 #include <com/sun/star/form/XReset.hpp> 60 #include <com/sun/star/frame/Desktop.hpp> 61 #include <com/sun/star/frame/FrameSearchFlag.hpp> 62 #include <com/sun/star/frame/XLayoutManager.hpp> 63 #include <com/sun/star/lang/DisposedException.hpp> 64 #include <com/sun/star/i18n/Collator.hpp> 65 #include <com/sun/star/sdb/CommandType.hpp> 66 #include <com/sun/star/sdb/SQLContext.hpp> 67 #include <com/sun/star/sdb/XBookmarksSupplier.hpp> 68 #include <com/sun/star/sdb/XCompletedConnection.hpp> 69 #include <com/sun/star/sdb/XDatabaseContext.hpp> 70 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp> 71 #include <com/sun/star/sdb/XDocumentDataSource.hpp> 72 #include <com/sun/star/sdb/XParametersSupplier.hpp> 73 #include <com/sun/star/sdb/XQueriesSupplier.hpp> 74 #include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp> 75 #include <com/sun/star/sdb/XResultSetAccess.hpp> 76 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> 77 #include <com/sun/star/sdb/application/NamedDatabaseObject.hpp> 78 #include <com/sun/star/sdbc/ColumnValue.hpp> 79 #include <com/sun/star/sdbc/DataType.hpp> 80 #include <com/sun/star/sdbc/FetchDirection.hpp> 81 #include <com/sun/star/sdbc/SQLWarning.hpp> 82 #include <com/sun/star/sdbc/XDataSource.hpp> 83 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> 84 #include <com/sun/star/sdbc/XWarningsSupplier.hpp> 85 #include <com/sun/star/sdbcx/Privilege.hpp> 86 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> 87 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> 88 #include <com/sun/star/sdbcx/XDrop.hpp> 89 #include <com/sun/star/sdbcx/XTablesSupplier.hpp> 90 #include <com/sun/star/sdbcx/XViewsSupplier.hpp> 91 #include <com/sun/star/task/InteractionHandler.hpp> 92 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> 93 #include <com/sun/star/util/XFlushable.hpp> 94 #include <com/sun/star/document/MacroExecMode.hpp> 95 #include <com/sun/star/ui/XContextMenuInterceptor.hpp> 96 97 #include <comphelper/processfactory.hxx> 98 #include <comphelper/extract.hxx> 99 #include <comphelper/sequence.hxx> 100 #include <comphelper/types.hxx> 101 #include <connectivity/dbexception.hxx> 102 #include <cppuhelper/exc_hlp.hxx> 103 #include <cppuhelper/typeprovider.hxx> 104 #include <sfx2/app.hxx> 105 #include <sfx2/dispatch.hxx> 106 #include <sot/storage.hxx> 107 #include <svl/filenotation.hxx> 108 #include <svl/intitem.hxx> 109 #include <unotools/moduleoptions.hxx> 110 #include <vcl/svlbitm.hxx> 111 #include <vcl/treelistbox.hxx> 112 #include <vcl/treelistentry.hxx> 113 #include <svx/algitem.hxx> 114 #include <svx/dataaccessdescriptor.hxx> 115 #include <svx/databaseregistrationui.hxx> 116 #include <toolkit/helper/vclunohelper.hxx> 117 #include <tools/diagnose_ex.h> 118 #include <osl/diagnose.h> 119 #include <sal/log.hxx> 120 #include <tools/multisel.hxx> 121 #include <tools/urlobj.hxx> 122 #include <unotools/confignode.hxx> 123 #include <vcl/split.hxx> 124 #include <vcl/stdtext.hxx> 125 #include <vcl/svapp.hxx> 126 #include <vcl/toolbox.hxx> 127 #include <vcl/waitobj.hxx> 128 #include <vcl/wrkwin.hxx> 129 #include <vcl/settings.hxx> 130 131 #include <memory> 132 133 using namespace ::com::sun::star::uno; 134 using namespace ::com::sun::star::awt; 135 using namespace ::com::sun::star::sdb; 136 using namespace ::com::sun::star::sdb::application; 137 using namespace ::com::sun::star::sdbc; 138 using namespace ::com::sun::star::sdbcx; 139 using namespace ::com::sun::star::beans; 140 using namespace ::com::sun::star::util; 141 using namespace ::com::sun::star::frame; 142 using namespace ::com::sun::star::container; 143 using namespace ::com::sun::star::lang; 144 using namespace ::com::sun::star::ui::dialogs; 145 using namespace ::com::sun::star::task; 146 using namespace ::com::sun::star::form; 147 using namespace ::com::sun::star::io; 148 using namespace ::com::sun::star::i18n; 149 using namespace ::com::sun::star::view; 150 using namespace ::com::sun::star::datatransfer; 151 using namespace ::com::sun::star::document; 152 using namespace ::com::sun::star::ui; 153 using namespace ::dbtools; 154 using namespace ::comphelper; 155 using namespace ::svx; 156 157 // SbaTableQueryBrowser 158 extern "C" void createRegistryInfo_OBrowser() 159 { 160 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::SbaTableQueryBrowser > aAutoRegistration; 161 } 162 163 namespace dbaui 164 { 165 166 namespace DatabaseObject = css::sdb::application::DatabaseObject; 167 namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer; 168 169 static void SafeAddPropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener) 170 { 171 Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo(); 172 if (xInfo->hasPropertyByName(rPropName)) 173 xSet->addPropertyChangeListener(rPropName, pListener); 174 } 175 176 static void SafeRemovePropertyListener(const Reference< XPropertySet > & xSet, const OUString& rPropName, XPropertyChangeListener* pListener) 177 { 178 Reference< XPropertySetInfo > xInfo = xSet->getPropertySetInfo(); 179 if (xInfo->hasPropertyByName(rPropName)) 180 xSet->removePropertyChangeListener(rPropName, pListener); 181 } 182 183 OUString SAL_CALL SbaTableQueryBrowser::getImplementationName() 184 { 185 return getImplementationName_Static(); 186 } 187 188 css::uno::Sequence<OUString> SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames() 189 { 190 return getSupportedServiceNames_Static(); 191 } 192 193 OUString SbaTableQueryBrowser::getImplementationName_Static() 194 { 195 return OUString("org.openoffice.comp.dbu.ODatasourceBrowser"); 196 } 197 198 css::uno::Sequence<OUString> SbaTableQueryBrowser::getSupportedServiceNames_Static() 199 { 200 css::uno::Sequence<OUString> aSupported { "com.sun.star.sdb.DataSourceBrowser" }; 201 return aSupported; 202 } 203 204 Reference< XInterface > SbaTableQueryBrowser::Create(const Reference<XMultiServiceFactory >& _rxFactory) 205 { 206 SolarMutexGuard aGuard; 207 return *(new SbaTableQueryBrowser(comphelper::getComponentContext(_rxFactory))); 208 } 209 210 SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM) 211 :SbaXDataBrowserController(_rM) 212 ,m_aSelectionListeners( getMutex() ) 213 ,m_aContextMenuInterceptors( getMutex() ) 214 ,m_aTableCopyHelper(this) 215 ,m_pTreeView(nullptr) 216 ,m_pSplitter(nullptr) 217 ,m_pCurrentlyDisplayed(nullptr) 218 ,m_nAsyncDrop(nullptr) 219 ,m_bQueryEscapeProcessing( false ) 220 ,m_bShowMenu(false) 221 ,m_bInSuspend(false) 222 ,m_bEnableBrowser(true) 223 { 224 } 225 226 SbaTableQueryBrowser::~SbaTableQueryBrowser() 227 { 228 if ( !rBHelper.bDisposed && !rBHelper.bInDispose ) 229 { 230 SAL_WARN("dbaccess.ui", "Please check who doesn't dispose this component!"); 231 // increment ref count to prevent double call of Dtor 232 osl_atomic_increment( &m_refCount ); 233 dispose(); 234 } 235 SolarMutexGuard g; 236 m_pTreeView.reset(); 237 m_pSplitter.reset(); 238 } 239 240 Any SAL_CALL SbaTableQueryBrowser::queryInterface(const Type& _rType) 241 { 242 if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) ) 243 { 244 OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" ); 245 if ( !!m_aDocScriptSupport && *m_aDocScriptSupport ) 246 return makeAny( Reference< XScriptInvocationContext >( this ) ); 247 return Any(); 248 } 249 250 Any aReturn = SbaXDataBrowserController::queryInterface(_rType); 251 if (!aReturn.hasValue()) 252 aReturn = SbaTableQueryBrowser_Base::queryInterface(_rType); 253 return aReturn; 254 } 255 256 Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes( ) 257 { 258 Sequence< Type > aTypes( ::comphelper::concatSequences( 259 SbaXDataBrowserController::getTypes(), 260 SbaTableQueryBrowser_Base::getTypes() 261 ) ); 262 263 OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" ); 264 if ( !m_aDocScriptSupport || !*m_aDocScriptSupport ) 265 { 266 auto newEnd = std::remove_if( aTypes.begin(), aTypes.end(), 267 [](const Type& type) 268 { return type == cppu::UnoType<XScriptInvocationContext>::get(); } ); 269 aTypes.realloc( std::distance(aTypes.begin(), newEnd) ); 270 } 271 return aTypes; 272 } 273 274 Sequence< sal_Int8 > SAL_CALL SbaTableQueryBrowser::getImplementationId( ) 275 { 276 return css::uno::Sequence<sal_Int8>(); 277 } 278 279 void SAL_CALL SbaTableQueryBrowser::disposing() 280 { 281 SolarMutexGuard aGuard; 282 // doin' a lot of VCL stuff here -> lock the SolarMutex 283 284 // kiss our listeners goodbye 285 css::lang::EventObject aEvt(*this); 286 m_aSelectionListeners.disposeAndClear(aEvt); 287 m_aContextMenuInterceptors.disposeAndClear(aEvt); 288 289 if (getBrowserView()) 290 { 291 // Need to do some cleaup of the data pointed to the tree view entries before we remove the treeview 292 clearTreeModel(); 293 m_pTreeView = nullptr; 294 getBrowserView()->setTreeView(nullptr); 295 } 296 297 // remove ourself as status listener 298 implRemoveStatusListeners(); 299 300 // remove the container listener from the database context 301 try 302 { 303 Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW ); 304 xDatabaseRegistrations->removeDatabaseRegistrationsListener( this ); 305 } 306 catch( const Exception& ) 307 { 308 DBG_UNHANDLED_EXCEPTION("dbaccess"); 309 } 310 311 // check out from all the objects we are listening 312 // the frame 313 if (m_xCurrentFrameParent.is()) 314 m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); 315 SbaXDataBrowserController::disposing(); 316 } 317 318 bool SbaTableQueryBrowser::Construct(vcl::Window* pParent) 319 { 320 if ( !SbaXDataBrowserController::Construct( pParent ) ) 321 return false; 322 323 try 324 { 325 Reference< XDatabaseRegistrations > xDatabaseRegistrations( m_xDatabaseContext, UNO_QUERY_THROW ); 326 xDatabaseRegistrations->addDatabaseRegistrationsListener( this ); 327 328 // the collator for the string compares 329 m_xCollator = Collator::create( getORB() ); 330 m_xCollator->loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 ); 331 } 332 catch(const Exception&) 333 { 334 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Construct: could not create (or start listening at) the database context!"); 335 } 336 // some help ids 337 if (getBrowserView() && getBrowserView()->getVclControl()) 338 { 339 340 // create controls and set sizes 341 const long nFrameWidth = getBrowserView()->LogicToPixel(::Size(3, 0), MapMode(MapUnit::MapAppFont)).Width(); 342 343 m_pSplitter = VclPtr<Splitter>::Create(getBrowserView(),WB_HSCROLL); 344 m_pSplitter->SetPosSizePixel( ::Point(0,0), ::Size(nFrameWidth,0) ); 345 m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) ); 346 347 m_pTreeView = VclPtr<DBTreeView>::Create(getBrowserView(), WB_TABSTOP | WB_BORDER); 348 m_pTreeView->SetPreExpandHandler(LINK(this, SbaTableQueryBrowser, OnExpandEntry)); 349 350 m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry)); 351 352 m_pTreeView->getListBox().setContextMenuProvider( this ); 353 m_pTreeView->getListBox().setControlActionListener( this ); 354 m_pTreeView->SetHelpId(HID_CTL_TREEVIEW); 355 356 // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide 357 m_pSplitter->SetSplitPosPixel(getBrowserView()->LogicToPixel(::Size(80, 0), MapMode(MapUnit::MapAppFont)).Width()); 358 359 getBrowserView()->setSplitter(m_pSplitter); 360 getBrowserView()->setTreeView(m_pTreeView); 361 362 // fill view with data 363 auto pTreeModel = m_pTreeView->GetTreeModel(); 364 pTreeModel->SetSortMode(SortAscending); 365 pTreeModel->SetCompareHdl(LINK(this, SbaTableQueryBrowser, OnTreeEntryCompare)); 366 m_pTreeView->setSelChangeHdl( LINK( this, SbaTableQueryBrowser, OnSelectionChange ) ); 367 368 // TODO 369 getBrowserView()->getVclControl()->SetHelpId(HID_CTL_TABBROWSER); 370 if (getBrowserView()->getVclControl()->GetHeaderBar()) 371 getBrowserView()->getVclControl()->GetHeaderBar()->SetHelpId(HID_DATABROWSE_HEADER); 372 InvalidateFeature(ID_BROWSER_EXPLORER); 373 } 374 375 return true; 376 } 377 378 namespace 379 { 380 struct SelectValueByName 381 { 382 const Any& operator()( OUString const& i_name ) const 383 { 384 return m_rCollection.get( i_name ); 385 } 386 387 explicit SelectValueByName( ::comphelper::NamedValueCollection const& i_collection ) 388 :m_rCollection( i_collection ) 389 { 390 } 391 392 ::comphelper::NamedValueCollection const& m_rCollection; 393 }; 394 } 395 396 void SbaTableQueryBrowser::impl_sanitizeRowSetClauses_nothrow() 397 { 398 try 399 { 400 Reference< XPropertySet > xRowSetProps( getRowSet(), UNO_QUERY_THROW ); 401 bool bEscapeProcessing = false; 402 OSL_VERIFY( xRowSetProps->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing ); 403 if ( !bEscapeProcessing ) 404 // don't touch or interpret anything if escape processing is disabled 405 return; 406 407 Reference< XSingleSelectQueryComposer > xComposer( createParser_nothrow() ); 408 if ( !xComposer.is() ) 409 // can't do anything. Already reported via assertion in createParser_nothrow. 410 return; 411 412 // the tables participating in the statement 413 const Reference< XTablesSupplier > xSuppTables( xComposer, UNO_QUERY_THROW ); 414 const Reference< XNameAccess > xTableNames( xSuppTables->getTables(), UNO_QUERY_THROW ); 415 416 // the columns participating in the statement 417 const Reference< XColumnsSupplier > xSuppColumns( xComposer, UNO_QUERY_THROW ); 418 const Reference< XNameAccess > xColumnNames( xSuppColumns->getColumns(), UNO_QUERY_THROW ); 419 420 // check if the order columns apply to tables which really exist in the statement 421 const Reference< XIndexAccess > xOrderColumns( xComposer->getOrderColumns(), UNO_SET_THROW ); 422 const sal_Int32 nOrderColumns( xOrderColumns->getCount() ); 423 bool invalidColumn = nOrderColumns == 0; 424 for ( sal_Int32 c=0; ( c < nOrderColumns ) && !invalidColumn; ++c ) 425 { 426 const Reference< XPropertySet > xOrderColumn( xOrderColumns->getByIndex(c), UNO_QUERY_THROW ); 427 OUString sTableName; 428 OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName ); 429 OUString sColumnName; 430 OSL_VERIFY( xOrderColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName ); 431 432 if ( sTableName.isEmpty() ) 433 { 434 if ( !xColumnNames->hasByName( sColumnName ) ) 435 { 436 invalidColumn = true; 437 break; 438 } 439 } 440 else 441 { 442 if ( !xTableNames->hasByName( sTableName ) ) 443 { 444 invalidColumn = true; 445 break; 446 } 447 448 const Reference< XColumnsSupplier > xSuppTableColumns( xTableNames->getByName( sTableName ), UNO_QUERY_THROW ); 449 const Reference< XNameAccess > xTableColumnNames( xSuppTableColumns->getColumns(), UNO_QUERY_THROW ); 450 if ( !xTableColumnNames->hasByName( sColumnName ) ) 451 { 452 invalidColumn = true; 453 break; 454 } 455 } 456 } 457 458 if ( invalidColumn ) 459 { 460 // reset the complete order statement at both the row set and the parser 461 xRowSetProps->setPropertyValue( PROPERTY_ORDER, makeAny( OUString() ) ); 462 xComposer->setOrder( "" ); 463 } 464 465 // check if the columns participating in the filter refer to existing tables 466 // TODO: there's no API at all for this. The method which comes nearest to what we need is 467 // "getStructuredFilter", but it returns pure column names only. That is, for a statement like 468 // "SELECT * FROM <table> WHERE <other_table>.<column> = <value>", it will return "<column>". But 469 // there's no API at all to retrieve the information about "<other_table>" - which is what would 470 // be needed here. 471 // That'd be a chance to replace getStructuredFilter with something more reasonable. 472 // So, what really would be handy, is some 473 // XNormalizedFilter getNormalizedFilter(); 474 // with 475 // interface XDisjunctiveFilterExpression 476 // { 477 // XConjunctiveFilterTerm getTerm( int index ); 478 // } 479 // interface XConjunctiveFilterTerm 480 // { 481 // ComparisonPredicate getPredicate( int index ); 482 // } 483 // struct ComparisonPredicate 484 // { 485 // XComparisonOperand Lhs; 486 // SQLFilterOperator Operator; 487 // XComparisonOperand Rhs; 488 // } 489 // interface XComparisonOperand 490 // { 491 // SQLFilterOperand Type; 492 // XPropertySet getColumn(); 493 // string getLiteral(); 494 // ... 495 // } 496 // enum SQLFilterOperand { Column, Literal, ... } 497 // ... or something like this .... 498 } 499 catch( const Exception& ) 500 { 501 DBG_UNHANDLED_EXCEPTION("dbaccess"); 502 } 503 } 504 505 bool SbaTableQueryBrowser::InitializeForm( const Reference< XPropertySet > & i_formProperties ) 506 { 507 if(!m_pCurrentlyDisplayed) 508 return true; 509 510 // this method set all format settings from the original table or query 511 try 512 { 513 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData()); 514 ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" ); 515 ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" ); 516 517 Reference< XPropertySetInfo > xPSI( pData->xObjectProperties->getPropertySetInfo(), UNO_SET_THROW ); 518 519 ::comphelper::NamedValueCollection aPropertyValues; 520 521 const OUString aTransferProperties[] = 522 { 523 OUString(PROPERTY_APPLYFILTER), 524 OUString(PROPERTY_FILTER), 525 OUString(PROPERTY_HAVING_CLAUSE), 526 OUString(PROPERTY_ORDER) 527 }; 528 for (const auto & aTransferPropertie : aTransferProperties) 529 { 530 if ( !xPSI->hasPropertyByName( aTransferPropertie ) ) 531 continue; 532 aPropertyValues.put( aTransferPropertie, pData->xObjectProperties->getPropertyValue( aTransferPropertie ) ); 533 } 534 535 std::vector< OUString > aNames( aPropertyValues.getNames() ); 536 std::sort(aNames.begin(), aNames.end()); 537 Sequence< OUString > aPropNames( comphelper::containerToSequence(aNames) ); 538 539 Sequence< Any > aPropValues( aNames.size() ); 540 std::transform( aNames.begin(), aNames.end(), aPropValues.getArray(), SelectValueByName( aPropertyValues ) ); 541 542 Reference< XMultiPropertySet > xFormMultiSet( i_formProperties, UNO_QUERY_THROW ); 543 xFormMultiSet->setPropertyValues( aPropNames, aPropValues ); 544 545 impl_sanitizeRowSetClauses_nothrow(); 546 } 547 catch ( const Exception& ) 548 { 549 DBG_UNHANDLED_EXCEPTION("dbaccess"); 550 return false; 551 } 552 553 return true; 554 } 555 556 void SbaTableQueryBrowser::initializePreviewMode() 557 { 558 if ( getBrowserView() && getBrowserView()->getVclControl() ) 559 { 560 getBrowserView()->getVclControl()->AlwaysEnableInput( false ); 561 getBrowserView()->getVclControl()->EnableInput( false ); 562 getBrowserView()->getVclControl()->ForceHideScrollbars(); 563 } 564 Reference< XPropertySet > xDataSourceSet(getRowSet(), UNO_QUERY); 565 if ( xDataSourceSet.is() ) 566 { 567 xDataSourceSet->setPropertyValue("AllowInserts",makeAny(false)); 568 xDataSourceSet->setPropertyValue("AllowUpdates",makeAny(false)); 569 xDataSourceSet->setPropertyValue("AllowDeletes",makeAny(false)); 570 } 571 } 572 573 void SbaTableQueryBrowser::InitializeGridModel(const Reference< css::form::XFormComponent > & xGrid) 574 { 575 try 576 { 577 Reference< css::form::XGridColumnFactory > xColFactory(xGrid, UNO_QUERY); 578 Reference< XNameContainer > xColContainer(xGrid, UNO_QUERY); 579 clearGridColumns( xColContainer ); 580 581 Reference< XChild > xGridAsChild(xGrid, UNO_QUERY); 582 Reference< XLoadable > xFormAsLoadable; 583 if (xGridAsChild.is()) 584 xFormAsLoadable.set(xGridAsChild->getParent(), css::uno::UNO_QUERY); 585 if (xFormAsLoadable.is() && xFormAsLoadable->isLoaded()) 586 { 587 // set the formats from the table 588 if(m_pCurrentlyDisplayed) 589 { 590 Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 )); 591 Sequence< Any> aValues(7 + ( m_bPreview ? 5 : 0 )); 592 593 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData()); 594 OSL_ENSURE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeGridModel: No table available!" ); 595 if ( !pData->xObjectProperties.is() ) 596 return; 597 598 OUString* pStringIter = aProperties.getArray(); 599 Any* pValueIter = aValues.getArray(); 600 if ( m_bPreview ) 601 { 602 *pStringIter++ = "AlwaysShowCursor"; 603 *pValueIter++ <<= false; 604 *pStringIter++ = PROPERTY_BORDER; 605 *pValueIter++ <<= sal_Int16(0); 606 } 607 608 *pStringIter++ = PROPERTY_FONT; 609 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_FONT); 610 *pStringIter++ = PROPERTY_TEXTEMPHASIS; 611 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTEMPHASIS); 612 *pStringIter++ = PROPERTY_TEXTRELIEF; 613 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTRELIEF); 614 if ( m_bPreview ) 615 { 616 *pStringIter++ = "HasNavigationBar"; 617 *pValueIter++ <<= false; 618 *pStringIter++ = "HasRecordMarker"; 619 *pValueIter++ <<= false; 620 } 621 *pStringIter++ = PROPERTY_ROW_HEIGHT; 622 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_ROW_HEIGHT); 623 if ( m_bPreview ) 624 { 625 *pStringIter++ = "Tabstop"; 626 *pValueIter++ <<= false; 627 } 628 *pStringIter++ = PROPERTY_TEXTCOLOR; 629 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTCOLOR); 630 *pStringIter++ = PROPERTY_TEXTLINECOLOR; 631 *pValueIter++ = pData->xObjectProperties->getPropertyValue(PROPERTY_TEXTLINECOLOR); 632 633 Reference< XMultiPropertySet > xFormMultiSet(xGrid, UNO_QUERY); 634 xFormMultiSet->setPropertyValues(aProperties, aValues); 635 } 636 637 // get the formats supplier of the database we're working with 638 Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormatter()->getNumberFormatsSupplier(); 639 640 Reference<XConnection> xConnection; 641 Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY); 642 xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection; 643 OSL_ENSURE(xConnection.is(),"A ActiveConnection should normally exists!"); 644 645 Reference<XChild> xChild(xConnection,UNO_QUERY); 646 Reference<XPropertySet> xDataSourceProp(xChild->getParent(),UNO_QUERY); 647 bool bSuppressVersionCol = false; 648 OSL_VERIFY( xDataSourceProp->getPropertyValue( PROPERTY_SUPPRESSVERSIONCL ) >>= bSuppressVersionCol ); 649 650 // insert the column into the gridcontrol so that we see something :-) 651 OUString aCurrentModelType; 652 Reference<XColumnsSupplier> xSupCols(getRowSet(),UNO_QUERY); 653 Reference<XNameAccess> xColumns = xSupCols->getColumns(); 654 655 OUString sDefaultProperty; 656 Reference< XPropertySet > xColumn; 657 Reference< XPropertySetInfo > xColPSI; 658 for (const OUString& rName : xColumns->getElementNames()) 659 { 660 xColumn.set( xColumns->getByName( rName ), UNO_QUERY_THROW ); 661 xColPSI.set( xColumn->getPropertySetInfo(), UNO_SET_THROW ); 662 663 // ignore the column when it is a rowversion one 664 if ( bSuppressVersionCol 665 && xColPSI->hasPropertyByName( PROPERTY_ISROWVERSION ) 666 && ::cppu::any2bool( xColumn->getPropertyValue( PROPERTY_ISROWVERSION ) ) 667 ) 668 continue; 669 670 // use the result set column's type to determine the type of grid column to create 671 bool bFormattedIsNumeric = true; 672 sal_Int32 nType = ::comphelper::getINT32( xColumn->getPropertyValue( PROPERTY_TYPE ) ); 673 674 std::vector< NamedValue > aInitialValues; 675 std::vector< OUString > aCopyProperties; 676 Any aDefault; 677 678 switch(nType) 679 { 680 case DataType::BIT: 681 case DataType::BOOLEAN: 682 { 683 aCurrentModelType = "CheckBox"; 684 aInitialValues.emplace_back( "VisualEffect", makeAny( VisualEffect::FLAT ) ); 685 sDefaultProperty = PROPERTY_DEFAULTSTATE; 686 687 sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN; 688 OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable ); 689 aInitialValues.emplace_back( 690 "TriState", 691 makeAny( ColumnValue::NO_NULLS != nNullable ) 692 ); 693 if ( ColumnValue::NO_NULLS == nNullable ) 694 aDefault <<= sal_Int16(TRISTATE_FALSE); 695 } 696 break; 697 698 case DataType::LONGVARCHAR: 699 case DataType::CLOB: 700 aInitialValues.emplace_back( "MultiLine", makeAny( true ) ); 701 SAL_FALLTHROUGH; 702 case DataType::BINARY: 703 case DataType::VARBINARY: 704 case DataType::LONGVARBINARY: 705 aCurrentModelType = "TextField"; 706 sDefaultProperty = PROPERTY_DEFAULTTEXT; 707 break; 708 709 case DataType::VARCHAR: 710 case DataType::CHAR: 711 bFormattedIsNumeric = false; 712 SAL_FALLTHROUGH; 713 default: 714 aCurrentModelType = "FormattedField"; 715 sDefaultProperty = PROPERTY_EFFECTIVEDEFAULT; 716 717 if ( xSupplier.is() ) 718 aInitialValues.emplace_back( "FormatsSupplier", makeAny( xSupplier ) ); 719 aInitialValues.emplace_back( "TreatAsNumber", makeAny( bFormattedIsNumeric ) ); 720 aCopyProperties.emplace_back(PROPERTY_FORMATKEY ); 721 break; 722 } 723 724 aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, makeAny( rName ) ); 725 OUString sLabel; 726 xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel; 727 if ( !sLabel.isEmpty() ) 728 aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( sLabel ) ); 729 else 730 aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( rName ) ); 731 732 Reference< XPropertySet > xGridCol( xColFactory->createColumn( aCurrentModelType ), UNO_SET_THROW ); 733 Reference< XPropertySetInfo > xGridColPSI( xGridCol->getPropertySetInfo(), UNO_SET_THROW ); 734 735 // calculate the default 736 if ( xGridColPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) ) 737 { 738 aDefault = xColumn->getPropertyValue( PROPERTY_CONTROLDEFAULT ); 739 // default value 740 if ( nType == DataType::BIT || nType == DataType::BOOLEAN ) 741 { 742 if ( aDefault.hasValue() ) 743 aDefault <<= (comphelper::getString(aDefault).toInt32() == 0) ? sal_Int16(TRISTATE_FALSE) : sal_Int16(TRISTATE_TRUE); 744 else 745 aDefault <<= sal_Int16(TRISTATE_INDET); 746 } 747 } 748 749 if ( aDefault.hasValue() ) 750 aInitialValues.emplace_back( sDefaultProperty, aDefault ); 751 752 // transfer properties from the definition to the UNO-model : 753 aCopyProperties.emplace_back(PROPERTY_HIDDEN ); 754 aCopyProperties.emplace_back(PROPERTY_WIDTH ); 755 756 // help text to display for the column 757 Any aDescription; 758 if ( xColPSI->hasPropertyByName( PROPERTY_HELPTEXT ) ) 759 aDescription = xColumn->getPropertyValue( PROPERTY_HELPTEXT ); 760 OUString sTemp; 761 aDescription >>= sTemp; 762 if ( sTemp.isEmpty() ) 763 xColumn->getPropertyValue( PROPERTY_DESCRIPTION ) >>= sTemp; 764 765 aDescription <<= sTemp; 766 aInitialValues.emplace_back( PROPERTY_HELPTEXT, aDescription ); 767 768 // ... horizontal justify 769 Any aAlign; aAlign <<= sal_Int16( 0 ); 770 Any aColAlign( xColumn->getPropertyValue( PROPERTY_ALIGN ) ); 771 if ( aColAlign.hasValue() ) 772 aAlign <<= sal_Int16( ::comphelper::getINT32( aColAlign ) ); 773 aInitialValues.emplace_back( PROPERTY_ALIGN, aAlign ); 774 775 // don't allow the mouse to scroll in the cells 776 if ( xGridColPSI->hasPropertyByName( PROPERTY_MOUSE_WHEEL_BEHAVIOR ) ) 777 aInitialValues.emplace_back( PROPERTY_MOUSE_WHEEL_BEHAVIOR, makeAny( MouseWheelBehavior::SCROLL_DISABLED ) ); 778 779 // now set all those values 780 for (auto const& property : aInitialValues) 781 { 782 xGridCol->setPropertyValue( property.Name, property.Value ); 783 } 784 for (auto const& copyPropertyName : aCopyProperties) 785 xGridCol->setPropertyValue( copyPropertyName, xColumn->getPropertyValue(copyPropertyName) ); 786 787 xColContainer->insertByName(rName, makeAny(xGridCol)); 788 } 789 } 790 } 791 catch(const Exception&) 792 { 793 DBG_UNHANDLED_EXCEPTION("dbaccess"); 794 } 795 } 796 797 static Reference<XPropertySet> getColumnHelper(SvTreeListEntry const * _pCurrentlyDisplayed, const Reference<XPropertySet>& _rxSource) 798 { 799 Reference<XPropertySet> xRet; 800 if(_pCurrentlyDisplayed) 801 { 802 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pCurrentlyDisplayed->GetUserData()); 803 Reference<XColumnsSupplier> xColumnsSup(pData->xObjectProperties,UNO_QUERY); 804 Reference<XNameAccess> xNames = xColumnsSup->getColumns(); 805 OUString aName; 806 _rxSource->getPropertyValue(PROPERTY_NAME) >>= aName; 807 if(xNames.is() && xNames->hasByName(aName)) 808 xRet.set(xNames->getByName(aName),UNO_QUERY); 809 } 810 return xRet; 811 } 812 813 void SbaTableQueryBrowser::transferChangedControlProperty(const OUString& _rProperty, const Any& _rNewValue) 814 { 815 if(m_pCurrentlyDisplayed) 816 { 817 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData()); 818 Reference< XPropertySet > xObjectProps(pData->xObjectProperties, UNO_QUERY); 819 OSL_ENSURE(xObjectProps.is(),"SbaTableQueryBrowser::transferChangedControlProperty: no table/query object!"); 820 if (xObjectProps.is()) 821 xObjectProps->setPropertyValue(_rProperty, _rNewValue); 822 } 823 } 824 825 void SbaTableQueryBrowser::propertyChange(const PropertyChangeEvent& evt) 826 { 827 SbaXDataBrowserController::propertyChange(evt); 828 829 try 830 { 831 Reference< XPropertySet > xSource(evt.Source, UNO_QUERY); 832 if (!xSource.is()) 833 return; 834 835 // one of the many properties which require us to update the definition ? 836 // a column's width ? 837 else if (evt.PropertyName == PROPERTY_WIDTH) 838 { // a column width has changed -> update the model 839 // (the update of the view is done elsewhere) 840 Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource); 841 if(xProp.is()) 842 { 843 if(!evt.NewValue.hasValue()) 844 xProp->setPropertyValue(PROPERTY_WIDTH,makeAny(sal_Int32(227))); 845 else 846 xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue); 847 } 848 } 849 850 // a column's 'visible' state ? 851 else if (evt.PropertyName == PROPERTY_HIDDEN) 852 { 853 Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource); 854 if(xProp.is()) 855 xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue); 856 } 857 858 // a columns alignment ? 859 else if (evt.PropertyName == PROPERTY_ALIGN) 860 { 861 Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource); 862 try 863 { 864 if(xProp.is()) 865 { 866 if(evt.NewValue.hasValue()) 867 { 868 sal_Int16 nAlign = 0; 869 if(evt.NewValue >>= nAlign) 870 xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(sal_Int32(nAlign))); 871 else 872 xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue); 873 } 874 else 875 xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(css::awt::TextAlign::LEFT)); 876 } 877 } 878 catch( const Exception& ) 879 { 880 DBG_UNHANDLED_EXCEPTION("dbaccess"); 881 } 882 } 883 884 // a column's format ? 885 else if ( evt.PropertyName == PROPERTY_FORMATKEY 886 && (TypeClass_LONG == evt.NewValue.getValueTypeClass()) 887 ) 888 { 889 // update the model (means the definition object) 890 Reference<XPropertySet> xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource); 891 if(xProp.is()) 892 xProp->setPropertyValue(PROPERTY_FORMATKEY,evt.NewValue); 893 } 894 895 // some table definition properties ? 896 // the height of the rows in the grid ? 897 else if (evt.PropertyName == PROPERTY_ROW_HEIGHT) 898 { 899 if(m_pCurrentlyDisplayed) 900 { 901 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(m_pCurrentlyDisplayed->GetUserData()); 902 OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" ); 903 904 bool bDefault = !evt.NewValue.hasValue(); 905 if (bDefault) 906 pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,makeAny(sal_Int32(45))); 907 else 908 pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,evt.NewValue); 909 } 910 } 911 912 else if ( evt.PropertyName == PROPERTY_FONT // the font ? 913 || evt.PropertyName == PROPERTY_TEXTCOLOR // the text color ? 914 || evt.PropertyName == PROPERTY_FILTER // the filter ? 915 || evt.PropertyName == PROPERTY_HAVING_CLAUSE // the having clause ? 916 || evt.PropertyName == PROPERTY_ORDER // the sort ? 917 || evt.PropertyName == PROPERTY_APPLYFILTER // the appliance of the filter ? 918 || evt.PropertyName == PROPERTY_TEXTLINECOLOR // the text line color ? 919 || evt.PropertyName == PROPERTY_TEXTEMPHASIS // the text emphasis ? 920 || evt.PropertyName == PROPERTY_TEXTRELIEF // the text relief ? 921 ) 922 { 923 transferChangedControlProperty(evt.PropertyName, evt.NewValue); 924 } 925 } 926 catch( const Exception& ) 927 { 928 DBG_UNHANDLED_EXCEPTION("dbaccess"); 929 } 930 } 931 932 sal_Bool SbaTableQueryBrowser::suspend(sal_Bool bSuspend) 933 { 934 SolarMutexGuard aSolarGuard; 935 ::osl::MutexGuard aGuard( getMutex() ); 936 if ( getView() && getView()->IsInModalMode() ) 937 return false; 938 bool bRet = false; 939 if ( !m_bInSuspend ) 940 { 941 m_bInSuspend = true; 942 if ( rBHelper.bDisposed ) 943 throw DisposedException( OUString(), *this ); 944 945 bRet = SbaXDataBrowserController::suspend(bSuspend); 946 if ( bRet && getView() ) 947 getView()->Hide(); 948 949 m_bInSuspend = false; 950 } 951 952 return bRet; 953 } 954 955 void SAL_CALL SbaTableQueryBrowser::statusChanged( const FeatureStateEvent& _rEvent ) 956 { 957 // search the external dispatcher causing this call 958 Reference< XDispatch > xSource(_rEvent.Source, UNO_QUERY); 959 bool bFound = false; 960 for (auto & externalFeature : m_aExternalFeatures) 961 { 962 if ( _rEvent.FeatureURL.Complete == externalFeature.second.aURL.Complete) 963 { 964 bFound = true; 965 OSL_ENSURE( xSource.get() == externalFeature.second.xDispatcher.get(), "SbaTableQueryBrowser::statusChanged: inconsistent!" ); 966 // update the enabled state 967 externalFeature.second.bEnabled = _rEvent.IsEnabled; 968 969 switch ( externalFeature.first ) 970 { 971 case ID_BROWSER_DOCUMENT_DATASOURCE: 972 { 973 // if it's the slot for the document data source, remember the state 974 Sequence< PropertyValue > aDescriptor; 975 bool bProperFormat = _rEvent.State >>= aDescriptor; 976 OSL_ENSURE(bProperFormat, "SbaTableQueryBrowser::statusChanged: need a data access descriptor here!"); 977 m_aDocumentDataSource.initializeFrom(aDescriptor); 978 979 OSL_ENSURE( ( m_aDocumentDataSource.has(DataAccessDescriptorProperty::DataSource) 980 || m_aDocumentDataSource.has(DataAccessDescriptorProperty::DatabaseLocation) 981 ) 982 && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command) 983 && m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType), 984 "SbaTableQueryBrowser::statusChanged: incomplete descriptor!"); 985 986 // check if we know the object which is set as document data source 987 checkDocumentDataSource(); 988 } 989 break; 990 991 default: 992 // update the toolbox 993 implCheckExternalSlot( externalFeature.first ); 994 break; 995 } 996 break; 997 } 998 } 999 1000 OSL_ENSURE(bFound, "SbaTableQueryBrowser::statusChanged: don't know who sent this!"); 1001 } 1002 1003 void SbaTableQueryBrowser::checkDocumentDataSource() 1004 { 1005 SvTreeListEntry* pDataSourceEntry = nullptr; 1006 SvTreeListEntry* pContainerEntry = nullptr; 1007 SvTreeListEntry* pObjectEntry = getObjectEntry( m_aDocumentDataSource, &pDataSourceEntry, &pContainerEntry ); 1008 bool bKnownDocDataSource = (nullptr != pObjectEntry); 1009 if (!bKnownDocDataSource) 1010 { 1011 if (nullptr != pDataSourceEntry) 1012 { // at least the data source is known 1013 if (nullptr != pContainerEntry) 1014 bKnownDocDataSource = true; // assume we know it. 1015 // TODO: should we expand the object container? This may be too expensive just for checking .... 1016 else 1017 { 1018 if ((nullptr == pObjectEntry) && m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType) && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command)) 1019 { // maybe we have a command to be displayed ? 1020 sal_Int32 nCommandType = CommandType::TABLE; 1021 m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType; 1022 1023 OUString sCommand; 1024 m_aDocumentDataSource[DataAccessDescriptorProperty::Command] >>= sCommand; 1025 1026 bKnownDocDataSource = (CommandType::COMMAND == nCommandType) && (!sCommand.isEmpty()); 1027 } 1028 } 1029 } 1030 } 1031 1032 if ( !bKnownDocDataSource ) 1033 m_aExternalFeatures[ ID_BROWSER_DOCUMENT_DATASOURCE ].bEnabled = false; 1034 1035 // update the toolbox 1036 implCheckExternalSlot(ID_BROWSER_DOCUMENT_DATASOURCE); 1037 } 1038 1039 void SbaTableQueryBrowser::extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor, OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing) 1040 { 1041 _rDataSource = _rDescriptor.getDataSource(); 1042 if ( _rDescriptor.has(DataAccessDescriptorProperty::Command) ) 1043 _rDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand; 1044 if ( _rDescriptor.has(DataAccessDescriptorProperty::CommandType) ) 1045 _rDescriptor[DataAccessDescriptorProperty::CommandType] >>= _rCommandType; 1046 1047 // escape processing is the only one allowed not to be present 1048 _rEscapeProcessing = true; 1049 if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing)) 1050 _rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]); 1051 } 1052 1053 namespace 1054 { 1055 bool getDataSourceDisplayName_isURL( const OUString& _rDS, OUString& _rDisplayName, OUString& _rUniqueId ) 1056 { 1057 INetURLObject aURL( _rDS ); 1058 if ( aURL.GetProtocol() != INetProtocol::NotValid ) 1059 { 1060 _rDisplayName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset); 1061 _rUniqueId = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 1062 return true; 1063 } 1064 _rDisplayName = _rDS; 1065 _rUniqueId.clear(); 1066 return false; 1067 } 1068 1069 struct FilterByEntryDataId : public IEntryFilter 1070 { 1071 OUString sId; 1072 explicit FilterByEntryDataId( const OUString& _rId ) : sId( _rId ) { } 1073 1074 virtual ~FilterByEntryDataId() {} 1075 1076 virtual bool includeEntry( SvTreeListEntry* _pEntry ) const override; 1077 }; 1078 1079 bool FilterByEntryDataId::includeEntry( SvTreeListEntry* _pEntry ) const 1080 { 1081 DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( _pEntry->GetUserData() ); 1082 return ( !pData || ( pData->sAccessor == sId ) ); 1083 } 1084 } 1085 1086 OUString SbaTableQueryBrowser::getDataSourceAccessor( SvTreeListEntry* _pDataSourceEntry ) const 1087 { 1088 OSL_ENSURE( _pDataSourceEntry, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry!" ); 1089 1090 DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( _pDataSourceEntry->GetUserData() ); 1091 OSL_ENSURE( pData, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry data!" ); 1092 OSL_ENSURE( pData->eType == etDatasource, "SbaTableQueryBrowser::getDataSourceAccessor: entry does not denote a data source!" ); 1093 return !pData->sAccessor.isEmpty() ? pData->sAccessor : GetEntryText( _pDataSourceEntry ); 1094 } 1095 1096 SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 _nCommandType, 1097 SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _ppContainerEntry, bool _bExpandAncestors, 1098 const SharedConnection& _rxConnection ) 1099 { 1100 if (_ppDataSourceEntry) 1101 *_ppDataSourceEntry = nullptr; 1102 if (_ppContainerEntry) 1103 *_ppContainerEntry = nullptr; 1104 1105 SvTreeListEntry* pObject = nullptr; 1106 if ( m_pTreeView ) 1107 { 1108 // look for the data source entry 1109 OUString sDisplayName, sDataSourceId; 1110 bool bIsDataSourceURL = getDataSourceDisplayName_isURL( _rDataSource, sDisplayName, sDataSourceId ); 1111 // the display name may differ from the URL for readability reasons 1112 // #i33699# 1113 1114 FilterByEntryDataId aFilter( sDataSourceId ); 1115 SvTreeListEntry* pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter ); 1116 if ( !pDataSource ) // check if the data source name is a file location 1117 { 1118 if ( bIsDataSourceURL ) 1119 { 1120 // special case, the data source is a URL 1121 // add new entries to the list box model 1122 implAddDatasource( _rDataSource, _rxConnection ); 1123 pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter ); 1124 OSL_ENSURE( pDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" ); 1125 } 1126 } 1127 if (_ppDataSourceEntry) 1128 // (caller wants to have it ...) 1129 *_ppDataSourceEntry = pDataSource; 1130 1131 if (pDataSource) 1132 { 1133 // expand if required so 1134 if (_bExpandAncestors) 1135 m_pTreeView->getListBox().Expand(pDataSource); 1136 1137 // look for the object container 1138 SvTreeListEntry* pCommandType = nullptr; 1139 switch (_nCommandType) 1140 { 1141 case CommandType::TABLE: 1142 pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_TABLES); 1143 break; 1144 1145 case CommandType::QUERY: 1146 pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_QUERIES); 1147 break; 1148 } 1149 1150 if (_ppContainerEntry) 1151 *_ppContainerEntry = pCommandType; 1152 1153 if (pCommandType) 1154 { 1155 // expand if required so 1156 if (_bExpandAncestors) 1157 { 1158 m_pTreeView->getListBox().Expand(pCommandType); 1159 } 1160 1161 // look for the object 1162 sal_Int32 nIndex = 0; 1163 do 1164 { 1165 OUString sPath; 1166 switch (_nCommandType) 1167 { 1168 case CommandType::TABLE: 1169 sPath = _rCommand; 1170 nIndex = -1; 1171 break; 1172 1173 case CommandType::QUERY: 1174 sPath = _rCommand.getToken( 0, '/', nIndex ); 1175 break; 1176 1177 default: 1178 assert(false); 1179 } 1180 pObject = m_pTreeView->getListBox().GetEntryPosByName(sPath, pCommandType); 1181 pCommandType = pObject; 1182 if ( nIndex >= 0 ) 1183 { 1184 if (ensureEntryObject(pObject)) 1185 { 1186 DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( pObject->GetUserData() ); 1187 Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY ); 1188 sal_Int32 nIndex2 = nIndex; 1189 sPath = _rCommand.getToken( 0, '/', nIndex2 ); 1190 try 1191 { 1192 if ( xCollection->hasByName(sPath) ) 1193 { 1194 if(!m_pTreeView->getListBox().GetEntryPosByName(sPath,pObject)) 1195 { 1196 Reference<XNameAccess> xChild(xCollection->getByName(sPath),UNO_QUERY); 1197 DBTreeListUserData* pEntryData = new DBTreeListUserData; 1198 pEntryData->eType = etQuery; 1199 if ( xChild.is() ) 1200 { 1201 pEntryData->eType = etQueryContainer; 1202 } 1203 implAppendEntry( pObject, sPath, pEntryData, pEntryData->eType ); 1204 } 1205 } 1206 } 1207 catch(const Exception&) 1208 { 1209 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree"); 1210 } 1211 } 1212 } 1213 } 1214 while ( nIndex >= 0 ); 1215 } 1216 } 1217 } 1218 return pObject; 1219 } 1220 1221 SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& _rDescriptor, 1222 SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _ppContainerEntry) 1223 { 1224 // extract the props from the descriptor 1225 OUString sDataSource; 1226 OUString sCommand; 1227 sal_Int32 nCommandType = CommandType::COMMAND; 1228 bool bEscapeProcessing = true; 1229 extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing); 1230 1231 return getObjectEntry( sDataSource, sCommand, nCommandType, _ppDataSourceEntry, _ppContainerEntry, false/*_bExpandAncestors*/ ); 1232 } 1233 1234 void SbaTableQueryBrowser::connectExternalDispatches() 1235 { 1236 Reference< XDispatchProvider > xProvider( getFrame(), UNO_QUERY ); 1237 OSL_ENSURE(xProvider.is(), "SbaTableQueryBrowser::connectExternalDispatches: no DispatchProvider !"); 1238 if (xProvider.is()) 1239 { 1240 if ( m_aExternalFeatures.empty() ) 1241 { 1242 const sal_Char* pURLs[] = { 1243 ".uno:DataSourceBrowser/DocumentDataSource", 1244 ".uno:DataSourceBrowser/FormLetter", 1245 ".uno:DataSourceBrowser/InsertColumns", 1246 ".uno:DataSourceBrowser/InsertContent", 1247 }; 1248 const sal_uInt16 nIds[] = { 1249 ID_BROWSER_DOCUMENT_DATASOURCE, 1250 ID_BROWSER_FORMLETTER, 1251 ID_BROWSER_INSERTCOLUMNS, 1252 ID_BROWSER_INSERTCONTENT 1253 }; 1254 1255 for ( size_t i=0; i < SAL_N_ELEMENTS( pURLs ); ++i ) 1256 { 1257 URL aURL; 1258 aURL.Complete = OUString::createFromAscii( pURLs[i] ); 1259 if ( m_xUrlTransformer.is() ) 1260 m_xUrlTransformer->parseStrict( aURL ); 1261 m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( aURL ); 1262 } 1263 } 1264 1265 for (auto & externalFeature : m_aExternalFeatures) 1266 { 1267 externalFeature.second.xDispatcher = xProvider->queryDispatch( 1268 externalFeature.second.aURL, "_parent", FrameSearchFlag::PARENT 1269 ); 1270 1271 if ( externalFeature.second.xDispatcher.get() == static_cast< XDispatch* >( this ) ) 1272 { 1273 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::connectExternalDispatches: this should not happen anymore!" ); 1274 // (nowadays, the URLs aren't in our SupportedFeatures list anymore, so we should 1275 // not supply a dispatcher for this) 1276 externalFeature.second.xDispatcher.clear(); 1277 } 1278 1279 if ( externalFeature.second.xDispatcher.is() ) 1280 { 1281 try 1282 { 1283 externalFeature.second.xDispatcher->addStatusListener( this, externalFeature.second.aURL ); 1284 } 1285 catch( const Exception& ) 1286 { 1287 DBG_UNHANDLED_EXCEPTION("dbaccess"); 1288 } 1289 } 1290 1291 implCheckExternalSlot( externalFeature.first ); 1292 } 1293 } 1294 } 1295 1296 void SbaTableQueryBrowser::implCheckExternalSlot( sal_uInt16 _nId ) 1297 { 1298 if ( !m_xMainToolbar.is() ) 1299 return; 1300 1301 VclPtr<vcl::Window> pToolboxWindow = VCLUnoHelper::GetWindow( m_xMainToolbar ); 1302 ToolBox* pToolbox = dynamic_cast< ToolBox* >( pToolboxWindow.get() ); 1303 OSL_ENSURE( pToolbox, "SbaTableQueryBrowser::implCheckExternalSlot: cannot obtain the toolbox window!" ); 1304 1305 // check if we have to hide this item from the toolbox 1306 if ( pToolbox ) 1307 { 1308 bool bHaveDispatcher = m_aExternalFeatures[ _nId ].xDispatcher.is(); 1309 if ( bHaveDispatcher != pToolbox->IsItemVisible( _nId ) ) 1310 bHaveDispatcher ? pToolbox->ShowItem( _nId ) : pToolbox->HideItem( _nId ); 1311 } 1312 1313 // and invalidate this feature in general 1314 InvalidateFeature( _nId ); 1315 } 1316 1317 void SAL_CALL SbaTableQueryBrowser::disposing( const css::lang::EventObject& _rSource ) 1318 { 1319 // our frame ? 1320 Reference< css::frame::XFrame > xSourceFrame(_rSource.Source, UNO_QUERY); 1321 if (m_xCurrentFrameParent.is() && (xSourceFrame == m_xCurrentFrameParent)) 1322 m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); 1323 else 1324 { 1325 // search the external dispatcher causing this call in our map 1326 Reference< XDispatch > xSource(_rSource.Source, UNO_QUERY); 1327 if(xSource.is()) 1328 { 1329 ExternalFeaturesMap::const_iterator aLoop = m_aExternalFeatures.begin(); 1330 ExternalFeaturesMap::const_iterator aEnd = m_aExternalFeatures.end(); 1331 while (aLoop != aEnd) 1332 { 1333 if ( aLoop->second.xDispatcher.get() == xSource.get() ) 1334 { 1335 sal_uInt16 nSlot = aLoop->first; 1336 1337 // remove it 1338 aLoop = m_aExternalFeatures.erase(aLoop); 1339 1340 // maybe update the UI 1341 implCheckExternalSlot(nSlot); 1342 1343 // continue, the same XDispatch may be responsible for more than one URL 1344 } 1345 ++aLoop; 1346 } 1347 } 1348 else 1349 { 1350 Reference<XConnection> xCon(_rSource.Source, UNO_QUERY); 1351 if ( xCon.is() && m_pTreeView ) 1352 { // our connection is in dispose so we have to find the entry equal with this connection 1353 // and close it what means to collapse the entry 1354 // get the top-level representing the removed data source 1355 SvTreeListEntry* pDSLoop = m_pTreeView->getListBox().FirstChild(nullptr); 1356 while (pDSLoop) 1357 { 1358 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pDSLoop->GetUserData()); 1359 if ( pData && pData->xConnection == xCon ) 1360 { 1361 // we set the connection to null to avoid a second disposing of the connection 1362 pData->xConnection.clear(); 1363 closeConnection(pDSLoop,false); 1364 break; 1365 } 1366 1367 pDSLoop = pDSLoop->NextSibling(); 1368 } 1369 } 1370 else 1371 SbaXDataBrowserController::disposing(_rSource); 1372 } 1373 } 1374 } 1375 1376 void SbaTableQueryBrowser::implRemoveStatusListeners() 1377 { 1378 // clear all old dispatches 1379 for (auto const& externalFeature : m_aExternalFeatures) 1380 { 1381 if ( externalFeature.second.xDispatcher.is() ) 1382 { 1383 try 1384 { 1385 externalFeature.second.xDispatcher->removeStatusListener( this, externalFeature.second.aURL ); 1386 } 1387 catch (Exception&) 1388 { 1389 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implRemoveStatusListeners: could not remove a status listener!"); 1390 } 1391 } 1392 } 1393 m_aExternalFeatures.clear(); 1394 } 1395 1396 sal_Bool SAL_CALL SbaTableQueryBrowser::select( const Any& _rSelection ) 1397 { 1398 SolarMutexGuard aGuard; 1399 // doin' a lot of VCL stuff here -> lock the SolarMutex 1400 1401 Sequence< PropertyValue > aDescriptorSequence; 1402 if (!(_rSelection >>= aDescriptorSequence)) 1403 throw IllegalArgumentException(OUString(), *this, 1); 1404 // TODO: error message 1405 1406 ODataAccessDescriptor aDescriptor; 1407 try 1408 { 1409 aDescriptor = ODataAccessDescriptor(aDescriptorSequence); 1410 } 1411 catch(const Exception&) 1412 { 1413 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::select: could not extract the descriptor!"); 1414 } 1415 1416 // check the presence of the props we need 1417 if ( !(aDescriptor.has(DataAccessDescriptorProperty::DataSource) || aDescriptor.has(DataAccessDescriptorProperty::DatabaseLocation)) || !aDescriptor.has(DataAccessDescriptorProperty::Command) || !aDescriptor.has(DataAccessDescriptorProperty::CommandType)) 1418 throw IllegalArgumentException(OUString(), *this, 1); 1419 // TODO: error message 1420 1421 return implSelect(aDescriptor,true); 1422 } 1423 1424 Any SAL_CALL SbaTableQueryBrowser::getSelection( ) 1425 { 1426 Any aReturn; 1427 1428 try 1429 { 1430 Reference< XLoadable > xLoadable(getRowSet(), UNO_QUERY); 1431 if (xLoadable.is() && xLoadable->isLoaded()) 1432 { 1433 Reference< XPropertySet > aFormProps(getRowSet(), UNO_QUERY); 1434 ODataAccessDescriptor aDescriptor(aFormProps); 1435 // remove properties which are not part of our "selection" 1436 aDescriptor.erase(DataAccessDescriptorProperty::Connection); 1437 aDescriptor.erase(DataAccessDescriptorProperty::Cursor); 1438 1439 aReturn <<= aDescriptor.createPropertyValueSequence(); 1440 } 1441 } 1442 catch( const Exception& ) 1443 { 1444 DBG_UNHANDLED_EXCEPTION("dbaccess"); 1445 } 1446 1447 return aReturn; 1448 } 1449 1450 void SAL_CALL SbaTableQueryBrowser::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) 1451 { 1452 m_aSelectionListeners.addInterface(_rxListener); 1453 } 1454 1455 void SAL_CALL SbaTableQueryBrowser::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) 1456 { 1457 m_aSelectionListeners.removeInterface(_rxListener); 1458 } 1459 1460 void SbaTableQueryBrowser::attachFrame(const Reference< css::frame::XFrame > & _xFrame) 1461 { 1462 implRemoveStatusListeners(); 1463 1464 if (m_xCurrentFrameParent.is()) 1465 m_xCurrentFrameParent->removeFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); 1466 1467 SbaXDataBrowserController::attachFrame(_xFrame); 1468 1469 Reference< XFrame > xCurrentFrame( getFrame() ); 1470 if ( xCurrentFrame.is() ) 1471 { 1472 m_xCurrentFrameParent = xCurrentFrame->findFrame("_parent",FrameSearchFlag::PARENT); 1473 if ( m_xCurrentFrameParent.is() ) 1474 m_xCurrentFrameParent->addFrameActionListener(static_cast<css::frame::XFrameActionListener*>(this)); 1475 1476 // obtain our toolbox 1477 try 1478 { 1479 Reference< XPropertySet > xFrameProps( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW ); 1480 Reference< XLayoutManager > xLayouter( 1481 xFrameProps->getPropertyValue("LayoutManager"), 1482 UNO_QUERY ); 1483 1484 if ( xLayouter.is() ) 1485 { 1486 Reference< XUIElement > xUI( 1487 xLayouter->getElement( "private:resource/toolbar/toolbar" ), 1488 UNO_SET_THROW ); 1489 m_xMainToolbar.set(xUI->getRealInterface(), css::uno::UNO_QUERY); 1490 OSL_ENSURE( m_xMainToolbar.is(), "SbaTableQueryBrowser::attachFrame: where's my toolbox?" ); 1491 } 1492 } 1493 catch( const Exception& ) 1494 { 1495 DBG_UNHANDLED_EXCEPTION("dbaccess"); 1496 } 1497 } 1498 1499 // get the dispatchers for the external slots 1500 connectExternalDispatches(); 1501 } 1502 1503 void SbaTableQueryBrowser::addModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel) 1504 { 1505 SbaXDataBrowserController::addModelListeners(_xGridControlModel); 1506 Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY); 1507 if (xSourceSet.is()) 1508 { 1509 xSourceSet->addPropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this)); 1510 xSourceSet->addPropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this)); 1511 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this)); 1512 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this)); 1513 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this)); 1514 xSourceSet->addPropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this)); 1515 } 1516 1517 } 1518 1519 void SbaTableQueryBrowser::removeModelListeners(const Reference< css::awt::XControlModel > & _xGridControlModel) 1520 { 1521 SbaXDataBrowserController::removeModelListeners(_xGridControlModel); 1522 Reference< XPropertySet > xSourceSet(_xGridControlModel, UNO_QUERY); 1523 if (xSourceSet.is()) 1524 { 1525 xSourceSet->removePropertyChangeListener(PROPERTY_ROW_HEIGHT, static_cast<XPropertyChangeListener*>(this)); 1526 xSourceSet->removePropertyChangeListener(PROPERTY_FONT, static_cast<XPropertyChangeListener*>(this)); 1527 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast<XPropertyChangeListener*>(this)); 1528 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast<XPropertyChangeListener*>(this)); 1529 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast<XPropertyChangeListener*>(this)); 1530 xSourceSet->removePropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast<XPropertyChangeListener*>(this)); 1531 } 1532 } 1533 1534 void SbaTableQueryBrowser::RowChanged() 1535 { 1536 if(getBrowserView()) 1537 { 1538 SbaGridControl* pControl = getBrowserView()->getVclControl(); 1539 if (!pControl->IsEditing()) 1540 InvalidateFeature(ID_BROWSER_COPY); 1541 } 1542 SbaXDataBrowserController::RowChanged(); 1543 } 1544 1545 void SbaTableQueryBrowser::ColumnChanged() 1546 { 1547 if(getBrowserView()) 1548 { 1549 SbaGridControl* pControl = getBrowserView()->getVclControl(); 1550 if (!pControl->IsEditing()) 1551 InvalidateFeature(ID_BROWSER_COPY); 1552 } 1553 SbaXDataBrowserController::ColumnChanged(); 1554 } 1555 1556 void SbaTableQueryBrowser::AddColumnListener(const Reference< XPropertySet > & xCol) 1557 { 1558 SbaXDataBrowserController::AddColumnListener(xCol); 1559 SafeAddPropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this)); 1560 SafeAddPropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this)); 1561 SafeAddPropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this)); 1562 SafeAddPropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this)); 1563 } 1564 1565 void SbaTableQueryBrowser::RemoveColumnListener(const Reference< XPropertySet > & xCol) 1566 { 1567 SbaXDataBrowserController::RemoveColumnListener(xCol); 1568 SafeRemovePropertyListener(xCol, PROPERTY_WIDTH, static_cast<XPropertyChangeListener*>(this)); 1569 SafeRemovePropertyListener(xCol, PROPERTY_HIDDEN, static_cast<XPropertyChangeListener*>(this)); 1570 SafeRemovePropertyListener(xCol, PROPERTY_ALIGN, static_cast<XPropertyChangeListener*>(this)); 1571 SafeRemovePropertyListener(xCol, PROPERTY_FORMATKEY, static_cast<XPropertyChangeListener*>(this)); 1572 } 1573 1574 void SbaTableQueryBrowser::criticalFail() 1575 { 1576 SbaXDataBrowserController::criticalFail(); 1577 unloadAndCleanup( false ); 1578 } 1579 1580 void SbaTableQueryBrowser::LoadFinished(bool _bWasSynch) 1581 { 1582 SbaXDataBrowserController::LoadFinished(_bWasSynch); 1583 1584 m_sQueryCommand.clear(); 1585 m_bQueryEscapeProcessing = false; 1586 1587 if (isValid() && !loadingCancelled()) 1588 { 1589 // did we load a query? 1590 bool bTemporary; // needed because we m_bQueryEscapeProcessing is only one bit wide (and we want to pass it by reference) 1591 if ( implGetQuerySignature( m_sQueryCommand, bTemporary ) ) 1592 m_bQueryEscapeProcessing = bTemporary; 1593 } 1594 1595 // if the form has been loaded, this means that our "selection" has changed 1596 css::lang::EventObject aEvent( *this ); 1597 m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent ); 1598 } 1599 1600 bool SbaTableQueryBrowser::getExternalSlotState( sal_uInt16 _nId ) const 1601 { 1602 bool bEnabled = false; 1603 ExternalFeaturesMap::const_iterator aPos = m_aExternalFeatures.find( _nId ); 1604 if ( ( m_aExternalFeatures.end() != aPos ) && aPos->second.xDispatcher.is() ) 1605 bEnabled = aPos->second.bEnabled; 1606 return bEnabled; 1607 } 1608 1609 FeatureState SbaTableQueryBrowser::GetState(sal_uInt16 nId) const 1610 { 1611 FeatureState aReturn; 1612 // (disabled automatically) 1613 1614 // no chance without a view 1615 if (!getBrowserView() || !getBrowserView()->getVclControl()) 1616 return aReturn; 1617 1618 switch ( nId ) 1619 { 1620 case ID_TREE_ADMINISTRATE: 1621 aReturn.bEnabled = true; 1622 return aReturn; 1623 1624 case ID_BROWSER_CLOSE: 1625 // the close button should always be enabled 1626 aReturn.bEnabled = !m_bEnableBrowser; 1627 return aReturn; 1628 1629 // "toggle explorer" is always enabled (if we have a explorer) 1630 case ID_BROWSER_EXPLORER: 1631 aReturn.bEnabled = m_bEnableBrowser; 1632 aReturn.bChecked = haveExplorer(); 1633 return aReturn; 1634 1635 case ID_BROWSER_REMOVEFILTER: 1636 return SbaXDataBrowserController::GetState( nId ); 1637 1638 case ID_BROWSER_COPY: 1639 if ( !m_pTreeView->HasChildPathFocus() ) 1640 // handled below 1641 break; 1642 SAL_FALLTHROUGH; 1643 case ID_TREE_CLOSE_CONN: 1644 case ID_TREE_EDIT_DATABASE: 1645 { 1646 SvTreeListEntry* pCurrentEntry( m_pTreeView->getListBox().GetCurEntry() ); 1647 EntryType eType = getEntryType( pCurrentEntry ); 1648 if ( eType == etUnknown ) 1649 return aReturn; 1650 1651 SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent( pCurrentEntry ); 1652 DBTreeListUserData* pDSData 1653 = pDataSourceEntry 1654 ? static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() ) 1655 : nullptr; 1656 1657 if ( nId == ID_TREE_CLOSE_CONN ) 1658 { 1659 aReturn.bEnabled = ( pDSData != nullptr ) && pDSData->xConnection.is(); 1660 } 1661 else if ( nId == ID_TREE_EDIT_DATABASE ) 1662 { 1663 ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( getORB(), 1664 "/org.openoffice.Office.DataAccess/Policies/Features/Common" ) ); 1665 bool bHaveEditDatabase( true ); 1666 OSL_VERIFY( aConfig.getNodeValue( "EditDatabaseFromDataSourceView" ) >>= bHaveEditDatabase ); 1667 aReturn.bEnabled = getORB().is() && ( pDataSourceEntry != nullptr ) && bHaveEditDatabase; 1668 } 1669 else if ( nId == ID_BROWSER_COPY ) 1670 { 1671 aReturn.bEnabled = isEntryCopyAllowed( pCurrentEntry ); 1672 } 1673 1674 return aReturn; 1675 } 1676 } 1677 1678 // all slots not handled above are not available if no form is loaded 1679 if (!isLoaded()) 1680 return aReturn; 1681 1682 try 1683 { 1684 bool bHandled = false; 1685 switch (nId) 1686 { 1687 case ID_BROWSER_DOCUMENT_DATASOURCE: 1688 // the slot is enabled if we have an external dispatcher able to handle it, 1689 // and the dispatcher must have enabled the slot in general 1690 aReturn.bEnabled = getExternalSlotState( ID_BROWSER_DOCUMENT_DATASOURCE ); 1691 bHandled = true; 1692 break; 1693 case ID_BROWSER_REFRESH: 1694 aReturn.bEnabled = true; 1695 bHandled = true; 1696 break; 1697 } 1698 1699 if (bHandled) 1700 return aReturn; 1701 1702 // no chance without valid models 1703 if (isValid() && !isValidCursor() && nId != ID_BROWSER_CLOSE) 1704 return aReturn; 1705 1706 switch (nId) 1707 { 1708 case ID_BROWSER_INSERTCOLUMNS: 1709 case ID_BROWSER_INSERTCONTENT: 1710 case ID_BROWSER_FORMLETTER: 1711 { 1712 // the slot is enabled if we have an external dispatcher able to handle it, 1713 // and the dispatcher must have enabled the slot in general 1714 aReturn.bEnabled = getExternalSlotState( nId ); 1715 1716 // for the Insert* slots, we need at least one selected row 1717 if (ID_BROWSER_FORMLETTER != nId) 1718 aReturn.bEnabled = aReturn.bEnabled && getBrowserView()->getVclControl()->GetSelectRowCount(); 1719 1720 // disabled for native queries which are not saved within the database 1721 Reference< XPropertySet > xDataSource(getRowSet(), UNO_QUERY); 1722 try 1723 { 1724 aReturn.bEnabled = aReturn.bEnabled && xDataSource.is(); 1725 1726 if (xDataSource.is()) 1727 { 1728 sal_Int32 nType = ::comphelper::getINT32(xDataSource->getPropertyValue(PROPERTY_COMMAND_TYPE)); 1729 aReturn.bEnabled = aReturn.bEnabled && 1730 ( ::comphelper::getBOOL(xDataSource->getPropertyValue(PROPERTY_ESCAPE_PROCESSING)) || 1731 (nType == css::sdb::CommandType::QUERY) ); 1732 } 1733 } 1734 catch(DisposedException&) 1735 { 1736 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: object already disposed!"); 1737 } 1738 catch( const Exception& ) 1739 { 1740 DBG_UNHANDLED_EXCEPTION("dbaccess"); 1741 } 1742 } 1743 break; 1744 1745 case ID_BROWSER_TITLE: 1746 { 1747 Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY); 1748 sal_Int32 nCommandType = CommandType::TABLE; 1749 xProp->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nCommandType; 1750 OUString sTitle; 1751 switch (nCommandType) 1752 { 1753 case CommandType::TABLE: 1754 sTitle = DBA_RES(STR_TBL_TITLE); break; 1755 case CommandType::QUERY: 1756 case CommandType::COMMAND: 1757 sTitle = DBA_RES(STR_QRY_TITLE); break; 1758 default: 1759 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::GetState: unknown command type!"); 1760 } 1761 OUString aName; 1762 xProp->getPropertyValue(PROPERTY_COMMAND) >>= aName; 1763 OUString sObject(aName); 1764 1765 aReturn.sTitle = sTitle.replaceFirst("#", sObject); 1766 aReturn.bEnabled = true; 1767 } 1768 break; 1769 case ID_BROWSER_TABLEATTR: 1770 case ID_BROWSER_ROWHEIGHT: 1771 case ID_BROWSER_COLATTRSET: 1772 case ID_BROWSER_COLWIDTH: 1773 aReturn.bEnabled = getBrowserView() && getBrowserView()->getVclControl() && isValid() && isValidCursor(); 1774 // aReturn.bEnabled &= getDefinition() && !getDefinition()->GetDatabase()->IsReadOnly(); 1775 break; 1776 1777 case ID_BROWSER_COPY: 1778 OSL_ENSURE( !m_pTreeView->HasChildPathFocus(), "SbaTableQueryBrowser::GetState( ID_BROWSER_COPY ): this should have been handled above!" ); 1779 if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing()) 1780 { 1781 SbaGridControl* pControl = getBrowserView()->getVclControl(); 1782 if ( pControl->GetSelectRowCount() ) 1783 { 1784 aReturn.bEnabled = m_aCurrentFrame.isActive(); 1785 break; 1786 } 1787 else 1788 aReturn.bEnabled = pControl->canCopyCellText(pControl->GetCurRow(), pControl->GetCurColumnId()); 1789 break; 1790 } 1791 SAL_FALLTHROUGH; 1792 default: 1793 return SbaXDataBrowserController::GetState(nId); 1794 } 1795 } 1796 catch(const Exception&) 1797 { 1798 DBG_UNHANDLED_EXCEPTION("dbaccess"); 1799 } 1800 1801 return aReturn; 1802 1803 } 1804 1805 void SbaTableQueryBrowser::Execute(sal_uInt16 nId, const Sequence< PropertyValue >& aArgs) 1806 { 1807 switch (nId) 1808 { 1809 default: 1810 SbaXDataBrowserController::Execute(nId,aArgs); 1811 break; 1812 1813 case ID_TREE_EDIT_DATABASE: 1814 implAdministrate( m_pTreeView->getListBox().GetCurEntry() ); 1815 break; 1816 1817 case ID_TREE_CLOSE_CONN: 1818 closeConnection( m_pTreeView->getListBox().GetRootLevelParent( m_pTreeView->getListBox().GetCurEntry() ) ); 1819 break; 1820 1821 case ID_TREE_ADMINISTRATE: 1822 svx::administrateDatabaseRegistration( getView() ); 1823 break; 1824 1825 case ID_BROWSER_REFRESH: 1826 { 1827 if ( !SaveModified( ) ) 1828 // nothing to do 1829 break; 1830 1831 bool bFullReinit = false; 1832 // check if the query signature (if the form is based on a query) has changed 1833 if ( !m_sQueryCommand.isEmpty() ) 1834 { 1835 OUString sNewQueryCommand; 1836 bool bNewQueryEP; 1837 1838 bool bIsQuery = 1839 implGetQuerySignature( sNewQueryCommand, bNewQueryEP ); 1840 OSL_ENSURE( bIsQuery, "SbaTableQueryBrowser::Execute: was a query before, but is not anymore?" ); 1841 1842 bFullReinit = ( sNewQueryCommand != m_sQueryCommand ) || ( m_bQueryEscapeProcessing != bNewQueryEP ); 1843 } 1844 if ( !bFullReinit ) 1845 { 1846 // let the base class do a simple reload 1847 SbaXDataBrowserController::Execute(nId,aArgs); 1848 break; 1849 } 1850 SAL_FALLTHROUGH; 1851 } 1852 1853 case ID_BROWSER_REFRESH_REBUILD: 1854 { 1855 if ( !SaveModified() ) 1856 // nothing to do 1857 break; 1858 1859 SvTreeListEntry* pSelected = m_pCurrentlyDisplayed; 1860 // unload 1861 unloadAndCleanup( false ); 1862 1863 // reselect the entry 1864 if ( pSelected ) 1865 { 1866 implSelect( pSelected ); 1867 } 1868 else 1869 { 1870 Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY); 1871 implSelect(svx::ODataAccessDescriptor(xProp)); 1872 } 1873 } 1874 break; 1875 1876 case ID_BROWSER_EXPLORER: 1877 toggleExplorer(); 1878 break; 1879 1880 case ID_BROWSER_DOCUMENT_DATASOURCE: 1881 implSelect(m_aDocumentDataSource); 1882 break; 1883 1884 case ID_BROWSER_INSERTCOLUMNS: 1885 case ID_BROWSER_INSERTCONTENT: 1886 case ID_BROWSER_FORMLETTER: 1887 if (getBrowserView() && isValidCursor()) 1888 { 1889 // the URL the slot id is assigned to 1890 OSL_ENSURE( m_aExternalFeatures.find( nId ) != m_aExternalFeatures.end(), 1891 "SbaTableQueryBrowser::Execute( ID_BROWSER_?): how could this ever be enabled?" ); 1892 URL aParentUrl = m_aExternalFeatures[ nId ].aURL; 1893 1894 // let the dispatcher execute the slot 1895 Reference< XDispatch > xDispatch( m_aExternalFeatures[ nId ].xDispatcher ); 1896 if (xDispatch.is()) 1897 { 1898 // set the properties for the dispatch 1899 1900 // first fill the selection 1901 SbaGridControl* pGrid = getBrowserView()->getVclControl(); 1902 MultiSelection* pSelection = const_cast<MultiSelection*>(pGrid->GetSelection()); 1903 Sequence< Any > aSelection; 1904 if ( !pGrid->IsAllSelected() ) 1905 { // transfer the selected rows only if not all rows are selected 1906 // (all rows means the whole table) 1907 // #i3832# 1908 if (pSelection != nullptr) 1909 { 1910 aSelection.realloc(pSelection->GetSelectCount()); 1911 long nIdx = pSelection->FirstSelected(); 1912 Any* pSelectionNos = aSelection.getArray(); 1913 while (nIdx != SFX_ENDOFSELECTION) 1914 { 1915 *pSelectionNos++ <<= static_cast<sal_Int32>(nIdx + 1); 1916 nIdx = pSelection->NextSelected(); 1917 } 1918 } 1919 } 1920 1921 Reference< XResultSet > xCursorClone; 1922 try 1923 { 1924 Reference< XResultSetAccess > xResultSetAccess(getRowSet(),UNO_QUERY); 1925 if (xResultSetAccess.is()) 1926 xCursorClone = xResultSetAccess->createResultSet(); 1927 } 1928 catch(DisposedException&) 1929 { 1930 SAL_WARN("dbaccess.ui", "Object already disposed!"); 1931 } 1932 catch(const Exception&) 1933 { 1934 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::Execute(ID_BROWSER_?): could not clone the cursor!"); 1935 } 1936 1937 Reference<XPropertySet> xProp(getRowSet(),UNO_QUERY); 1938 1939 try 1940 { 1941 ODataAccessDescriptor aDescriptor; 1942 OUString sDataSourceName; 1943 xProp->getPropertyValue(PROPERTY_DATASOURCENAME) >>= sDataSourceName; 1944 1945 aDescriptor.setDataSource(sDataSourceName); 1946 aDescriptor[DataAccessDescriptorProperty::Command] = xProp->getPropertyValue(PROPERTY_COMMAND); 1947 aDescriptor[DataAccessDescriptorProperty::CommandType] = xProp->getPropertyValue(PROPERTY_COMMAND_TYPE); 1948 aDescriptor[DataAccessDescriptorProperty::Connection] = xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION); 1949 aDescriptor[DataAccessDescriptorProperty::Cursor] <<= xCursorClone; 1950 if ( aSelection.getLength() ) 1951 { 1952 aDescriptor[DataAccessDescriptorProperty::Selection] <<= aSelection; 1953 aDescriptor[DataAccessDescriptorProperty::BookmarkSelection] <<= false; 1954 // these are selection indices 1955 // before we change this, all clients have to be adjusted 1956 // so that they recognize the new BookmarkSelection property! 1957 } 1958 1959 xDispatch->dispatch(aParentUrl, aDescriptor.createPropertyValueSequence()); 1960 } 1961 catch( const Exception& ) 1962 { 1963 DBG_UNHANDLED_EXCEPTION("dbaccess"); 1964 } 1965 } 1966 } 1967 break; 1968 1969 case ID_BROWSER_CLOSE: 1970 closeTask(); 1971 // if it's not 0, such a async close is already pending 1972 break; 1973 1974 case ID_BROWSER_COPY: 1975 if(m_pTreeView->HasChildPathFocus()) 1976 { 1977 copyEntry(m_pTreeView->getListBox().GetCurEntry()); 1978 } 1979 else if (getBrowserView() && getBrowserView()->getVclControl() && !getBrowserView()->getVclControl()->IsEditing() && getBrowserView()->getVclControl()->GetSelectRowCount() < 1) 1980 { 1981 SbaGridControl* pControl = getBrowserView()->getVclControl(); 1982 pControl->copyCellText(pControl->GetCurRow(), pControl->GetCurColumnId()); 1983 } 1984 else 1985 SbaXDataBrowserController::Execute(nId,aArgs); 1986 break; 1987 } 1988 } 1989 1990 void SbaTableQueryBrowser::implAddDatasource( const OUString& _rDataSourceName, const SharedConnection& _rxConnection ) 1991 { 1992 Image a, b, c; 1993 OUString d, e; 1994 implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection ); 1995 } 1996 1997 void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, Image& _rDbImage, 1998 OUString& _rQueryName, Image& _rQueryImage, OUString& _rTableName, Image& _rTableImage, 1999 const SharedConnection& _rxConnection) 2000 { 2001 SolarMutexGuard aGuard; 2002 // initialize the names/images if necessary 2003 if (_rQueryName.isEmpty()) 2004 _rQueryName = DBA_RES(RID_STR_QUERIES_CONTAINER); 2005 if (_rTableName.isEmpty()) 2006 _rTableName = DBA_RES(RID_STR_TABLES_CONTAINER); 2007 2008 if (!_rQueryImage) 2009 _rQueryImage = ImageProvider::getFolderImage( DatabaseObject::QUERY ); 2010 if (!_rTableImage) 2011 _rTableImage = ImageProvider::getFolderImage( DatabaseObject::TABLE ); 2012 2013 if (!_rDbImage) 2014 _rDbImage = ImageProvider::getDatabaseImage(); 2015 2016 // add the entry for the data source 2017 // special handling for data sources denoted by URLs - we do not want to display this ugly URL, do we? 2018 // #i33699# 2019 OUString sDSDisplayName, sDataSourceId; 2020 getDataSourceDisplayName_isURL( _rDbName, sDSDisplayName, sDataSourceId ); 2021 2022 SvTreeListEntry* pDatasourceEntry = m_pTreeView->getListBox().InsertEntry( sDSDisplayName, _rDbImage, _rDbImage ); 2023 DBTreeListUserData* pDSData = new DBTreeListUserData; 2024 pDSData->eType = etDatasource; 2025 pDSData->sAccessor = sDataSourceId; 2026 pDSData->xConnection = _rxConnection; 2027 pDatasourceEntry->SetUserData(pDSData); 2028 2029 // the child for the queries container 2030 { 2031 DBTreeListUserData* pQueriesData = new DBTreeListUserData; 2032 pQueriesData->eType = etQueryContainer; 2033 2034 m_pTreeView->getListBox().InsertEntry( 2035 _rQueryName, _rQueryImage, _rQueryImage, pDatasourceEntry, 2036 true /*ChildrenOnDemand*/, TREELIST_APPEND, pQueriesData ); 2037 } 2038 2039 // the child for the tables container 2040 { 2041 DBTreeListUserData* pTablesData = new DBTreeListUserData; 2042 pTablesData->eType = etTableContainer; 2043 2044 m_pTreeView->getListBox().InsertEntry( 2045 _rTableName, _rTableImage, _rTableImage, pDatasourceEntry, 2046 true /*ChildrenOnDemand*/, TREELIST_APPEND, pTablesData ); 2047 } 2048 2049 } 2050 2051 void SbaTableQueryBrowser::initializeTreeModel() 2052 { 2053 if (m_xDatabaseContext.is()) 2054 { 2055 Image aDBImage, aQueriesImage, aTablesImage; 2056 OUString sQueriesName, sTablesName; 2057 2058 // fill the model with the names of the registered datasources 2059 for (const OUString& rDatasource : m_xDatabaseContext->getElementNames()) 2060 implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() ); 2061 } 2062 } 2063 2064 void SbaTableQueryBrowser::populateTree(const Reference<XNameAccess>& _xNameAccess, 2065 SvTreeListEntry* _pParent, 2066 EntryType _eEntryType) 2067 { 2068 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pParent->GetUserData()); 2069 if(pData) // don't ask if the nameaccess is already set see OnExpandEntry views and tables 2070 pData->xContainer = _xNameAccess; 2071 2072 try 2073 { 2074 for (const OUString& rName : _xNameAccess->getElementNames()) 2075 { 2076 if( !m_pTreeView->getListBox().GetEntryPosByName(rName,_pParent)) 2077 { 2078 DBTreeListUserData* pEntryData = new DBTreeListUserData; 2079 pEntryData->eType = _eEntryType; 2080 if ( _eEntryType == etQuery ) 2081 { 2082 Reference<XNameAccess> xChild(_xNameAccess->getByName(rName),UNO_QUERY); 2083 if ( xChild.is() ) 2084 pEntryData->eType = etQueryContainer; 2085 } 2086 implAppendEntry( _pParent, rName, pEntryData, pEntryData->eType ); 2087 } 2088 } 2089 } 2090 catch(const Exception&) 2091 { 2092 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree"); 2093 } 2094 } 2095 2096 SvTreeListEntry* SbaTableQueryBrowser::implAppendEntry( SvTreeListEntry* _pParent, const OUString& _rName, void* _pUserData, EntryType _eEntryType ) 2097 { 2098 std::unique_ptr< ImageProvider > pImageProvider( getImageProviderFor( _pParent ) ); 2099 2100 Image aImage; 2101 pImageProvider->getImages( _rName, getDatabaseObjectType( _eEntryType ), aImage ); 2102 2103 SvTreeListEntry* pNewEntry = m_pTreeView->getListBox().InsertEntry( _rName, _pParent, _eEntryType == etQueryContainer , TREELIST_APPEND, _pUserData ); 2104 2105 m_pTreeView->getListBox().SetExpandedEntryBmp( pNewEntry, aImage ); 2106 m_pTreeView->getListBox().SetCollapsedEntryBmp( pNewEntry, aImage ); 2107 2108 return pNewEntry; 2109 } 2110 2111 IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, SvTreeListEntry*, _pParent, bool) 2112 { 2113 if (_pParent->HasChildren()) 2114 // nothing to do... 2115 return true; 2116 2117 SvTreeListEntry* pFirstParent = m_pTreeView->getListBox().GetRootLevelParent(_pParent); 2118 OSL_ENSURE(pFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!"); 2119 2120 DBTreeListUserData* pData = static_cast< DBTreeListUserData* >(_pParent->GetUserData()); 2121 assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!"); 2122 #if OSL_DEBUG_LEVEL > 0 2123 SvLBoxString* pString = static_cast<SvLBoxString*>(pFirstParent->GetFirstItem(SvLBoxItemType::String)); 2124 OSL_ENSURE(pString,"SbaTableQueryBrowser::OnExpandEntry: No string item!"); 2125 #endif 2126 2127 if (etTableContainer == pData->eType) 2128 { 2129 WaitObject aWaitCursor(getBrowserView()); 2130 2131 // it could be that we already have a connection 2132 SharedConnection xConnection; 2133 ensureConnection( pFirstParent, xConnection ); 2134 2135 if ( xConnection.is() ) 2136 { 2137 SQLExceptionInfo aInfo; 2138 try 2139 { 2140 Reference< XWarningsSupplier > xWarnings(xConnection, UNO_QUERY); 2141 if (xWarnings.is()) 2142 xWarnings->clearWarnings(); 2143 2144 // first insert the views because the tables can also include 2145 // views but that time the bitmap is the wrong one 2146 // the nameaccess will be overwritten in populateTree 2147 Reference<XViewsSupplier> xViewSup(xConnection,UNO_QUERY); 2148 if(xViewSup.is()) 2149 populateTree( xViewSup->getViews(), _pParent, etTableOrView ); 2150 2151 Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY); 2152 if(xTabSup.is()) 2153 { 2154 populateTree( xTabSup->getTables(), _pParent, etTableOrView ); 2155 Reference<XContainer> xCont(xTabSup->getTables(),UNO_QUERY); 2156 if(xCont.is()) 2157 // add as listener to know when elements are inserted or removed 2158 xCont->addContainerListener(this); 2159 } 2160 2161 if (xWarnings.is()) 2162 { 2163 SQLExceptionInfo aWarnings(xWarnings->getWarnings()); 2164 #if 0 2165 // Obviously this if test is always false. So to avoid a Clang warning 2166 // "use of logical '&&' with constant operand" I put this in #if 2167 // 0. Yeah, I know it is fairly likely nobody will ever read this 2168 // comment and make a decision what to do here, so I could as well 2169 // have just binned this... 2170 if (aWarnings.isValid() && sal_False) 2171 { 2172 SQLContext aContext; 2173 aContext.Message = DBA_RES(STR_OPENTABLES_WARNINGS); 2174 aContext.Details = DBA_RES(STR_OPENTABLES_WARNINGS_DETAILS); 2175 aContext.NextException = aWarnings.get(); 2176 aWarnings = aContext; 2177 showError(aWarnings); 2178 } 2179 #endif 2180 // TODO: we need a better concept for these warnings: 2181 // something like "don't show any warnings for this datasource, again" would be nice 2182 // But this requires an extension of the InteractionHandler and an additional property on the data source 2183 } 2184 } 2185 catch(const SQLContext& e) { aInfo = e; } 2186 catch(const SQLWarning& e) { aInfo = e; } 2187 catch(const SQLException& e) { aInfo = e; } 2188 catch(const WrappedTargetException& e) 2189 { 2190 SQLException aSql; 2191 if(e.TargetException >>= aSql) 2192 aInfo = aSql; 2193 else 2194 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: something strange happened!"); 2195 } 2196 catch( const Exception& ) 2197 { 2198 DBG_UNHANDLED_EXCEPTION("dbaccess"); 2199 } 2200 if (aInfo.isValid()) 2201 showError(aInfo); 2202 } 2203 else 2204 return false; 2205 // 0 indicates that an error occurred 2206 } 2207 else 2208 { // we have to expand the queries or bookmarks 2209 if (ensureEntryObject(_pParent)) 2210 { 2211 DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( _pParent->GetUserData() ); 2212 Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY ); 2213 populateTree( xCollection, _pParent, etQuery ); 2214 } 2215 } 2216 return true; 2217 } 2218 2219 bool SbaTableQueryBrowser::ensureEntryObject( SvTreeListEntry* _pEntry ) 2220 { 2221 OSL_ENSURE(_pEntry, "SbaTableQueryBrowser::ensureEntryObject: invalid argument!"); 2222 if (!_pEntry) 2223 return false; 2224 2225 EntryType eType = getEntryType( _pEntry ); 2226 2227 // the user data of the entry 2228 DBTreeListUserData* pEntryData = static_cast<DBTreeListUserData*>(_pEntry->GetUserData()); 2229 OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!"); 2230 2231 SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent(_pEntry); 2232 2233 bool bSuccess = false; 2234 switch (eType) 2235 { 2236 case etQueryContainer: 2237 if ( pEntryData->xContainer.is() ) 2238 { 2239 // nothing to do 2240 bSuccess = true; 2241 break; 2242 } 2243 2244 { 2245 SvTreeListEntry* pParent = m_pTreeView->getListBox().GetParent(_pEntry); 2246 if ( pParent != pDataSourceEntry ) 2247 { 2248 SvLBoxString* pString = static_cast<SvLBoxString*>(_pEntry->GetFirstItem(SvLBoxItemType::String)); 2249 OSL_ENSURE(pString,"There must be a string item!"); 2250 OUString aName(pString->GetText()); 2251 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pParent->GetUserData()); 2252 try 2253 { 2254 Reference< XNameAccess > xNameAccess(pData->xContainer,UNO_QUERY); 2255 if ( xNameAccess.is() ) 2256 pEntryData->xContainer.set(xNameAccess->getByName(aName),UNO_QUERY); 2257 } 2258 catch(const Exception& ) 2259 { 2260 DBG_UNHANDLED_EXCEPTION("dbaccess"); 2261 } 2262 2263 bSuccess = pEntryData->xContainer.is(); 2264 } 2265 else 2266 { 2267 try 2268 { 2269 Reference< XQueryDefinitionsSupplier > xQuerySup; 2270 m_xDatabaseContext->getByName( getDataSourceAccessor( pDataSourceEntry ) ) >>= xQuerySup; 2271 if (xQuerySup.is()) 2272 { 2273 Reference< XNameAccess > xQueryDefs = xQuerySup->getQueryDefinitions(); 2274 Reference< XContainer > xCont(xQueryDefs, UNO_QUERY); 2275 if (xCont.is()) 2276 // add as listener to get notified if elements are inserted or removed 2277 xCont->addContainerListener(this); 2278 2279 pEntryData->xContainer = xQueryDefs; 2280 bSuccess = pEntryData->xContainer.is(); 2281 } 2282 else { 2283 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: no XQueryDefinitionsSupplier interface!"); 2284 } 2285 } 2286 catch( const Exception& ) 2287 { 2288 DBG_UNHANDLED_EXCEPTION("dbaccess"); 2289 } 2290 } 2291 } 2292 break; 2293 2294 default: 2295 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::ensureEntryObject: ooops ... missing some implementation here!"); 2296 // TODO ... 2297 break; 2298 } 2299 2300 return bSuccess; 2301 } 2302 2303 bool SbaTableQueryBrowser::implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect) 2304 { 2305 // extract the props 2306 OUString sDataSource; 2307 OUString sCommand; 2308 sal_Int32 nCommandType = CommandType::COMMAND; 2309 bool bEscapeProcessing = true; 2310 extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing); 2311 2312 // select it 2313 return implSelect( sDataSource, sCommand, nCommandType, bEscapeProcessing, SharedConnection(), _bSelectDirect ); 2314 } 2315 2316 bool SbaTableQueryBrowser::implLoadAnything(const OUString& _rDataSourceName, const OUString& _rCommand, 2317 const sal_Int32 _nCommandType, const bool _bEscapeProcessing, const SharedConnection& _rxConnection) 2318 { 2319 try 2320 { 2321 Reference<XPropertySet> xProp( getRowSet(), UNO_QUERY_THROW ); 2322 Reference< XLoadable > xLoadable( xProp, UNO_QUERY_THROW ); 2323 // the values allowing the RowSet to re-execute 2324 xProp->setPropertyValue(PROPERTY_DATASOURCENAME, makeAny(_rDataSourceName)); 2325 if(_rxConnection.is()) 2326 xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( _rxConnection.getTyped() ) ); 2327 2328 // set this _before_ setting the connection, else the rowset would rebuild it ... 2329 xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, makeAny(_nCommandType)); 2330 xProp->setPropertyValue(PROPERTY_COMMAND, makeAny(_rCommand)); 2331 xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny(_bEscapeProcessing)); 2332 if ( m_bPreview ) 2333 { 2334 xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, makeAny(FetchDirection::FORWARD)); 2335 } 2336 2337 // the formatter depends on the data source we're working on, so rebuild it here ... 2338 initFormatter(); 2339 2340 // switch the grid to design mode while loading 2341 getBrowserView()->getGridControl()->setDesignMode(true); 2342 InitializeForm( xProp ); 2343 2344 bool bSuccess = true; 2345 2346 { 2347 { 2348 Reference< XNameContainer > xColContainer(getFormComponent(), UNO_QUERY); 2349 // first we have to clear the grid 2350 clearGridColumns(xColContainer); 2351 } 2352 FormErrorHelper aHelper(this); 2353 // load the form 2354 bSuccess = reloadForm(xLoadable); 2355 2356 // initialize the model 2357 InitializeGridModel(getFormComponent()); 2358 2359 Any aVal = xProp->getPropertyValue(PROPERTY_ISNEW); 2360 if (aVal.hasValue() && ::comphelper::getBOOL(aVal)) 2361 { 2362 // then set the default values and the parameters given from the parent 2363 Reference< XReset> xReset(xProp, UNO_QUERY); 2364 xReset->reset(); 2365 } 2366 2367 if ( m_bPreview ) 2368 initializePreviewMode(); 2369 2370 LoadFinished(true); 2371 } 2372 2373 InvalidateAll(); 2374 return bSuccess; 2375 } 2376 catch( const SQLException& ) 2377 { 2378 Any aException( ::cppu::getCaughtException() ); 2379 showError( SQLExceptionInfo( aException ) ); 2380 } 2381 catch( const WrappedTargetException& e ) 2382 { 2383 if ( e.TargetException.isExtractableTo( ::cppu::UnoType< SQLException >::get() ) ) 2384 showError( SQLExceptionInfo( e.TargetException ) ); 2385 else 2386 SAL_WARN("dbaccess", e); 2387 } 2388 catch(const Exception&) 2389 { 2390 DBG_UNHANDLED_EXCEPTION("dbaccess"); 2391 } 2392 2393 InvalidateAll(); 2394 return false; 2395 } 2396 2397 bool SbaTableQueryBrowser::implSelect(const OUString& _rDataSourceName, const OUString& _rCommand, 2398 const sal_Int32 _nCommandType, const bool _bEscapeProcessing, 2399 const SharedConnection& _rxConnection, 2400 bool _bSelectDirect) 2401 { 2402 if (_rDataSourceName.getLength() && _rCommand.getLength() && (-1 != _nCommandType)) 2403 { 2404 SvTreeListEntry* pDataSource = nullptr; 2405 SvTreeListEntry* pCommandType = nullptr; 2406 SvTreeListEntry* pCommand = getObjectEntry( _rDataSourceName, _rCommand, _nCommandType, &pDataSource, &pCommandType, true, _rxConnection ); 2407 2408 if (pCommand) 2409 { 2410 bool bSuccess = true; 2411 if ( _bSelectDirect ) 2412 { 2413 bSuccess = implSelect( pCommand ); 2414 } 2415 else 2416 { 2417 m_pTreeView->getListBox().Select( pCommand ); 2418 } 2419 2420 if ( bSuccess ) 2421 { 2422 m_pTreeView->getListBox().MakeVisible(pCommand); 2423 m_pTreeView->getListBox().SetCursor(pCommand); 2424 } 2425 } 2426 else if (!pCommandType) 2427 { 2428 if ( m_pCurrentlyDisplayed ) 2429 { // tell the old entry (if any) it has been deselected 2430 selectPath(m_pCurrentlyDisplayed, false); 2431 m_pCurrentlyDisplayed = nullptr; 2432 } 2433 2434 // we have a command and need to display this in the rowset 2435 return implLoadAnything(_rDataSourceName, _rCommand, _nCommandType, _bEscapeProcessing, _rxConnection); 2436 } 2437 } 2438 return false; 2439 } 2440 2441 IMPL_LINK_NOARG(SbaTableQueryBrowser, OnSelectionChange, LinkParamNone*, void) 2442 { 2443 implSelect( m_pTreeView->getListBox().FirstSelected() ); 2444 } 2445 2446 SvTreeListEntry* SbaTableQueryBrowser::implGetConnectionEntry(SvTreeListEntry* _pEntry) const 2447 { 2448 SvTreeListEntry* pCurrentEntry = _pEntry; 2449 DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() ); 2450 while(pEntryData->eType != etDatasource ) 2451 { 2452 pCurrentEntry = m_pTreeView->GetTreeModel()->GetParent(pCurrentEntry); 2453 pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() ); 2454 } 2455 return pCurrentEntry; 2456 } 2457 2458 bool SbaTableQueryBrowser::implSelect( SvTreeListEntry* _pEntry ) 2459 { 2460 if ( !_pEntry ) 2461 return false; 2462 2463 DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( _pEntry->GetUserData() ); 2464 switch (pEntryData->eType) 2465 { 2466 case etTableOrView: 2467 case etQuery: 2468 break; 2469 default: 2470 // nothing to do 2471 return false; 2472 } 2473 2474 OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(_pEntry), "SbaTableQueryBrowser::implSelect: invalid entry (1)!"); 2475 OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(m_pTreeView->GetTreeModel()->GetParent(_pEntry)), "SbaTableQueryBrowser::implSelect: invalid entry (2)!"); 2476 2477 // get the entry for the tables or queries 2478 SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(_pEntry); 2479 DBTreeListUserData* pContainerData = static_cast<DBTreeListUserData*>(pContainer->GetUserData()); 2480 2481 // get the entry for the datasource 2482 SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer); 2483 DBTreeListUserData* pConData = static_cast<DBTreeListUserData*>(pConnection->GetUserData()); 2484 2485 // reinitialize the rowset 2486 // but first check if it is necessary 2487 // get all old properties 2488 Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY); 2489 OUString aOldName; 2490 xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName; 2491 sal_Int32 nOldType = 0; 2492 xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType; 2493 Reference<XConnection> xOldConnection(xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY); 2494 2495 // the name of the table or query 2496 SvLBoxString* pString = static_cast<SvLBoxString*>(_pEntry->GetFirstItem(SvLBoxItemType::String)); 2497 OSL_ENSURE(pString,"There must be a string item!"); 2498 const OUString sSimpleName = pString->GetText(); 2499 OUStringBuffer sNameBuffer(sSimpleName); 2500 if ( etQueryContainer == pContainerData->eType ) 2501 { 2502 SvTreeListEntry* pTemp = pContainer; 2503 while( m_pTreeView->GetTreeModel()->GetParent(pTemp) != pConnection ) 2504 { 2505 sNameBuffer.insert(0,'/'); 2506 pString = static_cast<SvLBoxString*>(pTemp->GetFirstItem(SvLBoxItemType::String)); 2507 OSL_ENSURE(pString,"There must be a string item!"); 2508 sNameBuffer.insert(0,pString->GetText()); 2509 pTemp = m_pTreeView->GetTreeModel()->GetParent(pTemp); 2510 } 2511 } 2512 OUString aName = sNameBuffer.makeStringAndClear(); 2513 2514 sal_Int32 nCommandType = ( etTableContainer == pContainerData->eType) 2515 ? CommandType::TABLE 2516 : CommandType::QUERY; 2517 2518 // check if need to rebuild the rowset 2519 bool bRebuild = ( xOldConnection != pConData->xConnection ) 2520 || ( nOldType != nCommandType ) 2521 || ( aName != aOldName ); 2522 2523 Reference< css::form::XLoadable > xLoadable = getLoadable(); 2524 bRebuild |= !xLoadable->isLoaded(); 2525 bool bSuccess = true; 2526 if ( bRebuild ) 2527 { 2528 try 2529 { 2530 WaitObject aWaitCursor(getBrowserView()); 2531 2532 // tell the old entry it has been deselected 2533 selectPath(m_pCurrentlyDisplayed, false); 2534 m_pCurrentlyDisplayed = nullptr; 2535 2536 // not really loaded 2537 m_pCurrentlyDisplayed = _pEntry; 2538 // tell the new entry it has been selected 2539 selectPath(m_pCurrentlyDisplayed); 2540 2541 // get the name of the data source currently selected 2542 ensureConnection( m_pCurrentlyDisplayed, pConData->xConnection ); 2543 2544 if ( !pConData->xConnection.is() ) 2545 { 2546 unloadAndCleanup( false ); 2547 return false; 2548 } 2549 2550 Reference<XNameAccess> xNameAccess; 2551 switch(nCommandType) 2552 { 2553 case CommandType::TABLE: 2554 { 2555 // only for tables 2556 if ( !pContainerData->xContainer.is() ) 2557 { 2558 Reference<XTablesSupplier> xSup( pConData->xConnection, UNO_QUERY ); 2559 if(xSup.is()) 2560 xNameAccess = xSup->getTables(); 2561 2562 pContainerData->xContainer = xNameAccess; 2563 } 2564 else 2565 xNameAccess.set( pContainerData->xContainer, UNO_QUERY ); 2566 } 2567 break; 2568 case CommandType::QUERY: 2569 { 2570 if ( pContainerData->xContainer.is() ) 2571 xNameAccess.set( pContainerData->xContainer, UNO_QUERY ); 2572 else 2573 { 2574 Reference<XQueriesSupplier> xSup( pConData->xConnection, UNO_QUERY ); 2575 if(xSup.is()) 2576 xNameAccess = xSup->getQueries(); 2577 } 2578 } 2579 break; 2580 } 2581 OUString sStatus(DBA_RES(CommandType::TABLE == nCommandType ? STR_LOADING_TABLE : STR_LOADING_QUERY)); 2582 sStatus = sStatus.replaceFirst("$name$", aName); 2583 BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sStatus); 2584 2585 bool bEscapeProcessing = true; 2586 if(xNameAccess.is() && xNameAccess->hasByName(sSimpleName)) 2587 { 2588 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(_pEntry->GetUserData()); 2589 if ( !pData->xObjectProperties.is() ) 2590 { 2591 Reference<XInterface> xObject; 2592 if(xNameAccess->getByName(sSimpleName) >>= xObject) // remember the table or query object 2593 { 2594 pData->xObjectProperties.set(xObject, css::uno::UNO_QUERY); 2595 // if the query contains a parameterized statement and preview is enabled we won't get any data. 2596 if ( nCommandType == CommandType::QUERY && xObject.is() ) 2597 { 2598 Reference<XPropertySet> xObjectProps(xObject,UNO_QUERY); 2599 xObjectProps->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bEscapeProcessing; 2600 if ( m_bPreview ) 2601 { 2602 OUString sSql; 2603 xObjectProps->getPropertyValue(PROPERTY_COMMAND) >>= sSql; 2604 Reference< XMultiServiceFactory > xFactory( pConData->xConnection, UNO_QUERY ); 2605 if (xFactory.is()) 2606 { 2607 try 2608 { 2609 Reference<XSingleSelectQueryAnalyzer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); 2610 if ( xAnalyzer.is() ) 2611 { 2612 xAnalyzer->setQuery(sSql); 2613 Reference<XParametersSupplier> xParSup(xAnalyzer,UNO_QUERY); 2614 if ( xParSup->getParameters()->getCount() > 0 ) 2615 { 2616 OUString sFilter = " WHERE "; 2617 sFilter = sFilter + xAnalyzer->getFilter(); 2618 OUString sReplace(sSql); 2619 sReplace = sReplace.replaceFirst(sFilter, ""); 2620 xAnalyzer->setQuery(sReplace); 2621 Reference<XSingleSelectQueryComposer> xComposer(xAnalyzer,UNO_QUERY); 2622 xComposer->setFilter("0=1"); 2623 aName = xAnalyzer->getQuery(); 2624 nCommandType = CommandType::COMMAND; 2625 } 2626 } 2627 } 2628 catch (Exception&) 2629 { 2630 DBG_UNHANDLED_EXCEPTION("dbaccess"); 2631 } 2632 } 2633 } 2634 } 2635 } 2636 } 2637 } 2638 2639 OUString sDataSourceName( getDataSourceAccessor( pConnection ) ); 2640 bSuccess = implLoadAnything( sDataSourceName, aName, nCommandType, bEscapeProcessing, pConData->xConnection ); 2641 if ( !bSuccess ) 2642 { // clean up 2643 criticalFail(); 2644 } 2645 } 2646 catch(const SQLException& e) 2647 { 2648 showError(SQLExceptionInfo(e)); 2649 // reset the values 2650 xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any()); 2651 xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any()); 2652 bSuccess = false; 2653 } 2654 catch(WrappedTargetException& e) 2655 { 2656 SQLException aSql; 2657 if(e.TargetException >>= aSql) 2658 showError(SQLExceptionInfo(aSql)); 2659 else 2660 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::implSelect: something strange happened!"); 2661 // reset the values 2662 xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any()); 2663 xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any()); 2664 bSuccess = false; 2665 } 2666 catch(const Exception&) 2667 { 2668 // reset the values 2669 xRowSetProps->setPropertyValue(PROPERTY_DATASOURCENAME,Any()); 2670 xRowSetProps->setPropertyValue(PROPERTY_ACTIVE_CONNECTION,Any()); 2671 bSuccess = false; 2672 } 2673 } 2674 return bSuccess; 2675 } 2676 2677 SvTreeListEntry* SbaTableQueryBrowser::getEntryFromContainer(const Reference<XNameAccess>& _rxNameAccess) 2678 { 2679 DBTreeListBox& rListBox = m_pTreeView->getListBox(); 2680 SvTreeListEntry* pContainer = nullptr; 2681 SvTreeListEntry* pDSLoop = rListBox.FirstChild(nullptr); 2682 while (pDSLoop) 2683 { 2684 pContainer = rListBox.GetEntry(pDSLoop, CONTAINER_QUERIES); 2685 DBTreeListUserData* pQueriesData = static_cast<DBTreeListUserData*>(pContainer->GetUserData()); 2686 if ( pQueriesData && pQueriesData->xContainer == _rxNameAccess ) 2687 break; 2688 2689 pContainer = rListBox.GetEntry(pDSLoop, CONTAINER_TABLES); 2690 DBTreeListUserData* pTablesData = static_cast<DBTreeListUserData*>(pContainer->GetUserData()); 2691 if ( pTablesData && pTablesData->xContainer == _rxNameAccess ) 2692 break; 2693 2694 pDSLoop = pDSLoop->NextSibling(); 2695 pContainer = nullptr; 2696 } 2697 return pContainer; 2698 } 2699 2700 void SAL_CALL SbaTableQueryBrowser::elementInserted( const ContainerEvent& _rEvent ) 2701 { 2702 SolarMutexGuard aSolarGuard; 2703 2704 Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY); 2705 // first search for a definition container where we can insert this element 2706 2707 SvTreeListEntry* pEntry = getEntryFromContainer(xNames); 2708 if(pEntry) // found one 2709 { 2710 // insert the new entry into the tree 2711 DBTreeListUserData* pContainerData = static_cast<DBTreeListUserData*>(pEntry->GetUserData()); 2712 OSL_ENSURE(pContainerData, "elementInserted: There must be user data for this type!"); 2713 2714 DBTreeListUserData* pNewData = new DBTreeListUserData; 2715 bool bIsTable = etTableContainer == pContainerData->eType; 2716 if ( bIsTable ) 2717 { 2718 _rEvent.Element >>= pNewData->xObjectProperties;// remember the new element 2719 pNewData->eType = etTableOrView; 2720 } 2721 else 2722 { 2723 if (static_cast<sal_Int32>(m_pTreeView->getListBox().GetChildCount(pEntry)) < ( xNames->getElementNames().getLength() - 1 ) ) 2724 { 2725 // the item inserts its children on demand, but it has not been expanded yet. So ensure here and 2726 // now that it has all items 2727 populateTree(xNames, pEntry, etQuery ); 2728 } 2729 pNewData->eType = etQuery; 2730 } 2731 implAppendEntry( pEntry, ::comphelper::getString( _rEvent.Accessor ), pNewData, pNewData->eType ); 2732 } 2733 else 2734 SbaXDataBrowserController::elementInserted(_rEvent); 2735 } 2736 2737 bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(const OUString& _sName, SvTreeListEntry const * _pContainer) 2738 { 2739 return m_pCurrentlyDisplayed 2740 && getEntryType(m_pCurrentlyDisplayed) == getChildType(_pContainer) 2741 && m_pTreeView->getListBox().GetParent(m_pCurrentlyDisplayed) == _pContainer 2742 && m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed) == _sName; 2743 } 2744 2745 void SAL_CALL SbaTableQueryBrowser::elementRemoved( const ContainerEvent& _rEvent ) 2746 { 2747 SolarMutexGuard aSolarGuard; 2748 2749 Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY); 2750 // get the top-level representing the removed data source 2751 // and search for the queries and tables 2752 SvTreeListEntry* pContainer = getEntryFromContainer(xNames); 2753 if ( pContainer ) 2754 { // a query or table has been removed 2755 OUString aName = ::comphelper::getString(_rEvent.Accessor); 2756 2757 if ( isCurrentlyDisplayedChanged( aName, pContainer) ) 2758 { // the element displayed currently has been replaced 2759 2760 // we need to remember the old value 2761 SvTreeListEntry* pTemp = m_pCurrentlyDisplayed; 2762 2763 // unload 2764 unloadAndCleanup( false ); // don't dispose the connection 2765 2766 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pTemp->GetUserData()); 2767 pTemp->SetUserData(nullptr); 2768 delete pData; 2769 // the data could be null because we have a table which isn't correct 2770 m_pTreeView->GetTreeModel()->Remove(pTemp); 2771 } 2772 else 2773 { 2774 // remove the entry from the model 2775 SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer); 2776 while(pChild) 2777 { 2778 if (m_pTreeView->getListBox().GetEntryText(pChild) == aName) 2779 { 2780 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pChild->GetUserData()); 2781 pChild->SetUserData(nullptr); 2782 delete pData; 2783 m_pTreeView->GetTreeModel()->Remove(pChild); 2784 break; 2785 } 2786 pChild = pChild->NextSibling(); 2787 } 2788 } 2789 2790 // maybe the object which is part of the document data source has been removed 2791 checkDocumentDataSource(); 2792 } 2793 else 2794 SbaXDataBrowserController::elementRemoved(_rEvent); 2795 } 2796 2797 void SAL_CALL SbaTableQueryBrowser::elementReplaced( const ContainerEvent& _rEvent ) 2798 { 2799 SolarMutexGuard aSolarGuard; 2800 2801 Reference< XNameAccess > xNames(_rEvent.Source, UNO_QUERY); 2802 SvTreeListEntry* pContainer = getEntryFromContainer(xNames); 2803 if ( pContainer ) 2804 { // a table or query as been replaced 2805 OUString aName = ::comphelper::getString(_rEvent.Accessor); 2806 2807 if ( isCurrentlyDisplayedChanged( aName, pContainer) ) 2808 { // the element displayed currently has been replaced 2809 2810 // we need to remember the old value 2811 SvTreeListEntry* pTemp = m_pCurrentlyDisplayed; 2812 unloadAndCleanup( false ); // don't dispose the connection 2813 2814 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pTemp->GetUserData()); 2815 if (pData) 2816 { 2817 if ( etTableOrView == pData->eType ) 2818 { // only insert userdata when we have a table because the query is only a commanddefinition object and not a query 2819 _rEvent.Element >>= pData->xObjectProperties; // remember the new element 2820 } 2821 else 2822 { 2823 pTemp->SetUserData(nullptr); 2824 delete pData; 2825 } 2826 } 2827 } 2828 else 2829 { 2830 // find the entry for this name 2831 SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer); 2832 while(pChild) 2833 { 2834 if (m_pTreeView->getListBox().GetEntryText(pChild) == aName) 2835 { 2836 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pChild->GetUserData()); 2837 if (pData) 2838 { 2839 if ( etTableOrView == pData->eType ) 2840 { // only insert userdata when we have a table because the query is only a commanddefinition object and not a query 2841 _rEvent.Element >>= pData->xObjectProperties; // remember the new element 2842 } 2843 else 2844 { 2845 pChild->SetUserData(nullptr); 2846 delete pData; 2847 } 2848 } 2849 break; 2850 } 2851 pChild = pChild->NextSibling(); 2852 } 2853 } 2854 2855 // maybe the object which is part of the document data source has been removed 2856 checkDocumentDataSource(); 2857 } 2858 else if (xNames.get() == m_xDatabaseContext.get()) 2859 { // a datasource has been replaced in the context 2860 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::elementReplaced: no support for replaced data sources!"); 2861 // very suspicious: the database context should not allow to replace data source, only to register 2862 // and revoke them 2863 } 2864 else 2865 SbaXDataBrowserController::elementReplaced(_rEvent); 2866 } 2867 2868 void SbaTableQueryBrowser::impl_releaseConnection( SharedConnection& _rxConnection ) 2869 { 2870 // remove as event listener 2871 Reference< XComponent > xComponent( _rxConnection, UNO_QUERY ); 2872 if ( xComponent.is() ) 2873 { 2874 Reference< XEventListener > xListener( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY ); 2875 xComponent->removeEventListener( xListener ); 2876 } 2877 2878 try 2879 { 2880 // temporary (hopefully!) hack for #i55274# 2881 Reference< XFlushable > xFlush( _rxConnection, UNO_QUERY ); 2882 if ( xFlush.is() ) 2883 xFlush->flush(); 2884 } 2885 catch( const Exception& ) 2886 { 2887 DBG_UNHANDLED_EXCEPTION("dbaccess"); 2888 } 2889 2890 // clear 2891 _rxConnection.clear(); 2892 // will implicitly dispose if we have the ownership, since xConnection is a SharedConnection 2893 } 2894 2895 void SbaTableQueryBrowser::disposeConnection( SvTreeListEntry* _pDSEntry ) 2896 { 2897 OSL_ENSURE( _pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" ); 2898 OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" ); 2899 2900 if ( _pDSEntry ) 2901 { 2902 DBTreeListUserData* pTreeListData = static_cast< DBTreeListUserData* >( _pDSEntry->GetUserData() ); 2903 if ( pTreeListData ) 2904 impl_releaseConnection( pTreeListData->xConnection ); 2905 } 2906 } 2907 2908 void SbaTableQueryBrowser::closeConnection(SvTreeListEntry* _pDSEntry, bool _bDisposeConnection) 2909 { 2910 OSL_ENSURE(_pDSEntry, "SbaTableQueryBrowser::closeConnection: invalid entry (NULL)!"); 2911 OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!"); 2912 2913 // if one of the entries of the given DS is displayed currently, unload the form 2914 if (m_pCurrentlyDisplayed && (m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed) == _pDSEntry)) 2915 unloadAndCleanup(_bDisposeConnection); 2916 2917 // collapse the query/table container 2918 for (SvTreeListEntry* pContainers = m_pTreeView->GetTreeModel()->FirstChild(_pDSEntry); pContainers; pContainers = pContainers->NextSibling()) 2919 { 2920 SvTreeListEntry* pElements = m_pTreeView->GetTreeModel()->FirstChild(pContainers); 2921 if ( pElements ) 2922 m_pTreeView->getListBox().Collapse(pContainers); 2923 m_pTreeView->getListBox().EnableExpandHandler(pContainers); 2924 // and delete their children (they are connection-relative) 2925 for (; pElements; ) 2926 { 2927 SvTreeListEntry* pRemove = pElements; 2928 pElements = pElements->NextSibling(); 2929 DBTreeListUserData* pData = static_cast<DBTreeListUserData*>(pRemove->GetUserData()); 2930 pRemove->SetUserData(nullptr); 2931 delete pData; 2932 m_pTreeView->GetTreeModel()->Remove(pRemove); 2933 } 2934 } 2935 // collapse the entry itself 2936 m_pTreeView->getListBox().Collapse(_pDSEntry); 2937 2938 // dispose/reset the connection 2939 if ( _bDisposeConnection ) 2940 disposeConnection( _pDSEntry ); 2941 } 2942 2943 void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection ) 2944 { 2945 if (!m_pCurrentlyDisplayed) 2946 // nothing to do 2947 return; 2948 2949 SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed); 2950 2951 // de-select the path for the currently displayed table/query 2952 if (m_pCurrentlyDisplayed) 2953 { 2954 selectPath(m_pCurrentlyDisplayed, false); 2955 } 2956 m_pCurrentlyDisplayed = nullptr; 2957 2958 try 2959 { 2960 // get the active connection. We need to dispose it. 2961 Reference< XPropertySet > xRowSetProps(getRowSet(),UNO_QUERY); 2962 Reference< XConnection > xConn; 2963 xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION) >>= xConn; 2964 #if OSL_DEBUG_LEVEL > 0 2965 { 2966 Reference< XComponent > xComp( 2967 xRowSetProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION), 2968 css::uno::UNO_QUERY); 2969 } 2970 #endif 2971 2972 // unload the form 2973 Reference< XLoadable > xLoadable = getLoadable(); 2974 if (xLoadable->isLoaded()) 2975 xLoadable->unload(); 2976 2977 // clear the grid control 2978 Reference< XNameContainer > xConta(getControlModel(),UNO_QUERY); 2979 clearGridColumns(xConta); 2980 2981 // dispose the connection 2982 if(_bDisposeConnection) 2983 disposeConnection( pDSEntry ); 2984 } 2985 catch(SQLException& e) 2986 { 2987 showError(SQLExceptionInfo(e)); 2988 } 2989 catch(WrappedTargetException& e) 2990 { 2991 SQLException aSql; 2992 if(e.TargetException >>= aSql) 2993 showError(SQLExceptionInfo(aSql)); 2994 else 2995 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: something strange happened!"); 2996 } 2997 catch(const Exception&) 2998 { 2999 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::unloadAndCleanup: could not reset the form"); 3000 } 3001 } 3002 3003 namespace 3004 { 3005 Reference< XInterface > lcl_getDataSource( const Reference< XDatabaseContext >& _rxDatabaseContext, 3006 const OUString& _rDataSourceName, const Reference< XConnection >& _rxConnection ) 3007 { 3008 Reference< XDataSource > xDataSource; 3009 try 3010 { 3011 if ( !_rDataSourceName.isEmpty() && _rxDatabaseContext->hasByName( _rDataSourceName ) ) 3012 xDataSource.set( _rxDatabaseContext->getByName( _rDataSourceName ), UNO_QUERY_THROW ); 3013 3014 if ( !xDataSource.is() ) 3015 { 3016 Reference< XChild > xConnAsChild( _rxConnection, UNO_QUERY ); 3017 if ( xConnAsChild.is() ) 3018 xDataSource.set( xConnAsChild->getParent(), UNO_QUERY_THROW ); 3019 } 3020 } 3021 catch( const Exception& ) 3022 { 3023 DBG_UNHANDLED_EXCEPTION("dbaccess"); 3024 } 3025 return xDataSource.get(); 3026 } 3027 } 3028 3029 void SbaTableQueryBrowser::impl_initialize() 3030 { 3031 SolarMutexGuard aGuard; 3032 // doin' a lot of VCL stuff here -> lock the SolarMutex 3033 3034 // first initialize the parent 3035 SbaXDataBrowserController::impl_initialize(); 3036 3037 Reference<XConnection> xForeignConnection; 3038 Reference< XFrame > xFrame; 3039 3040 OUString aTableName, aCatalogName, aSchemaName; 3041 3042 bool bEscapeProcessing = true; 3043 sal_Int32 nInitialDisplayCommandType = CommandType::COMMAND; 3044 OUString sInitialDataSourceName; 3045 OUString sInitialCommand; 3046 3047 const NamedValueCollection& rArguments( getInitParams() ); 3048 3049 rArguments.get_ensureType( PROPERTY_DATASOURCENAME, sInitialDataSourceName ); 3050 rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, nInitialDisplayCommandType ); 3051 rArguments.get_ensureType( PROPERTY_COMMAND, sInitialCommand ); 3052 rArguments.get_ensureType( PROPERTY_ACTIVE_CONNECTION, xForeignConnection ); 3053 rArguments.get_ensureType( PROPERTY_UPDATE_CATALOGNAME, aCatalogName ); 3054 rArguments.get_ensureType( PROPERTY_UPDATE_SCHEMANAME, aSchemaName ); 3055 rArguments.get_ensureType( PROPERTY_UPDATE_TABLENAME, aTableName ); 3056 rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing ); 3057 rArguments.get_ensureType( "Frame", xFrame ); 3058 rArguments.get_ensureType( PROPERTY_SHOWMENU, m_bShowMenu ); 3059 3060 // disable the browser if either of ShowTreeViewButton (compatibility name) or EnableBrowser 3061 // is present and set to FALSE 3062 bool bDisableBrowser = !rArguments.getOrDefault( "ShowTreeViewButton", true ) // compatibility name 3063 || !rArguments.getOrDefault( PROPERTY_ENABLE_BROWSER, true ); 3064 OSL_ENSURE( !rArguments.has( "ShowTreeViewButton" ), 3065 "SbaTableQueryBrowser::impl_initialize: ShowTreeViewButton is superseded by EnableBrowser!" ); 3066 m_bEnableBrowser = !bDisableBrowser; 3067 3068 // hide the tree view it is disabled in general, or if the settings tell to hide it initially 3069 bool bHideTreeView = ( !m_bEnableBrowser ) 3070 || !rArguments.getOrDefault( "ShowTreeView", true ) // compatibility name 3071 || !rArguments.getOrDefault( PROPERTY_SHOW_BROWSER, true ); 3072 OSL_ENSURE( !rArguments.has( "ShowTreeView" ), 3073 "SbaTableQueryBrowser::impl_initialize: ShowTreeView is superseded by ShowBrowser!" ); 3074 3075 if ( bHideTreeView ) 3076 hideExplorer(); 3077 else 3078 showExplorer(); 3079 3080 if ( m_bPreview ) 3081 { 3082 try 3083 { 3084 Sequence< OUString> aProperties(5); 3085 Sequence< Any> aValues(5); 3086 3087 OUString* pStringIter = aProperties.getArray(); 3088 Any* pValueIter = aValues.getArray(); 3089 *pStringIter++ = "AlwaysShowCursor"; 3090 *pValueIter++ <<= false; 3091 *pStringIter++ = PROPERTY_BORDER; 3092 *pValueIter++ <<= sal_Int16(0); 3093 3094 *pStringIter++ = "HasNavigationBar"; 3095 *pValueIter++ <<= false; 3096 *pStringIter++ = "HasRecordMarker"; 3097 *pValueIter++ <<= false; 3098 3099 *pStringIter++ = "Tabstop"; 3100 *pValueIter++ <<= false; 3101 3102 Reference< XMultiPropertySet > xFormMultiSet(getFormComponent(), UNO_QUERY); 3103 if ( xFormMultiSet.is() ) 3104 xFormMultiSet->setPropertyValues(aProperties, aValues); 3105 } 3106 catch(const Exception&) 3107 { 3108 DBG_UNHANDLED_EXCEPTION("dbaccess"); 3109 } 3110 } 3111 3112 // are we loaded into a (sub)frame of an embedded document (i.e. a form belonging to a database 3113 // document)? 3114 bool bSubFrameOfEmbeddedDocument = false; 3115 if ( xFrame.is() ) 3116 { 3117 Reference<XFramesSupplier> xSup = xFrame->getCreator(); 3118 Reference<XController> xCont = xSup.is() ? xSup->getController() : Reference<XController>(); 3119 3120 bSubFrameOfEmbeddedDocument = xCont.is() && ::dbtools::isEmbeddedInDatabase( xCont->getModel(), xForeignConnection ); 3121 } 3122 3123 // if we have a connection at this point, it was either passed from outside, our 3124 // determined from a outer DB document. In both cases, do not dispose it later on. 3125 SharedConnection xConnection( xForeignConnection, SharedConnection::NoTakeOwnership ); 3126 3127 // should we display all registered databases in the left hand side tree? 3128 // or only *one* special? 3129 bool bLimitedTreeEntries = false; 3130 // if we're part of a frame which is a secondary frame of a database document, then only 3131 // display the database for this document, not all registered ones 3132 bLimitedTreeEntries |= bSubFrameOfEmbeddedDocument; 3133 // if the tree view is not to be displayed at all, then only display the data source 3134 // which was given as initial selection 3135 bLimitedTreeEntries |= !m_bEnableBrowser; 3136 3137 if ( bLimitedTreeEntries ) 3138 { 3139 if ( xConnection.is() ) 3140 { 3141 startConnectionListening( xConnection ); 3142 3143 // if no initial name was given, try to obtain one from the data source 3144 if ( sInitialDataSourceName.isEmpty() ) 3145 { 3146 Reference< XChild > xChild( xConnection, UNO_QUERY ); 3147 Reference< XPropertySet > xDataSourceProperties; 3148 if ( xChild.is() ) 3149 xDataSourceProperties.set(xChild->getParent(), css::uno::UNO_QUERY); 3150 if ( xDataSourceProperties.is() ) 3151 { 3152 try 3153 { 3154 OSL_VERIFY( xDataSourceProperties->getPropertyValue( PROPERTY_NAME ) >>= sInitialDataSourceName ); 3155 } 3156 catch( const Exception& ) 3157 { 3158 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: a connection parent which does not have a 'Name'!??" ); 3159 } 3160 } 3161 } 3162 } 3163 3164 implAddDatasource( sInitialDataSourceName, xConnection ); 3165 m_pTreeView->getListBox().Expand( m_pTreeView->getListBox().First() ); 3166 } 3167 else 3168 initializeTreeModel(); 3169 3170 if ( m_bEnableBrowser ) 3171 { 3172 m_aDocScriptSupport = ::boost::optional< bool >( false ); 3173 } 3174 else 3175 { 3176 // we are not used as "browser", but as mere view for a single table/query/command. In particular, 3177 // there is a specific database document which we belong to. 3178 Reference< XOfficeDatabaseDocument > xDocument( getDataSourceOrModel( 3179 lcl_getDataSource( m_xDatabaseContext, sInitialDataSourceName, xConnection ) ), UNO_QUERY ); 3180 m_aDocScriptSupport = ::boost::optional< bool >( Reference< XEmbeddedScripts >( xDocument, UNO_QUERY ).is() ); 3181 } 3182 3183 if ( implSelect( sInitialDataSourceName, sInitialCommand, nInitialDisplayCommandType, bEscapeProcessing, xConnection, true ) ) 3184 { 3185 try 3186 { 3187 Reference< XPropertySet > xRowSetProps(getRowSet(), UNO_QUERY); 3188 xRowSetProps->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,makeAny(aCatalogName)); 3189 xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,makeAny(aSchemaName)); 3190 xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,makeAny(aTableName)); 3191 3192 } 3193 catch(const Exception&) 3194 { 3195 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::impl_initialize: could not set the update related names!"); 3196 } 3197 } 3198 3199 InvalidateAll(); 3200 } 3201 3202 bool SbaTableQueryBrowser::haveExplorer() const 3203 { 3204 return m_pTreeView && m_pTreeView->IsVisible(); 3205 } 3206 3207 void SbaTableQueryBrowser::hideExplorer() 3208 { 3209 if (!haveExplorer()) 3210 return; 3211 if (!getBrowserView()) 3212 return; 3213 3214 m_pTreeView->Hide(); 3215 m_pSplitter->Hide(); 3216 getBrowserView()->Resize(); 3217 3218 InvalidateFeature(ID_BROWSER_EXPLORER); 3219 } 3220 3221 void SbaTableQueryBrowser::showExplorer() 3222 { 3223 if (haveExplorer()) 3224 return; 3225 3226 if (!getBrowserView()) 3227 return; 3228 3229 m_pTreeView->Show(); 3230 m_pSplitter->Show(); 3231 getBrowserView()->Resize(); 3232 3233 InvalidateFeature(ID_BROWSER_EXPLORER); 3234 } 3235 3236 bool SbaTableQueryBrowser::ensureConnection(SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection) 3237 { 3238 SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(_pAnyEntry); 3239 DBTreeListUserData* pDSData = 3240 pDSEntry 3241 ? static_cast<DBTreeListUserData*>(pDSEntry->GetUserData()) 3242 : nullptr; 3243 3244 return ensureConnection( pDSEntry, pDSData, _rConnection ); 3245 } 3246 3247 std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor( SvTreeListEntry* _pAnyEntry ) 3248 { 3249 std::unique_ptr< ImageProvider > pImageProvider( new ImageProvider ); 3250 SharedConnection xConnection; 3251 if ( getExistentConnectionFor( _pAnyEntry, xConnection ) ) 3252 pImageProvider.reset( new ImageProvider( xConnection ) ); 3253 return pImageProvider; 3254 } 3255 3256 bool SbaTableQueryBrowser::getExistentConnectionFor( SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection ) 3257 { 3258 SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent( _pAnyEntry ); 3259 DBTreeListUserData* pDSData = 3260 pDSEntry 3261 ? static_cast< DBTreeListUserData* >( pDSEntry->GetUserData() ) 3262 : nullptr; 3263 if ( pDSData ) 3264 _rConnection = pDSData->xConnection; 3265 return _rConnection.is(); 3266 } 3267 3268 bool SbaTableQueryBrowser::impl_isDataSourceEntry( SvTreeListEntry* _pEntry ) const 3269 { 3270 return m_pTreeView->GetTreeModel()->GetRootLevelParent( _pEntry ) == _pEntry; 3271 } 3272 3273 bool SbaTableQueryBrowser::ensureConnection( SvTreeListEntry* _pDSEntry, void* pDSData, SharedConnection& _rConnection ) 3274 { 3275 OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" ); 3276 if(_pDSEntry) 3277 { 3278 DBTreeListUserData* pTreeListData = static_cast<DBTreeListUserData*>(pDSData); 3279 OUString aDSName = GetEntryText(_pDSEntry); 3280 3281 if ( pTreeListData ) 3282 _rConnection = pTreeListData->xConnection; 3283 3284 if ( !_rConnection.is() && pTreeListData ) 3285 { 3286 // show the "connecting to ..." status 3287 OUString sConnecting(DBA_RES(STR_CONNECTING_DATASOURCE)); 3288 sConnecting = sConnecting.replaceFirst("$name$", aDSName); 3289 BrowserViewStatusDisplay aShowStatus(static_cast<UnoDataBrowserView*>(getView()), sConnecting); 3290 3291 // build a string showing context information in case of error 3292 OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE)); 3293 sConnectingContext = sConnectingContext.replaceFirst("$name$", aDSName); 3294 3295 // connect 3296 _rConnection.reset( 3297 connect( getDataSourceAccessor( _pDSEntry ), sConnectingContext, nullptr ), 3298 SharedConnection::TakeOwnership 3299 ); 3300 3301 // remember the connection 3302 pTreeListData->xConnection = _rConnection; 3303 } 3304 } 3305 3306 return _rConnection.is(); 3307 } 3308 3309 IMPL_LINK( SbaTableQueryBrowser, OnTreeEntryCompare, const SvSortData&, _rSortData, sal_Int32 ) 3310 { 3311 const SvTreeListEntry* pLHS = _rSortData.pLeft; 3312 const SvTreeListEntry* pRHS = _rSortData.pRight; 3313 OSL_ENSURE(pLHS && pRHS, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid tree entries!"); 3314 // we want the table entry and the end so we have to do a check 3315 3316 if (isContainer(pRHS)) 3317 { 3318 // don't use getEntryType (directly or indirecly) for the LHS: 3319 // LHS is currently being inserted, so it is not "completely valid" at the moment 3320 3321 const EntryType eRight = getEntryType(pRHS); 3322 if (etTableContainer == eRight) 3323 // every other container should be placed _before_ the bookmark container 3324 return -1; 3325 3326 const OUString sLeft = m_pTreeView->getListBox().GetEntryText(const_cast<SvTreeListEntry*>(pLHS)); 3327 3328 EntryType eLeft = etTableContainer; 3329 if (DBA_RES(RID_STR_TABLES_CONTAINER) == sLeft) 3330 eLeft = etTableContainer; 3331 else if (DBA_RES(RID_STR_QUERIES_CONTAINER) == sLeft) 3332 eLeft = etQueryContainer; 3333 3334 if ( eLeft == eRight ) 3335 return 0; 3336 3337 if ( ( eLeft == etTableContainer ) && ( eRight == etQueryContainer ) ) 3338 return 1; 3339 3340 if ( ( eLeft == etQueryContainer ) && ( eRight == etTableContainer ) ) 3341 return -1; 3342 3343 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::OnTreeEntryCompare: unexpected case!" ); 3344 return 0; 3345 } 3346 3347 const SvLBoxString* pLeftTextItem = static_cast<const SvLBoxString*>(pLHS->GetFirstItem(SvLBoxItemType::String)); 3348 const SvLBoxString* pRightTextItem = static_cast<const SvLBoxString*>(pRHS->GetFirstItem(SvLBoxItemType::String)); 3349 OSL_ENSURE(pLeftTextItem && pRightTextItem, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid text items!"); 3350 3351 OUString sLeftText = pLeftTextItem->GetText(); 3352 OUString sRightText = pRightTextItem->GetText(); 3353 3354 sal_Int32 nCompareResult = 0; // equal by default 3355 3356 if (m_xCollator.is()) 3357 { 3358 try 3359 { 3360 nCompareResult = m_xCollator->compareString(sLeftText, sRightText); 3361 } 3362 catch(const Exception&) 3363 { 3364 } 3365 } 3366 else 3367 // default behaviour if we do not have a collator -> do the simple string compare 3368 nCompareResult = sLeftText.compareTo(sRightText); 3369 3370 return nCompareResult; 3371 } 3372 3373 void SbaTableQueryBrowser::implAdministrate( SvTreeListEntry* _pApplyTo ) 3374 { 3375 OSL_PRECOND( _pApplyTo, "SbaTableQueryBrowser::implAdministrate: illegal entry!" ); 3376 if ( !_pApplyTo ) 3377 return; 3378 3379 try 3380 { 3381 // get the desktop object 3382 Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() ); 3383 3384 // the initial selection 3385 SvTreeListEntry* pTopLevelSelected = _pApplyTo; 3386 while (pTopLevelSelected && m_pTreeView->getListBox().GetParent(pTopLevelSelected)) 3387 pTopLevelSelected = m_pTreeView->getListBox().GetParent(pTopLevelSelected); 3388 OUString sInitialSelection; 3389 if (pTopLevelSelected) 3390 sInitialSelection = getDataSourceAccessor( pTopLevelSelected ); 3391 3392 Reference< XDataSource > xDataSource( getDataSourceByName( sInitialSelection, getView(), getORB(), nullptr ) ); 3393 Reference< XModel > xDocumentModel( getDataSourceOrModel( xDataSource ), UNO_QUERY ); 3394 3395 if ( xDocumentModel.is() ) 3396 { 3397 Reference< XInteractionHandler2 > xInteractionHandler( 3398 InteractionHandler::createWithParent(getORB(), nullptr) ); 3399 3400 ::comphelper::NamedValueCollection aLoadArgs; 3401 aLoadArgs.put( "Model", xDocumentModel ); 3402 aLoadArgs.put( "InteractionHandler", xInteractionHandler ); 3403 aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); 3404 3405 Sequence< PropertyValue > aLoadArgPV; 3406 aLoadArgs >>= aLoadArgPV; 3407 3408 xFrameLoader->loadComponentFromURL( 3409 xDocumentModel->getURL(), 3410 "_default", 3411 FrameSearchFlag::ALL | FrameSearchFlag::GLOBAL, 3412 aLoadArgPV 3413 ); 3414 } 3415 } 3416 catch( const Exception& ) 3417 { 3418 DBG_UNHANDLED_EXCEPTION("dbaccess"); 3419 } 3420 } 3421 3422 bool SbaTableQueryBrowser::requestQuickHelp( const SvTreeListEntry* _pEntry, OUString& _rText ) const 3423 { 3424 const DBTreeListUserData* pData = static_cast< const DBTreeListUserData* >( _pEntry->GetUserData() ); 3425 if ( ( pData->eType == etDatasource ) && !pData->sAccessor.isEmpty() ) 3426 { 3427 _rText = ::svt::OFileNotation( pData->sAccessor ).get( ::svt::OFileNotation::N_SYSTEM ); 3428 return true; 3429 } 3430 return false; 3431 } 3432 3433 OUString SbaTableQueryBrowser::getContextMenuResourceName( Control& _rControl ) const 3434 { 3435 OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl, 3436 "SbaTableQueryBrowser::getContextMenuResourceName: where does this come from?" ); 3437 if ( &m_pTreeView->getListBox() != &_rControl ) 3438 return OUString(); 3439 3440 return OUString("explorer"); 3441 } 3442 3443 IController& SbaTableQueryBrowser::getCommandController() 3444 { 3445 return *this; 3446 } 3447 3448 ::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors() 3449 { 3450 return &m_aContextMenuInterceptors; 3451 } 3452 3453 Any SbaTableQueryBrowser::getCurrentSelection( Control& _rControl ) const 3454 { 3455 OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl, 3456 "SbaTableQueryBrowser::getCurrentSelection: where does this come from?" ); 3457 3458 if ( &m_pTreeView->getListBox() != &_rControl ) 3459 return Any(); 3460 3461 SvTreeListEntry* pSelected = m_pTreeView->getListBox().FirstSelected(); 3462 if ( !pSelected ) 3463 return Any(); 3464 3465 OSL_ENSURE( m_pTreeView->getListBox().NextSelected( pSelected ) == nullptr, 3466 "SbaTableQueryBrowser::getCurrentSelection: single-selection is expected here!" ); 3467 3468 NamedDatabaseObject aSelectedObject; 3469 DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pSelected->GetUserData() ); 3470 aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType ); 3471 3472 switch ( aSelectedObject.Type ) 3473 { 3474 case DatabaseObject::QUERY: 3475 case DatabaseObject::TABLE: 3476 aSelectedObject.Name = m_pTreeView->getListBox().GetEntryText( pSelected ); 3477 break; 3478 3479 case DatabaseObjectContainer::DATA_SOURCE: 3480 case DatabaseObjectContainer::QUERIES: 3481 case DatabaseObjectContainer::TABLES: 3482 aSelectedObject.Name = getDataSourceAccessor( pSelected ); 3483 break; 3484 3485 default: 3486 SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" ); 3487 break; 3488 } 3489 3490 return makeAny( aSelectedObject ); 3491 } 3492 3493 bool SbaTableQueryBrowser::implGetQuerySignature( OUString& _rCommand, bool& _bEscapeProcessing ) 3494 { 3495 _rCommand.clear(); 3496 _bEscapeProcessing = false; 3497 3498 try 3499 { 3500 // contain the dss (data source signature) of the form 3501 OUString sDataSourceName; 3502 OUString sCommand; 3503 sal_Int32 nCommandType = CommandType::COMMAND; 3504 Reference< XPropertySet > xRowsetProps( getRowSet(), UNO_QUERY ); 3505 ODataAccessDescriptor aDesc( xRowsetProps ); 3506 sDataSourceName = aDesc.getDataSource(); 3507 aDesc[ DataAccessDescriptorProperty::Command ] >>= sCommand; 3508 aDesc[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType; 3509 3510 // do we need to do anything? 3511 if ( CommandType::QUERY != nCommandType ) 3512 return false; 3513 3514 // get the query object 3515 Reference< XQueryDefinitionsSupplier > xSuppQueries; 3516 Reference< XNameAccess > xQueries; 3517 Reference< XPropertySet > xQuery; 3518 m_xDatabaseContext->getByName( sDataSourceName ) >>= xSuppQueries; 3519 if ( xSuppQueries.is() ) 3520 xQueries = xSuppQueries->getQueryDefinitions(); 3521 if ( xQueries.is() ) 3522 xQueries->getByName( sCommand ) >>= xQuery; 3523 OSL_ENSURE( xQuery.is(), "SbaTableQueryBrowser::implGetQuerySignature: could not retrieve the query object!" ); 3524 3525 // get the two properties we need 3526 if ( xQuery.is() ) 3527 { 3528 xQuery->getPropertyValue( PROPERTY_COMMAND ) >>= _rCommand; 3529 _bEscapeProcessing = ::cppu::any2bool( xQuery->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) ); 3530 return true; 3531 } 3532 } 3533 catch( const Exception& ) 3534 { 3535 DBG_UNHANDLED_EXCEPTION("dbaccess"); 3536 } 3537 3538 return false; 3539 } 3540 3541 void SbaTableQueryBrowser::frameAction(const css::frame::FrameActionEvent& aEvent) 3542 { 3543 if (aEvent.Frame == m_xCurrentFrameParent) 3544 { 3545 if(aEvent.Action == FrameAction_COMPONENT_DETACHING) 3546 implRemoveStatusListeners(); 3547 else if (aEvent.Action == FrameAction_COMPONENT_REATTACHED) 3548 connectExternalDispatches(); 3549 } 3550 else 3551 SbaXDataBrowserController::frameAction(aEvent); 3552 3553 } 3554 3555 void SbaTableQueryBrowser::clearGridColumns(const Reference< XNameContainer >& _xColContainer) 3556 { 3557 // first we have to clear the grid 3558 Reference< XInterface > xColumn; 3559 for (const OUString& rName : _xColContainer->getElementNames()) 3560 { 3561 _xColContainer->getByName(rName) >>= xColumn; 3562 _xColContainer->removeByName(rName); 3563 ::comphelper::disposeComponent(xColumn); 3564 } 3565 } 3566 3567 void SbaTableQueryBrowser::loadMenu(const Reference< XFrame >& _xFrame) 3568 { 3569 if ( m_bShowMenu ) 3570 { 3571 OGenericUnoController::loadMenu(_xFrame); 3572 } 3573 else if ( !m_bPreview ) 3574 { 3575 Reference< css::frame::XLayoutManager > xLayoutManager = getLayoutManager(_xFrame); 3576 3577 if ( xLayoutManager.is() ) 3578 { 3579 xLayoutManager->lock(); 3580 xLayoutManager->createElement( "private:resource/toolbar/toolbar" ); 3581 xLayoutManager->unlock(); 3582 xLayoutManager->doLayout(); 3583 } 3584 onLoadedMenu( xLayoutManager ); 3585 } 3586 } 3587 3588 OUString SbaTableQueryBrowser::getPrivateTitle() const 3589 { 3590 OUString sTitle; 3591 if ( m_pCurrentlyDisplayed ) 3592 { 3593 SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(m_pCurrentlyDisplayed); 3594 // get the entry for the datasource 3595 SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer); 3596 OUString sName = m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed); 3597 sTitle = GetEntryText( pConnection ); 3598 INetURLObject aURL(sTitle); 3599 if ( aURL.GetProtocol() != INetProtocol::NotValid ) 3600 sTitle = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset); 3601 if ( !sName.isEmpty() ) 3602 { 3603 sName += " - "; 3604 sName += sTitle; 3605 sTitle = sName; 3606 } 3607 } 3608 3609 return sTitle; 3610 } 3611 3612 bool SbaTableQueryBrowser::preReloadForm() 3613 { 3614 bool bIni = false; 3615 if ( !m_pCurrentlyDisplayed ) 3616 { 3617 // switch the grid to design mode while loading 3618 getBrowserView()->getGridControl()->setDesignMode(true); 3619 // we had an invalid statement so we need to connect the column models 3620 Reference<XPropertySet> xRowSetProps(getRowSet(),UNO_QUERY); 3621 svx::ODataAccessDescriptor aDesc(xRowSetProps); 3622 // extract the props 3623 OUString sDataSource; 3624 OUString sCommand; 3625 sal_Int32 nCommandType = CommandType::COMMAND; 3626 bool bEscapeProcessing = true; 3627 extractDescriptorProps(aDesc, sDataSource, sCommand, nCommandType, bEscapeProcessing); 3628 if ( !sDataSource.isEmpty() && !sCommand.isEmpty() && (-1 != nCommandType) ) 3629 { 3630 SvTreeListEntry* pDataSource = nullptr; 3631 SvTreeListEntry* pCommandType = nullptr; 3632 m_pCurrentlyDisplayed = getObjectEntry( sDataSource, sCommand, nCommandType, &pDataSource, &pCommandType ); 3633 bIni = true; 3634 } 3635 } 3636 return bIni; 3637 } 3638 3639 void SbaTableQueryBrowser::postReloadForm() 3640 { 3641 InitializeGridModel(getFormComponent()); 3642 LoadFinished(true); 3643 } 3644 3645 Reference< XEmbeddedScripts > SAL_CALL SbaTableQueryBrowser::getScriptContainer() 3646 { 3647 // update our database document 3648 Reference< XModel > xDocument; 3649 try 3650 { 3651 Reference< XPropertySet > xCursorProps( getRowSet(), UNO_QUERY_THROW ); 3652 Reference< XConnection > xConnection( xCursorProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ), UNO_QUERY ); 3653 if ( xConnection.is() ) 3654 { 3655 Reference< XChild > xChild( xConnection, UNO_QUERY_THROW ); 3656 Reference< XDocumentDataSource > xDataSource( xChild->getParent(), UNO_QUERY_THROW ); 3657 xDocument.set( xDataSource->getDatabaseDocument(), UNO_QUERY_THROW ); 3658 } 3659 } 3660 catch( const Exception& ) 3661 { 3662 DBG_UNHANDLED_EXCEPTION("dbaccess"); 3663 } 3664 Reference< XEmbeddedScripts > xScripts( xDocument, UNO_QUERY ); 3665 OSL_ENSURE( xScripts.is() || !xDocument.is(), 3666 "SbaTableQueryBrowser::getScriptContainer: invalid database document!" ); 3667 return xScripts; 3668 } 3669 3670 void SAL_CALL SbaTableQueryBrowser::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) 3671 { 3672 if ( Interceptor.is() ) 3673 m_aContextMenuInterceptors.addInterface( Interceptor ); 3674 } 3675 3676 void SAL_CALL SbaTableQueryBrowser::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) 3677 { 3678 if ( Interceptor.is() ) 3679 m_aContextMenuInterceptors.removeInterface( Interceptor ); 3680 } 3681 3682 void SAL_CALL SbaTableQueryBrowser::registeredDatabaseLocation( const DatabaseRegistrationEvent& Event ) 3683 { 3684 SolarMutexGuard aGuard; 3685 implAddDatasource( Event.Name, SharedConnection() ); 3686 } 3687 3688 void SbaTableQueryBrowser::impl_cleanupDataSourceEntry( const OUString& _rDataSourceName ) 3689 { 3690 // get the top-level representing the removed data source 3691 SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().FirstChild( nullptr ); 3692 while ( pDataSourceEntry ) 3693 { 3694 if ( m_pTreeView->getListBox().GetEntryText( pDataSourceEntry ) == _rDataSourceName ) 3695 break; 3696 3697 pDataSourceEntry = pDataSourceEntry->NextSibling(); 3698 } 3699 3700 OSL_ENSURE( pDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" ); 3701 if ( !pDataSourceEntry ) 3702 return; 3703 3704 if ( isSelected( pDataSourceEntry ) ) 3705 { // a table or query belonging to the deleted data source is currently being displayed. 3706 OSL_ENSURE( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) == pDataSourceEntry, 3707 "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (1)!" ); 3708 unloadAndCleanup(); 3709 } 3710 else 3711 OSL_ENSURE( 3712 ( nullptr == m_pCurrentlyDisplayed ) 3713 || ( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) != pDataSourceEntry ), 3714 "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (2)!"); 3715 3716 // delete any user data of the child entries of the to-be-removed entry 3717 std::pair<SvTreeListEntries::const_iterator, SvTreeListEntries::const_iterator> aIters = 3718 m_pTreeView->GetTreeModel()->GetChildIterators(pDataSourceEntry); 3719 3720 SvTreeListEntries::const_iterator it = aIters.first, itEnd = aIters.second; 3721 3722 for (; it != itEnd; ++it) 3723 { 3724 SvTreeListEntry* pEntry = (*it).get(); 3725 const DBTreeListUserData* pData = static_cast<const DBTreeListUserData*>(pEntry->GetUserData()); 3726 pEntry->SetUserData(nullptr); 3727 delete pData; 3728 } 3729 3730 // remove the entry 3731 DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() ); 3732 pDataSourceEntry->SetUserData( nullptr ); 3733 delete pData; 3734 m_pTreeView->GetTreeModel()->Remove( pDataSourceEntry ); 3735 } 3736 3737 void SAL_CALL SbaTableQueryBrowser::revokedDatabaseLocation( const DatabaseRegistrationEvent& Event ) 3738 { 3739 SolarMutexGuard aGuard; 3740 3741 impl_cleanupDataSourceEntry( Event.Name ); 3742 3743 // maybe the object which is part of the document data source has been removed 3744 checkDocumentDataSource(); 3745 } 3746 3747 void SAL_CALL SbaTableQueryBrowser::changedDatabaseLocation( const DatabaseRegistrationEvent& Event ) 3748 { 3749 SolarMutexGuard aGuard; 3750 3751 // in case the data source was expanded, and connected, we need to clean it up 3752 // for simplicity, just do as if the data source were completely removed and re-added 3753 impl_cleanupDataSourceEntry( Event.Name ); 3754 implAddDatasource( Event.Name, SharedConnection() ); 3755 } 3756 3757 } // namespace dbaui 3758 3759 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 3760
