summaryrefslogtreecommitdiffstats
path: root/dbaccess/source/ui/app
diff options
context:
space:
mode:
Diffstat (limited to 'dbaccess/source/ui/app')
-rw-r--r--dbaccess/source/ui/app/AppController.cxx2809
-rw-r--r--dbaccess/source/ui/app/AppController.hxx526
-rw-r--r--dbaccess/source/ui/app/AppControllerDnD.cxx808
-rw-r--r--dbaccess/source/ui/app/AppControllerGen.cxx741
-rw-r--r--dbaccess/source/ui/app/AppDetailPageHelper.cxx1305
-rw-r--r--dbaccess/source/ui/app/AppDetailPageHelper.hxx350
-rw-r--r--dbaccess/source/ui/app/AppDetailView.cxx877
-rw-r--r--dbaccess/source/ui/app/AppDetailView.hxx368
-rw-r--r--dbaccess/source/ui/app/AppIconControl.cxx106
-rw-r--r--dbaccess/source/ui/app/AppIconControl.hxx48
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.cxx180
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.hxx92
-rw-r--r--dbaccess/source/ui/app/AppTitleWindow.cxx182
-rw-r--r--dbaccess/source/ui/app/AppTitleWindow.hxx76
-rw-r--r--dbaccess/source/ui/app/AppView.cxx524
-rw-r--r--dbaccess/source/ui/app/AppView.hxx297
-rw-r--r--dbaccess/source/ui/app/subcomponentmanager.cxx555
-rw-r--r--dbaccess/source/ui/app/subcomponentmanager.hxx123
-rw-r--r--dbaccess/source/ui/app/window_layout.txt49
19 files changed, 10016 insertions, 0 deletions
diff --git a/dbaccess/source/ui/app/AppController.cxx b/dbaccess/source/ui/app/AppController.cxx
new file mode 100644
index 000000000..402880eed
--- /dev/null
+++ b/dbaccess/source/ui/app/AppController.cxx
@@ -0,0 +1,2809 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "AppController.hxx"
+#include <core_resource.hxx>
+#include <strings.hxx>
+#include <advancedsettingsdlg.hxx>
+#include "subcomponentmanager.hxx"
+#include <uiservices.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/ErrorMessageDialog.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+#include <svl/filenotation.hxx>
+#include <vcl/treelistbox.hxx>
+#include <vcl/transfer.hxx>
+#include <svtools/cliplistener.hxx>
+
+#include <comphelper/sequence.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <unotools/closeveto.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/historyoptions.hxx>
+
+#include <sfx2/mailmodelapi.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/QuerySaveDocument.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <svx/dbaexchange.hxx>
+#include <svx/dbaobjectex.hxx>
+#include <svx/svxdlg.hxx>
+
+#include <osl/mutex.hxx>
+#include "AppView.hxx"
+#include <browserids.hxx>
+#include <dbu_reghelper.hxx>
+#include <strings.hrc>
+#include <defaultobjectnamecheck.hxx>
+#include <databaseobjectview.hxx>
+#include "AppDetailView.hxx"
+#include <linkeddocuments.hxx>
+#include <UITools.hxx>
+#include <dsntypes.hxx>
+#include <dlgsave.hxx>
+#include <dbaccess_slotid.hrc>
+
+extern "C" void createRegistryInfo_ODBApplication()
+{
+ static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OApplicationController > aAutoRegistration;
+}
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::svx;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::task;
+using ::com::sun::star::document::XEmbeddedScripts;
+using ::com::sun::star::document::XDocumentEventBroadcaster;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject;
+namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer;
+
+OUString SAL_CALL OApplicationController::getImplementationName()
+{
+ return getImplementationName_Static();
+}
+
+OUString OApplicationController::getImplementationName_Static()
+{
+ return SERVICE_SDB_APPLICATIONCONTROLLER;
+}
+
+Sequence< OUString> OApplicationController::getSupportedServiceNames_Static()
+{
+ Sequence<OUString> aSupported { "com.sun.star.sdb.application.DefaultViewController" };
+ return aSupported;
+}
+
+Sequence< OUString> SAL_CALL OApplicationController::getSupportedServiceNames()
+{
+ return getSupportedServiceNames_Static();
+}
+
+Reference< XInterface > OApplicationController::Create(const Reference<XMultiServiceFactory >& _rxFactory)
+{
+ return *(new OApplicationController( comphelper::getComponentContext(_rxFactory)));
+}
+
+namespace {
+
+class SelectionGuard;
+
+}
+
+// OApplicationController
+class SelectionNotifier
+{
+private:
+ ::comphelper::OInterfaceContainerHelper2 m_aSelectionListeners;
+ ::cppu::OWeakObject& m_rContext;
+ sal_Int32 m_nSelectionNestingLevel;
+
+public:
+ SelectionNotifier( ::osl::Mutex& _rMutex, ::cppu::OWeakObject& _rContext )
+ :m_aSelectionListeners( _rMutex )
+ ,m_rContext( _rContext )
+ ,m_nSelectionNestingLevel( 0 )
+ {
+ }
+
+ SelectionNotifier(const SelectionNotifier&) = delete;
+ const SelectionNotifier& operator=(const SelectionNotifier&) = delete;
+
+ void addListener( const Reference< XSelectionChangeListener >& Listener )
+ {
+ m_aSelectionListeners.addInterface( Listener );
+ }
+
+ void removeListener( const Reference< XSelectionChangeListener >& Listener )
+ {
+ m_aSelectionListeners.removeInterface( Listener );
+ }
+
+ void disposing()
+ {
+ EventObject aEvent( m_rContext );
+ m_aSelectionListeners.disposeAndClear( aEvent );
+ }
+
+ struct SelectionGuardAccess { friend SelectionGuard; private: SelectionGuardAccess() { } };
+
+ /** enters a block which modifies the selection of our owner.
+
+ Can be called multiple times, the only important thing is to call leaveSelection
+ equally often.
+ */
+ void enterSelection( SelectionGuardAccess )
+ {
+ ++m_nSelectionNestingLevel;
+ }
+
+ /** leaves a block which modifies the selection of our owner
+
+ Must be paired with enterSelection calls.
+
+ When the last block is left, i.e. the last leaveSelection call is made on the current stack,
+ then our SelectionChangeListeners are notified
+ */
+ void leaveSelection( SelectionGuardAccess )
+ {
+ if ( --m_nSelectionNestingLevel == 0 )
+ {
+ EventObject aEvent( m_rContext );
+ m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent );
+ }
+ }
+};
+
+namespace {
+
+class SelectionGuard
+{
+public:
+ explicit SelectionGuard( SelectionNotifier& _rNotifier )
+ :m_rNotifier( _rNotifier )
+ {
+ m_rNotifier.enterSelection( SelectionNotifier::SelectionGuardAccess() );
+ }
+
+ ~SelectionGuard()
+ {
+ m_rNotifier.leaveSelection( SelectionNotifier::SelectionGuardAccess() );
+ }
+
+ SelectionGuard(const SelectionGuard&) = delete;
+ const SelectionGuard& operator=(const SelectionGuard&) = delete;
+
+private:
+ SelectionNotifier& m_rNotifier;
+};
+
+}
+
+// OApplicationController
+OApplicationController::OApplicationController(const Reference< XComponentContext >& _rxORB)
+ :OGenericUnoController( _rxORB )
+ ,m_aContextMenuInterceptors( getMutex() )
+ ,m_pSubComponentManager( new SubComponentManager( *this, getSharedMutex() ) )
+ ,m_aTypeCollection( _rxORB )
+ ,m_aTableCopyHelper(this)
+ ,m_nAsyncDrop(nullptr)
+ ,m_aSelectContainerEvent( LINK( this, OApplicationController, OnSelectContainer ) )
+ ,m_ePreviewMode(E_PREVIEWNONE)
+ ,m_eCurrentType(E_NONE)
+ ,m_bNeedToReconnect(false)
+ ,m_bSuspended( false )
+ ,m_pSelectionNotifier( new SelectionNotifier( getMutex(), *this ) )
+{
+}
+
+OApplicationController::~OApplicationController()
+{
+ if ( !rBHelper.bDisposed && !rBHelper.bInDispose )
+ {
+ OSL_FAIL("Please check who doesn't dispose this component!");
+ // increment ref count to prevent double call of Dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+ clearView();
+}
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2(OApplicationController,OGenericUnoController,OApplicationController_Base)
+IMPLEMENT_FORWARD_XINTERFACE2(OApplicationController,OGenericUnoController,OApplicationController_Base)
+void OApplicationController::disconnect()
+{
+ if ( m_xDataSourceConnection.is() )
+ stopConnectionListening( m_xDataSourceConnection );
+
+ try
+ {
+ // temporary (hopefully!) hack for #i55274#
+ Reference< XFlushable > xFlush( m_xDataSourceConnection, UNO_QUERY );
+ if ( xFlush.is() && m_xMetaData.is() && !m_xMetaData->isReadOnly() )
+ xFlush->flush();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xDataSourceConnection.clear();
+ m_xMetaData.clear();
+
+ InvalidateAll();
+}
+
+void SAL_CALL OApplicationController::disposing()
+{
+ for( const auto& rContainerListener : m_aCurrentContainers )
+ {
+ if( rContainerListener.is() )
+ {
+ rContainerListener->removeContainerListener( this );
+ }
+ }
+
+ m_aCurrentContainers.clear();
+ m_pSubComponentManager->disposing();
+ m_pSelectionNotifier->disposing();
+
+ if ( getView() )
+ {
+ getContainer()->showPreview(nullptr);
+ m_pClipboardNotifier->ClearCallbackLink();
+ m_pClipboardNotifier->RemoveListener( getView() );
+ m_pClipboardNotifier.clear();
+ }
+
+ disconnect();
+ try
+ {
+ Reference < XFrame > xFrame;
+ attachFrame( xFrame );
+
+ if ( m_xDataSource.is() )
+ {
+ m_xDataSource->removePropertyChangeListener(OUString(), this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_INFO, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_URL, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_ISPASSWORDREQUIRED, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_LAYOUTINFORMATION, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_SUPPRESSVERSIONCL, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_TABLEFILTER, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_TABLETYPEFILTER, this);
+ m_xDataSource->removePropertyChangeListener(PROPERTY_USER, this);
+ m_xDataSource = nullptr;
+ }
+
+ Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ xBroadcaster->removeModifyListener(static_cast<XModifyListener*>(this));
+
+ if ( m_xModel.is() )
+ {
+ OUString sUrl = m_xModel->getURL();
+ if ( !sUrl.isEmpty() )
+ {
+ ::comphelper::NamedValueCollection aArgs( m_xModel->getArgs() );
+ if ( aArgs.getOrDefault( "PickListEntry", true ) )
+ {
+ OUString aFilter;
+ INetURLObject aURL( m_xModel->getURL() );
+ std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter();
+ if ( pFilter )
+ aFilter = pFilter->GetFilterName();
+
+ // add to svtool history options
+ SvtHistoryOptions().AppendItem( ePICKLIST,
+ aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
+ aFilter,
+ getStrippedDatabaseName(),
+ std::nullopt);
+
+ // add to recent document list
+ if ( aURL.GetProtocol() == INetProtocol::File )
+ Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
+ pFilter ? pFilter->GetMimeType() : OUString(),
+ pFilter ? pFilter->GetServiceName() : OUString() );
+ }
+ }
+
+ m_xModel->disconnectController( this );
+
+ m_xModel.clear();
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ clearView();
+ OGenericUnoController::disposing(); // here the m_refCount must be equal 5
+}
+
+bool OApplicationController::Construct(vcl::Window* _pParent)
+{
+ setView( VclPtr<OApplicationView>::Create( _pParent, getORB(), *this, m_ePreviewMode ) );
+
+ // late construction
+ bool bSuccess = false;
+ try
+ {
+ getContainer()->Construct();
+ bSuccess = true;
+ }
+ catch(const SQLException&)
+ {
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("OApplicationController::Construct : the construction of UnoDataBrowserView failed !");
+ }
+
+ if ( !bSuccess )
+ {
+ clearView();
+ return false;
+ }
+
+ // now that we have a view we can create the clipboard listener
+ m_aSystemClipboard = TransferableDataHelper::CreateFromSystemClipboard( getView() );
+ m_aSystemClipboard.StartClipboardListening( );
+
+ m_pClipboardNotifier = new TransferableClipboardListener( LINK( this, OApplicationController, OnClipboardChanged ) );
+ m_pClipboardNotifier->AddListener( getView() );
+
+ OGenericUnoController::Construct( _pParent );
+ getView()->Show();
+
+ return true;
+}
+
+void SAL_CALL OApplicationController::disposing(const EventObject& _rSource)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ Reference<XConnection> xCon(_rSource.Source, UNO_QUERY);
+ if ( xCon.is() )
+ {
+ OSL_ENSURE( m_xDataSourceConnection == xCon,
+ "OApplicationController::disposing: which connection does this come from?" );
+
+ if ( getContainer() && getContainer()->getElementType() == E_TABLE )
+ getContainer()->clearPages();
+ if ( m_xDataSourceConnection == xCon )
+ {
+ m_xMetaData.clear();
+ m_xDataSourceConnection.clear();
+ }
+ }
+ else if ( _rSource.Source == m_xModel )
+ {
+ m_xModel.clear();
+ }
+ else if ( _rSource.Source == m_xDataSource )
+ {
+ m_xDataSource = nullptr;
+ }
+ else
+ {
+ Reference<XContainer> xContainer( _rSource.Source, UNO_QUERY );
+ if ( xContainer.is() )
+ {
+ TContainerVector::iterator aFind = std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer);
+ if ( aFind != m_aCurrentContainers.end() )
+ m_aCurrentContainers.erase(aFind);
+ }
+ OGenericUnoController::disposing( _rSource );
+ }
+}
+
+sal_Bool SAL_CALL OApplicationController::suspend(sal_Bool bSuspend)
+{
+ // notify the OnPrepareViewClosing event (before locking any mutex)
+ Reference< XDocumentEventBroadcaster > xBroadcaster( m_xModel, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->notifyDocumentEvent(
+ "OnPrepareViewClosing",
+ this,
+ Any()
+ );
+ }
+
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( getView() && getView()->IsInModalMode() )
+ return false;
+
+ bool bCanSuspend = true;
+
+ if ( m_bSuspended != bool(bSuspend) )
+ {
+ if ( bSuspend && !closeSubComponents() )
+ return false;
+
+ Reference<XModifiable> xModi(m_xModel,UNO_QUERY);
+ Reference<XStorable> xStor(getModel(),UNO_QUERY);
+
+ if ( bSuspend
+ && xStor.is()
+ && !xStor->isReadonly()
+ && ( xModi.is()
+ && xModi->isModified()
+ )
+ )
+ {
+ switch (ExecuteQuerySaveDocument(getFrameWeld(), getStrippedDatabaseName()))
+ {
+ case RET_YES:
+ Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>());
+ bCanSuspend = !xModi->isModified();
+ // when we save the document this must be false else some press cancel
+ break;
+ case RET_CANCEL:
+ bCanSuspend = false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if ( bCanSuspend )
+ m_bSuspended = bSuspend;
+
+ return bCanSuspend;
+}
+
+FeatureState OApplicationController::GetState(sal_uInt16 _nId) const
+{
+ FeatureState aReturn;
+ aReturn.bEnabled = false;
+ // check this first
+ if ( !getContainer() || m_bReadOnly )
+ return aReturn;
+
+ try
+ {
+ switch (_nId)
+ {
+ case SID_OPENURL:
+ aReturn.bEnabled = true;
+ if ( m_xModel.is() )
+ aReturn.sTitle = m_xModel->getURL();
+ break;
+ case ID_BROWSER_COPY:
+ {
+ sal_Int32 nCount = getContainer()->getSelectionCount();
+ aReturn.bEnabled = nCount >= 1;
+ if ( aReturn.bEnabled && nCount == 1 && getContainer()->getElementType() == E_TABLE )
+ aReturn.bEnabled = getContainer()->isALeafSelected();
+ }
+ break;
+ case ID_BROWSER_CUT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() >= 1;
+ aReturn.bEnabled = aReturn.bEnabled && (getContainer()->getElementType() != E_TABLE || getContainer()->isCutAllowed());
+ break;
+ case ID_BROWSER_PASTE:
+ switch( getContainer()->getElementType() )
+ {
+ case E_TABLE:
+ aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly() && isTableFormat();
+ break;
+ case E_QUERY:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getViewClipboard().HasFormat(SotClipboardFormatId::DBACCESS_QUERY);
+ break;
+ default:
+ aReturn.bEnabled = !isDataSourceReadOnly() && OComponentTransferable::canExtractComponentDescriptor(getViewClipboard().GetDataFlavorExVector(),getContainer()->getElementType() == E_FORM);
+ }
+ break;
+ case SID_DB_APP_PASTE_SPECIAL:
+ aReturn.bEnabled = getContainer()->getElementType() == E_TABLE && !isDataSourceReadOnly() && !isConnectionReadOnly() && isTableFormat();
+ break;
+ case SID_OPENDOC:
+ aReturn.bEnabled = true;
+ break;
+ case ID_BROWSER_SAVEDOC:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ break;
+ case ID_BROWSER_SAVEASDOC:
+ aReturn.bEnabled = true;
+ break;
+ case ID_BROWSER_SORTUP:
+ aReturn.bEnabled = getContainer()->isFilled() && getContainer()->getElementCount();
+ aReturn.bChecked = aReturn.bEnabled && getContainer()->isSortUp();
+ break;
+ case ID_BROWSER_SORTDOWN:
+ aReturn.bEnabled = getContainer()->isFilled() && getContainer()->getElementCount();
+ aReturn.bChecked = aReturn.bEnabled && !getContainer()->isSortUp();
+ break;
+
+ case SID_NEWDOC:
+ case SID_APP_NEW_FORM:
+ case ID_DOCUMENT_CREATE_REPWIZ:
+ aReturn.bEnabled = !isDataSourceReadOnly() && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER);
+ break;
+ case SID_APP_NEW_REPORT:
+ aReturn.bEnabled = !isDataSourceReadOnly()
+ && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER);
+ if ( aReturn.bEnabled )
+ {
+ Reference< XContentEnumerationAccess > xEnumAccess(m_xContext->getServiceManager(), UNO_QUERY);
+ aReturn.bEnabled = xEnumAccess.is();
+ if ( aReturn.bEnabled )
+ {
+ const OUString sReportEngineServiceName = ::dbtools::getDefaultReportEngineServiceName(m_xContext);
+ aReturn.bEnabled = !sReportEngineServiceName.isEmpty();
+ if ( aReturn.bEnabled )
+ {
+ const Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(sReportEngineServiceName);
+ aReturn.bEnabled = xEnumDrivers.is() && xEnumDrivers->hasMoreElements();
+ }
+ }
+ }
+ break;
+ case SID_DB_APP_VIEW_TABLES:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_TABLE;
+ break;
+ case SID_DB_APP_VIEW_QUERIES:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_QUERY;
+ break;
+ case SID_DB_APP_VIEW_FORMS:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_FORM;
+ break;
+ case SID_DB_APP_VIEW_REPORTS:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getElementType() == E_REPORT;
+ break;
+ case ID_NEW_QUERY_DESIGN:
+ case ID_NEW_QUERY_SQL:
+ case ID_APP_NEW_QUERY_AUTO_PILOT:
+ case SID_DB_FORM_NEW_PILOT:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ break;
+ case ID_NEW_VIEW_DESIGN:
+ case SID_DB_NEW_VIEW_SQL:
+ case ID_NEW_VIEW_DESIGN_AUTO_PILOT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly();
+ if ( aReturn.bEnabled )
+ {
+ Reference<XViewsSupplier> xViewsSup( getConnection(), UNO_QUERY );
+ aReturn.bEnabled = xViewsSup.is();
+ }
+ break;
+ case ID_NEW_TABLE_DESIGN:
+ case ID_NEW_TABLE_DESIGN_AUTO_PILOT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && !isConnectionReadOnly();
+ break;
+ case ID_DIRECT_SQL:
+ aReturn.bEnabled = true;
+ break;
+ case SID_APP_NEW_FOLDER:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() <= 1;
+ if ( aReturn.bEnabled )
+ {
+ const ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = eType == E_REPORT || eType == E_FORM;
+ }
+ break;
+ case SID_FORM_CREATE_REPWIZ_PRE_SEL:
+ case SID_REPORT_CREATE_REPWIZ_PRE_SEL:
+ case SID_APP_NEW_REPORT_PRE_SEL:
+ aReturn.bEnabled = !isDataSourceReadOnly()
+ && SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::WRITER)
+ && getContainer()->isALeafSelected();
+ if ( aReturn.bEnabled )
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = eType == E_QUERY || eType == E_TABLE;
+ if ( aReturn.bEnabled && SID_APP_NEW_REPORT_PRE_SEL == _nId )
+ {
+ Reference< XContentEnumerationAccess > xEnumAccess(m_xContext->getServiceManager(), UNO_QUERY);
+ aReturn.bEnabled = xEnumAccess.is();
+ if ( aReturn.bEnabled )
+ {
+ static const char s_sReportDesign[] = "org.libreoffice.report.pentaho.SOReportJobFactory";
+ Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(s_sReportDesign);
+ aReturn.bEnabled = xEnumDrivers.is() && xEnumDrivers->hasMoreElements();
+ }
+ }
+ }
+ break;
+ case SID_DB_APP_DELETE:
+ case SID_DB_APP_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(getContainer()->getElementType(), _nId == SID_DB_APP_DELETE);
+ break;
+ case SID_DB_APP_TABLE_DELETE:
+ case SID_DB_APP_TABLE_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_TABLE, _nId == SID_DB_APP_TABLE_DELETE);
+ break;
+ case SID_DB_APP_QUERY_DELETE:
+ case SID_DB_APP_QUERY_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_QUERY, _nId == SID_DB_APP_QUERY_DELETE);
+ break;
+ case SID_DB_APP_FORM_DELETE:
+ case SID_DB_APP_FORM_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_FORM, _nId == SID_DB_APP_FORM_DELETE);
+ break;
+ case SID_DB_APP_REPORT_DELETE:
+ case SID_DB_APP_REPORT_RENAME:
+ aReturn.bEnabled = isRenameDeleteAllowed(E_REPORT, _nId == SID_DB_APP_REPORT_DELETE);
+ break;
+
+ case SID_SELECTALL:
+ aReturn.bEnabled = getContainer()->getElementCount() > 0 && getContainer()->getSelectionCount() != getContainer()->getElementCount();
+ break;
+ case SID_DB_APP_EDIT:
+ case SID_DB_APP_TABLE_EDIT:
+ case SID_DB_APP_QUERY_EDIT:
+ case SID_DB_APP_FORM_EDIT:
+ case SID_DB_APP_REPORT_EDIT:
+ aReturn.bEnabled = !isDataSourceReadOnly() && getContainer()->getSelectionCount() > 0
+ && getContainer()->isALeafSelected();
+ break;
+ case SID_DB_APP_EDIT_SQL_VIEW:
+ if ( isDataSourceReadOnly() )
+ aReturn.bEnabled = false;
+ else
+ {
+ switch ( getContainer()->getElementType() )
+ {
+ case E_QUERY:
+ aReturn.bEnabled = ( getContainer()->getSelectionCount() > 0 )
+ && ( getContainer()->isALeafSelected() );
+ break;
+ case E_TABLE:
+ aReturn.bEnabled = false;
+ // there's one exception: views which support altering their underlying
+ // command can be edited in SQL view, too
+ if ( ( getContainer()->getSelectionCount() > 0 )
+ && ( getContainer()->isALeafSelected() )
+ )
+ {
+ std::vector< OUString > aSelected;
+ getSelectionElementNames( aSelected );
+ bool bAlterableViews = true;
+ for (auto const& selectedName : aSelected)
+ {
+ bAlterableViews &= impl_isAlterableView_nothrow(selectedName);
+ if (!bAlterableViews)
+ break;
+ }
+ aReturn.bEnabled = bAlterableViews;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case SID_DB_APP_OPEN:
+ case SID_DB_APP_TABLE_OPEN:
+ case SID_DB_APP_QUERY_OPEN:
+ case SID_DB_APP_FORM_OPEN:
+ case SID_DB_APP_REPORT_OPEN:
+ aReturn.bEnabled = getContainer()->getSelectionCount() > 0 && getContainer()->isALeafSelected();
+ break;
+ case SID_DB_APP_DSUSERADMIN:
+ aReturn.bEnabled = !dbaccess::ODsnTypeCollection::isEmbeddedDatabase(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL)));
+ break;
+ case SID_DB_APP_DSRELDESIGN:
+ aReturn.bEnabled = true;
+ break;
+ case SID_DB_APP_TABLEFILTER:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ break;
+ case SID_DB_APP_REFRESH_TABLES:
+ aReturn.bEnabled = getContainer()->getElementType() == E_TABLE && isConnected();
+ break;
+ case SID_DB_APP_DSPROPS:
+ aReturn.bEnabled = m_xDataSource.is() && dbaccess::ODsnTypeCollection::isShowPropertiesEnabled(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL)));
+ break;
+ case SID_DB_APP_DSCONNECTION_TYPE:
+ aReturn.bEnabled = !isDataSourceReadOnly() && m_xDataSource.is() && !dbaccess::ODsnTypeCollection::isEmbeddedDatabase(::comphelper::getString(m_xDataSource->getPropertyValue(PROPERTY_URL)));
+ break;
+ case SID_DB_APP_DSADVANCED_SETTINGS:
+ aReturn.bEnabled = m_xDataSource.is() && AdvancedSettingsDialog::doesHaveAnyAdvancedSettings( m_aTypeCollection.getType(::comphelper::getString( m_xDataSource->getPropertyValue( PROPERTY_URL ) )) );
+ break;
+ case SID_DB_APP_CONVERTTOVIEW:
+ aReturn.bEnabled = !isDataSourceReadOnly();
+ if ( aReturn.bEnabled )
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = eType == E_QUERY && getContainer()->getSelectionCount() > 0;
+ if ( aReturn.bEnabled )
+ {
+ Reference<XViewsSupplier> xViewSup( getConnection(), UNO_QUERY );
+ aReturn.bEnabled = xViewSup.is() && Reference<XAppend>(xViewSup->getViews(),UNO_QUERY).is();
+ }
+ }
+ break;
+ case SID_DB_APP_DISABLE_PREVIEW:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getPreviewMode() == E_PREVIEWNONE;
+ break;
+ case SID_DB_APP_VIEW_DOCINFO_PREVIEW:
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = (E_REPORT == eType || E_FORM == eType);
+ aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENTINFO;
+ }
+ break;
+ case SID_DB_APP_VIEW_DOC_PREVIEW:
+ aReturn.bEnabled = true;
+ aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENT;
+ break;
+ case ID_BROWSER_UNDO:
+ aReturn.bEnabled = false;
+ break;
+ case SID_MAIL_SENDDOC:
+ aReturn.bEnabled = true;
+ break;
+ case SID_DB_APP_SENDREPORTASMAIL:
+ {
+ ElementType eType = getContainer()->getElementType();
+ aReturn.bEnabled = E_REPORT == eType && getContainer()->getSelectionCount() > 0 && getContainer()->isALeafSelected();
+ }
+ break;
+ case SID_DB_APP_SENDREPORTTOWRITER:
+ case SID_DB_APP_DBADMIN:
+ aReturn.bEnabled = false;
+ break;
+ case SID_DB_APP_STATUS_TYPE:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ {
+ OUString sURL;
+ m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL;
+ OUString sDSTypeName;
+ if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase( sURL ) )
+ {
+ sDSTypeName = DBA_RES(RID_STR_EMBEDDED_DATABASE);
+ }
+ else
+ {
+ sDSTypeName = m_aTypeCollection.getTypeDisplayName(sURL);
+ }
+ aReturn.sTitle = sDSTypeName;
+ }
+ break;
+ case SID_DB_APP_STATUS_DBNAME:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ {
+ OUString sURL;
+ m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL;
+ OUString sDatabaseName;
+ OUString sHostName;
+ sal_Int32 nPortNumber( -1 );
+
+ m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber );
+
+ if ( sDatabaseName.isEmpty() )
+ sDatabaseName = m_aTypeCollection.cutPrefix( sURL );
+ if ( m_aTypeCollection.isFileSystemBased(sURL) )
+ {
+ sDatabaseName = SvtPathOptions().SubstituteVariable( sDatabaseName );
+ if ( !sDatabaseName.isEmpty() )
+ {
+ ::svt::OFileNotation aFileNotation(sDatabaseName);
+ // set this decoded URL as text
+ sDatabaseName = aFileNotation.get(::svt::OFileNotation::N_SYSTEM);
+ }
+ }
+
+ if ( sDatabaseName.isEmpty() )
+ sDatabaseName = m_aTypeCollection.getTypeDisplayName( sURL );
+
+ aReturn.sTitle = sDatabaseName;
+ }
+ break;
+ case SID_DB_APP_STATUS_USERNAME:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ m_xDataSource->getPropertyValue( PROPERTY_USER ) >>= aReturn.sTitle;
+ break;
+ case SID_DB_APP_STATUS_HOSTNAME:
+ aReturn.bEnabled = m_xDataSource.is();
+ if ( aReturn.bEnabled )
+ {
+ OUString sURL;
+ m_xDataSource->getPropertyValue( PROPERTY_URL ) >>= sURL;
+
+ OUString sHostName, sDatabaseName;
+ sal_Int32 nPortNumber = -1;
+ m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber );
+ aReturn.sTitle = sHostName;
+ }
+ break;
+ default:
+ aReturn = OGenericUnoController::GetState(_nId);
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return aReturn;
+}
+
+namespace
+{
+ bool lcl_handleException_nothrow( const Reference< XModel >& _rxDocument, const Any& _rException )
+ {
+ bool bHandled = false;
+
+ // try handling the error with an interaction handler
+ ::comphelper::NamedValueCollection aArgs( _rxDocument->getArgs() );
+ Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) );
+ if ( xHandler.is() )
+ {
+ rtl::Reference pRequest( new ::comphelper::OInteractionRequest( _rException ) );
+ rtl::Reference pApprove( new ::comphelper::OInteractionApprove );
+ pRequest->addContinuation( pApprove.get() );
+
+ try
+ {
+ xHandler->handle( pRequest.get() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ bHandled = pApprove->wasSelected();
+ }
+ return bHandled;
+ }
+}
+
+void OApplicationController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( isUserDefinedFeature( _nId ) )
+ {
+ OGenericUnoController::Execute( _nId, aArgs );
+ return;
+ }
+
+ if ( !getContainer() || m_bReadOnly )
+ return; // return without execution
+
+ try
+ {
+ switch(_nId)
+ {
+ case ID_BROWSER_CUT:
+ getContainer()->cut();
+ break;
+ case ID_BROWSER_COPY:
+ {
+ rtl::Reference<TransferableHelper> pTransfer = copyObject();
+ if ( pTransfer )
+ pTransfer->CopyToClipboard(getView());
+ }
+ break;
+ case ID_BROWSER_PASTE:
+ {
+ const TransferableDataHelper& rTransferData( getViewClipboard() );
+ ElementType eType = getContainer()->getElementType();
+
+ switch( eType )
+ {
+ case E_TABLE:
+ {
+ // get the selected tablename
+ std::vector< OUString > aList;
+ getSelectionElementNames( aList );
+ if ( !aList.empty() )
+ m_aTableCopyHelper.SetTableNameForAppend( *aList.begin() );
+ else
+ m_aTableCopyHelper.ResetTableNameForAppend();
+
+ m_aTableCopyHelper.pasteTable( rTransferData , getDatabaseName(), ensureConnection() );
+ }
+ break;
+
+ case E_QUERY:
+ if ( rTransferData.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) )
+ paste( E_QUERY, ODataAccessObjectTransferable::extractObjectDescriptor( rTransferData ) );
+ break;
+ default:
+ {
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ OUString sFolderNameToInsertInto;
+ if ( !aList.empty() )
+ {
+ Reference< XHierarchicalNameAccess > xContainer(getElements(eType),UNO_QUERY);
+ if ( xContainer.is()
+ && xContainer->hasByHierarchicalName(*aList.begin())
+ && (xContainer->getByHierarchicalName(*aList.begin()) >>= xContainer)
+ && xContainer.is()
+ )
+ sFolderNameToInsertInto = *aList.begin();
+ }
+ paste( eType, OComponentTransferable::extractComponentDescriptor( rTransferData ),
+ sFolderNameToInsertInto );
+ }
+ break;
+ }
+ }
+ break;
+ case SID_DB_APP_PASTE_SPECIAL:
+ {
+ if ( !aArgs.hasElements() )
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(getFrameWeld()));
+ std::vector<SotClipboardFormatId> aFormatIds;
+ getSupportedFormats(getContainer()->getElementType(),aFormatIds);
+ for (auto const& formatId : aFormatIds)
+ pDlg->Insert(formatId,"");
+
+ const TransferableDataHelper& rClipboard = getViewClipboard();
+ pasteFormat(pDlg->GetFormat(rClipboard.GetTransferable()));
+ }
+ else
+ {
+ const PropertyValue* pIter = aArgs.getConstArray();
+ const PropertyValue* pEnd = pIter + aArgs.getLength();
+ for( ; pIter != pEnd ; ++pIter)
+ {
+ if ( pIter->Name == "FormatStringId" )
+ {
+ sal_uLong nTmp;
+ if ( pIter->Value >>= nTmp )
+ pasteFormat(static_cast<SotClipboardFormatId>(nTmp));
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case SID_OPENDOC:
+ {
+ Reference < XDispatchProvider > xProv( getFrame(), UNO_QUERY );
+ if ( xProv.is() )
+ {
+ URL aURL;
+ aURL.Complete = ".uno:Open";
+
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aURL );
+ Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
+ if ( xDisp.is() )
+ xDisp->dispatch( aURL, Sequence < PropertyValue >() );
+ }
+ }
+ break;
+ case ID_BROWSER_SAVEDOC:
+ {
+ Reference< XStorable > xStore( m_xModel, UNO_QUERY_THROW );
+ try
+ {
+ xStore->store();
+ }
+ catch( const Exception& )
+ {
+ lcl_handleException_nothrow( m_xModel, ::cppu::getCaughtException() );
+ }
+ }
+ break;
+
+ case ID_BROWSER_SAVEASDOC:
+ {
+ OUString sUrl;
+ if ( m_xModel.is() )
+ sUrl = m_xModel->getURL();
+ if ( sUrl.isEmpty() )
+ sUrl = SvtPathOptions().GetWorkPath();
+
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE, getFrameWeld());
+ aFileDlg.SetDisplayDirectory( sUrl );
+
+ std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter();
+ if ( pFilter )
+ {
+ aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension());
+ aFileDlg.SetCurrentFilter(pFilter->GetUIName());
+ }
+
+ if ( aFileDlg.Execute() != ERRCODE_NONE )
+ break;
+
+ Reference<XStorable> xStore( m_xModel, UNO_QUERY_THROW );
+ INetURLObject aURL( aFileDlg.GetPath() );
+ try
+ {
+ xStore->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Sequence< PropertyValue >() );
+ }
+ catch( const Exception& )
+ {
+ lcl_handleException_nothrow( m_xModel, ::cppu::getCaughtException() );
+ }
+
+ /*updateTitle();*/
+ m_bCurrentlyModified = false;
+ InvalidateFeature(ID_BROWSER_SAVEDOC);
+ if ( getContainer()->getElementType() == E_NONE )
+ {
+ getContainer()->selectContainer(E_NONE);
+ getContainer()->selectContainer(E_TABLE);
+ // #i95524#
+ getContainer()->Invalidate();
+ refreshTables();
+ }
+
+ }
+ break;
+ case ID_BROWSER_SORTUP:
+ getContainer()->sortUp();
+ InvalidateFeature(ID_BROWSER_SORTDOWN);
+ break;
+ case ID_BROWSER_SORTDOWN:
+ getContainer()->sortDown();
+ InvalidateFeature(ID_BROWSER_SORTUP);
+ break;
+
+ case ID_NEW_TABLE_DESIGN_AUTO_PILOT:
+ case ID_NEW_VIEW_DESIGN_AUTO_PILOT:
+ case ID_APP_NEW_QUERY_AUTO_PILOT:
+ case SID_DB_FORM_NEW_PILOT:
+ case SID_REPORT_CREATE_REPWIZ_PRE_SEL:
+ case SID_APP_NEW_REPORT_PRE_SEL:
+ case SID_FORM_CREATE_REPWIZ_PRE_SEL:
+ case ID_DOCUMENT_CREATE_REPWIZ:
+ case SID_APP_NEW_FORM:
+ case SID_APP_NEW_REPORT:
+ case ID_NEW_QUERY_SQL:
+ case ID_NEW_QUERY_DESIGN:
+ case ID_NEW_TABLE_DESIGN:
+ {
+ ElementType eType = E_TABLE;
+ bool bAutoPilot = false;
+ ::comphelper::NamedValueCollection aCreationArgs;
+
+ switch( _nId )
+ {
+ case SID_DB_FORM_NEW_PILOT:
+ case SID_FORM_CREATE_REPWIZ_PRE_SEL:
+ bAutoPilot = true;
+ [[fallthrough]];
+ case SID_APP_NEW_FORM:
+ eType = E_FORM;
+ break;
+ case ID_DOCUMENT_CREATE_REPWIZ:
+ case SID_REPORT_CREATE_REPWIZ_PRE_SEL:
+ bAutoPilot = true;
+ [[fallthrough]];
+ case SID_APP_NEW_REPORT:
+ case SID_APP_NEW_REPORT_PRE_SEL:
+ eType = E_REPORT;
+ break;
+ case ID_APP_NEW_QUERY_AUTO_PILOT:
+ bAutoPilot = true;
+ eType = E_QUERY;
+ break;
+ case ID_NEW_QUERY_DESIGN:
+ aCreationArgs.put( OUString(PROPERTY_GRAPHICAL_DESIGN), true );
+ [[fallthrough]];
+ case ID_NEW_QUERY_SQL:
+ eType = E_QUERY;
+ break;
+ case ID_NEW_TABLE_DESIGN_AUTO_PILOT:
+ bAutoPilot = true;
+ [[fallthrough]];
+ case ID_NEW_TABLE_DESIGN:
+ break;
+ default:
+ OSL_FAIL("illegal switch call!");
+ }
+ if ( bAutoPilot )
+ getContainer()->PostUserEvent( LINK( this, OApplicationController, OnCreateWithPilot ), reinterpret_cast< void* >( eType ) );
+ else
+ {
+ Reference< XComponent > xDocDefinition;
+ newElement( eType, aCreationArgs, xDocDefinition );
+ }
+ }
+ break;
+ case SID_APP_NEW_FOLDER:
+ {
+ ElementType eType = getContainer()->getElementType();
+ OUString sName = getContainer()->getQualifiedName( nullptr );
+ insertHierachyElement(eType,sName);
+ }
+ break;
+ case ID_NEW_VIEW_DESIGN:
+ case SID_DB_NEW_VIEW_SQL:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ {
+ QueryDesigner aDesigner( getORB(), this, getFrame(), true );
+
+ ::comphelper::NamedValueCollection aCreationArgs;
+ aCreationArgs.put( OUString(PROPERTY_GRAPHICAL_DESIGN), ID_NEW_VIEW_DESIGN == _nId );
+
+ const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource, aCreationArgs );
+ onDocumentOpened( OUString(), E_QUERY, E_OPEN_DESIGN, xComponent, nullptr );
+ }
+ }
+ break;
+ case SID_DB_APP_DELETE:
+ case SID_DB_APP_TABLE_DELETE:
+ case SID_DB_APP_QUERY_DELETE:
+ case SID_DB_APP_FORM_DELETE:
+ case SID_DB_APP_REPORT_DELETE:
+ deleteEntries();
+ break;
+ case SID_DB_APP_RENAME:
+ case SID_DB_APP_TABLE_RENAME:
+ case SID_DB_APP_QUERY_RENAME:
+ case SID_DB_APP_FORM_RENAME:
+ case SID_DB_APP_REPORT_RENAME:
+ renameEntry();
+ break;
+ case SID_DB_APP_EDIT:
+ case SID_DB_APP_EDIT_SQL_VIEW:
+ case SID_DB_APP_TABLE_EDIT:
+ case SID_DB_APP_QUERY_EDIT:
+ case SID_DB_APP_FORM_EDIT:
+ case SID_DB_APP_REPORT_EDIT:
+ doAction( _nId, E_OPEN_DESIGN );
+ break;
+ case SID_DB_APP_OPEN:
+ case SID_DB_APP_TABLE_OPEN:
+ case SID_DB_APP_QUERY_OPEN:
+ case SID_DB_APP_FORM_OPEN:
+ case SID_DB_APP_REPORT_OPEN:
+ doAction( _nId, E_OPEN_NORMAL );
+ break;
+ case SID_DB_APP_CONVERTTOVIEW:
+ doAction( _nId, E_OPEN_NORMAL );
+ break;
+ case SID_SELECTALL:
+ getContainer()->selectAll();
+ InvalidateAll();
+ break;
+ case SID_DB_APP_DSRELDESIGN:
+ {
+ Reference< XComponent > xRelationDesigner;
+ if ( !m_pSubComponentManager->activateSubFrame( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xRelationDesigner ) )
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ {
+ RelationDesigner aDesigner( getORB(), this, m_aCurrentFrame.getFrame() );
+
+ const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource );
+ onDocumentOpened( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xComponent, nullptr );
+ }
+ }
+ }
+ break;
+ case SID_DB_APP_DSUSERADMIN:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ openDialog("com.sun.star.sdb.UserAdministrationDialog");
+ }
+ break;
+ case SID_DB_APP_TABLEFILTER:
+ // opens the table filter dialog for the selected data source
+ openDialog( "com.sun.star.sdb.TableFilterDialog" );
+ askToReconnect();
+ break;
+ case SID_DB_APP_REFRESH_TABLES:
+ refreshTables();
+ break;
+ case SID_DB_APP_DSPROPS:
+ // opens the administration dialog for the selected data source
+ openDialog( "com.sun.star.sdb.DatasourceAdministrationDialog" );
+ askToReconnect();
+ break;
+ case SID_DB_APP_DSADVANCED_SETTINGS:
+ openDialog("com.sun.star.sdb.AdvancedDatabaseSettingsDialog");
+ askToReconnect();
+ break;
+ case SID_DB_APP_DSCONNECTION_TYPE:
+ openDialog("com.sun.star.sdb.DataSourceTypeChangeDialog");
+ askToReconnect();
+ break;
+ case ID_DIRECT_SQL:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ // opens the DirectSQLDialog to execute hand made sql statements.
+ openDialog( SERVICE_SDB_DIRECTSQLDIALOG );
+ }
+ break;
+ case SID_DB_APP_VIEW_TABLES:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_TABLE ) );
+ break;
+ case SID_DB_APP_VIEW_QUERIES:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_QUERY ) );
+ break;
+ case SID_DB_APP_VIEW_FORMS:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_FORM ) );
+ break;
+ case SID_DB_APP_VIEW_REPORTS:
+ m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_REPORT ) );
+ break;
+ case SID_DB_APP_DISABLE_PREVIEW:
+ m_ePreviewMode = E_PREVIEWNONE;
+ getContainer()->switchPreview(m_ePreviewMode);
+ break;
+ case SID_DB_APP_VIEW_DOCINFO_PREVIEW:
+ m_ePreviewMode = E_DOCUMENTINFO;
+ getContainer()->switchPreview(m_ePreviewMode);
+ break;
+ case SID_DB_APP_VIEW_DOC_PREVIEW:
+ m_ePreviewMode = E_DOCUMENT;
+ getContainer()->switchPreview(m_ePreviewMode);
+ break;
+ case SID_MAIL_SENDDOC:
+ {
+ SfxMailModel aSendMail;
+ if ( aSendMail.AttachDocument(getModel(), OUString()) == SfxMailModel::SEND_MAIL_OK )
+ aSendMail.Send( getFrame() );
+ }
+ break;
+ case SID_DB_APP_SENDREPORTASMAIL:
+ doAction( _nId, E_OPEN_FOR_MAIL );
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ InvalidateFeature(_nId);
+}
+
+void OApplicationController::describeSupportedFeatures()
+{
+ OGenericUnoController::describeSupportedFeatures();
+
+ implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:SendMail", SID_MAIL_SENDDOC, CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBSendReportAsMail",SID_DB_APP_SENDREPORTASMAIL,
+ CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBSendReportToWriter",SID_DB_APP_SENDREPORTTOWRITER,
+ CommandGroup::DOCUMENT );
+ implDescribeSupportedFeature( ".uno:DBNewForm", SID_APP_NEW_FORM, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewFolder", SID_APP_NEW_FOLDER, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewFormAutoPilot", SID_DB_FORM_NEW_PILOT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewFormAutoPilotWithPreSelection",
+ SID_FORM_CREATE_REPWIZ_PRE_SEL,
+ CommandGroup::APPLICATION );
+
+ implDescribeSupportedFeature( ".uno:DBNewReport", SID_APP_NEW_REPORT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewReportAutoPilot",
+ ID_DOCUMENT_CREATE_REPWIZ, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewReportAutoPilotWithPreSelection",
+ SID_REPORT_CREATE_REPWIZ_PRE_SEL,
+ CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBNewQuery", ID_NEW_QUERY_DESIGN, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewQuerySql", ID_NEW_QUERY_SQL, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewQueryAutoPilot",ID_APP_NEW_QUERY_AUTO_PILOT,
+ CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewTable", ID_NEW_TABLE_DESIGN, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewTableAutoPilot",ID_NEW_TABLE_DESIGN_AUTO_PILOT,
+ CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewView", ID_NEW_VIEW_DESIGN, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DBNewViewSQL", SID_DB_NEW_VIEW_SQL, CommandGroup::INSERT );
+
+ implDescribeSupportedFeature( ".uno:DBDelete", SID_DB_APP_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Delete", SID_DB_APP_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBRename", SID_DB_APP_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBEdit", SID_DB_APP_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBEditSqlView", SID_DB_APP_EDIT_SQL_VIEW, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBOpen", SID_DB_APP_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBTableDelete", SID_DB_APP_TABLE_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBTableRename", SID_DB_APP_TABLE_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBTableEdit", SID_DB_APP_TABLE_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBTableOpen", SID_DB_APP_TABLE_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBQueryDelete", SID_DB_APP_QUERY_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBQueryRename", SID_DB_APP_QUERY_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBQueryEdit", SID_DB_APP_QUERY_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBQueryOpen", SID_DB_APP_QUERY_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBFormDelete", SID_DB_APP_FORM_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBFormRename", SID_DB_APP_FORM_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBFormEdit", SID_DB_APP_FORM_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBFormOpen", SID_DB_APP_FORM_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:DBReportDelete", SID_DB_APP_REPORT_DELETE, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBReportRename", SID_DB_APP_REPORT_RENAME, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBReportEdit", SID_DB_APP_REPORT_EDIT, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBReportOpen", SID_DB_APP_REPORT_OPEN, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:SelectAll", SID_SELECTALL, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT );
+
+ implDescribeSupportedFeature( ".uno:Sortup", ID_BROWSER_SORTUP, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:SortDown", ID_BROWSER_SORTDOWN, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBRelationDesign", SID_DB_APP_DSRELDESIGN, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBUserAdmin", SID_DB_APP_DSUSERADMIN, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBTableFilter", SID_DB_APP_TABLEFILTER, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBDSProperties", SID_DB_APP_DSPROPS, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBDSConnectionType", SID_DB_APP_DSCONNECTION_TYPE,
+ CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBDSAdvancedSettings",
+ SID_DB_APP_DSADVANCED_SETTINGS,
+ CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:PasteSpecial", SID_DB_APP_PASTE_SPECIAL, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBConvertToView", SID_DB_APP_CONVERTTOVIEW, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:DBRefreshTables", SID_DB_APP_REFRESH_TABLES, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBDirectSQL", ID_DIRECT_SQL, CommandGroup::APPLICATION );
+ implDescribeSupportedFeature( ".uno:DBViewTables", SID_DB_APP_VIEW_TABLES, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewQueries", SID_DB_APP_VIEW_QUERIES, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewForms", SID_DB_APP_VIEW_FORMS, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBViewReports", SID_DB_APP_VIEW_REPORTS, CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBDisablePreview", SID_DB_APP_DISABLE_PREVIEW,CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBShowDocInfoPreview",
+ SID_DB_APP_VIEW_DOCINFO_PREVIEW,
+ CommandGroup::VIEW );
+ implDescribeSupportedFeature( ".uno:DBShowDocPreview", SID_DB_APP_VIEW_DOC_PREVIEW,
+ CommandGroup::VIEW );
+
+ implDescribeSupportedFeature( ".uno:OpenUrl", SID_OPENURL, CommandGroup::APPLICATION );
+
+ // this one should not appear under Tools->Customize->Keyboard
+ implDescribeSupportedFeature( ".uno:DBNewReportWithPreSelection",
+ SID_APP_NEW_REPORT_PRE_SEL );
+ implDescribeSupportedFeature( ".uno:DBDSImport", SID_DB_APP_DSIMPORT);
+ implDescribeSupportedFeature( ".uno:DBDSExport", SID_DB_APP_DSEXPORT);
+ implDescribeSupportedFeature( ".uno:DBDBAdmin", SID_DB_APP_DBADMIN);
+
+ // status info
+ implDescribeSupportedFeature( ".uno:DBStatusType", SID_DB_APP_STATUS_TYPE);
+ implDescribeSupportedFeature( ".uno:DBStatusDBName", SID_DB_APP_STATUS_DBNAME);
+ implDescribeSupportedFeature( ".uno:DBStatusUserName", SID_DB_APP_STATUS_USERNAME);
+ implDescribeSupportedFeature( ".uno:DBStatusHostName", SID_DB_APP_STATUS_HOSTNAME);
+}
+
+OApplicationView* OApplicationController::getContainer() const
+{
+ return static_cast< OApplicationView* >( getView() );
+}
+
+// css::container::XContainerListener
+void SAL_CALL OApplicationController::elementInserted( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY);
+ if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() )
+ return;
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ if ( !getContainer() )
+ return;
+
+ OUString sName;
+ _rEvent.Accessor >>= sName;
+ ElementType eType = getElementType(xContainer);
+
+ switch( eType )
+ {
+ case E_TABLE:
+ ensureConnection();
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference< XContainer > xSubContainer(_rEvent.Element,UNO_QUERY);
+ if ( xSubContainer.is() )
+ containerFound(xSubContainer);
+ }
+ break;
+ default:
+ break;
+ }
+ getContainer()->elementAdded(eType,sName,_rEvent.Element);
+}
+
+void SAL_CALL OApplicationController::elementRemoved( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY);
+ if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() )
+ return;
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ OUString sName;
+ _rEvent.Accessor >>= sName;
+ ElementType eType = getElementType(xContainer);
+ switch( eType )
+ {
+ case E_TABLE:
+ ensureConnection();
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference<XContent> xContent(xContainer,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ sName = xContent->getIdentifier()->getContentIdentifier() + "/" + sName;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ getContainer()->elementRemoved(eType,sName);
+}
+
+void SAL_CALL OApplicationController::elementReplaced( const ContainerEvent& _rEvent )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Reference< XContainer > xContainer(_rEvent.Source, UNO_QUERY);
+ if ( std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xContainer) == m_aCurrentContainers.end() )
+ return;
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ OUString sName;
+ try
+ {
+ _rEvent.Accessor >>= sName;
+ Reference<XPropertySet> xProp(_rEvent.Element,UNO_QUERY);
+ OUString sNewName;
+
+ ElementType eType = getElementType(xContainer);
+ switch( eType )
+ {
+ case E_TABLE:
+ {
+ ensureConnection();
+ if ( xProp.is() && m_xMetaData.is() )
+ sNewName = ::dbaui::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InDataManipulation, false );
+ }
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference<XContent> xContent(xContainer,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ sName = xContent->getIdentifier()->getContentIdentifier() + "/" + sName;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ // getContainer()->elementReplaced(getContainer()->getElementType(),sName,sNewName);
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+namespace
+{
+ OUString lcl_getToolBarResource(ElementType _eType)
+ {
+ OUString sToolbar;
+ switch(_eType)
+ {
+ case E_TABLE:
+ sToolbar = "private:resource/toolbar/tableobjectbar";
+ break;
+ case E_QUERY:
+ sToolbar = "private:resource/toolbar/queryobjectbar";
+ break;
+ case E_FORM:
+ sToolbar = "private:resource/toolbar/formobjectbar";
+ break;
+ case E_REPORT:
+ sToolbar = "private:resource/toolbar/reportobjectbar";
+ break;
+ case E_NONE:
+ break;
+ default:
+ OSL_FAIL("Invalid ElementType!");
+ break;
+ }
+ return sToolbar;
+ }
+}
+
+bool OApplicationController::onContainerSelect(ElementType _eType)
+{
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+
+ if ( m_eCurrentType != _eType && _eType != E_NONE )
+ {
+ SelectionGuard aSelGuard( *m_pSelectionNotifier );
+
+ if ( _eType == E_TABLE )
+ {
+ try
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() && getContainer()->getDetailView() )
+ {
+ getContainer()->getDetailView()->createTablesPage(xConnection);
+ Reference<XTablesSupplier> xTabSup(xConnection,UNO_QUERY);
+ if ( xTabSup.is() )
+ addContainerListener(xTabSup->getTables());
+ }
+ else
+ {
+ return false;
+ }
+ }
+ catch( const Exception& )
+ {
+ return false;
+ }
+ }
+ else if ( _eType == E_QUERY )
+ {
+ // tdf#126578: retrieve connection to be able to call "Create as View"
+ ensureConnection();
+ }
+ Reference< XLayoutManager > xLayoutManager = getLayoutManager( getFrame() );
+ if ( xLayoutManager.is() )
+ {
+ OUString sToolbar = lcl_getToolBarResource(_eType);
+ OUString sDestroyToolbar = lcl_getToolBarResource(m_eCurrentType);
+
+ xLayoutManager->lock();
+ xLayoutManager->destroyElement( sDestroyToolbar );
+ if ( !sToolbar.isEmpty() )
+ {
+ xLayoutManager->createElement( sToolbar );
+ xLayoutManager->requestElement( sToolbar );
+ }
+ xLayoutManager->unlock();
+ xLayoutManager->doLayout();
+ }
+
+ if ( _eType != E_TABLE && getContainer()->getDetailView() )
+ {
+ Reference< XNameAccess > xContainer = getElements(_eType);
+ addContainerListener(xContainer);
+ getContainer()->getDetailView()->createPage(_eType,xContainer);
+ }
+
+ SelectionByElementType::const_iterator pendingSelection = m_aPendingSelection.find( _eType );
+ if ( pendingSelection != m_aPendingSelection.end() )
+ {
+ getContainer()->selectElements( comphelper::containerToSequence(pendingSelection->second) );
+
+ m_aPendingSelection.erase( pendingSelection );
+ }
+
+ InvalidateAll();
+ }
+ m_eCurrentType = _eType;
+
+ return true;
+}
+
+bool OApplicationController::onEntryDoubleClick( SvTreeListBox const & _rTree )
+{
+ if ( getContainer() && getContainer()->isLeaf( _rTree.GetHdlEntry() ) )
+ {
+ try
+ {
+ // opens a new frame with either the table or the query or report or form or view
+ openElementWithArguments(
+ getContainer()->getQualifiedName( _rTree.GetHdlEntry() ),
+ getContainer()->getElementType(),
+ E_OPEN_NORMAL,
+ 0,
+ ::comphelper::NamedValueCollection() );
+ return true; // handled
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ return false; // not handled
+}
+
+bool OApplicationController::impl_isAlterableView_nothrow( const OUString& _rTableOrViewName ) const
+{
+ OSL_PRECOND( m_xDataSourceConnection.is(), "OApplicationController::impl_isAlterableView_nothrow: no connection!" );
+
+ bool bIsAlterableView( false );
+ try
+ {
+ Reference< XViewsSupplier > xViewsSupp( m_xDataSourceConnection, UNO_QUERY );
+ Reference< XNameAccess > xViews;
+ if ( xViewsSupp.is() )
+ xViews = xViewsSupp->getViews();
+
+ Reference< XAlterView > xAsAlterableView;
+ if ( xViews.is() && xViews->hasByName( _rTableOrViewName ) )
+ xAsAlterableView.set( xViews->getByName( _rTableOrViewName ), UNO_QUERY );
+
+ bIsAlterableView = xAsAlterableView.is();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bIsAlterableView;
+}
+
+Reference< XComponent > OApplicationController::openElementWithArguments( const OUString& _sName, ElementType _eType,
+ ElementOpenMode _eOpenMode, sal_uInt16 _nInstigatorCommand, const ::comphelper::NamedValueCollection& _rAdditionalArguments )
+{
+ OSL_PRECOND( getContainer(), "OApplicationController::openElementWithArguments: no view!" );
+ if ( !getContainer() )
+ return nullptr;
+
+ Reference< XComponent > xRet;
+ if ( _eOpenMode == E_OPEN_DESIGN )
+ {
+ // https://bz.apache.org/ooo/show_bug.cgi?id=30382
+ getContainer()->showPreview(nullptr);
+ }
+
+ bool isStandaloneDocument = false;
+ switch ( _eType )
+ {
+ case E_REPORT:
+ if ( _eOpenMode != E_OPEN_DESIGN )
+ {
+ // reports which are opened in a mode other than design are no sub components of our application
+ // component, but standalone documents.
+ isStandaloneDocument = true;
+ }
+ [[fallthrough]];
+ case E_FORM:
+ {
+ if ( isStandaloneDocument || !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) )
+ {
+ std::unique_ptr< OLinkedDocumentsAccess > aHelper = getDocumentsAccess( _eType );
+ if ( !aHelper->isConnected() )
+ break;
+
+ Reference< XComponent > xDefinition;
+ xRet = aHelper->open( _sName, xDefinition, _eOpenMode, _rAdditionalArguments );
+
+ if ( !isStandaloneDocument )
+ onDocumentOpened( _sName, _eType, _eOpenMode, xRet, xDefinition );
+ }
+ }
+ break;
+
+ case E_QUERY:
+ case E_TABLE:
+ {
+ if ( !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) )
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( !xConnection.is() )
+ break;
+
+ std::unique_ptr< DatabaseObjectView > pDesigner;
+ ::comphelper::NamedValueCollection aArguments( _rAdditionalArguments );
+
+ Any aDataSource;
+ if ( _eOpenMode == E_OPEN_DESIGN )
+ {
+ bool bAddViewTypeArg = false;
+
+ if ( _eType == E_TABLE )
+ {
+ if ( impl_isAlterableView_nothrow( _sName ) )
+ {
+ pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), true ) );
+ bAddViewTypeArg = true;
+ }
+ else
+ {
+ pDesigner.reset( new TableDesigner( getORB(), this, m_aCurrentFrame.getFrame() ) );
+ }
+ }
+ else if ( _eType == E_QUERY )
+ {
+ pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), false ) );
+ bAddViewTypeArg = true;
+ }
+ aDataSource <<= m_xDataSource;
+
+ if ( bAddViewTypeArg )
+ {
+ const bool bQueryGraphicalMode =( _nInstigatorCommand != SID_DB_APP_EDIT_SQL_VIEW );
+ aArguments.put( OUString(PROPERTY_GRAPHICAL_DESIGN), bQueryGraphicalMode );
+ }
+
+ }
+ else
+ {
+ pDesigner.reset( new ResultSetBrowser( getORB(), this, m_aCurrentFrame.getFrame(), _eType == E_TABLE ) );
+
+ if ( !aArguments.has( OUString(PROPERTY_SHOWMENU) ) )
+ aArguments.put( OUString(PROPERTY_SHOWMENU), makeAny( true ) );
+
+ aDataSource <<= getDatabaseName();
+ }
+
+ xRet.set( pDesigner->openExisting( aDataSource, _sName, aArguments ) );
+ onDocumentOpened( _sName, _eType, _eOpenMode, xRet, nullptr );
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "OApplicationController::openElement: illegal object type!" );
+ break;
+ }
+ return xRet;
+}
+
+IMPL_LINK( OApplicationController, OnSelectContainer, void*, _pType, void )
+{
+ ElementType eType = static_cast<ElementType>(reinterpret_cast< sal_IntPtr >( _pType ));
+ if (getContainer())
+ getContainer()->selectContainer(eType);
+}
+
+IMPL_LINK( OApplicationController, OnCreateWithPilot, void*, _pType, void )
+{
+ ElementType eType = static_cast<ElementType>(reinterpret_cast< sal_IntPtr >( _pType ));
+ newElementWithPilot( eType );
+}
+
+void OApplicationController::newElementWithPilot( ElementType _eType )
+{
+ utl::CloseVeto aKeepDoc( getFrame() );
+ // prevent the document being closed while the wizard is open
+
+ OSL_ENSURE( getContainer(), "OApplicationController::newElementWithPilot: without a view?" );
+
+ switch ( _eType )
+ {
+ case E_REPORT:
+ case E_FORM:
+ {
+ std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess(_eType);
+ if ( aHelper->isConnected() )
+ {
+ sal_Int32 nCommandType = -1;
+ const OUString sCurrentSelected( getCurrentlySelectedName( nCommandType ) );
+ if ( E_REPORT == _eType )
+ aHelper->newReportWithPilot( nCommandType, sCurrentSelected );
+ else
+ aHelper->newFormWithPilot( nCommandType, sCurrentSelected );
+ }
+ }
+ break;
+ case E_QUERY:
+ case E_TABLE:
+ {
+ std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess(_eType);
+ if ( aHelper->isConnected() )
+ {
+ if ( E_QUERY == _eType )
+ aHelper->newQueryWithPilot();
+ else
+ aHelper->newTableWithPilot();
+ }
+ }
+ break;
+ case E_NONE:
+ break;
+ }
+
+ // no need for onDocumentOpened, the table wizard opens the created table by using
+ // XDatabaseDocumentUI::loadComponent method.
+}
+
+Reference< XComponent > OApplicationController::newElement( ElementType _eType, const ::comphelper::NamedValueCollection& i_rAdditionalArguments,
+ Reference< XComponent >& o_rDocumentDefinition )
+{
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+
+ Reference< XComponent > xComponent;
+ o_rDocumentDefinition.clear();
+
+ switch ( _eType )
+ {
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::unique_ptr<OLinkedDocumentsAccess> aHelper = getDocumentsAccess( _eType );
+ if ( !aHelper->isConnected() )
+ break;
+
+ xComponent = aHelper->newDocument( _eType == E_FORM ? ID_FORM_NEW_TEXT : ID_REPORT_NEW_TEXT, i_rAdditionalArguments, o_rDocumentDefinition );
+ }
+ break;
+
+ case E_QUERY:
+ case E_TABLE:
+ {
+ std::unique_ptr< DatabaseObjectView > pDesigner;
+ SharedConnection xConnection( ensureConnection() );
+ if ( !xConnection.is() )
+ break;
+
+ if ( _eType == E_TABLE )
+ {
+ pDesigner.reset( new TableDesigner( getORB(), this, getFrame() ) );
+ }
+ else if ( _eType == E_QUERY )
+ {
+ pDesigner.reset( new QueryDesigner( getORB(), this, getFrame(), false ) );
+ }
+
+ Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ xComponent = pDesigner->createNew( xDataSource, i_rAdditionalArguments );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "OApplicationController::newElement: illegal type!" );
+ break;
+ }
+
+ if ( xComponent.is() )
+ onDocumentOpened( OUString(), _eType, E_OPEN_DESIGN, xComponent, o_rDocumentDefinition );
+
+ return xComponent;
+}
+
+void OApplicationController::addContainerListener(const Reference<XNameAccess>& _xCollection)
+{
+ try
+ {
+ Reference< XContainer > xCont(_xCollection, UNO_QUERY);
+ if ( xCont.is() )
+ {
+ // add as listener to get notified if elements are inserted or removed
+ TContainerVector::const_iterator aFind = std::find(m_aCurrentContainers.begin(),m_aCurrentContainers.end(),xCont);
+ if ( aFind == m_aCurrentContainers.end() )
+ {
+ xCont->addContainerListener(this);
+ m_aCurrentContainers.push_back(xCont);
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::renameEntry()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ OSL_ENSURE(getContainer(),"View is NULL! -> GPF");
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+
+ Reference< XNameAccess > xContainer = getElements(getContainer()->getElementType());
+ OSL_ENSURE(aList.size() == 1,"Invalid rename call here. More than one element!");
+ if ( aList.empty() )
+ return;
+
+ try
+ {
+ if ( xContainer.is() )
+ {
+ std::unique_ptr< IObjectNameCheck > pNameChecker;
+ std::unique_ptr<OSaveAsDlg> xDialog;
+
+ Reference<XRename> xRename;
+ const ElementType eType = getContainer()->getElementType();
+ switch( eType )
+ {
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference<XHierarchicalNameContainer> xHNames(xContainer, UNO_QUERY);
+ if ( xHNames.is() )
+ {
+ OUString sLabel;
+ if ( eType == E_FORM )
+ sLabel = DBA_RES(STR_FRM_LABEL);
+ else
+ sLabel = DBA_RES(STR_RPT_LABEL);
+
+ OUString sName = *aList.begin();
+ if ( xHNames->hasByHierarchicalName(sName) )
+ {
+ xRename.set(xHNames->getByHierarchicalName(sName),UNO_QUERY);
+ Reference<XChild> xChild(xRename,UNO_QUERY);
+ if ( xChild.is() )
+ {
+ Reference<XHierarchicalNameContainer> xParent(xChild->getParent(),UNO_QUERY);
+ if ( xParent.is() )
+ {
+ xHNames = xParent;
+ Reference<XPropertySet>(xRename,UNO_QUERY_THROW)->getPropertyValue(PROPERTY_NAME) >>= sName;
+ }
+ }
+ pNameChecker.reset( new HierarchicalNameCheck( xHNames.get(), OUString() ) );
+ xDialog.reset(new OSaveAsDlg(
+ getFrameWeld(), getORB(), sName, sLabel, *pNameChecker, SADFlags::TitleRename));
+ }
+ }
+ }
+ break;
+ case E_TABLE:
+ ensureConnection();
+ if ( !getConnection().is() )
+ break;
+ [[fallthrough]];
+ case E_QUERY:
+ if ( xContainer->hasByName(*aList.begin()) )
+ {
+ xRename.set(xContainer->getByName(*aList.begin()),UNO_QUERY);
+ sal_Int32 nCommandType = eType == E_QUERY ? CommandType::QUERY : CommandType::TABLE;
+
+ ensureConnection();
+ pNameChecker.reset( new DynamicTableOrQueryNameCheck( getConnection(), nCommandType ) );
+ xDialog.reset(new OSaveAsDlg(getFrameWeld(), nCommandType, getORB(), getConnection(),
+ *aList.begin(), *pNameChecker, SADFlags::TitleRename));
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (xRename.is() && xDialog)
+ {
+
+ bool bTryAgain = true;
+ while( bTryAgain )
+ {
+ if (xDialog->run() == RET_OK)
+ {
+ try
+ {
+ OUString sNewName;
+ if ( eType == E_TABLE )
+ {
+ OUString sName = xDialog->getName();
+ OUString sCatalog = xDialog->getCatalog();
+ OUString sSchema = xDialog->getSchema();
+
+ sNewName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sName, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ else
+ sNewName = xDialog->getName();
+
+ OUString sOldName = *aList.begin();
+ if ( eType == E_FORM || eType == E_REPORT )
+ {
+ Reference<XContent> xContent(xRename,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ sOldName = xContent->getIdentifier()->getContentIdentifier();
+ }
+ }
+
+ xRename->rename(sNewName);
+
+ if ( eType == E_TABLE )
+ {
+ Reference<XPropertySet> xProp(xRename,UNO_QUERY);
+ sNewName = ::dbaui::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InDataManipulation, false );
+ }
+ getContainer()->elementReplaced( eType , sOldName, sNewName );
+
+ bTryAgain = false;
+ }
+ catch(const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+
+ }
+ catch(const ElementExistException& e)
+ {
+ OUString sMsg(DBA_RES(STR_NAME_ALREADY_EXISTS));
+ showError(SQLExceptionInfo(SQLException(sMsg.replaceAll("#", e.Message), e.Context, "S1000", 0, Any())));
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ else
+ bTryAgain = false;
+ }
+ }
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::onSelectionChanged()
+{
+ InvalidateAll();
+
+ SelectionGuard aSelGuard( *m_pSelectionNotifier );
+
+ OApplicationView* pView = getContainer();
+ if ( !pView )
+ return;
+
+ if ( pView->getSelectionCount() == 1 )
+ {
+ const ElementType eType = pView->getElementType();
+ if ( pView->isALeafSelected() )
+ {
+ const OUString sName = pView->getQualifiedName( nullptr /* means 'first selected' */ );
+ showPreviewFor( eType, sName );
+ }
+ }
+}
+
+void OApplicationController::showPreviewFor(const ElementType _eType,const OUString& _sName)
+{
+ if ( m_ePreviewMode == E_PREVIEWNONE )
+ return;
+
+ OApplicationView* pView = getContainer();
+ if ( !pView )
+ return;
+
+ try
+ {
+ switch( _eType )
+ {
+ case E_FORM:
+ case E_REPORT:
+ {
+ Reference< XHierarchicalNameAccess > xContainer( getElements( _eType ), UNO_QUERY_THROW );
+ Reference< XContent> xContent( xContainer->getByHierarchicalName( _sName ), UNO_QUERY_THROW );
+ pView->showPreview( xContent );
+ }
+ break;
+
+ case E_TABLE:
+ case E_QUERY:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ pView->showPreview( getDatabaseName(), xConnection, _sName, _eType == E_TABLE );
+ }
+ return;
+
+ default:
+ OSL_FAIL( "OApplicationController::showPreviewFor: unexpected element type!" );
+ break;
+ }
+ }
+ catch( const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+IMPL_LINK_NOARG(OApplicationController, OnClipboardChanged, TransferableDataHelper*, void)
+{
+ OnInvalidateClipboard();
+}
+
+void OApplicationController::OnInvalidateClipboard()
+{
+ InvalidateFeature(ID_BROWSER_CUT);
+ InvalidateFeature(ID_BROWSER_COPY);
+ InvalidateFeature(ID_BROWSER_PASTE);
+ InvalidateFeature(SID_DB_APP_PASTE_SPECIAL);
+}
+
+void OApplicationController::onCopyEntry()
+{
+ Execute(ID_BROWSER_COPY,Sequence<PropertyValue>());
+}
+
+void OApplicationController::onPasteEntry()
+{
+ Execute(ID_BROWSER_PASTE,Sequence<PropertyValue>());
+}
+
+void OApplicationController::onDeleteEntry()
+{
+ ElementType eType = getContainer()->getElementType();
+ sal_uInt16 nId = 0;
+ switch(eType)
+ {
+ case E_TABLE:
+ nId = SID_DB_APP_TABLE_DELETE;
+ break;
+ case E_QUERY:
+ nId = SID_DB_APP_QUERY_DELETE;
+ break;
+ case E_FORM:
+ nId = SID_DB_APP_FORM_DELETE;
+ break;
+ case E_REPORT:
+ nId = SID_DB_APP_REPORT_DELETE;
+ break;
+ default:
+ OSL_FAIL("Invalid ElementType!");
+ break;
+ }
+ executeChecked(nId,Sequence<PropertyValue>());
+}
+
+OUString OApplicationController::getContextMenuResourceName( Control& /*_rControl*/ ) const
+{
+ return "edit";
+}
+
+IController& OApplicationController::getCommandController()
+{
+ return *this;
+}
+
+::comphelper::OInterfaceContainerHelper2* OApplicationController::getContextMenuInterceptors()
+{
+ return &m_aContextMenuInterceptors;
+}
+
+Any OApplicationController::getCurrentSelection( Control& _rControl ) const
+{
+ Sequence< NamedDatabaseObject > aSelection;
+ getContainer()->describeCurrentSelectionForControl( _rControl, aSelection );
+ return makeAny( aSelection );
+}
+
+bool OApplicationController::requestQuickHelp( const SvTreeListEntry* /*_pEntry*/, OUString& /*_rText*/ ) const
+{
+ return false;
+}
+
+bool OApplicationController::requestDrag( const Point& /*_rPosPixel*/ )
+{
+ rtl::Reference<TransferableHelper> pTransfer;
+ if ( getContainer() && getContainer()->getSelectionCount() )
+ {
+ try
+ {
+ pTransfer = copyObject( );
+
+ if ( pTransfer && getContainer()->getDetailView() )
+ {
+ ElementType eType = getContainer()->getElementType();
+ pTransfer->StartDrag( getContainer()->getDetailView()->getTreeWindow(), ((eType == E_FORM || eType == E_REPORT) ? DND_ACTION_COPYMOVE : DND_ACTION_COPY) );
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ return pTransfer.is();
+}
+
+sal_Int8 OApplicationController::queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors )
+{
+ sal_Int8 nActionAskedFor = _rEvt.mnAction;
+ // check if we're a table or query container
+ OApplicationView* pView = getContainer();
+ if ( pView && !isDataSourceReadOnly() )
+ {
+ ElementType eType = pView->getElementType();
+ if ( eType != E_NONE && (eType != E_TABLE || !isConnectionReadOnly()) )
+ {
+ // check for the concrete type
+ if(std::any_of(_rFlavors.begin(),_rFlavors.end(),TAppSupportedSotFunctor(eType)))
+ return DND_ACTION_COPY;
+ if ( eType == E_FORM || eType == E_REPORT )
+ {
+ sal_Int8 nAction = OComponentTransferable::canExtractComponentDescriptor(_rFlavors,eType == E_FORM) ? DND_ACTION_COPY : DND_ACTION_NONE;
+ if ( nAction != DND_ACTION_NONE )
+ {
+ SvTreeListEntry* pHitEntry = pView->getEntry(_rEvt.maPosPixel);
+ OUString sName;
+ if ( pHitEntry )
+ {
+ sName = pView->getQualifiedName( pHitEntry );
+ if ( !sName.isEmpty() )
+ {
+ Reference< XHierarchicalNameAccess > xContainer(getElements(pView->getElementType()),UNO_QUERY);
+ if ( xContainer.is() && xContainer->hasByHierarchicalName(sName) )
+ {
+ Reference< XHierarchicalNameAccess > xHitObject(xContainer->getByHierarchicalName(sName),UNO_QUERY);
+ if ( xHitObject.is() )
+ nAction = nActionAskedFor & DND_ACTION_COPYMOVE;
+ }
+ else
+ nAction = DND_ACTION_NONE;
+ }
+ }
+ }
+ return nAction;
+ }
+ }
+ }
+
+ return DND_ACTION_NONE;
+}
+
+sal_Int8 OApplicationController::executeDrop( const ExecuteDropEvent& _rEvt )
+{
+ OApplicationView* pView = getContainer();
+ if ( !pView || pView->getElementType() == E_NONE )
+ {
+ OSL_FAIL("OApplicationController::executeDrop: what the hell did queryDrop do?");
+ // queryDrop should not have allowed us to reach this situation...
+ return DND_ACTION_NONE;
+ }
+
+ // a TransferableDataHelper for accessing the dropped data
+ TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable);
+
+ // reset the data of the previous async drop (if any)
+ if ( m_nAsyncDrop )
+ Application::RemoveUserEvent(m_nAsyncDrop);
+
+ m_nAsyncDrop = nullptr;
+ m_aAsyncDrop.aDroppedData.clear();
+ m_aAsyncDrop.nType = pView->getElementType();
+ m_aAsyncDrop.nAction = _rEvt.mnAction;
+ m_aAsyncDrop.bError = false;
+ m_aAsyncDrop.bHtml = false;
+ m_aAsyncDrop.aUrl.clear();
+
+ // loop through the available formats and see what we can do...
+ // first we have to check if it is our own format, if not we have to copy the stream :-(
+ if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(aDroppedData.GetDataFlavorExVector()) )
+ {
+ m_aAsyncDrop.aDroppedData = ODataAccessObjectTransferable::extractObjectDescriptor(aDroppedData);
+
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop));
+ return DND_ACTION_COPY;
+ }
+ else if ( OComponentTransferable::canExtractComponentDescriptor(aDroppedData.GetDataFlavorExVector(),m_aAsyncDrop.nType == E_FORM) )
+ {
+ m_aAsyncDrop.aDroppedData = OComponentTransferable::extractComponentDescriptor(aDroppedData);
+ SvTreeListEntry* pHitEntry = pView->getEntry(_rEvt.maPosPixel);
+ if ( pHitEntry )
+ m_aAsyncDrop.aUrl = pView->getQualifiedName( pHitEntry );
+
+ sal_Int8 nAction = _rEvt.mnAction;
+ Reference<XContent> xContent;
+ m_aAsyncDrop.aDroppedData[DataAccessDescriptorProperty::Component] >>= xContent;
+ if ( xContent.is() )
+ {
+ OUString sName = xContent->getIdentifier()->getContentIdentifier();
+ sName = sName.copy(sName.indexOf('/') + 1);
+ if ( m_aAsyncDrop.aUrl.getLength() >= sName.getLength() && m_aAsyncDrop.aUrl.startsWith(sName) )
+ {
+ m_aAsyncDrop.aDroppedData.clear();
+ return DND_ACTION_NONE;
+ }
+
+ // check if move is allowed, if another object with the same name exists only copy is allowed
+ Reference< XHierarchicalNameAccess > xContainer(getElements(m_aAsyncDrop.nType),UNO_QUERY);
+ Reference<XNameAccess> xNameAccess(xContainer,UNO_QUERY);
+
+ if ( !m_aAsyncDrop.aUrl.isEmpty() && xContainer.is() && xContainer->hasByHierarchicalName(m_aAsyncDrop.aUrl) )
+ xNameAccess.set(xContainer->getByHierarchicalName(m_aAsyncDrop.aUrl),UNO_QUERY);
+
+ if ( xNameAccess.is() )
+ {
+ Reference<XPropertySet> xProp(xContent,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
+ if ( xNameAccess.is() && xNameAccess->hasByName(sName) )
+ nAction &= ~DND_ACTION_MOVE;
+ }
+ else
+ nAction &= ~DND_ACTION_MOVE;
+ }
+ }
+ if ( nAction != DND_ACTION_NONE )
+ {
+ m_aAsyncDrop.nAction = nAction;
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop));
+ }
+ else
+ m_aAsyncDrop.aDroppedData.clear();
+ return nAction;
+ }
+ else
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() && m_aTableCopyHelper.copyTagTable( aDroppedData, m_aAsyncDrop, xConnection ) )
+ {
+ // asynchron because we some dialogs and we aren't allowed to show them while in D&D
+ m_nAsyncDrop = Application::PostUserEvent(LINK(this, OApplicationController, OnAsyncDrop));
+ return DND_ACTION_COPY;
+ }
+ }
+
+ return DND_ACTION_NONE;
+}
+
+Reference< XModel > SAL_CALL OApplicationController::getModel()
+{
+ return m_xModel;
+}
+
+void OApplicationController::onAttachedFrame()
+{
+ sal_Int32 nConnectedControllers( 0 );
+ try
+ {
+ Reference< XModel2 > xModel( m_xModel, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumControllers( xModel->getControllers(), UNO_SET_THROW );
+ while ( xEnumControllers->hasMoreElements() )
+ {
+ Reference< XController > xController( xEnumControllers->nextElement(), UNO_QUERY_THROW );
+ ++nConnectedControllers;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( nConnectedControllers > 1 )
+ { // we are not the first connected controller, there were already others
+ return;
+ }
+
+ OnFirstControllerConnected();
+}
+
+void OApplicationController::OnFirstControllerConnected()
+{
+ if ( !m_xModel.is() )
+ {
+ OSL_FAIL( "OApplicationController::OnFirstControllerConnected: too late!" );
+ }
+
+ // if we have forms or reports which contain macros/scripts, then show a warning
+ // which suggests the user to migrate them to the database document
+ Reference< XEmbeddedScripts > xDocumentScripts( m_xModel, UNO_QUERY );
+ if ( xDocumentScripts.is() )
+ {
+ // no need to show this warning, obviously the document supports embedding scripts
+ // into itself, so there are no "old-style" forms/reports which have macros/scripts
+ // themselves
+ return;
+ }
+
+ try
+ {
+ // If the migration just happened, but was not successful, the document is reloaded.
+ // In this case, we should not show the warning, again.
+ ::comphelper::NamedValueCollection aModelArgs( m_xModel->getArgs() );
+ if ( aModelArgs.getOrDefault( "SuppressMigrationWarning", false ) )
+ return;
+
+ // also, if the document is read-only, then no migration is possible, and the
+ // respective menu entry is hidden. So, don't show the warning in this case, too.
+ if ( Reference< XStorable >( m_xModel, UNO_QUERY_THROW )->isReadonly() )
+ return;
+
+ SQLWarning aWarning;
+ aWarning.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS);
+ SQLException aDetail;
+ aDetail.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS_DETAIL);
+ aWarning.NextException <<= aDetail;
+
+ Reference< XExecutableDialog > xDialog = ErrorMessageDialog::create( getORB(), "", nullptr, makeAny( aWarning ) );
+ xDialog->execute();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OApplicationController::attachFrame( const Reference< XFrame > & i_rxFrame )
+{
+ SolarMutexGuard aSolarGuard; // avoid deadlock in XModel calls
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ OGenericUnoController::attachFrame( i_rxFrame );
+ if ( getFrame().is() )
+ onAttachedFrame();
+}
+
+sal_Bool SAL_CALL OApplicationController::attachModel(const Reference< XModel > & _rxModel)
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ const Reference< XOfficeDatabaseDocument > xOfficeDoc( _rxModel, UNO_QUERY );
+ const Reference< XModifiable > xDocModify( _rxModel, UNO_QUERY );
+ if ( ( !xOfficeDoc.is() || !xDocModify.is() ) && _rxModel.is() )
+ {
+ OSL_FAIL( "OApplicationController::attachModel: invalid model!" );
+ return false;
+ }
+
+ if ( m_xModel.is() && ( m_xModel != _rxModel ) && ( _rxModel.is() ) )
+ {
+ OSL_ENSURE( false, "OApplicationController::attachModel: missing implementation: setting a new model while we have another one!" );
+ // we'd need to completely update our view here, close sub components, and the like
+ return false;
+ }
+
+ const OUString aPropertyNames[] =
+ {
+ OUString(PROPERTY_URL), OUString(PROPERTY_USER)
+ };
+
+ // disconnect from old model
+ try
+ {
+ if ( m_xDataSource.is() )
+ {
+ for (const auto & aPropertyName : aPropertyNames)
+ {
+ m_xDataSource->removePropertyChangeListener( aPropertyName, this );
+ }
+ }
+
+ Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ xBroadcaster->removeModifyListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xModel = _rxModel;
+ m_xDataSource.set( xOfficeDoc.is() ? xOfficeDoc->getDataSource() : Reference< XDataSource >(), UNO_QUERY );
+
+ // connect to new model
+ try
+ {
+ if ( m_xDataSource.is() )
+ {
+ for (const auto & aPropertyName : aPropertyNames)
+ {
+ m_xDataSource->addPropertyChangeListener( aPropertyName, this );
+ }
+ }
+
+ Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY_THROW );
+ xBroadcaster->addModifyListener( this );
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // initial preview mode
+ if ( m_xDataSource.is() )
+ {
+ try
+ {
+ // to get the 'modified' for the data source
+ ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) );
+ if ( aLayoutInfo.has( OUString(INFO_PREVIEW) ) )
+ {
+ const sal_Int32 nPreviewMode( aLayoutInfo.getOrDefault( INFO_PREVIEW, sal_Int32(0) ) );
+ m_ePreviewMode = static_cast< PreviewMode >( nPreviewMode );
+ if ( getView() )
+ getContainer()->switchPreview( m_ePreviewMode );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ return true;
+}
+
+void OApplicationController::containerFound( const Reference< XContainer >& _xContainer)
+{
+ try
+ {
+ if ( _xContainer.is() )
+ {
+ m_aCurrentContainers.push_back(_xContainer);
+ _xContainer->addContainerListener(this);
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OUString OApplicationController::getCurrentlySelectedName(sal_Int32& _rnCommandType) const
+{
+ _rnCommandType = ( (getContainer()->getElementType() == E_QUERY)
+ ? CommandType::QUERY : ( (getContainer()->getElementType() == E_TABLE) ? CommandType::TABLE : -1 ));
+
+ OUString sName;
+ if ( _rnCommandType != -1 )
+ {
+ try
+ {
+ sName = getContainer()->getQualifiedName( nullptr );
+ OSL_ENSURE( !sName.isEmpty(), "OApplicationController::getCurrentlySelectedName: no name given!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ return sName;
+}
+
+void SAL_CALL OApplicationController::addSelectionChangeListener( const Reference< view::XSelectionChangeListener >& Listener )
+{
+ m_pSelectionNotifier->addListener( Listener );
+}
+
+void SAL_CALL OApplicationController::removeSelectionChangeListener( const Reference< view::XSelectionChangeListener >& Listener )
+{
+ m_pSelectionNotifier->removeListener( Listener );
+}
+
+sal_Bool SAL_CALL OApplicationController::select( const Any& _aSelection )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ Sequence< OUString> aSelection;
+ if ( !_aSelection.hasValue() || !getView() )
+ {
+ getContainer()->selectElements(aSelection);
+ return true;
+ }
+
+ // BEGIN compatibility
+ Sequence< NamedValue > aCurrentSelection;
+ if ( (_aSelection >>= aCurrentSelection) && aCurrentSelection.hasElements() )
+ {
+ ElementType eType = E_NONE;
+ const NamedValue* pIter = aCurrentSelection.getConstArray();
+ const NamedValue* pEnd = pIter + aCurrentSelection.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( pIter->Name == "Type" )
+ {
+ sal_Int32 nType = 0;
+ pIter->Value >>= nType;
+ if ( nType < DatabaseObject::TABLE || nType > DatabaseObject::REPORT )
+ throw IllegalArgumentException();
+ eType = static_cast< ElementType >( nType );
+ }
+ else if ( pIter->Name == "Selection" )
+ pIter->Value >>= aSelection;
+ }
+
+ m_aSelectContainerEvent.CancelCall(); // just in case the async select request was running
+ getContainer()->selectContainer(eType);
+ getContainer()->selectElements(aSelection);
+ return true;
+ }
+ // END compatibility
+
+ Sequence< NamedDatabaseObject > aSelectedObjects;
+ if ( !( _aSelection >>= aSelectedObjects ) )
+ {
+ aSelectedObjects.realloc( 1 );
+ if ( !( _aSelection >>= aSelectedObjects[0] ) )
+ throw IllegalArgumentException();
+ }
+
+ SelectionByElementType aSelectedElements;
+ ElementType eSelectedCategory = E_NONE;
+ for ( const NamedDatabaseObject* pObject = aSelectedObjects.getConstArray();
+ pObject != aSelectedObjects.getConstArray() + aSelectedObjects.getLength();
+ ++pObject
+ )
+ {
+ switch ( pObject->Type )
+ {
+ case DatabaseObject::TABLE:
+ case DatabaseObjectContainer::SCHEMA:
+ case DatabaseObjectContainer::CATALOG:
+ aSelectedElements[ E_TABLE ].push_back( pObject->Name );
+ break;
+ case DatabaseObject::QUERY:
+ aSelectedElements[ E_QUERY ].push_back( pObject->Name );
+ break;
+ case DatabaseObject::FORM:
+ case DatabaseObjectContainer::FORMS_FOLDER:
+ aSelectedElements[ E_FORM ].push_back( pObject->Name );
+ break;
+ case DatabaseObject::REPORT:
+ case DatabaseObjectContainer::REPORTS_FOLDER:
+ aSelectedElements[ E_REPORT ].push_back( pObject->Name );
+ break;
+ case DatabaseObjectContainer::TABLES:
+ case DatabaseObjectContainer::QUERIES:
+ case DatabaseObjectContainer::FORMS:
+ case DatabaseObjectContainer::REPORTS:
+ if ( eSelectedCategory != E_NONE )
+ throw IllegalArgumentException(
+ DBA_RES(RID_STR_NO_DIFF_CAT),
+ *this, sal_Int16( pObject - aSelectedObjects.getConstArray() ) );
+ eSelectedCategory =
+ ( pObject->Type == DatabaseObjectContainer::TABLES ) ? E_TABLE
+ : ( pObject->Type == DatabaseObjectContainer::QUERIES ) ? E_QUERY
+ : ( pObject->Type == DatabaseObjectContainer::FORMS ) ? E_FORM
+ : ( pObject->Type == DatabaseObjectContainer::REPORTS ) ? E_REPORT
+ : E_NONE;
+ break;
+
+ default:
+ case DatabaseObjectContainer::DATA_SOURCE:
+ {
+ OUString sMessage(
+ DBA_RES(RID_STR_UNSUPPORTED_OBJECT_TYPE).
+ replaceFirst("$type$", OUString::number(pObject->Type)));
+ throw IllegalArgumentException(sMessage, *this, sal_Int16( pObject - aSelectedObjects.getConstArray() ));
+ }
+ }
+ }
+ for (auto const& selectedElement : aSelectedElements)
+ {
+ if ( selectedElement.first == m_eCurrentType )
+ {
+ getContainer()->selectElements( comphelper::containerToSequence(selectedElement.second) );
+ }
+ else
+ {
+ m_aPendingSelection[ selectedElement.first ] = selectedElement.second;
+ }
+ }
+
+ m_aSelectContainerEvent.CancelCall(); // just in case the async select request was running
+ getContainer()->selectContainer( eSelectedCategory );
+
+ return true;
+}
+
+Any SAL_CALL OApplicationController::getSelection( )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ Sequence< NamedDatabaseObject > aCurrentSelection;
+ const ElementType eType( getContainer()->getElementType() );
+ if ( eType != E_NONE )
+ {
+ getContainer()->describeCurrentSelectionForType( eType, aCurrentSelection );
+ if ( !aCurrentSelection.hasElements() )
+ { // if no objects are selected, add an entry to the sequence which describes the overall category
+ // which is selected currently
+ aCurrentSelection.realloc(1);
+ aCurrentSelection[0].Name = getDatabaseName();
+ switch ( eType )
+ {
+ case E_TABLE: aCurrentSelection[0].Type = DatabaseObjectContainer::TABLES; break;
+ case E_QUERY: aCurrentSelection[0].Type = DatabaseObjectContainer::QUERIES; break;
+ case E_FORM: aCurrentSelection[0].Type = DatabaseObjectContainer::FORMS; break;
+ case E_REPORT: aCurrentSelection[0].Type = DatabaseObjectContainer::REPORTS; break;
+ default:
+ OSL_FAIL( "OApplicationController::getSelection: unexpected current element type!" );
+ break;
+ }
+ }
+ }
+ return makeAny( aCurrentSelection );
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppController.hxx b/dbaccess/source/ui/app/AppController.hxx
new file mode 100644
index 000000000..2edda8efd
--- /dev/null
+++ b/dbaccess/source/ui/app/AppController.hxx
@@ -0,0 +1,526 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPCONTROLLER_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPCONTROLLER_HXX
+
+#include <AppElementType.hxx>
+#include <callbacks.hxx>
+#include <commontypes.hxx>
+#include <dsntypes.hxx>
+#include <dbaccess/genericcontroller.hxx>
+#include <linkeddocuments.hxx>
+#include <TableCopyHelper.hxx>
+
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/ui/XContextMenuInterception.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase5.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <vcl/transfer.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+
+#include <memory>
+
+class SvTreeListEntry;
+class SvTreeListBox;
+class TransferableHelper;
+class TransferableClipboardListener;
+
+namespace com::sun::star {
+ namespace container {
+ class XNameContainer;
+ class XContainer;
+ }
+ namespace ucb {
+ class XContent;
+ }
+}
+
+namespace dbaui
+{
+ class SubComponentManager;
+ class OApplicationController;
+ class OApplicationView;
+ class OLinkedDocumentsAccess;
+ class SelectionNotifier;
+
+ typedef ::cppu::ImplHelper5 < css::container::XContainerListener
+ , css::beans::XPropertyChangeListener
+ , css::sdb::application::XDatabaseDocumentUI
+ , css::ui::XContextMenuInterception
+ , css::view::XSelectionSupplier
+ > OApplicationController_Base;
+
+
+ class OApplicationController
+ :public OGenericUnoController
+ ,public OApplicationController_Base
+ ,public IControlActionListener
+ ,public IContextMenuProvider
+ {
+ public:
+ typedef std::vector< css::uno::Reference< css::container::XContainer > > TContainerVector;
+
+ private:
+
+ OTableCopyHelper::DropDescriptor m_aAsyncDrop;
+
+ SharedConnection m_xDataSourceConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData >
+ m_xMetaData;
+
+ TransferableDataHelper m_aSystemClipboard; // content of the clipboard
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xDataSource;
+ css::uno::Reference< css::frame::XModel >
+ m_xModel;
+ ::comphelper::OInterfaceContainerHelper2
+ m_aContextMenuInterceptors;
+
+ TContainerVector m_aCurrentContainers; // the containers where we are listener on
+ ::rtl::Reference< SubComponentManager >
+ m_pSubComponentManager;
+ ::dbaccess::ODsnTypeCollection
+ m_aTypeCollection;
+ OTableCopyHelper m_aTableCopyHelper;
+ rtl::Reference<TransferableClipboardListener>
+ m_pClipboardNotifier; // notifier for changes in the clipboard
+ ImplSVEvent * m_nAsyncDrop;
+ OAsynchronousLink m_aSelectContainerEvent;
+ PreviewMode m_ePreviewMode; // the mode of the preview
+ ElementType m_eCurrentType;
+ bool m_bNeedToReconnect; // true when the settings of the data source were modified and the connection is no longer up to date
+ bool m_bSuspended; // is true when the controller was already suspended
+
+ std::unique_ptr< SelectionNotifier >
+ m_pSelectionNotifier;
+ typedef std::map< ElementType, std::vector< OUString > > SelectionByElementType;
+ SelectionByElementType m_aPendingSelection;
+
+ private:
+
+ OApplicationView* getContainer() const;
+
+ /** returns the database name
+ @return
+ the database name
+ */
+ OUString getDatabaseName() const;
+
+ /** returns the stripped database name.
+ @return
+ The stripped database name either the registered name or if it is a file url the last segment.
+ */
+ OUString getStrippedDatabaseName() const;
+
+ /** return the element type for given container
+ @param _xContainer The container where the element type has to be found
+ @return the element type corresponding to the given container
+ */
+ static ElementType getElementType(const css::uno::Reference< css::container::XContainer >& _xContainer);
+
+ /** opens a new sub frame with a table/query/form/report/view, passing additional arguments
+ */
+ css::uno::Reference< css::lang::XComponent > openElementWithArguments(
+ const OUString& _sName,
+ ElementType _eType,
+ ElementOpenMode _eOpenMode,
+ sal_uInt16 _nInstigatorCommand,
+ const ::comphelper::NamedValueCollection& _rAdditionalArguments
+ );
+
+ /** opens a new frame for creation or auto pilot
+ @param _eType
+ Defines the type to open
+ @param i_rAdditionalArguments
+ Additional arguments to pass when creating the component
+ */
+ css::uno::Reference< css::lang::XComponent >
+ newElement(
+ ElementType _eType,
+ const ::comphelper::NamedValueCollection& i_rAdditionalArguments,
+ css::uno::Reference< css::lang::XComponent >& o_rDocumentDefinition
+ );
+
+ /** creates a new database object, using an auto pilot
+ @param _eType
+ Defines the type of the object to create
+ @precond
+ Our mutex must not be locked.
+ @since #i39203#
+ */
+ void newElementWithPilot( ElementType _eType );
+
+ /** converts the query to a view
+ @param _sName
+ The name of the query.
+ */
+ void convertToView(const OUString& _sName);
+
+ /** checks if the connection for the selected data source is read only. If the connection doesn't exist, <TRUE/> will be returned.
+ @return
+ <TRUE/> if read only or doesn't exist, otherwise <FALSE/>
+ */
+ bool isConnectionReadOnly() const;
+
+ /// fills the list with the selected entries.
+ void getSelectionElementNames( std::vector< OUString>& _rNames ) const;
+
+ /// deletes the entries selected.
+ void deleteEntries();
+
+ /// renames the selected entry in the detail page
+ void renameEntry();
+
+ /** deletes queries, forms, or reports
+ @param _eType
+ the type of the objects
+ @param _rList
+ The names of the elements to delete
+ @param _bConfirm
+ determines whether the user must confirm the deletion
+ */
+ void deleteObjects( ElementType _eType,
+ const std::vector< OUString>& _rList,
+ bool _bConfirm );
+
+ /** deletes tables.
+ @param _rList
+ The list of tables.
+ */
+ void deleteTables(const std::vector< OUString>& _rList);
+
+ /// copies the current object into clipboard
+ TransferableHelper* copyObject();
+
+ /// returns the nameaccess
+ css::uno::Reference< css::container::XNameAccess > getElements(ElementType _eType);
+
+ /** returns the document access for the specific type
+ @param _eType
+ the type
+ @return std::unique_ptr<OLinkedDocumentsAccess>
+ */
+ std::unique_ptr<OLinkedDocumentsAccess> getDocumentsAccess(ElementType _eType);
+
+ /// returns the query definitions of the active data source.
+ css::uno::Reference< css::container::XNameContainer> getQueryDefinitions() const;
+
+ /** pastes a special format from the system clipboard to the currently selected object types
+ @param _nFormatId
+ The format to be copied.
+ */
+ void pasteFormat(SotClipboardFormatId _nFormatId);
+
+ /** pastes a query, form or report into the data source
+ @param _eType
+ The type of the object to paste.
+ @param _rPasteData
+ The data descriptor.
+ @param _sParentFolder
+ The name of the parent folder if it exists.
+ @param _bMove
+ if <TRUE/> the name of the content must be inserted without any change, otherwise not.
+ @return
+ <TRUE/> if the paste operations was successful, otherwise <FALSE/>.
+ */
+ bool paste( ElementType _eType, const svx::ODataAccessDescriptor& _rPasteData, const OUString& _sParentFolder = OUString(), bool _bMove = false);
+
+ /// returns the system clipboard.
+ const TransferableDataHelper& getViewClipboard() const { return m_aSystemClipboard; }
+
+ /// returns <TRUE/> if the clipboard supports a table format, otherwise <FALSE/>.
+ bool isTableFormat() const;
+
+ /** fills the vector with all supported formats
+ @param _eType
+ The type for which we need the formats
+ @param _rFormatIds
+ The vector to be filled up.
+ */
+ static void getSupportedFormats(ElementType _eType,std::vector<SotClipboardFormatId>& _rFormatIds);
+
+ /** adds a listener to the current name access.
+ @param _xCollection
+ The collection where we want to listen on.
+ */
+ void addContainerListener(const css::uno::Reference< css::container::XNameAccess>& _xCollection);
+
+ /** opens a uno dialog with the currently selected data source as initialize argument
+ @param _sServiceName
+ The service name of the dialog to be executed.
+ */
+ void openDialog(const OUString& _sServiceName);
+
+ /** when the settings of the data source changed,
+ it opens a dialog which ask to close all depending documents, then recreate the connection.
+ The SolarMutex has to be locked before calling this.
+ */
+ void askToReconnect();
+
+ /** remember a newly opened sub document for later access
+ */
+ void onDocumentOpened(
+ const OUString& _rName,
+ const sal_Int32 _nType,
+ const ElementOpenMode _eMode,
+ const css::uno::Reference< css::lang::XComponent >& _xDocument,
+ const css::uno::Reference< css::lang::XComponent >& _xDefinition
+ );
+
+ /** Inserts a new object into the hierarchy given be the type.
+ @param _eType
+ Where to insert the new item.
+ @param _sParentFolder
+ The name of the parent folder if it exists.
+ @param _xContent
+ The content to insert.
+ @param _bMove
+ if <TRUE/> the name of the content must be inserted without any change, otherwise not.
+ @return
+ <TRUE/> if the insert operations was successful, otherwise <FALSE/>.
+ */
+ bool insertHierachyElement( ElementType _eType
+ ,const OUString& _sParentFolder
+ ,bool _bCollection = true
+ ,const css::uno::Reference< css::ucb::XContent>& _xContent = css::uno::Reference< css::ucb::XContent>()
+ ,bool _bMove = false);
+ /** checks if delete command or rename command is allowed
+ @param _eType
+ The element type.
+ @param _bDelete
+ If <TRUE> then the delete command should be checked.
+ @return
+ <TRUE> if the command is allowed
+ */
+ bool isRenameDeleteAllowed(ElementType _eType, bool _bDelete) const;
+ /** all selected entries will be opened, or edited, or converted to a view
+ @param _nId
+ The slot which should be executed.
+ @param _eOpenMode
+ Defines the mode of opening. @see ElementOpenMode
+ */
+ void doAction(sal_uInt16 _nId, ElementOpenMode _eOpenMode);
+
+ /** returns the currently selected table or query name.
+ *
+ * \return the name of the currently table or query. If the tables or query container is selected otherwise an empty string will be returned.
+ */
+ OUString getCurrentlySelectedName(sal_Int32& _rnCommandType) const;
+
+ /** shows the preview for the given entry
+ */
+ void showPreviewFor( const ElementType _eType,const OUString& _sName );
+
+ /** called we were attached to a frame
+
+ In particular, this is called *after* the controller has been announced to the model
+ (XModel::connectController)
+ */
+ void onAttachedFrame();
+
+ /// determines whether the given table name denotes a view which can be altered
+ bool impl_isAlterableView_nothrow( const OUString& _rTableOrViewName ) const;
+
+ /** verifies the object type denotes a valid DatabaseObject, and the object name denotes an existing
+ object of this type. Throws if not.
+ */
+ void impl_validateObjectTypeAndName_throw( const sal_Int32 _nObjectType, const ::std::optional< OUString >& i_rObjectName );
+
+ protected:
+ // initializing members
+
+ // state of a feature. 'feature' may be the handle of a css::util::URL somebody requested a dispatch interface for OR a toolbar slot.
+ virtual FeatureState GetState(sal_uInt16 nId) const override;
+ // execute a feature
+ virtual void Execute(sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs) override;
+
+ // OGenericUnoController
+ virtual void onLoadedMenu( const css::uno::Reference< css::frame::XLayoutManager >& _xLayoutManager ) override;
+
+ virtual css::uno::Reference< css::frame::XModel > getPrivateModel() const override
+ {
+ return m_xModel;
+ }
+
+ virtual ~OApplicationController() override;
+
+ public:
+ explicit OApplicationController(const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override;
+ // need by registration
+ /// @throws css::uno::RuntimeException
+ static OUString getImplementationName_Static();
+ /// @throws css::uno::RuntimeException
+ static css::uno::Sequence< OUString > getSupportedServiceNames_Static();
+ static css::uno::Reference< css::uno::XInterface >
+ Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&);
+
+ // css::frame::XController
+ virtual void SAL_CALL attachFrame(const css::uno::Reference< css::frame::XFrame > & xFrame) override;
+ virtual sal_Bool SAL_CALL suspend(sal_Bool bSuspend) override;
+ virtual sal_Bool SAL_CALL attachModel(const css::uno::Reference< css::frame::XModel > & xModel) override;
+ virtual css::uno::Reference< css::frame::XModel > SAL_CALL getModel() override;
+
+ // css::container::XContainerListener
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& Event) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& Event) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XDatabaseDocumentUI
+ virtual css::uno::Reference< css::sdbc::XDataSource > SAL_CALL getDataSource() override;
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL getApplicationMainWindow() override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getActiveConnection() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::lang::XComponent > > SAL_CALL getSubComponents() override;
+ virtual sal_Bool SAL_CALL isConnected( ) override;
+ // DO NOT CALL with getMutex() held!!
+ virtual void SAL_CALL connect( ) override;
+ virtual css::beans::Pair< ::sal_Int32, OUString > SAL_CALL identifySubComponent( const css::uno::Reference< css::lang::XComponent >& SubComponent ) override;
+ virtual sal_Bool SAL_CALL closeSubComponents( ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponent( ::sal_Int32 ObjectType, const OUString& ObjectName, sal_Bool ForEditing ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponentWithArguments( ::sal_Int32 ObjectType, const OUString& ObjectName, sal_Bool ForEditing, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL createComponent( ::sal_Int32 ObjectType, css::uno::Reference< css::lang::XComponent >& o_DocumentDefinition ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL createComponentWithArguments( ::sal_Int32 ObjectType, const css::uno::Sequence< css::beans::PropertyValue >& Arguments, css::uno::Reference< css::lang::XComponent >& o_DocumentDefinition ) override;
+
+ // XContextMenuInterception
+ virtual void SAL_CALL registerContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override;
+ virtual void SAL_CALL releaseContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor >& Interceptor ) override;
+
+ // XSelectionSupplier
+ virtual sal_Bool SAL_CALL select( const css::uno::Any& xSelection ) override;
+ virtual css::uno::Any SAL_CALL getSelection( ) override;
+ virtual void SAL_CALL addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override;
+
+ /** retrieves the current connection, creates it if necessary
+
+ If an error occurs, then this is either stored in the location pointed to by <arg>_pErrorInfo</arg>,
+ or, if <code>_pErrorInfo</code> is <NULL/>, then the error is displayed to the user.
+
+ DO NOT CALL with getMutex() held!!
+ */
+ const SharedConnection& ensureConnection( ::dbtools::SQLExceptionInfo* _pErrorInfo = nullptr );
+
+ /** retrieves the current connection
+ */
+ const SharedConnection& getConnection() const { return m_xDataSourceConnection; }
+
+ /// determines whether we're currently connected to the database
+ bool isConnected() const { return m_xDataSourceConnection.is(); }
+
+ /** refreshes the tables
+ */
+ void refreshTables();
+
+ /** called when an entry in a tree list box has been double-clicked
+ @param _rTree
+ The tree list box.
+ @return
+ <TRUE/> if the double click event has been handled by the called, and should not
+ be processed further.
+ */
+ bool onEntryDoubleClick(SvTreeListBox const & _rTree);
+ /** called when a container (category) in the application view has been selected
+ @param _pTree
+ The tree list box.
+ @return
+ <TRUE/> if the container could be changed otherwise <FALSE/>
+ */
+ bool onContainerSelect(ElementType _eType);
+ /** called when an entry in a tree view has been selected
+ @param _pEntry
+ the selected entry
+ */
+ void onSelectionChanged();
+ /** called when a "Copy" command is executed in a tree view
+ */
+ void onCopyEntry();
+ /** called when a "Paste" command is executed in a tree view
+ */
+ void onPasteEntry();
+ /** called when a "Delete" command is executed in a tree view
+ */
+ void onDeleteEntry();
+ /// called when the preview mode was changed
+ void previewChanged( sal_Int32 _nMode);
+ /// called when an object container of any kind was found during enumerating tree view elements
+ void containerFound( const css::uno::Reference< css::container::XContainer >& _xContainer);
+
+ // IController
+ virtual bool isDataSourceReadOnly() const override;
+
+ // IControlActionListener overridables
+ virtual bool requestQuickHelp( const SvTreeListEntry* _pEntry, OUString& _rText ) const override;
+ virtual bool requestDrag( const Point& _rPosPixel ) override;
+ virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override;
+ virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override;
+
+ // IContextMenuProvider
+ virtual OUString getContextMenuResourceName( Control& _rControl ) const override;
+ virtual IController& getCommandController() override;
+ virtual ::comphelper::OInterfaceContainerHelper2*
+ getContextMenuInterceptors() override;
+ virtual css::uno::Any
+ getCurrentSelection( Control& _rControl ) const override;
+
+ void OnInvalidateClipboard();
+ DECL_LINK( OnClipboardChanged, TransferableDataHelper*, void );
+ DECL_LINK( OnAsyncDrop, void*, void );
+ DECL_LINK( OnCreateWithPilot, void*, void );
+ DECL_LINK( OnSelectContainer, void*, void );
+ void OnFirstControllerConnected();
+
+ protected:
+ using OGenericUnoController::connect;
+
+ /** disconnects from our XConnection, and cleans up this connection
+ */
+ void disconnect();
+
+ // late construction
+ virtual bool Construct(vcl::Window* pParent) override;
+ virtual void describeSupportedFeatures() override;
+
+ protected:
+ // XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+
+} // namespace dbaui
+
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPCONTROLLER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppControllerDnD.cxx b/dbaccess/source/ui/app/AppControllerDnD.cxx
new file mode 100644
index 000000000..98d622584
--- /dev/null
+++ b/dbaccess/source/ui/app/AppControllerDnD.cxx
@@ -0,0 +1,808 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "AppController.hxx"
+#include <comphelper/property.hxx>
+#include <core_resource.hxx>
+#include <strings.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <dlgsave.hxx>
+#include <vcl/weld.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <connectivity/dbexception.hxx>
+#include <sal/log.hxx>
+#include "AppView.hxx"
+#include <svx/dataaccessdescriptor.hxx>
+#include <svx/dbaobjectex.hxx>
+#include <strings.hrc>
+#include <vcl/svapp.hxx>
+#include <linkeddocuments.hxx>
+#include <connectivity/dbtools.hxx>
+#include <dbexchange.hxx>
+#include <UITools.hxx>
+#include <algorithm>
+#include <iterator>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <svtools/querydelete.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <defaultobjectnamecheck.hxx>
+#include <osl/mutex.hxx>
+#include "subcomponentmanager.hxx"
+#include <set>
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::svx;
+using namespace ::svtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::util;
+
+void OApplicationController::deleteTables(const std::vector< OUString>& _rList)
+{
+ SharedConnection xConnection( ensureConnection() );
+
+ Reference<XTablesSupplier> xSup(xConnection,UNO_QUERY);
+ OSL_ENSURE(xSup.is(),"OApplicationController::deleteTable: no XTablesSupplier!");
+ if ( !xSup.is() )
+ return;
+
+ Reference<XNameAccess> xTables = xSup->getTables();
+ Reference<XDrop> xDrop(xTables,UNO_QUERY);
+ if ( xDrop.is() )
+ {
+ bool bConfirm = true;
+ std::vector< OUString>::const_iterator aEnd = _rList.end();
+ for (std::vector< OUString>::const_iterator aIter = _rList.begin(); aIter != aEnd; ++aIter)
+ {
+ OUString sTableName = *aIter;
+
+ sal_Int32 nResult = RET_YES;
+ if ( bConfirm )
+ nResult = ::dbaui::askForUserAction(getFrameWeld(), STR_TITLE_CONFIRM_DELETION, STR_QUERY_DELETE_TABLE, _rList.size() > 1 && (aIter+1) != _rList.end(), sTableName);
+
+ bool bUserConfirmedDelete =
+ ( RET_YES == nResult )
+ || ( RET_ALL == nResult );
+ if ( bUserConfirmedDelete && m_pSubComponentManager->closeSubFrames( sTableName, E_TABLE ) )
+ {
+ SQLExceptionInfo aErrorInfo;
+ try
+ {
+ if ( xTables->hasByName(sTableName) )
+ xDrop->dropByName(sTableName);
+ else
+ {// could be a view
+ Reference<XViewsSupplier> xViewsSup(xConnection,UNO_QUERY);
+
+ Reference<XNameAccess> xViews;
+ if ( xViewsSup.is() )
+ {
+ xViews = xViewsSup->getViews();
+ if ( xViews.is() && xViews->hasByName(sTableName) )
+ {
+ xDrop.set(xViews,UNO_QUERY);
+ if ( xDrop.is() )
+ xDrop->dropByName(sTableName);
+ }
+ }
+ }
+ }
+ catch(SQLContext& e) { aErrorInfo = e; }
+ catch(SQLWarning& e) { aErrorInfo = e; }
+ catch(SQLException& e) { aErrorInfo = e; }
+ catch(WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if(e.TargetException >>= aSql)
+ aErrorInfo = aSql;
+ else
+ OSL_FAIL("OApplicationController::implDropTable: something strange happened!");
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( aErrorInfo.isValid() )
+ showError(aErrorInfo);
+
+ if ( RET_ALL == nResult )
+ bConfirm = false;
+ }
+ else
+ break;
+ }
+ }
+ else
+ {
+ OUString sMessage(DBA_RES(STR_MISSING_TABLES_XDROP));
+ std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sMessage));
+ xError->run();
+ }
+}
+
+void OApplicationController::deleteObjects( ElementType _eType, const std::vector< OUString>& _rList, bool _bConfirm )
+{
+ Reference< XNameContainer > xNames( getElements( _eType ), UNO_QUERY );
+ Reference< XHierarchicalNameContainer > xHierarchyName( xNames, UNO_QUERY );
+ if ( !xNames.is() )
+ return;
+
+ short eResult = _bConfirm ? svtools::QUERYDELETE_YES : svtools::QUERYDELETE_ALL;
+
+ // The list of elements to delete is allowed to contain related elements: A given element may
+ // be the ancestor or child of another element from the list.
+ // We want to ensure that ancestors get deleted first, so we normalize the list in this respect.
+ // #i33353#
+ std::set< OUString > aDeleteNames;
+ // Note that this implicitly uses std::less< OUString > a comparison operation, which
+ // results in lexicographical order, which is exactly what we need, because "foo" is *before*
+ // any "foo/bar" in this order.
+ std::copy(
+ _rList.begin(), _rList.end(),
+ std::insert_iterator< std::set< OUString > >( aDeleteNames, aDeleteNames.begin() )
+ );
+
+ std::set< OUString >::size_type nCount = aDeleteNames.size();
+ for ( std::set< OUString >::size_type nObjectsLeft = nCount; !aDeleteNames.empty(); )
+ {
+ std::set< OUString >::const_iterator aThisRound = aDeleteNames.begin();
+
+ if ( eResult != svtools::QUERYDELETE_ALL )
+ {
+ svtools::QueryDeleteDlg_Impl aDlg(getFrameWeld(), *aThisRound);
+
+ if ( nObjectsLeft > 1 )
+ aDlg.EnableAllButton();
+
+ eResult = aDlg.run();
+ }
+
+ bool bSuccess = false;
+
+ bool bUserConfirmedDelete =
+ ( eResult == svtools::QUERYDELETE_ALL )
+ || ( eResult == svtools::QUERYDELETE_YES );
+
+ if ( bUserConfirmedDelete
+ && ( _eType != E_QUERY || m_pSubComponentManager->closeSubFrames( *aThisRound, _eType ) )
+ )
+ {
+ try
+ {
+ if ( xHierarchyName.is() )
+ xHierarchyName->removeByHierarchicalName( *aThisRound );
+ else
+ xNames->removeByName( *aThisRound );
+
+ bSuccess = true;
+
+ // now that we removed the element, care for all its child elements
+ // which may also be a part of the list
+ // #i33353#
+ OSL_ENSURE( aThisRound->getLength() - 1 >= 0, "OApplicationController::deleteObjects: empty name?" );
+ OUString sSmallestSiblingName = *aThisRound + OUStringChar( sal_Unicode( '/' + 1) );
+
+ std::set< OUString >::const_iterator aUpperChildrenBound = aDeleteNames.lower_bound( sSmallestSiblingName );
+ for ( std::set< OUString >::const_iterator aObsolete = aThisRound;
+ aObsolete != aUpperChildrenBound;
+ )
+ {
+ std::set< OUString >::const_iterator aNextObsolete = aObsolete; ++aNextObsolete;
+ aDeleteNames.erase( aObsolete );
+ --nObjectsLeft;
+ aObsolete = aNextObsolete;
+ }
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch(const WrappedTargetException& e)
+ {
+ SQLException aSql;
+ if ( e.TargetException >>= aSql )
+ showError( SQLExceptionInfo( e.TargetException ) );
+ else
+ OSL_FAIL( "OApplicationController::deleteObjects: something strange happened!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ // okay, this object could not be deleted (or the user did not want to delete it),
+ // but continue with the rest
+ aDeleteNames.erase( aThisRound );
+ --nObjectsLeft;
+ }
+ }
+}
+
+void OApplicationController::deleteEntries()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( !getContainer() )
+ return;
+
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ ElementType eType = getContainer()->getElementType();
+ switch(eType)
+ {
+ case E_TABLE:
+ deleteTables(aList);
+ break;
+ case E_QUERY:
+ deleteObjects( E_QUERY, aList, true );
+ break;
+ case E_FORM:
+ deleteObjects( E_FORM, aList, true );
+ break;
+ case E_REPORT:
+ deleteObjects( E_REPORT, aList, true );
+ break;
+ case E_NONE:
+ break;
+ }
+}
+
+// DO NOT CALL with getMutex() held!!
+const SharedConnection& OApplicationController::ensureConnection( ::dbtools::SQLExceptionInfo* _pErrorInfo )
+{
+
+ // This looks like double checked locking, but it is not,
+ // because every access (read *or* write) to m_xDataSourceConnection
+ // is mutexed.
+ // See http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
+ // for what I'm referring to.
+ // We cannot use the TLS (thread-local storage) solution
+ // since support for TLS is not up to the snuff on Windows :-(
+
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( m_xDataSourceConnection.is() )
+ return m_xDataSourceConnection;
+ }
+
+ weld::WaitObject aWO(getFrameWeld());
+ Reference<XConnection> conn;
+ {
+ SolarMutexGuard aSolarGuard;
+
+ OUString sConnectingContext(DBA_RES(STR_COULDNOTCONNECT_DATASOURCE));
+ sConnectingContext = sConnectingContext.replaceFirst("$name$", getStrippedDatabaseName());
+
+ // do the connection *without* holding getMutex() to avoid deadlock
+ // when we are not in the main thread and we need username/password
+ // (and thus to display a dialog, which will be done by the main thread)
+ // and there is an event that needs getMutex() *before* us in the main thread's queue
+ // See fdo#63391
+ conn.set( connect( getDatabaseName(), sConnectingContext, _pErrorInfo ) );
+ }
+
+ if (conn.is())
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( m_xDataSourceConnection.is() )
+ {
+ Reference< XComponent > comp (conn, UNO_QUERY);
+ if(comp.is())
+ {
+ try
+ {
+ comp->dispose();
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "dbaui::OApplicationController::ensureConnection could not dispose of temporary unused connection" );
+ }
+ }
+ conn.clear();
+ }
+ else
+ {
+ m_xDataSourceConnection.reset(conn);
+ SQLExceptionInfo aError;
+ try
+ {
+ m_xMetaData = m_xDataSourceConnection->getMetaData();
+ }
+ catch( const SQLException& )
+ {
+ aError = ::cppu::getCaughtException();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ if ( aError.isValid() )
+ {
+ if ( _pErrorInfo )
+ {
+ *_pErrorInfo = aError;
+ }
+ else
+ {
+ SolarMutexGuard aSolarGuard;
+ showError( aError );
+ }
+ }
+ }
+ }
+
+ return m_xDataSourceConnection;
+}
+
+bool OApplicationController::isDataSourceReadOnly() const
+{
+ Reference<XStorable> xStore(m_xModel,UNO_QUERY);
+ return !xStore.is() || xStore->isReadonly();
+}
+
+bool OApplicationController::isConnectionReadOnly() const
+{
+ bool bIsConnectionReadOnly = true;
+ if ( m_xMetaData.is() )
+ {
+ try
+ {
+ bIsConnectionReadOnly = m_xMetaData->isReadOnly();
+ }
+ catch(const SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ // TODO check configuration
+ return bIsConnectionReadOnly;
+}
+
+Reference< XNameAccess > OApplicationController::getElements( ElementType _eType )
+{
+ Reference< XNameAccess > xElements;
+ try
+ {
+ switch ( _eType )
+ {
+ case E_REPORT:
+ {
+ Reference< XReportDocumentsSupplier > xSupp( m_xModel, UNO_QUERY_THROW );
+ xElements.set( xSupp->getReportDocuments(), UNO_SET_THROW );
+ }
+ break;
+
+ case E_FORM:
+ {
+ Reference< XFormDocumentsSupplier > xSupp( m_xModel, UNO_QUERY_THROW );
+ xElements.set( xSupp->getFormDocuments(), UNO_SET_THROW );
+ }
+ break;
+
+ case E_QUERY:
+ {
+ xElements.set( getQueryDefinitions(), UNO_QUERY_THROW );
+ }
+ break;
+
+ case E_TABLE:
+ {
+ if ( m_xDataSourceConnection.is() )
+ {
+ Reference< XTablesSupplier > xSup( getConnection(), UNO_QUERY_THROW );
+ xElements.set( xSup->getTables(), UNO_SET_THROW );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return xElements;
+}
+
+void OApplicationController::getSelectionElementNames(std::vector< OUString>& _rNames) const
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ OSL_ENSURE(getContainer(),"View isn't valid! -> GPF");
+
+ getContainer()->getSelectionElementNames( _rNames );
+}
+
+std::unique_ptr< OLinkedDocumentsAccess > OApplicationController::getDocumentsAccess( ElementType _eType )
+{
+ OSL_ENSURE( ( _eType == E_TABLE ) || ( _eType == E_QUERY ) || ( _eType == E_FORM ) || ( _eType == E_REPORT ),
+ "OApplicationController::getDocumentsAccess: only forms and reports are supported here!" );
+
+ SharedConnection xConnection( ensureConnection() );
+ Reference< XNameAccess > xDocContainer;
+
+ if ( ( _eType == E_FORM ) || ( _eType == E_REPORT ) )
+ {
+ xDocContainer.set( getElements( _eType ) );
+ OSL_ENSURE( xDocContainer.is(), "OApplicationController::getDocumentsAccess: invalid container!" );
+ }
+
+ std::unique_ptr< OLinkedDocumentsAccess > pDocuments( new OLinkedDocumentsAccess(
+ getFrameWeld(), this, getORB(), xDocContainer, xConnection, getDatabaseName()
+ ) );
+ return pDocuments;
+}
+
+TransferableHelper* OApplicationController::copyObject()
+{
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ ElementType eType = getContainer()->getElementType();
+ TransferableHelper* pData = nullptr;
+ switch( eType )
+ {
+ case E_TABLE:
+ case E_QUERY:
+ {
+ SharedConnection xConnection( ensureConnection() );
+ Reference< XDatabaseMetaData> xMetaData;
+ if ( xConnection.is() )
+ xMetaData = xConnection->getMetaData();
+
+ OUString sName = getContainer()->getQualifiedName( nullptr );
+ if ( !sName.isEmpty() )
+ {
+ OUString sDataSource = getDatabaseName();
+
+ if ( eType == E_TABLE )
+ {
+ pData = new ODataClipboard(sDataSource, CommandType::TABLE, sName, xConnection, getNumberFormatter(xConnection, getORB()), getORB());
+ }
+ else
+ {
+ pData = new ODataClipboard(sDataSource, CommandType::QUERY, sName, getNumberFormatter(xConnection, getORB()), getORB());
+ }
+ }
+ }
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ Reference< XHierarchicalNameAccess > xElements(getElements(eType),UNO_QUERY);
+ if ( xElements.is() && !aList.empty() )
+ {
+ Reference< XContent> xContent(xElements->getByHierarchicalName(*aList.begin()),UNO_QUERY);
+ pData = new OComponentTransferable( getDatabaseName(), xContent );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // the ownership goes to ODataClipboards
+ return pData;
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return nullptr;
+}
+
+bool OApplicationController::paste( ElementType _eType, const svx::ODataAccessDescriptor& _rPasteData, const OUString& _sParentFolder, bool _bMove)
+{
+ try
+ {
+ if ( _eType == E_QUERY )
+ {
+ sal_Int32 nCommandType = CommandType::TABLE;
+ if ( _rPasteData.has(DataAccessDescriptorProperty::CommandType) )
+ _rPasteData[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
+
+ if ( CommandType::QUERY == nCommandType || CommandType::COMMAND == nCommandType )
+ {
+ // read all necessary data
+
+ OUString sCommand;
+ bool bEscapeProcessing = true;
+
+ _rPasteData[DataAccessDescriptorProperty::Command] >>= sCommand;
+ if ( _rPasteData.has(DataAccessDescriptorProperty::EscapeProcessing) )
+ _rPasteData[DataAccessDescriptorProperty::EscapeProcessing] >>= bEscapeProcessing;
+
+ // plausibility check
+ bool bValidDescriptor = false;
+ OUString sDataSourceName = _rPasteData.getDataSource();
+ if (CommandType::QUERY == nCommandType)
+ bValidDescriptor = sDataSourceName.getLength() && sCommand.getLength();
+ else if (CommandType::COMMAND == nCommandType)
+ bValidDescriptor = !sCommand.isEmpty();
+ if (!bValidDescriptor)
+ {
+ OSL_FAIL("OApplicationController::paste: invalid descriptor!");
+ return false;
+ }
+
+ // the target object name (as we'll suggest it to the user)
+ OUString sTargetName;
+ try
+ {
+ if ( CommandType::QUERY == nCommandType )
+ sTargetName = sCommand;
+
+ if ( sTargetName.isEmpty() )
+ {
+ OUString sDefaultName = DBA_RES(STR_QRY_TITLE);
+ sDefaultName = sDefaultName.getToken( 0, ' ' );
+
+ Reference< XNameAccess > xQueries( getQueryDefinitions(), UNO_QUERY_THROW );
+ sTargetName = ::dbtools::createUniqueName( xQueries, sDefaultName, false );
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ Reference< XPropertySet > xQuery;
+ if (CommandType::QUERY == nCommandType)
+ {
+ // need to extract the statement and the escape processing flag from the query object
+ bool bSuccess = false;
+ try
+ {
+ // the concrete query
+ Reference< XQueryDefinitionsSupplier > xSourceQuerySup(
+ getDataSourceByName( sDataSourceName, getFrameWeld(), getORB(), nullptr ),
+ UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSourceQuerySup->getQueryDefinitions(), UNO_SET_THROW );
+ if ( xQueries->hasByName( sCommand ) )
+ {
+ xQuery.set( xQueries->getByName(sCommand), UNO_QUERY_THROW );
+ bSuccess = true;
+ }
+ }
+ catch(SQLException&) { throw; } // caught and handled by the outer catch
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if (!bSuccess)
+ {
+ OSL_FAIL("OApplicationController::paste: could not extract the source query object!");
+ // TODO: maybe this is worth an error message to be displayed to the user...
+ return false;
+ }
+ }
+
+ Reference< XNameContainer > xDestQueries = getQueryDefinitions();
+ Reference< XSingleServiceFactory > xQueryFactory(xDestQueries, UNO_QUERY);
+ if (!xQueryFactory.is())
+ {
+ OSL_FAIL("OApplicationController::paste: invalid destination query container!");
+ return false;
+ }
+
+ // here we have everything needed to create a new query object...
+ // ... ehm, except a new name
+ ensureConnection();
+
+ DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::QUERY );
+ ::dbtools::SQLExceptionInfo aDummy;
+ bool bNeedAskForName = ( sCommand.isEmpty() )
+ /* we did not have a source name, so the target name was auto-generated */
+ || ( !aNameChecker.isNameValid( sTargetName, aDummy ) );
+ /* name is invalid in the target DB (e.g. because it already
+ has a /table/ with that name) */
+ if ( bNeedAskForName )
+ {
+ OSaveAsDlg aAskForName(getFrameWeld(),
+ CommandType::QUERY,
+ getORB(),
+ getConnection(),
+ sTargetName,
+ aNameChecker,
+ SADFlags::AdditionalDescription | SADFlags::TitlePasteAs );
+ if ( RET_OK != aAskForName.run() )
+ // cancelled by the user
+ return false;
+ sTargetName = aAskForName.getName();
+ }
+
+ // create a new object
+ Reference< XPropertySet > xNewQuery(xQueryFactory->createInstance(), UNO_QUERY);
+ OSL_ENSURE(xNewQuery.is(), "OApplicationController::paste: invalid object created by factory!");
+ if (xNewQuery.is())
+ {
+ // initialize
+ if ( xQuery.is() )
+ ::comphelper::copyProperties(xQuery,xNewQuery);
+ else
+ {
+ xNewQuery->setPropertyValue(PROPERTY_COMMAND,makeAny(sCommand));
+ xNewQuery->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,makeAny(bEscapeProcessing));
+ }
+ // insert
+ xDestQueries->insertByName( sTargetName, makeAny(xNewQuery) );
+ xNewQuery.set(xDestQueries->getByName( sTargetName),UNO_QUERY);
+ if ( xQuery.is() && xNewQuery.is() )
+ {
+ Reference<XColumnsSupplier> xSrcColSup(xQuery,UNO_QUERY);
+ Reference<XColumnsSupplier> xDstColSup(xNewQuery,UNO_QUERY);
+ if ( xSrcColSup.is() && xDstColSup.is() )
+ {
+ Reference<XNameAccess> xSrcNameAccess = xSrcColSup->getColumns();
+ Reference<XNameAccess> xDstNameAccess = xDstColSup->getColumns();
+ Reference<XDataDescriptorFactory> xFac(xDstNameAccess,UNO_QUERY);
+ Reference<XAppend> xAppend(xFac,UNO_QUERY);
+ if ( xSrcNameAccess.is() && xDstNameAccess.is() && xSrcNameAccess->hasElements() && xAppend.is() )
+ {
+ Reference<XPropertySet> xDstProp(xFac->createDataDescriptor());
+
+ Sequence< OUString> aSeq = xSrcNameAccess->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for( ; pIter != pEnd ; ++pIter)
+ {
+ Reference<XPropertySet> xSrcProp(xSrcNameAccess->getByName(*pIter),UNO_QUERY);
+ ::comphelper::copyProperties(xSrcProp,xDstProp);
+ xAppend->appendByDescriptor(xDstProp);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ SAL_WARN("dbaccess", "There should be a sequence in it!");
+ return true;
+ }
+ else if ( _rPasteData.has(DataAccessDescriptorProperty::Component) ) // forms or reports
+ {
+ Reference<XContent> xContent;
+ _rPasteData[DataAccessDescriptorProperty::Component] >>= xContent;
+ return insertHierachyElement(_eType,_sParentFolder,Reference<XNameAccess>(xContent,UNO_QUERY).is(),xContent,_bMove);
+ }
+ }
+ catch(const SQLException&) { showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return false;
+}
+
+Reference<XNameContainer> OApplicationController::getQueryDefinitions() const
+{
+ Reference<XQueryDefinitionsSupplier> xSet(m_xDataSource,UNO_QUERY);
+ Reference<XNameContainer> xNames;
+ if ( xSet.is() )
+ {
+ xNames.set(xSet->getQueryDefinitions(),UNO_QUERY);
+ }
+ return xNames;
+}
+
+void OApplicationController::getSupportedFormats(ElementType _eType,std::vector<SotClipboardFormatId>& _rFormatIds)
+{
+ switch( _eType )
+ {
+ case E_TABLE:
+ _rFormatIds.push_back(SotClipboardFormatId::DBACCESS_TABLE);
+ _rFormatIds.push_back(SotClipboardFormatId::RTF);
+ _rFormatIds.push_back(SotClipboardFormatId::HTML);
+ [[fallthrough]];
+ case E_QUERY:
+ _rFormatIds.push_back(SotClipboardFormatId::DBACCESS_QUERY);
+ break;
+ default:
+ break;
+ }
+}
+
+bool OApplicationController::isTableFormat() const
+{
+ return OTableCopyHelper::isTableFormat(getViewClipboard());
+}
+
+IMPL_LINK_NOARG( OApplicationController, OnAsyncDrop, void*, void )
+{
+ m_nAsyncDrop = nullptr;
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( m_aAsyncDrop.nType == E_TABLE )
+ {
+ SharedConnection xConnection( ensureConnection() );
+ if ( xConnection.is() )
+ m_aTableCopyHelper.asyncCopyTagTable( m_aAsyncDrop, getDatabaseName(), xConnection );
+ }
+ else
+ {
+ if ( paste(m_aAsyncDrop.nType,m_aAsyncDrop.aDroppedData,m_aAsyncDrop.aUrl,m_aAsyncDrop.nAction == DND_ACTION_MOVE)
+ && m_aAsyncDrop.nAction == DND_ACTION_MOVE )
+ {
+ Reference<XContent> xContent;
+ m_aAsyncDrop.aDroppedData[DataAccessDescriptorProperty::Component] >>= xContent;
+ std::vector< OUString> aList;
+ sal_Int32 nIndex = 0;
+ OUString sName = xContent->getIdentifier()->getContentIdentifier();
+ OUString sErase = sName.getToken(0,'/',nIndex); // we don't want to have the "private:forms" part
+ if ( nIndex != -1 )
+ {
+ aList.push_back(sName.copy(sErase.getLength() + 1));
+ deleteObjects( m_aAsyncDrop.nType, aList, false );
+ }
+ }
+ }
+
+ m_aAsyncDrop.aDroppedData.clear();
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppControllerGen.cxx b/dbaccess/source/ui/app/AppControllerGen.cxx
new file mode 100644
index 000000000..2466f22df
--- /dev/null
+++ b/dbaccess/source/ui/app/AppControllerGen.cxx
@@ -0,0 +1,741 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppController.hxx"
+#include "AppDetailView.hxx"
+#include "AppView.hxx"
+#include <core_resource.hxx>
+#include <dbaccess_slotid.hrc>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <defaultobjectnamecheck.hxx>
+#include <dlgsave.hxx>
+#include <UITools.hxx>
+#include "subcomponentmanager.hxx"
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <sfx2/mailmodelapi.hxx>
+#include <svx/dbaexchange.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <vcl/weld.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/syswin.hxx>
+#include <osl/mutex.hxx>
+
+namespace dbaui
+{
+using namespace ::dbtools;
+using namespace ::connectivity;
+using namespace ::svx;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ucb;
+
+using ::com::sun::star::ui::XContextMenuInterceptor;
+
+namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject;
+namespace ErrorCondition = ::com::sun::star::sdb::ErrorCondition;
+
+void OApplicationController::convertToView(const OUString& _sName)
+{
+ try
+ {
+ SharedConnection xConnection( getConnection() );
+ Reference< XQueriesSupplier > xSup( xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSup->getQueries(), UNO_SET_THROW );
+ Reference< XPropertySet > xSourceObject( xQueries->getByName( _sName ), UNO_QUERY_THROW );
+
+ Reference< XTablesSupplier > xTablesSup( xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xTables( xTablesSup->getTables(), UNO_SET_THROW );
+
+ Reference< XDatabaseMetaData > xMeta = xConnection->getMetaData();
+
+ const OUString aDefaultName = ::dbaui::createDefaultName(xMeta, xTables, DBA_RES(STR_TBL_TITLE).getToken(0, ' '));
+
+ DynamicTableOrQueryNameCheck aNameChecker( xConnection, CommandType::TABLE );
+ OSaveAsDlg aDlg(getFrameWeld(), CommandType::TABLE, getORB(), xConnection, aDefaultName, aNameChecker, SADFlags::NONE);
+ if (aDlg.run() == RET_OK)
+ {
+ OUString sName = aDlg.getName();
+ OUString sCatalog = aDlg.getCatalog();
+ OUString sSchema = aDlg.getSchema();
+ OUString sNewName(
+ ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sName, false, ::dbtools::EComposeRule::InTableDefinitions ) );
+ Reference<XPropertySet> xView = ::dbaui::createView(sNewName,xConnection,xSourceObject);
+ if ( !xView.is() )
+ throw SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE),*this, "S1000",0,Any());
+ getContainer()->elementAdded(E_TABLE,sNewName,makeAny(xView));
+ }
+ }
+ catch(const SQLException& )
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::pasteFormat(SotClipboardFormatId _nFormatId)
+{
+ if ( _nFormatId == SotClipboardFormatId::NONE )
+ return;
+
+ try
+ {
+ const TransferableDataHelper& rClipboard = getViewClipboard();
+ ElementType eType = getContainer()->getElementType();
+ if ( eType == E_TABLE )
+ {
+ m_aTableCopyHelper.pasteTable( _nFormatId, rClipboard, getDatabaseName(), ensureConnection() );
+ }
+ else
+ paste( eType, ODataAccessObjectTransferable::extractObjectDescriptor( rClipboard ) );
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::openDialog( const OUString& _sServiceName )
+{
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ weld::WaitObject aWO(getFrameWeld());
+
+ Sequence< Any > aArgs(3);
+ sal_Int32 nArgPos = 0;
+
+ Reference< css::awt::XWindow> xWindow = getTopMostContainerWindow();
+ if ( !xWindow.is() )
+ {
+ OSL_ENSURE( getContainer(), "OApplicationController::Construct: have no view!" );
+ if ( getContainer() )
+ xWindow = VCLUnoHelper::GetInterface(getView()->Window::GetParent());
+ }
+ // the parent window
+ aArgs[nArgPos++] <<= PropertyValue( "ParentWindow",
+ 0,
+ makeAny(xWindow),
+ PropertyState_DIRECT_VALUE);
+
+ // the initial selection
+ OUString sInitialSelection;
+ if ( getContainer() )
+ sInitialSelection = getDatabaseName();
+ if ( !sInitialSelection.isEmpty() )
+ {
+ aArgs[ nArgPos++ ] <<= PropertyValue(
+ "InitialSelection", 0,
+ makeAny( sInitialSelection ), PropertyState_DIRECT_VALUE );
+ }
+
+ SharedConnection xConnection( getConnection() );
+ if ( xConnection.is() )
+ {
+ aArgs[ nArgPos++ ] <<= PropertyValue(
+ PROPERTY_ACTIVE_CONNECTION, 0,
+ makeAny( xConnection ), PropertyState_DIRECT_VALUE );
+ }
+ aArgs.realloc( nArgPos );
+
+ // create the dialog
+ Reference< XExecutableDialog > xAdminDialog;
+ xAdminDialog.set(
+ getORB()->getServiceManager()->createInstanceWithArgumentsAndContext(_sServiceName, aArgs, getORB()),
+ UNO_QUERY);
+
+ // execute it
+ if (xAdminDialog.is())
+ xAdminDialog->execute();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OApplicationController::refreshTables()
+{
+ if ( !(getContainer() && getContainer()->getDetailView()) )
+ return;
+
+ weld::WaitObject aWO(getFrameWeld());
+ OSL_ENSURE(getContainer()->getElementType() == E_TABLE,"Only allowed when the tables container is selected!");
+ try
+ {
+ Reference<XRefreshable> xRefresh(getElements(E_TABLE),UNO_QUERY);
+ if ( xRefresh.is() )
+ xRefresh->refresh();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Could not refresh tables!");
+ }
+
+ getContainer()->getDetailView()->clearPages(false);
+ getContainer()->getDetailView()->createTablesPage( ensureConnection() );
+}
+
+void SAL_CALL OApplicationController::propertyChange( const PropertyChangeEvent& evt )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( evt.PropertyName == PROPERTY_USER )
+ {
+ m_bNeedToReconnect = true;
+ InvalidateFeature(SID_DB_APP_STATUS_USERNAME);
+ }
+ else if ( evt.PropertyName == PROPERTY_URL )
+ {
+ m_bNeedToReconnect = true;
+ InvalidateFeature(SID_DB_APP_STATUS_DBNAME);
+ InvalidateFeature(SID_DB_APP_STATUS_TYPE);
+ InvalidateFeature(SID_DB_APP_STATUS_HOSTNAME);
+ }
+ else if ( PROPERTY_NAME == evt.PropertyName )
+ {
+ const ElementType eType = getContainer()->getElementType();
+ if ( eType == E_FORM || eType == E_REPORT )
+ {
+ OUString sOldName,sNewName;
+ evt.OldValue >>= sOldName;
+ evt.NewValue >>= sNewName;
+
+ // if the old name is empty, then this is a newly inserted content. We're notified of it via the
+ // elementInserted method, so there's no need to handle it here.
+
+ if ( !sOldName.isEmpty() )
+ {
+ Reference<XChild> xChild(evt.Source,UNO_QUERY);
+ if ( xChild.is() )
+ {
+ Reference<XContent> xContent(xChild->getParent(),UNO_QUERY);
+ if ( xContent.is() )
+ sOldName = xContent->getIdentifier()->getContentIdentifier() + "/" + sOldName;
+ }
+
+ getContainer()->elementReplaced( eType , sOldName, sNewName );
+ }
+ }
+ }
+
+ EventObject aEvt;
+ aEvt.Source = m_xModel;
+ modified(aEvt);
+}
+
+Reference< XDataSource > SAL_CALL OApplicationController::getDataSource()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY );
+ return xDataSource;
+}
+
+Reference< XWindow > SAL_CALL OApplicationController::getApplicationMainWindow()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ Reference< XFrame > xFrame( getFrame(), UNO_SET_THROW );
+ Reference< XWindow > xWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
+ return xWindow;
+}
+
+Sequence< Reference< XComponent > > SAL_CALL OApplicationController::getSubComponents()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_pSubComponentManager->getSubComponents();
+}
+
+Reference< XConnection > SAL_CALL OApplicationController::getActiveConnection()
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_xDataSourceConnection.getTyped();
+}
+
+sal_Bool SAL_CALL OApplicationController::isConnected( )
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_xDataSourceConnection.is();
+}
+
+void SAL_CALL OApplicationController::connect( )
+{
+ SQLExceptionInfo aError;
+ SharedConnection xConnection = ensureConnection( &aError );
+ if ( !xConnection.is() )
+ {
+ if ( aError.isValid() )
+ aError.doThrow();
+
+ // no particular error, but nonetheless could not connect -> throw a generic exception
+ OUString sConnectingContext( DBA_RES( STR_COULDNOTCONNECT_DATASOURCE ) );
+ ::dbtools::throwGenericSQLException( sConnectingContext.replaceFirst( "$name$", getStrippedDatabaseName() ), *this );
+ }
+}
+
+beans::Pair< ::sal_Int32, OUString > SAL_CALL OApplicationController::identifySubComponent( const Reference< XComponent >& i_rSubComponent )
+{
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ sal_Int32 nType = -1;
+ OUString sName;
+
+ if ( !m_pSubComponentManager->lookupSubComponent( i_rSubComponent, sName, nType ) )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ if ( nType == SID_DB_APP_DSRELDESIGN )
+ // this is somewhat hacky ... we're expected to return a DatabaseObject value. However, there is no such
+ // value for the relation design. /me thinks we should change the API definition here ...
+ nType = -1;
+
+ return beans::Pair< ::sal_Int32, OUString >( nType, sName );
+}
+
+sal_Bool SAL_CALL OApplicationController::closeSubComponents( )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+ return m_pSubComponentManager->closeSubComponents();
+}
+
+namespace
+{
+ ElementType lcl_objectType2ElementType( const sal_Int32 _nObjectType )
+ {
+ ElementType eType( E_NONE );
+ switch ( _nObjectType )
+ {
+ case DatabaseObject::TABLE: eType = E_TABLE; break;
+ case DatabaseObject::QUERY: eType = E_QUERY; break;
+ case DatabaseObject::FORM: eType = E_FORM; break;
+ case DatabaseObject::REPORT: eType = E_REPORT; break;
+ default:
+ OSL_FAIL( "lcl_objectType2ElementType: unsupported object type!" );
+ // this should have been caught earlier
+ }
+ return eType;
+ }
+}
+
+void OApplicationController::impl_validateObjectTypeAndName_throw( const sal_Int32 _nObjectType, const ::std::optional< OUString >& i_rObjectName )
+{
+ // ensure we're connected
+ if ( !isConnected() )
+ {
+ SQLError aError;
+ aError.raiseException( ErrorCondition::DB_NOT_CONNECTED, *this );
+ }
+
+ // ensure a proper object type
+ if ( ( _nObjectType != DatabaseObject::TABLE )
+ && ( _nObjectType != DatabaseObject::QUERY )
+ && ( _nObjectType != DatabaseObject::FORM )
+ && ( _nObjectType != DatabaseObject::REPORT )
+ )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ if ( !i_rObjectName )
+ return;
+
+ // ensure an existing object
+ Reference< XNameAccess > xContainer( getElements( lcl_objectType2ElementType( _nObjectType ) ) );
+ if ( !xContainer.is() )
+ // all possible reasons for this (e.g. not being connected currently) should
+ // have been handled before
+ throw RuntimeException( OUString(), *this );
+
+ bool bExistentObject = false;
+ switch ( _nObjectType )
+ {
+ case DatabaseObject::TABLE:
+ case DatabaseObject::QUERY:
+ bExistentObject = xContainer->hasByName( *i_rObjectName );
+ break;
+ case DatabaseObject::FORM:
+ case DatabaseObject::REPORT:
+ {
+ Reference< XHierarchicalNameAccess > xHierarchy( xContainer, UNO_QUERY_THROW );
+ bExistentObject = xHierarchy->hasByHierarchicalName( *i_rObjectName );
+ }
+ break;
+ }
+
+ if ( !bExistentObject )
+ throw NoSuchElementException( *i_rObjectName, *this );
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::loadComponent( ::sal_Int32 ObjectType,
+ const OUString& ObjectName, sal_Bool ForEditing )
+{
+ return loadComponentWithArguments( ObjectType, ObjectName, ForEditing, Sequence< PropertyValue >() );
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::loadComponentWithArguments( ::sal_Int32 ObjectType,
+ const OUString& ObjectName, sal_Bool ForEditing, const Sequence< PropertyValue >& Arguments )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ impl_validateObjectTypeAndName_throw( ObjectType, ObjectName );
+
+ Reference< XComponent > xComponent( openElementWithArguments(
+ ObjectName,
+ lcl_objectType2ElementType( ObjectType ),
+ ForEditing ? E_OPEN_DESIGN : E_OPEN_NORMAL,
+ ForEditing ? SID_DB_APP_EDIT : SID_DB_APP_OPEN,
+ ::comphelper::NamedValueCollection( Arguments )
+ ) );
+
+ return xComponent;
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::createComponent( ::sal_Int32 i_nObjectType, Reference< XComponent >& o_DocumentDefinition )
+{
+ return createComponentWithArguments( i_nObjectType, Sequence< PropertyValue >(), o_DocumentDefinition );
+}
+
+Reference< XComponent > SAL_CALL OApplicationController::createComponentWithArguments( ::sal_Int32 i_nObjectType, const Sequence< PropertyValue >& i_rArguments, Reference< XComponent >& o_DocumentDefinition )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ impl_validateObjectTypeAndName_throw( i_nObjectType, ::std::optional< OUString >() );
+
+ Reference< XComponent > xComponent( newElement(
+ lcl_objectType2ElementType( i_nObjectType ),
+ ::comphelper::NamedValueCollection( i_rArguments ),
+ o_DocumentDefinition
+ ) );
+
+ return xComponent;
+}
+
+void SAL_CALL OApplicationController::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
+{
+ if ( Interceptor.is() )
+ m_aContextMenuInterceptors.addInterface( Interceptor );
+}
+
+void SAL_CALL OApplicationController::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor )
+{
+ m_aContextMenuInterceptors.removeInterface( Interceptor );
+}
+
+void OApplicationController::previewChanged( sal_Int32 _nMode )
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ if ( m_xDataSource.is() && !isDataSourceReadOnly() )
+ {
+ try
+ {
+ ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) );
+ sal_Int32 nOldMode = aLayoutInfo.getOrDefault( "Preview", _nMode );
+ if ( nOldMode != _nMode )
+ {
+ aLayoutInfo.put( "Preview", _nMode );
+ m_xDataSource->setPropertyValue( PROPERTY_LAYOUTINFORMATION, makeAny( aLayoutInfo.getPropertyValues() ) );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ InvalidateFeature(SID_DB_APP_DISABLE_PREVIEW);
+ InvalidateFeature(SID_DB_APP_VIEW_DOCINFO_PREVIEW);
+ InvalidateFeature(SID_DB_APP_VIEW_DOC_PREVIEW);
+}
+
+void OApplicationController::askToReconnect()
+{
+ if ( !m_bNeedToReconnect )
+ return;
+
+ m_bNeedToReconnect = false;
+ bool bClear = true;
+ if ( !m_pSubComponentManager->empty() )
+ {
+ std::unique_ptr<weld::MessageDialog> xQry(Application::CreateMessageDialog(getFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ DBA_RES(STR_QUERY_CLOSEDOCUMENTS)));
+ switch (xQry->run())
+ {
+ case RET_YES:
+ closeSubComponents();
+ break;
+ default:
+ bClear = false;
+ break;
+ }
+ }
+ if ( bClear )
+ {
+ ElementType eType = getContainer()->getElementType();
+ disconnect();
+ getContainer()->getDetailView()->clearPages(false);
+ getContainer()->selectContainer(E_NONE); // invalidate the old selection
+ m_eCurrentType = E_NONE;
+ getContainer()->selectContainer(eType); // reselect the current one again
+ }
+}
+
+OUString OApplicationController::getDatabaseName() const
+{
+ OUString sDatabaseName;
+ try
+ {
+ if ( m_xDataSource.is() )
+ {
+ OSL_VERIFY( m_xDataSource->getPropertyValue( PROPERTY_NAME ) >>= sDatabaseName );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sDatabaseName;
+}
+
+OUString OApplicationController::getStrippedDatabaseName() const
+{
+ OUString sDatabaseName;
+ return ::dbaui::getStrippedDatabaseName( m_xDataSource, sDatabaseName );
+}
+
+void OApplicationController::onDocumentOpened( const OUString& _rName, const sal_Int32 _nType,
+ const ElementOpenMode _eMode, const Reference< XComponent >& _xDocument, const Reference< XComponent >& _rxDefinition )
+{
+ if ( !_xDocument.is() )
+ return;
+
+ try
+ {
+ OSL_ENSURE( _xDocument.is(), "OApplicationController::onDocumentOpened: is there any *valid* scenario where this fails?" );
+ m_pSubComponentManager->onSubComponentOpened( _rName, _nType, _eMode, _xDocument.is() ? _xDocument : _rxDefinition );
+
+ if ( _rxDefinition.is() )
+ {
+ Reference< XPropertySet > xProp( _rxDefinition, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPSI( xProp->getPropertySetInfo(), UNO_SET_THROW );
+ xProp->addPropertyChangeListener( PROPERTY_NAME, static_cast< XPropertyChangeListener* >( this ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+bool OApplicationController::insertHierachyElement(ElementType _eType, const OUString& _sParentFolder, bool _bCollection, const Reference<XContent>& _xContent, bool _bMove)
+{
+ Reference<XHierarchicalNameContainer> xNames(getElements(_eType), UNO_QUERY);
+ return dbaui::insertHierachyElement(getFrameWeld()
+ ,getORB()
+ ,xNames
+ ,_sParentFolder
+ ,_eType == E_FORM
+ ,_bCollection
+ ,_xContent
+ ,_bMove);
+}
+
+bool OApplicationController::isRenameDeleteAllowed(ElementType _eType, bool _bDelete) const
+{
+ ElementType eType = getContainer()->getElementType();
+ bool bEnabled = !isDataSourceReadOnly() && eType == _eType;
+ if ( bEnabled )
+ {
+
+ if ( E_TABLE == eType )
+ bEnabled = !isConnectionReadOnly() && getContainer()->isALeafSelected();
+
+ bool bCompareRes = false;
+ if ( _bDelete )
+ bCompareRes = getContainer()->getSelectionCount() > 0;
+ else
+ {
+ bCompareRes = getContainer()->getSelectionCount() == 1;
+ if ( bEnabled && bCompareRes && E_TABLE == eType )
+ {
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+
+ try
+ {
+ Reference< XNameAccess > xContainer = const_cast<OApplicationController*>(this)->getElements(eType);
+ bEnabled = (xContainer.is() && xContainer->hasByName(*aList.begin()));
+ if ( bEnabled )
+ bEnabled = Reference<XRename>(xContainer->getByName(*aList.begin()),UNO_QUERY).is();
+ }
+ catch(Exception&)
+ {
+ bEnabled = false;
+ }
+ }
+ }
+
+ bEnabled = bEnabled && bCompareRes;
+ }
+ return bEnabled;
+}
+
+void OApplicationController::onLoadedMenu(const Reference< css::frame::XLayoutManager >& _xLayoutManager)
+{
+
+ if ( !_xLayoutManager.is() )
+ return;
+
+ static const char s_sStatusbar[] = "private:resource/statusbar/statusbar";
+ _xLayoutManager->createElement( s_sStatusbar );
+ _xLayoutManager->requestElement( s_sStatusbar );
+
+ if ( getContainer() )
+ {
+ // we need to share the "mnemonic space":
+ MnemonicGenerator aMnemonicGenerator;
+ // - the menu already has mnemonics
+ SystemWindow* pSystemWindow = getContainer()->GetSystemWindow();
+ MenuBar* pMenu = pSystemWindow ? pSystemWindow->GetMenuBar() : nullptr;
+ if ( pMenu )
+ {
+ sal_uInt16 nMenuItems = pMenu->GetItemCount();
+ for ( sal_uInt16 i = 0; i < nMenuItems; ++i )
+ aMnemonicGenerator.RegisterMnemonic( pMenu->GetItemText( pMenu->GetItemId( i ) ) );
+ }
+ // - the icons should use automatic ones
+ getContainer()->createIconAutoMnemonics( aMnemonicGenerator );
+ // - as well as the entries in the task pane
+ getContainer()->setTaskExternalMnemonics( aMnemonicGenerator );
+ }
+
+ Execute( SID_DB_APP_VIEW_FORMS, Sequence< PropertyValue >() );
+ InvalidateAll();
+}
+
+void OApplicationController::doAction(sal_uInt16 _nId, const ElementOpenMode _eOpenMode)
+{
+ std::vector< OUString> aList;
+ getSelectionElementNames(aList);
+ ElementType eType = getContainer()->getElementType();
+ ::comphelper::NamedValueCollection aArguments;
+ ElementOpenMode eOpenMode = _eOpenMode;
+ if ( eType == E_REPORT && E_OPEN_FOR_MAIL == _eOpenMode )
+ {
+ aArguments.put("Hidden",true);
+ eOpenMode = E_OPEN_NORMAL;
+ }
+
+ std::vector< std::pair< OUString ,Reference< XModel > > > aComponents;
+ for (auto const& elem : aList)
+ {
+ if ( SID_DB_APP_CONVERTTOVIEW == _nId )
+ convertToView(elem);
+ else
+ {
+ Reference< XModel > xModel( openElementWithArguments( elem, eType, eOpenMode, _nId,aArguments ), UNO_QUERY );
+ aComponents.emplace_back( elem, xModel );
+ }
+ }
+
+ // special handling for mail, if more than one document is selected attach them all
+ if ( _eOpenMode != E_OPEN_FOR_MAIL )
+ return;
+
+
+ SfxMailModel aSendMail;
+ SfxMailModel::SendMailResult eResult = SfxMailModel::SEND_MAIL_OK;
+ for (auto const& component : aComponents)
+ {
+ try
+ {
+ Reference< XModel > xModel = component.second;
+
+ // Send document as e-Mail using stored/default type
+ eResult = aSendMail.AttachDocument(xModel,component.first);
+ ::comphelper::disposeComponent(xModel);
+ if (eResult != SfxMailModel::SEND_MAIL_OK)
+ break;
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ if ( !aSendMail.IsEmpty() )
+ aSendMail.Send( getFrame() );
+}
+
+ElementType OApplicationController::getElementType(const Reference< XContainer >& _xContainer)
+{
+ ElementType eRet = E_NONE;
+ Reference<XServiceInfo> xServiceInfo(_xContainer,UNO_QUERY);
+ if ( xServiceInfo.is() )
+ {
+ if ( xServiceInfo->supportsService(SERVICE_SDBCX_TABLES) )
+ eRet = E_TABLE;
+ else if ( xServiceInfo->supportsService(SERVICE_NAME_FORM_COLLECTION) )
+ eRet = E_FORM;
+ else if ( xServiceInfo->supportsService(SERVICE_NAME_REPORT_COLLECTION) )
+ eRet = E_REPORT;
+ else
+ eRet = E_QUERY;
+ }
+ return eRet;
+}
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.cxx b/dbaccess/source/ui/app/AppDetailPageHelper.cxx
new file mode 100644
index 000000000..502ad243c
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailPageHelper.cxx
@@ -0,0 +1,1305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppDetailPageHelper.hxx"
+#include <tools/diagnose_ex.h>
+#include <tabletree.hxx>
+#include <dbtreelistbox.hxx>
+#include <com/sun/star/awt/XTabController.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/frame/thePopupMenuControllerFactory.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/frame/Frame.hpp>
+#include <com/sun/star/frame/XFrames.hpp>
+#include <com/sun/star/frame/XFramesSupplier.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/ucb/Command.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include "AppView.hxx"
+#include <helpids.h>
+#include <strings.hxx>
+#include <dbaccess_slotid.hrc>
+#include <databaseobjectview.hxx>
+#include <imageprovider.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/event.hxx>
+#include <toolkit/awt/vclxmenu.hxx>
+#include <tools/stream.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/treelistentry.hxx>
+#include "AppController.hxx"
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <memory>
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdb::application;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star;
+using ::com::sun::star::awt::XTabController;
+
+namespace dbaui
+{
+ namespace DatabaseObject = css::sdb::application::DatabaseObject;
+ namespace DatabaseObjectContainer = css::sdb::application::DatabaseObjectContainer;
+}
+
+namespace
+{
+ SvTreeListEntry* lcl_findEntry_impl(DBTreeListBox const & rTree, const OUString& _rName, SvTreeListEntry* _pFirst)
+ {
+ SvTreeListEntry* pReturn = nullptr;
+ sal_Int32 nIndex = 0;
+ OUString sName( _rName.getToken(0,'/',nIndex) );
+
+ SvTreeListEntry* pEntry = _pFirst;
+ while( pEntry )
+ {
+ if ( rTree.GetEntryText(pEntry) == sName )
+ {
+ if ( nIndex != -1 )
+ {
+ sName = _rName.getToken(0,'/',nIndex);
+ pEntry = rTree.FirstChild(pEntry);
+ }
+ else
+ {
+ pReturn = pEntry;
+ break;
+ }
+ }
+ else
+ pEntry = pEntry->NextSibling();
+ }
+ return pReturn;
+ }
+ SvTreeListEntry* lcl_findEntry(DBTreeListBox const & rTree, const OUString& _rName,SvTreeListEntry* _pFirst)
+ {
+ sal_Int32 nIndex = 0;
+ OUString sErase = _rName.getToken(0,'/',nIndex); // we don't want to have the "private:forms" part
+ return (nIndex != -1 ? lcl_findEntry_impl(rTree,_rName.copy(sErase.getLength() + 1),_pFirst) : nullptr);
+ }
+ class OTablePreviewWindow : public vcl::Window
+ {
+ DECL_LINK(OnDisableInput, void*, void);
+ void ImplInitSettings();
+ protected:
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+ public:
+ OTablePreviewWindow( vcl::Window* pParent, WinBits nStyle );
+ virtual bool EventNotify( NotifyEvent& rNEvt ) override;
+ };
+ OTablePreviewWindow::OTablePreviewWindow(vcl::Window* pParent, WinBits nStyle) : Window( pParent, nStyle)
+ {
+ ImplInitSettings();
+ }
+ bool OTablePreviewWindow::EventNotify( NotifyEvent& rNEvt )
+ {
+ bool bRet = Window::EventNotify(rNEvt);
+ if ( rNEvt.GetType() == MouseNotifyEvent::INPUTENABLE && IsInputEnabled() )
+ PostUserEvent( LINK( this, OTablePreviewWindow, OnDisableInput), nullptr, true );
+ return bRet;
+ }
+ IMPL_LINK_NOARG(OTablePreviewWindow, OnDisableInput, void*, void)
+ {
+ EnableInput(false);
+ }
+ void OTablePreviewWindow::DataChanged( const DataChangedEvent& rDCEvt )
+ {
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+ }
+ void OTablePreviewWindow::ImplInitSettings()
+ {
+ //FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+ }
+
+}
+
+OAppDetailPageHelper::OAppDetailPageHelper(vcl::Window* _pParent,OAppBorderWindow& _rBorderWin,PreviewMode _ePreviewMode) : Window(_pParent,WB_DIALOGCONTROL)
+ ,m_rBorderWin(_rBorderWin)
+ ,m_aFL(VclPtr<FixedLine>::Create(this,WB_VERT))
+ ,m_aTBPreview(VclPtr<ToolBox>::Create(this,WB_TABSTOP) )
+ ,m_aBorder(VclPtr<Window>::Create(this,WB_BORDER | WB_READONLY))
+ ,m_aPreview(VclPtr<OPreviewWindow>::Create(m_aBorder.get()))
+ ,m_aDocumentInfo(VclPtr< ::svtools::ODocumentInfoPreview>::Create(m_aBorder.get(), WB_LEFT | WB_VSCROLL | WB_READONLY) )
+ ,m_ePreviewMode(_ePreviewMode)
+{
+ m_aBorder->SetBorderStyle(WindowBorderStyle::MONO);
+
+ m_aTBPreview->SetOutStyle(TOOLBOX_STYLE_FLAT);
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:DBDisablePreview",
+ "com.sun.star.sdb.OfficeDatabaseDocument");
+ m_aTBPreview->InsertItem(SID_DB_APP_DISABLE_PREVIEW,
+ vcl::CommandInfoProvider::GetLabelForCommand(aProperties),
+ ToolBoxItemBits::LEFT|ToolBoxItemBits::DROPDOWNONLY|ToolBoxItemBits::AUTOSIZE|ToolBoxItemBits::RADIOCHECK);
+ m_aTBPreview->SetHelpId(HID_APP_VIEW_PREVIEW_CB);
+ m_aTBPreview->SetDropdownClickHdl( LINK( this, OAppDetailPageHelper, OnDropdownClickHdl ) );
+ m_aTBPreview->Enable();
+
+ m_aPreview->SetHelpId(HID_APP_VIEW_PREVIEW_1);
+
+ m_pTablePreview.set( VclPtr<OTablePreviewWindow>::Create(m_aBorder.get(), WB_READONLY | WB_DIALOGCONTROL ) );
+ m_pTablePreview->SetHelpId(HID_APP_VIEW_PREVIEW_2);
+
+ m_aDocumentInfo->SetHelpId(HID_APP_VIEW_PREVIEW_3);
+
+ m_xWindow = VCLUnoHelper::GetInterface( m_pTablePreview );
+
+ for (VclPtr<DBTreeListBox> & rpBox : m_pLists)
+ rpBox = nullptr;
+ ImplInitSettings();
+}
+
+OAppDetailPageHelper::~OAppDetailPageHelper()
+{
+ disposeOnce();
+}
+
+void OAppDetailPageHelper::dispose()
+{
+ try
+ {
+ Reference< ::util::XCloseable> xCloseable(m_xFrame,UNO_QUERY);
+ if ( xCloseable.is() )
+ xCloseable->close(true);
+ m_xFrame.clear();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Exception thrown while disposing preview frame!");
+ }
+
+ for (VclPtr<DBTreeListBox> & rpBox : m_pLists)
+ {
+ if ( rpBox )
+ {
+ rpBox->clearCurrentSelection();
+ rpBox->Hide();
+ rpBox->clearCurrentSelection(); // why a second time?
+ rpBox.disposeAndClear();
+ }
+ }
+ m_pTablePreview.disposeAndClear();
+ m_aDocumentInfo.disposeAndClear();
+ m_aPreview.disposeAndClear();
+ m_aBorder.disposeAndClear();
+ m_aTBPreview.disposeAndClear();
+ m_aFL.disposeAndClear();
+
+ vcl::Window::dispose();
+}
+
+int OAppDetailPageHelper::getVisibleControlIndex() const
+{
+ int i = 0;
+ for (; i < E_ELEMENT_TYPE_COUNT ; ++i)
+ {
+ if ( m_pLists[i] && m_pLists[i]->IsVisible() )
+ break;
+ }
+ return i;
+}
+
+void OAppDetailPageHelper::selectAll()
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ m_pLists[nPos]->SelectAll(true);
+ }
+}
+
+void OAppDetailPageHelper::sort(int _nPos,SvSortMode _eSortMode )
+{
+ OSL_ENSURE(m_pLists[_nPos],"List can not be NULL! ->GPF");
+ SvTreeList* pModel = m_pLists[_nPos]->GetModel();
+ SvSortMode eOldSortMode = pModel->GetSortMode();
+ pModel->SetSortMode(_eSortMode);
+ if ( eOldSortMode != _eSortMode )
+ pModel->Resort();
+}
+
+bool OAppDetailPageHelper::isSortUp() const
+{
+ SvSortMode eSortMode = SortNone;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ SvTreeList* pModel = m_pLists[nPos]->GetModel();
+ eSortMode = pModel->GetSortMode();
+ }
+ return eSortMode == SortAscending;
+}
+
+void OAppDetailPageHelper::sortDown()
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ sort(nPos,SortDescending);
+}
+
+void OAppDetailPageHelper::sortUp()
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ sort(nPos,SortAscending);
+}
+
+void OAppDetailPageHelper::getSelectionElementNames( std::vector< OUString>& _rNames ) const
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return;
+
+ DBTreeListBox& rTree = *m_pLists[nPos];
+ sal_Int32 nCount = rTree.GetEntryCount();
+ _rNames.reserve(nCount);
+ SvTreeListEntry* pEntry = rTree.FirstSelected();
+ ElementType eType = getElementType();
+ while( pEntry )
+ {
+ if ( eType == E_TABLE )
+ {
+ if( rTree.GetChildCount(pEntry) == 0 )
+ _rNames.push_back( getQualifiedName( pEntry ) );
+ }
+ else
+ {
+ OUString sName = rTree.GetEntryText(pEntry);
+ SvTreeListEntry* pParent = rTree.GetParent(pEntry);
+ while(pParent)
+ {
+ sName = rTree.GetEntryText(pParent) + "/" + sName;
+ pParent = rTree.GetParent(pParent);
+ }
+ _rNames.push_back(sName);
+ }
+ pEntry = rTree.NextSelected(pEntry);
+ }
+}
+
+void OAppDetailPageHelper::describeCurrentSelectionForControl( const Control& _rControl, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ for (size_t i=0; i < E_ELEMENT_TYPE_COUNT; ++i)
+ {
+ if ( m_pLists[i] == &_rControl )
+ {
+ describeCurrentSelectionForType(static_cast<ElementType>(i), _out_rSelectedObjects);
+ return;
+ }
+ }
+ OSL_FAIL( "OAppDetailPageHelper::describeCurrentSelectionForControl: invalid control!" );
+}
+
+void OAppDetailPageHelper::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ OSL_ENSURE( _eType < E_ELEMENT_TYPE_COUNT, "OAppDetailPageHelper::describeCurrentSelectionForType: invalid type!" );
+ DBTreeListBox* pList = ( _eType < E_ELEMENT_TYPE_COUNT ) ? m_pLists[ _eType ].get() : nullptr;
+ OSL_ENSURE( pList, "OAppDetailPageHelper::describeCurrentSelectionForType: "
+ "You really should ensure this type has already been viewed before!" );
+ if ( !pList )
+ return;
+
+ std::vector< NamedDatabaseObject > aSelected;
+
+ SvTreeListEntry* pEntry = pList->FirstSelected();
+ while( pEntry )
+ {
+ NamedDatabaseObject aObject;
+ switch ( _eType )
+ {
+ case E_TABLE:
+ {
+ OTableTreeListBox& rTableTree = dynamic_cast< OTableTreeListBox& >( *pList );
+ aObject = rTableTree.describeObject( pEntry );
+ }
+ break;
+ case E_QUERY:
+ aObject.Type = DatabaseObject::QUERY;
+ aObject.Name = pList->GetEntryText( pEntry );
+ break;
+
+ case E_FORM:
+ case E_REPORT:
+ {
+ OUString sName = pList->GetEntryText(pEntry);
+ SvTreeListEntry* pParent = pList->GetParent(pEntry);
+ while ( pParent )
+ {
+ OUStringBuffer buffer;
+ buffer.append( pList->GetEntryText( pParent ) );
+ buffer.append( '/' );
+ buffer.append( sName );
+ sName = buffer.makeStringAndClear();
+
+ pParent = pList->GetParent( pParent );
+ }
+
+ if ( isLeaf( pEntry ) )
+ aObject.Type = ( _eType == E_FORM ) ? DatabaseObject::FORM : DatabaseObject::REPORT;
+ else
+ aObject.Type = ( _eType == E_FORM ) ? DatabaseObjectContainer::FORMS_FOLDER : DatabaseObjectContainer::REPORTS_FOLDER;
+ aObject.Name = sName;
+ }
+ break;
+ default:
+ OSL_FAIL( "OAppDetailPageHelper::describeCurrentSelectionForType: unexpected type!" );
+ break;
+ }
+
+ if ( !aObject.Name.isEmpty() )
+ {
+ aSelected.push_back( aObject );
+ }
+
+ pEntry = pList->NextSelected(pEntry);
+ }
+
+ _out_rSelectedObjects = comphelper::containerToSequence( aSelected );
+}
+
+void OAppDetailPageHelper::selectElements(const Sequence< OUString>& _aNames)
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return;
+
+ DBTreeListBox& rTree = *m_pLists[nPos];
+ rTree.SelectAll(false);
+ const OUString* pIter = _aNames.getConstArray();
+ const OUString* pEnd = pIter + _aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ SvTreeListEntry* pEntry = rTree.GetEntryPosByName(*pIter);
+ if ( pEntry )
+ rTree.Select(pEntry);
+ }
+}
+
+OUString OAppDetailPageHelper::getQualifiedName( SvTreeListEntry* _pEntry ) const
+{
+ int nPos = getVisibleControlIndex();
+ OUString sComposedName;
+
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return sComposedName;
+
+ OSL_ENSURE(m_pLists[nPos],"Tables tree view is NULL! -> GPF");
+ DBTreeListBox& rTree = *m_pLists[nPos];
+
+ SvTreeListEntry* pEntry = _pEntry;
+ if ( !pEntry )
+ pEntry = rTree.FirstSelected();
+
+ if ( !pEntry )
+ return sComposedName;
+
+ if ( getElementType() == E_TABLE )
+ {
+ const OTableTreeListBox& rTreeView = dynamic_cast< const OTableTreeListBox& >( *m_pLists[nPos] );
+ sComposedName = rTreeView.getQualifiedTableName( pEntry );
+ }
+ else
+ {
+ sComposedName = rTree.GetEntryText(pEntry);
+ SvTreeListEntry* pParent = rTree.GetParent(pEntry);
+ while(pParent)
+ {
+ sComposedName = rTree.GetEntryText(pParent) + "/" + sComposedName;
+ pParent = rTree.GetParent(pParent);
+ }
+ }
+
+ return sComposedName;
+}
+
+ElementType OAppDetailPageHelper::getElementType() const
+{
+ int nPos = getVisibleControlIndex();
+ return static_cast<ElementType>(nPos);
+}
+
+sal_Int32 OAppDetailPageHelper::getSelectionCount()
+{
+ sal_Int32 nCount = 0;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeListBox& rTree = *m_pLists[nPos];
+ SvTreeListEntry* pEntry = rTree.FirstSelected();
+ while( pEntry )
+ {
+ ++nCount;
+ pEntry = rTree.NextSelected(pEntry);
+ }
+ }
+ return nCount;
+}
+
+sal_Int32 OAppDetailPageHelper::getElementCount() const
+{
+ sal_Int32 nCount = 0;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ nCount = m_pLists[nPos]->GetEntryCount();
+ }
+ return nCount;
+}
+
+bool OAppDetailPageHelper::isLeaf(SvTreeListEntry const * _pEntry)
+{
+ if ( !_pEntry )
+ return false;
+ sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() );
+ return !( ( nEntryType == DatabaseObjectContainer::TABLES )
+ || ( nEntryType == DatabaseObjectContainer::CATALOG )
+ || ( nEntryType == DatabaseObjectContainer::SCHEMA )
+ || ( nEntryType == DatabaseObjectContainer::FORMS_FOLDER )
+ || ( nEntryType == DatabaseObjectContainer::REPORTS_FOLDER ));
+}
+
+bool OAppDetailPageHelper::isALeafSelected() const
+{
+ int nPos = getVisibleControlIndex();
+ bool bLeafSelected = false;
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeListBox& rTree = *m_pLists[nPos];
+ SvTreeListEntry* pEntry = rTree.FirstSelected( );
+ while( !bLeafSelected && pEntry )
+ {
+ bLeafSelected = isLeaf( pEntry );
+ pEntry = rTree.NextSelected(pEntry);
+ }
+ }
+ return bLeafSelected;
+}
+
+SvTreeListEntry* OAppDetailPageHelper::getEntry( const Point& _aPosPixel) const
+{
+ SvTreeListEntry* pReturn = nullptr;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ pReturn = m_pLists[nPos]->GetEntry( _aPosPixel, true );
+ return pReturn;
+}
+
+void OAppDetailPageHelper::createTablesPage(const Reference< XConnection>& _xConnection)
+{
+ OSL_ENSURE(_xConnection.is(),"Connection is NULL! -> GPF");
+
+ if ( !m_pLists[E_TABLE] )
+ {
+ VclPtrInstance<OTableTreeListBox> pTreeView(this,
+ WB_HASLINES | WB_SORT | WB_HASBUTTONS | WB_HSCROLL |WB_HASBUTTONSATROOT | WB_TABSTOP);
+ pTreeView->SetHelpId(HID_APP_TABLE_TREE);
+ m_pLists[E_TABLE] = pTreeView;
+
+ createTree( pTreeView,
+ ImageProvider::getDefaultImage( DatabaseObject::TABLE )
+ );
+
+ pTreeView->notifyHiContrastChanged();
+ m_aBorder->SetZOrder(pTreeView, ZOrderFlags::Behind);
+ }
+ if ( !m_pLists[E_TABLE]->GetEntryCount() )
+ {
+ static_cast<OTableTreeListBox*>(m_pLists[E_TABLE].get())->UpdateTableList(_xConnection);
+
+ SvTreeListEntry* pEntry = m_pLists[E_TABLE]->First();
+ if ( pEntry )
+ m_pLists[E_TABLE]->Expand(pEntry);
+ m_pLists[E_TABLE]->SelectAll(false);
+ }
+
+ setDetailPage(m_pLists[E_TABLE]);
+}
+
+OUString OAppDetailPageHelper::getElementIcons(ElementType _eType)
+{
+ sal_Int32 nDatabaseObjectType( 0 );
+ switch(_eType )
+ {
+ case E_FORM: nDatabaseObjectType = DatabaseObject::FORM; break;
+ case E_REPORT: nDatabaseObjectType = DatabaseObject::REPORT; break;
+ case E_QUERY: nDatabaseObjectType = DatabaseObject::QUERY; break;
+ default:
+ OSL_FAIL( "OAppDetailPageHelper::GetElementIcons: invalid element type!" );
+ return OUString();
+ }
+
+ return ImageProvider::getDefaultImageResourceID(nDatabaseObjectType);
+}
+
+void OAppDetailPageHelper::createPage(ElementType _eType,const Reference< XNameAccess >& _xContainer)
+{
+ OSL_ENSURE(E_TABLE != _eType,"E_TABLE isn't allowed.");
+
+ OString sHelpId;
+ Image aFolderImage;
+ switch( _eType )
+ {
+ case E_FORM:
+ sHelpId = HID_APP_FORM_TREE;
+ aFolderImage = ImageProvider::getFolderImage( DatabaseObject::FORM );
+ break;
+ case E_REPORT:
+ sHelpId = HID_APP_REPORT_TREE;
+ aFolderImage = ImageProvider::getFolderImage( DatabaseObject::REPORT );
+ break;
+ case E_QUERY:
+ sHelpId = HID_APP_QUERY_TREE;
+ aFolderImage = ImageProvider::getFolderImage( DatabaseObject::QUERY );
+ break;
+ default:
+ OSL_FAIL("Illegal call!");
+ }
+ OUString sImageId = getElementIcons(_eType);
+
+ if ( !m_pLists[_eType] )
+ {
+ m_pLists[_eType] = createSimpleTree( sHelpId, aFolderImage );
+ }
+
+ if ( m_pLists[_eType] )
+ {
+ if ( !m_pLists[_eType]->GetEntryCount() && _xContainer.is() )
+ {
+ fillNames( _xContainer, _eType, sImageId, nullptr );
+
+ m_pLists[_eType]->SelectAll(false);
+ }
+ setDetailPage(m_pLists[_eType]);
+ }
+}
+
+void OAppDetailPageHelper::setDetailPage(vcl::Window* _pWindow)
+{
+ OSL_ENSURE(_pWindow,"OAppDetailPageHelper::setDetailPage: Window is NULL!");
+ vcl::Window* pCurrent = getCurrentView();
+ if ( pCurrent )
+ pCurrent->Hide();
+
+ showPreview(nullptr);
+ bool bHasFocus = false;
+ m_aFL->Show();
+ {
+ bHasFocus = pCurrent != nullptr && pCurrent->HasChildPathFocus();
+ _pWindow->Show();
+ }
+ m_aTBPreview->Show();
+ m_aBorder->Show();
+ switchPreview(m_ePreviewMode,true);
+
+ if ( bHasFocus )
+ _pWindow->GrabFocus();
+ Resize();
+}
+
+namespace
+{
+ namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer;
+
+ sal_Int32 lcl_getFolderIndicatorForType( const ElementType _eType )
+ {
+ const sal_Int32 nFolderIndicator =
+ ( _eType == E_FORM ) ? DatabaseObjectContainer::FORMS_FOLDER
+ : ( _eType == E_REPORT ) ? DatabaseObjectContainer::REPORTS_FOLDER : -1;
+ return nFolderIndicator;
+ }
+}
+
+void OAppDetailPageHelper::fillNames( const Reference< XNameAccess >& _xContainer, const ElementType _eType,
+ const OUString& rImageId, SvTreeListEntry* _pParent )
+{
+ OSL_ENSURE(_xContainer.is(),"Data source is NULL! -> GPF");
+ OSL_ENSURE( ( _eType >= E_TABLE ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OAppDetailPageHelper::fillNames: invalid type!" );
+
+ DBTreeListBox* pList = m_pLists[ _eType ].get();
+ OSL_ENSURE( pList, "OAppDetailPageHelper::fillNames: you really should create the list before calling this!" );
+ if ( !pList )
+ return;
+
+ if ( !(_xContainer.is() && _xContainer->hasElements()) )
+ return;
+
+ const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType );
+
+ Sequence< OUString> aSeq = _xContainer->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ SvTreeListEntry* pEntry = nullptr;
+ Reference<XNameAccess> xSubElements(_xContainer->getByName(*pIter),UNO_QUERY);
+ if ( xSubElements.is() )
+ {
+ pEntry = pList->InsertEntry( *pIter, _pParent, false, TREELIST_APPEND, reinterpret_cast< void* >( nFolderIndicator ) );
+ getBorderWin().getView()->getAppController().containerFound( Reference< XContainer >( xSubElements, UNO_QUERY ) );
+ fillNames( xSubElements, _eType, rImageId, pEntry );
+ }
+ else
+ {
+ pEntry = pList->InsertEntry( *pIter, _pParent );
+
+ Image aImage(StockImage::Yes, rImageId);
+ pList->SetExpandedEntryBmp(pEntry, aImage);
+ pList->SetCollapsedEntryBmp(pEntry, aImage);
+ }
+ }
+}
+
+DBTreeListBox* OAppDetailPageHelper::createSimpleTree( const OString& _sHelpId, const Image& _rImage)
+{
+ VclPtrInstance<DBTreeListBox> pTreeView(this,
+ WB_HASLINES | WB_SORT | WB_HASBUTTONS | WB_HSCROLL |WB_HASBUTTONSATROOT | WB_TABSTOP);
+ pTreeView->SetHelpId( _sHelpId );
+ return createTree( pTreeView, _rImage );
+}
+
+DBTreeListBox* OAppDetailPageHelper::createTree( DBTreeListBox* _pTreeView, const Image& _rImage )
+{
+ weld::WaitObject aWaitCursor(GetFrameWeld());
+
+ _pTreeView->SetStyle(_pTreeView->GetStyle() | WB_HASLINES | WB_SORT | WB_HASBUTTONS | WB_HSCROLL |WB_HASBUTTONSATROOT | WB_TABSTOP);
+ _pTreeView->GetModel()->SetSortMode(SortAscending);
+ _pTreeView->EnableCheckButton( nullptr ); // do not show any buttons
+ _pTreeView->SetSelectionMode(SelectionMode::Multiple);
+
+ _pTreeView->SetDefaultCollapsedEntryBmp( _rImage );
+ _pTreeView->SetDefaultExpandedEntryBmp( _rImage );
+
+ _pTreeView->SetDoubleClickHdl(LINK(this, OAppDetailPageHelper, OnEntryDoubleClick));
+ _pTreeView->SetEnterKeyHdl(LINK(this, OAppDetailPageHelper, OnEntryEnterKey));
+ _pTreeView->SetSelChangeHdl(LINK(this, OAppDetailPageHelper, OnEntrySelChange));
+
+ _pTreeView->setCopyHandler(LINK(this, OAppDetailPageHelper, OnCopyEntry));
+ _pTreeView->setPasteHandler(LINK(this, OAppDetailPageHelper, OnPasteEntry));
+ _pTreeView->setDeleteHandler(LINK(this, OAppDetailPageHelper, OnDeleteEntry));
+
+ _pTreeView->setControlActionListener( &getBorderWin().getView()->getAppController() );
+ _pTreeView->setContextMenuProvider( &getBorderWin().getView()->getAppController() );
+
+ return _pTreeView;
+}
+
+void OAppDetailPageHelper::clearPages()
+{
+ showPreview(nullptr);
+ for (VclPtr<DBTreeListBox> & rpBox : m_pLists)
+ {
+ if ( rpBox )
+ rpBox->Clear();
+ }
+}
+
+bool OAppDetailPageHelper::isFilled() const
+{
+ size_t i = 0;
+ for (; i < E_ELEMENT_TYPE_COUNT && !m_pLists[i]; ++i)
+ ;
+ return i != E_ELEMENT_TYPE_COUNT;
+}
+
+void OAppDetailPageHelper::elementReplaced(ElementType _eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName )
+{
+ DBTreeListBox* pTreeView = getCurrentView();
+ if ( !pTreeView )
+ return;
+
+ SvTreeListEntry* pEntry = nullptr;
+ switch( _eType )
+ {
+ case E_TABLE:
+ static_cast<OTableTreeListBox*>(pTreeView)->removedTable( _rOldName );
+ static_cast<OTableTreeListBox*>(pTreeView)->addedTable( _rNewName );
+ return;
+
+ case E_QUERY:
+ pEntry = lcl_findEntry_impl(*pTreeView,_rOldName,pTreeView->First());
+ break;
+ case E_FORM:
+ case E_REPORT:
+ pEntry = lcl_findEntry(*pTreeView,_rOldName,pTreeView->First());
+ break;
+ default:
+ OSL_FAIL("Invalid element type");
+ }
+ OSL_ENSURE(pEntry,"Do you know that the name isn't existence!");
+ if ( pEntry )
+ {
+ pTreeView->SetEntryText(pEntry,_rNewName);
+ }
+}
+
+SvTreeListEntry* OAppDetailPageHelper::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject )
+{
+ SvTreeListEntry* pRet = nullptr;
+ DBTreeListBox* pTreeView = m_pLists[_eType].get();
+ if( _eType == E_TABLE && pTreeView )
+ {
+ pRet = static_cast<OTableTreeListBox*>(pTreeView)->addedTable( _rName );
+ }
+ else if ( pTreeView )
+ {
+
+ SvTreeListEntry* pEntry = nullptr;
+ Reference<XChild> xChild(_rObject,UNO_QUERY);
+ if ( xChild.is() && E_QUERY != _eType )
+ {
+ Reference<XContent> xContent(xChild->getParent(),UNO_QUERY);
+ if ( xContent.is() )
+ {
+ OUString sName = xContent->getIdentifier()->getContentIdentifier();
+ pEntry = lcl_findEntry(*pTreeView,sName,pTreeView->First());
+ }
+ }
+
+ OUString sImageId = getElementIcons(_eType);
+ Reference<XNameAccess> xContainer(_rObject,UNO_QUERY);
+ if ( xContainer.is() )
+ {
+ const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType );
+ pRet = pTreeView->InsertEntry( _rName, pEntry, false, TREELIST_APPEND, reinterpret_cast< void* >( nFolderIndicator ) );
+ fillNames( xContainer, _eType, sImageId, pRet );
+ }
+ else
+ {
+ pRet = pTreeView->InsertEntry( _rName, pEntry );
+
+ Image aImage(StockImage::Yes, sImageId);
+ pTreeView->SetExpandedEntryBmp( pRet, aImage );
+ pTreeView->SetCollapsedEntryBmp( pRet, aImage );
+ }
+ }
+ return pRet;
+}
+
+void OAppDetailPageHelper::elementRemoved( ElementType _eType,const OUString& _rName )
+{
+ DBTreeListBox* pTreeView = getCurrentView();
+ if ( !pTreeView )
+ return;
+
+ switch( _eType )
+ {
+ case E_TABLE:
+ // we don't need to clear the table here, it is already done by the dispose listener
+ static_cast< OTableTreeListBox* >( pTreeView )->removedTable( _rName );
+ break;
+ case E_QUERY:
+ if (auto pEntry = lcl_findEntry_impl(*pTreeView, _rName, pTreeView->First()))
+ pTreeView->GetModel()->Remove(pEntry);
+ break;
+ case E_FORM:
+ case E_REPORT:
+ if (auto pEntry = lcl_findEntry(*pTreeView, _rName, pTreeView->First()))
+ pTreeView->GetModel()->Remove(pEntry);
+ break;
+ default:
+ OSL_FAIL("Invalid element type");
+ }
+ if ( !pTreeView->GetEntryCount() )
+ showPreview(nullptr);
+}
+
+IMPL_LINK(OAppDetailPageHelper, OnEntryEnterKey, DBTreeListBox*, _pTree, void )
+{
+ OnEntryDoubleClick(_pTree);
+}
+IMPL_LINK(OAppDetailPageHelper, OnEntryDoubleClick, SvTreeListBox*, _pTree, bool)
+{
+ OSL_ENSURE( _pTree, "OAppDetailPageHelper, OnEntryDoubleClick: invalid callback!" );
+ bool bHandled = ( _pTree != nullptr ) && getBorderWin().getView()->getAppController().onEntryDoubleClick( *_pTree );
+ return bHandled;
+}
+
+IMPL_LINK_NOARG(OAppDetailPageHelper, OnEntrySelChange, LinkParamNone*, void)
+{
+ getBorderWin().getView()->getAppController().onSelectionChanged();
+}
+
+IMPL_LINK_NOARG( OAppDetailPageHelper, OnCopyEntry, LinkParamNone*, void )
+{
+ getBorderWin().getView()->getAppController().onCopyEntry();
+}
+
+IMPL_LINK_NOARG( OAppDetailPageHelper, OnPasteEntry, LinkParamNone*, void )
+{
+ getBorderWin().getView()->getAppController().onPasteEntry();
+}
+
+IMPL_LINK_NOARG( OAppDetailPageHelper, OnDeleteEntry, LinkParamNone*, void )
+{
+ getBorderWin().getView()->getAppController().onDeleteEntry();
+}
+
+void OAppDetailPageHelper::Resize()
+{
+ // parent window dimension
+ Size aOutputSize( GetOutputSize() );
+ long nOutputWidth = aOutputSize.Width();
+ long nOutputHeight = aOutputSize.Height();
+
+ vcl::Window* pWindow = getCurrentView();
+ if ( !pWindow )
+ return;
+
+ Size aFLSize = LogicToPixel(Size(2, 6), MapMode(MapUnit::MapAppFont));
+ sal_Int32 n6PPT = aFLSize.Height();
+ long nHalfOutputWidth = static_cast<long>(nOutputWidth * 0.5);
+
+ pWindow->SetPosSizePixel( Point(0, 0), Size(nHalfOutputWidth - n6PPT, nOutputHeight) );
+
+ m_aFL->SetPosSizePixel( Point(nHalfOutputWidth , 0 ), Size(aFLSize.Width(), nOutputHeight ) );
+
+ Size aTBSize = m_aTBPreview->CalcWindowSizePixel();
+ m_aTBPreview->SetPosSizePixel(Point(nOutputWidth - aTBSize.getWidth(), 0 ),
+ aTBSize );
+
+ m_aBorder->SetPosSizePixel(Point(nHalfOutputWidth + aFLSize.Width() + n6PPT, aTBSize.getHeight() + n6PPT ),
+ Size(nHalfOutputWidth - aFLSize.Width() - n6PPT, nOutputHeight - 2*n6PPT - aTBSize.getHeight()) );
+ m_aPreview->SetPosSizePixel(Point(0,0),m_aBorder->GetSizePixel() );
+ m_aDocumentInfo->SetPosSizePixel(Point(0,0),m_aBorder->GetSizePixel() );
+ m_pTablePreview->SetPosSizePixel(Point(0,0),m_aBorder->GetSizePixel() );
+}
+
+
+bool OAppDetailPageHelper::isPreviewEnabled() const
+{
+ return m_ePreviewMode != E_PREVIEWNONE;
+}
+
+namespace
+{
+ OUString stripTrailingDots(const OUString& rStr)
+ {
+ return comphelper::string::stripEnd(rStr, '.');
+ }
+}
+
+void OAppDetailPageHelper::switchPreview(PreviewMode _eMode,bool _bForce)
+{
+ if ( !(m_ePreviewMode != _eMode || _bForce) )
+ return;
+
+ m_ePreviewMode = _eMode;
+
+ getBorderWin().getView()->getAppController().previewChanged(static_cast<sal_Int32>(m_ePreviewMode));
+
+ OUString aCommand;
+ switch ( m_ePreviewMode )
+ {
+ case E_PREVIEWNONE:
+ aCommand = ".uno:DBDisablePreview";
+ break;
+ case E_DOCUMENT:
+ aCommand = ".uno:DBShowDocPreview";
+ break;
+ case E_DOCUMENTINFO:
+ if ( getBorderWin().getView()->getAppController().isCommandEnabled(SID_DB_APP_VIEW_DOCINFO_PREVIEW) )
+ aCommand = ".uno:DBShowDocInfoPreview";
+ else
+ {
+ m_ePreviewMode = E_PREVIEWNONE;
+ aCommand = ".uno:DBDisablePreview";
+ }
+ break;
+ }
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, "com.sun.star.sdb.OfficeDatabaseDocument");
+ OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+ m_aTBPreview->SetItemText(SID_DB_APP_DISABLE_PREVIEW, stripTrailingDots(aCommandLabel));
+ Resize();
+
+ // simulate a selectionChanged event at the controller, to force the preview to be updated
+ if ( isPreviewEnabled() )
+ {
+ if ( getCurrentView() && getCurrentView()->FirstSelected() )
+ {
+ getBorderWin().getView()->getAppController().onSelectionChanged();
+ }
+ }
+ else
+ {
+ m_pTablePreview->Hide();
+ m_aPreview->Hide();
+ m_aDocumentInfo->Hide();
+ }
+}
+
+void OAppDetailPageHelper::showPreview(const Reference< XContent >& _xContent)
+{
+ if ( !isPreviewEnabled() )
+ return;
+
+ m_pTablePreview->Hide();
+
+ weld::WaitObject aWaitCursor(GetFrameWeld());
+ try
+ {
+ Reference<XCommandProcessor> xContent(_xContent,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ css::ucb::Command aCommand;
+ if ( m_ePreviewMode == E_DOCUMENT )
+ aCommand.Name = "preview";
+ else
+ aCommand.Name = "getDocumentInfo";
+
+ Any aPreview = xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >());
+ if ( m_ePreviewMode == E_DOCUMENT )
+ {
+ m_aDocumentInfo->Hide();
+ m_aPreview->Show();
+
+ Graphic aGraphic;
+ Sequence < sal_Int8 > aBmpSequence;
+ if ( aPreview >>= aBmpSequence )
+ {
+ SvMemoryStream aData( aBmpSequence.getArray(),
+ aBmpSequence.getLength(),
+ StreamMode::READ );
+
+ GraphicConverter::Import(aData,aGraphic);
+ }
+ m_aPreview->setGraphic( aGraphic );
+ m_aPreview->Invalidate();
+ }
+ else
+ {
+ m_aPreview->Hide();
+ m_aDocumentInfo->clear();
+ m_aDocumentInfo->Show();
+ Reference<document::XDocumentProperties> xProp(
+ aPreview, UNO_QUERY);
+ if ( xProp.is() )
+ m_aDocumentInfo->fill(xProp);
+ }
+ }
+ else
+ {
+ m_aPreview->Hide();
+ m_aDocumentInfo->Hide();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OAppDetailPageHelper::showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable)
+{
+ if ( !isPreviewEnabled() )
+ return;
+
+ weld::WaitObject aWaitCursor(GetFrameWeld());
+ m_aPreview->Hide();
+ m_aDocumentInfo->Hide();
+ m_pTablePreview->Show();
+ if ( !m_xFrame.is() )
+ {
+ try
+ {
+ m_xFrame = Frame::create( getBorderWin().getView()->getORB() );
+ m_xFrame->initialize( m_xWindow );
+
+ // no layout manager (and thus no toolbars) in the preview
+ // Must be called after initialize ... but before any other call to this frame.
+ // Otherwise frame throws "life time exceptions" as e.g. NON_INITIALIZED
+ m_xFrame->setLayoutManager( Reference< XLayoutManager >() );
+
+ Reference<XFramesSupplier> xSup(getBorderWin().getView()->getAppController().getXController()->getFrame(),UNO_QUERY);
+ if ( xSup.is() )
+ {
+ Reference<XFrames> xFrames = xSup->getFrames();
+ xFrames->append( Reference<XFrame>(m_xFrame,UNO_QUERY_THROW));
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+
+ Reference< XDatabaseDocumentUI > xApplication( getBorderWin().getView()->getAppController().getXController(), UNO_QUERY );
+ std::unique_ptr< DatabaseObjectView > pDispatcher( new ResultSetBrowser(
+ getBorderWin().getView()->getORB(),
+ xApplication, nullptr, _bTable
+ ) );
+ pDispatcher->setTargetFrame( Reference<XFrame>(m_xFrame,UNO_QUERY_THROW) );
+
+ ::comphelper::NamedValueCollection aArgs;
+ aArgs.put( "Preview", true );
+ aArgs.put( "ReadOnly", true );
+ aArgs.put( "AsTemplate", false );
+ aArgs.put( OUString(PROPERTY_SHOWMENU), false );
+
+ Reference< XController > xPreview( pDispatcher->openExisting( makeAny( _sDataSourceName ), _sName, aArgs ), UNO_QUERY );
+ bool bClearPreview = !xPreview.is();
+
+ // clear the preview when the query or table could not be loaded
+ if ( !bClearPreview )
+ {
+ Reference< XTabController > xTabController( xPreview, UNO_QUERY );
+ bClearPreview = !xTabController.is();
+ if ( !bClearPreview )
+ {
+ Reference< XLoadable > xLoadable( xTabController->getModel(), UNO_QUERY );
+ bClearPreview = !( xLoadable.is() && xLoadable->isLoaded() );
+ }
+ }
+ if ( bClearPreview )
+ showPreview(nullptr);
+}
+
+IMPL_LINK_NOARG(OAppDetailPageHelper, OnDropdownClickHdl, ToolBox*, void)
+{
+ m_aTBPreview->EndSelection();
+
+ // tell the toolbox that the item is pressed down
+ m_aTBPreview->SetItemDown( SID_DB_APP_DISABLE_PREVIEW, true );
+
+ // simulate a mouse move (so the "down" state is really painted)
+ Point aPoint = m_aTBPreview->GetItemRect( SID_DB_APP_DISABLE_PREVIEW ).TopLeft();
+ MouseEvent aMove( aPoint, 0, MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::SYNTHETIC );
+ m_aTBPreview->MouseMove( aMove );
+
+ m_aTBPreview->PaintImmediately();
+
+ // execute the menu
+ css::uno::Reference<css::uno::XComponentContext> xContext(getBorderWin().getView()->getORB());
+ css::uno::Reference<css::frame::XUIControllerFactory> xPopupMenuFactory(css::frame::thePopupMenuControllerFactory::get(xContext));
+ if (!xPopupMenuFactory.is())
+ return;
+
+ css::uno::Sequence<css::uno::Any> aArgs {
+ css::uno::makeAny(comphelper::makePropertyValue("InToolbar", true)),
+ css::uno::makeAny(comphelper::makePropertyValue("ModuleIdentifier", OUString("com.sun.star.sdb.OfficeDatabaseDocument"))),
+ css::uno::makeAny(comphelper::makePropertyValue("Frame", getBorderWin().getView()->getAppController().getFrame())) };
+
+ css::uno::Reference<css::frame::XPopupMenuController> xPopupController(
+ xPopupMenuFactory->createInstanceWithArgumentsAndContext(".uno:DBPreview", aArgs, xContext), css::uno::UNO_QUERY);
+
+ if (!xPopupController.is())
+ return;
+
+ rtl::Reference xPopupMenu(new VCLXPopupMenu);
+ xPopupController->setPopupMenu(xPopupMenu.get());
+ VclPtr<PopupMenu> aMenu(static_cast<PopupMenu*>(xPopupMenu->GetMenu()));
+
+ sal_uInt16 nSelectedAction = aMenu->Execute(m_aTBPreview.get(), m_aTBPreview->GetItemRect( SID_DB_APP_DISABLE_PREVIEW ));
+ // "cleanup" the toolbox state
+ MouseEvent aLeave( aPoint, 0, MouseEventModifiers::LEAVEWINDOW | MouseEventModifiers::SYNTHETIC );
+ m_aTBPreview->MouseMove( aLeave );
+ m_aTBPreview->SetItemDown( SID_DB_APP_DISABLE_PREVIEW, false);
+ if ( nSelectedAction )
+ {
+ m_aTBPreview->SetItemText(SID_DB_APP_DISABLE_PREVIEW, stripTrailingDots(aMenu->GetItemText(nSelectedAction)));
+ Resize();
+ }
+
+ css::uno::Reference<css::lang::XComponent> xComponent(xPopupController, css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+void OAppDetailPageHelper::KeyInput( const KeyEvent& rKEvt )
+{
+ SvTreeListBox* pCurrentView = getCurrentView();
+ OSL_PRECOND( pCurrentView, "OAppDetailPageHelper::KeyInput: how this?" );
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ if ( ( KEY_RETURN == nCode ) && pCurrentView )
+ {
+ getBorderWin().getView()->getAppController().onEntryDoubleClick( *pCurrentView );
+ }
+ else
+ Window::KeyInput(rKEvt);
+}
+
+void OAppDetailPageHelper::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+
+ {
+ ImplInitSettings();
+ if ( m_pLists[ E_TABLE ] )
+ {
+ OTableTreeListBox* pTableTree = dynamic_cast< OTableTreeListBox* >( m_pLists[ E_TABLE ].get() );
+ OSL_ENSURE( pTableTree != nullptr, "OAppDetailPageHelper::DataChanged: a tree list for tables which is no TableTreeList?" );
+ if ( pTableTree )
+ pTableTree->notifyHiContrastChanged();
+ }
+ }
+}
+
+void OAppDetailPageHelper::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+ m_aTBPreview->SetPointFont(*m_aTBPreview, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+ m_aBorder->SetTextColor( rStyleSettings.GetFieldTextColor() );
+ m_aBorder->SetTextFillColor();
+ m_aTBPreview->SetTextColor( rStyleSettings.GetFieldTextColor() );
+ m_aTBPreview->SetTextFillColor();
+ SetBackground( rStyleSettings.GetFieldColor() );
+ m_aBorder->SetBackground( rStyleSettings.GetFieldColor() );
+ m_aFL->SetBackground( rStyleSettings.GetFieldColor() );
+ m_aDocumentInfo->SetBackground( rStyleSettings.GetFieldColor() );
+ m_aTBPreview->SetBackground( rStyleSettings.GetFieldColor() );
+ m_pTablePreview->SetBackground( rStyleSettings.GetFieldColor() );
+}
+
+OPreviewWindow::OPreviewWindow(vcl::Window* _pParent)
+: Window(_pParent)
+{
+ ImplInitSettings();
+}
+
+bool OPreviewWindow::ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const
+{
+ const Size aWinSize( GetOutputSizePixel() );
+ Size aNewSize( LogicToPixel( rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode() ) );
+ bool bRet = false;
+
+ if( aNewSize.Width() && aNewSize.Height() )
+ {
+ // scale to fit window
+ const double fGrfWH = static_cast<double>(aNewSize.Width()) / aNewSize.Height();
+ const double fWinWH = static_cast<double>(aWinSize.Width()) / aWinSize.Height();
+
+ if ( fGrfWH < fWinWH )
+ {
+ aNewSize.setWidth( static_cast<long>( aWinSize.Height() * fGrfWH ) );
+ aNewSize.setHeight( aWinSize.Height() );
+ }
+ else
+ {
+ aNewSize.setWidth( aWinSize.Width() );
+ aNewSize.setHeight( static_cast<long>( aWinSize.Width() / fGrfWH) );
+ }
+
+ const Point aNewPos( ( aWinSize.Width() - aNewSize.Width() ) >> 1,
+ ( aWinSize.Height() - aNewSize.Height() ) >> 1 );
+
+ rResultRect = tools::Rectangle( aNewPos, aNewSize );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void OPreviewWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ Window::Paint(rRenderContext, rRect);
+
+ if (ImplGetGraphicCenterRect(m_aGraphicObj.GetGraphic(), m_aPreviewRect))
+ {
+ const Point aPos(m_aPreviewRect.TopLeft());
+ const Size aSize(m_aPreviewRect.GetSize());
+
+ if (m_aGraphicObj.IsAnimated())
+ m_aGraphicObj.StartAnimation(&rRenderContext, aPos, aSize);
+ else
+ m_aGraphicObj.Draw(&rRenderContext, aPos, aSize);
+ }
+}
+
+void OPreviewWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OPreviewWindow::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.hxx b/dbaccess/source/ui/app/AppDetailPageHelper.hxx
new file mode 100644
index 000000000..1dd89d84a
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailPageHelper.hxx
@@ -0,0 +1,350 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILPAGEHELPER_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILPAGEHELPER_HXX
+
+#include <vector>
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <AppElementType.hxx>
+#include <vcl/treelistbox.hxx>
+#include <svtools/DocumentInfoPreview.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/GraphicObject.hxx>
+
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::frame { class XFrame2; }
+namespace com::sun::star::io { class XPersist; }
+
+#define ELEMENT_COUNT size_t(E_ELEMENT_TYPE_COUNT)
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class DBTreeListBox;
+
+ class OPreviewWindow : public vcl::Window
+ {
+ GraphicObject m_aGraphicObj;
+ tools::Rectangle m_aPreviewRect;
+
+ /** gets the graphic center rect
+ @param rGraphic
+ the graphic
+ @param rResultRect
+ the resulting rectangle
+
+ @return
+ <TRUE/> when successful
+ */
+ bool ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const;
+ void ImplInitSettings();
+ protected:
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+ public:
+ explicit OPreviewWindow(vcl::Window* _pParent);
+
+ // Window overrides
+ virtual void Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect) override;
+
+ void setGraphic(const Graphic& _rGraphic ) { m_aGraphicObj.SetGraphic(_rGraphic); }
+ };
+ // A helper class for the controls in the detail page.
+ // Combines general functionality.
+ class OAppDetailPageHelper : public vcl::Window
+ {
+ VclPtr<DBTreeListBox> m_pLists[ELEMENT_COUNT];
+ OAppBorderWindow& m_rBorderWin;
+ VclPtr<FixedLine> m_aFL;
+ VclPtr<ToolBox> m_aTBPreview;
+ VclPtr<Window> m_aBorder;
+ VclPtr<OPreviewWindow> m_aPreview;
+ VclPtr< ::svtools::ODocumentInfoPreview>
+ m_aDocumentInfo;
+ VclPtr<vcl::Window> m_pTablePreview;
+ PreviewMode m_ePreviewMode;
+ css::uno::Reference < css::frame::XFrame2 >
+ m_xFrame;
+ css::uno::Reference< css::awt::XWindow >
+ m_xWindow;
+
+ /// returns the index of the visible control
+ int getVisibleControlIndex() const;
+
+ /** sorts the entries in the tree list box.
+ @param _nPos
+ Which list should be sorted.
+ @param _eSortMode
+ How should be sorted.
+ */
+ void sort(int _nPos,SvSortMode _eSortMode );
+
+ /** retrieves the resource ids of the images representing elements of the given type
+ */
+ static OUString getElementIcons(ElementType _eType);
+
+ /** fills the names in the listbox
+ @param _xContainer
+ This can either be the queries, forms or report names.
+ @param _eType
+ the type of elements which are being filled
+ @param _nImageId
+ the resource id of the image to use for non-container entries
+ @param _pParent
+ The parent of the entries to be inserted.
+ */
+ void fillNames( const css::uno::Reference< css::container::XNameAccess >& _xContainer,
+ const ElementType _eType,
+ const OUString& rImageId,
+ SvTreeListEntry* _pParent );
+
+ /** sets the detail page
+ @param _pWindow
+ The control which should be visible.
+ */
+ void setDetailPage(vcl::Window* _pWindow);
+
+ /** sets all HandleCallbacks
+ @param _pTreeView
+ The newly created DBTreeListBox
+ @param _rImage
+ the resource id of the default icon
+ @return
+ The new tree.
+ */
+ DBTreeListBox* createTree( DBTreeListBox* _pTreeView, const Image& _rImage );
+
+ /** creates the tree and sets all HandleCallbacks
+ @param _nHelpId
+ The help id of the control
+ @param _nCollapsedBitmap
+ The image to use in high contrast mode.
+ @return
+ The new tree.
+ */
+ DBTreeListBox* createSimpleTree( const OString& _sHelpId, const Image& _rImage);
+
+ DECL_LINK( OnEntryDoubleClick, SvTreeListBox*, bool );
+ DECL_LINK( OnEntryEnterKey, DBTreeListBox*, void );
+ DECL_LINK( OnEntrySelChange, LinkParamNone*, void );
+
+ DECL_LINK( OnCopyEntry, LinkParamNone*, void );
+ DECL_LINK( OnPasteEntry, LinkParamNone*, void );
+ DECL_LINK( OnDeleteEntry, LinkParamNone*, void );
+
+ // click a TB slot
+ DECL_LINK(OnDropdownClickHdl, ToolBox*, void);
+
+ OAppBorderWindow& getBorderWin() const { return m_rBorderWin; }
+ void ImplInitSettings();
+
+ public:
+ OAppDetailPageHelper(vcl::Window* _pParent,OAppBorderWindow& _rBorderWin,PreviewMode _ePreviewMode);
+ virtual ~OAppDetailPageHelper() override;
+ virtual void dispose() override;
+
+ // Window overrides
+ virtual void Resize() override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+
+ /** creates the tables page
+ @param _xConnection
+ The connection to get the table names
+ */
+ void createTablesPage(const css::uno::Reference< css::sdbc::XConnection>& _xConnection);
+
+ /** creates the page for the specific type.
+ @param _eType
+ The type which should be created. E_TABLE isn't allowed.
+ @param _xContainer
+ The container of the elements to be inserted.
+ */
+ void createPage(ElementType _eType,const css::uno::Reference< css::container::XNameAccess >& _xContainer);
+
+ /** returns the current visible tree list box
+ */
+ DBTreeListBox* getCurrentView() const
+ {
+ ElementType eType = getElementType();
+ return (eType != E_NONE ) ? m_pLists[static_cast<sal_Int32>(eType)].get() : nullptr;
+ }
+
+ /// select all entries in the visible control
+ void selectAll();
+
+ /// returns <TRUE/> if it sorts ascending
+ bool isSortUp() const;
+
+ /// sorts all entries ascending
+ void sortDown();
+
+ /// sorts all entries descending
+ void sortUp();
+
+ /** returns the element names which are selected
+ @param _rNames
+ The list will be filled.
+ */
+ void getSelectionElementNames( std::vector< OUString>& _rNames ) const;
+
+ /** describes the current selection for the given control
+ */
+ void describeCurrentSelectionForControl(
+ const Control& _rControl,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** describes the current selection for the given ElementType
+ */
+ void describeCurrentSelectionForType(
+ const ElementType _eType,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** select all names on the currently selected container. Non existence names where ignored.
+ *
+ * \param _aNames the element names
+ */
+ void selectElements(const css::uno::Sequence< OUString>& _aNames);
+
+ /** return the qualified name.
+ @param _pEntry
+ The entry of a table, or query, form, report to get the qualified name.
+ If the entry is <NULL/>, the first selected is chosen.
+ @return
+ the qualified name
+ */
+ OUString getQualifiedName( SvTreeListEntry* _pEntry ) const;
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /// returns the count of selected entries
+ sal_Int32 getSelectionCount();
+
+ /// returns the count of entries
+ sal_Int32 getElementCount() const;
+
+ /** returns if an entry is a leaf
+ @param _pEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ static bool isLeaf(SvTreeListEntry const * _pEntry);
+
+ /** returns if one of the selected entries is a leaf
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isALeafSelected() const;
+
+ SvTreeListEntry* getEntry( const Point& _aPosPixel ) const;
+
+ /// clears the detail pages
+ void clearPages();
+
+ /// returns <TRUE/> when a detail page was filled
+ bool isFilled() const;
+
+ /** adds a new object to the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the object to be inserted
+ @param _rObject
+ The object to add.
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ SvTreeListEntry* elementAdded(ElementType eType
+ ,const OUString& _rName
+ ,const css::uno::Any& _rObject );
+
+ /** replaces an objects name with a new one
+ @param _eType
+ The type where the entry should be appended.
+ @param _rOldName
+ The old name of the object to be replaced
+ @param _rNewName
+ The new name of the object to be replaced
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ void elementReplaced(ElementType eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName );
+
+ /** removes an element from the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the element to be removed.
+ @param _rxConn
+ If we remove a table, the connection must be set.
+ */
+ void elementRemoved(ElementType _eType
+ ,const OUString& _rName );
+
+ /// returns the preview mode
+ PreviewMode getPreviewMode() const { return m_ePreviewMode;}
+
+ /// <TRUE/> if the preview is enabled
+ bool isPreviewEnabled() const;
+
+ /** switches to the given preview mode
+ @param _eMode
+ the mode to set for the preview
+ @param _bForce
+ Force the preview to be reset
+ */
+ void switchPreview(PreviewMode _eMode,bool _bForce = false);
+
+ /** shows the Preview of the content when it is enabled.
+ @param _xContent
+ The content which must support the "preview" command.
+ */
+ void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent);
+
+ /** shows the Preview of a table or query
+ @param _sDataSourceName
+ the name of the data source
+ @param _sName
+ the name of table or query
+ @param _bTable
+ <TRUE/> if it is a table, otherwise <FALSE/>
+ @return void
+ */
+ void showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable);
+
+ protected:
+ void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ };
+}
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILPAGEHELPER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailView.cxx b/dbaccess/source/ui/app/AppDetailView.cxx
new file mode 100644
index 000000000..39da2cd49
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailView.cxx
@@ -0,0 +1,877 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppDetailView.hxx"
+#include <osl/diagnose.h>
+#include <helpids.h>
+#include <strings.hrc>
+#include "AppView.hxx"
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XImageManager.hpp>
+#include <com/sun/star/ui/ImageType.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <core_resource.hxx>
+#include <vcl/event.hxx>
+#include <vcl/image.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/settings.hxx>
+#include "AppDetailPageHelper.hxx"
+#include <dbaccess/IController.hxx>
+#include <vcl/treelistentry.hxx>
+#include <vcl/viewdataentry.hxx>
+#include <algorithm>
+#include <dbtreelistbox.hxx>
+#include <imageprovider.hxx>
+#include "AppController.hxx"
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::graphic;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using ::com::sun::star::util::URL;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+#define SPACEBETWEENENTRIES 4
+
+TaskEntry::TaskEntry( const char* _pAsciiUNOCommand, const char* _pHelpID, const char* pTitleResourceID, bool _bHideWhenDisabled )
+ :sUNOCommand( OUString::createFromAscii( _pAsciiUNOCommand ) )
+ ,pHelpID( _pHelpID )
+ ,sTitle( DBA_RES(pTitleResourceID) )
+ ,bHideWhenDisabled( _bHideWhenDisabled )
+{
+}
+
+OCreationList::OCreationList( OTasksWindow& _rParent )
+ :SvTreeListBox( &_rParent, WB_TABSTOP | WB_HASBUTTONSATROOT | WB_HASBUTTONS )
+ ,m_rTaskWindow( _rParent )
+ ,m_pMouseDownEntry( nullptr )
+ ,m_pLastActiveEntry( nullptr )
+{
+ SetSpaceBetweenEntries(SPACEBETWEENENTRIES);
+ SetSelectionMode( SelectionMode::NONE );
+ SetNoAutoCurEntry( true );
+ SetNodeDefaultImages( );
+ EnableEntryMnemonics();
+}
+
+void OCreationList::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect )
+{
+ SetBackground();
+
+ if (m_pMouseDownEntry)
+ m_aOriginalFont = rRenderContext.GetFont();
+
+ m_aOriginalBackgroundColor = rRenderContext.GetBackground().GetColor();
+ SvTreeListBox::Paint(rRenderContext, _rRect);
+ rRenderContext.SetBackground(m_aOriginalBackgroundColor);
+
+ if (m_pMouseDownEntry)
+ rRenderContext.SetFont(m_aOriginalFont);
+}
+
+void OCreationList::PreparePaint(vcl::RenderContext& rRenderContext, SvTreeListEntry& rEntry)
+{
+ Wallpaper aEntryBackground(m_aOriginalBackgroundColor);
+
+ if (&rEntry == GetCurEntry())
+ {
+ // draw a selection background
+ bool bIsMouseDownEntry = ( &rEntry == m_pMouseDownEntry );
+ vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, GetBoundingRect(&rEntry),
+ bIsMouseDownEntry ? 1 : 2, false, true, false );
+
+ if (bIsMouseDownEntry)
+ {
+ vcl::Font aFont(rRenderContext.GetFont());
+ aFont.SetColor(rRenderContext.GetSettings().GetStyleSettings().GetHighlightTextColor());
+ rRenderContext.SetFont(aFont);
+ }
+
+ // and temporary set a transparent background, for all the other
+ // paint operations the SvTreeListBox is going to do
+ aEntryBackground = Wallpaper();
+ }
+
+ rRenderContext.SetBackground(aEntryBackground);
+ rEntry.SetBackColor(aEntryBackground.GetColor());
+}
+
+void OCreationList::SelectSearchEntry( const void* _pEntry )
+{
+ SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
+ OSL_ENSURE( pEntry, "OCreationList::SelectSearchEntry: invalid entry!" );
+
+ if ( pEntry )
+ setCurrentEntryInvalidate( pEntry );
+
+ if ( !HasChildPathFocus() )
+ GrabFocus();
+}
+
+void OCreationList::ExecuteSearchEntry( const void* _pEntry ) const
+{
+ SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
+ OSL_ENSURE( pEntry, "OCreationList::ExecuteSearchEntry: invalid entry!" );
+ OSL_ENSURE( pEntry == GetCurEntry(), "OCreationList::ExecuteSearchEntry: SelectSearchEntry should have been called before!" );
+
+ if ( pEntry )
+ onSelected( pEntry );
+}
+
+tools::Rectangle OCreationList::GetFocusRect(const SvTreeListEntry* _pEntry, long _nLine)
+{
+ tools::Rectangle aRect = SvTreeListBox::GetFocusRect( _pEntry, _nLine );
+ aRect.SetLeft( 0 );
+
+ // try to let the focus rect start before the bitmap item - this looks better
+ const SvLBoxItem* pBitmapItem = _pEntry->GetFirstItem(SvLBoxItemType::ContextBmp);
+ SvLBoxTab* pTab = pBitmapItem ? GetTab( _pEntry, pBitmapItem ) : nullptr;
+ SvViewDataItem* pItemData = pBitmapItem ? GetViewDataItem( _pEntry, pBitmapItem ) : nullptr;
+ OSL_ENSURE( pTab && pItemData, "OCreationList::GetFocusRect: could not find the first bitmap item!" );
+ if ( pTab && pItemData )
+ aRect.SetLeft( pTab->GetPos() - pItemData->mnWidth / 2 );
+
+ // inflate the rectangle a little bit - looks better, too
+ aRect.SetLeft( std::max< long >( 0, aRect.Left() - 2 ) );
+ aRect.SetRight( std::min< long >( GetOutputSizePixel().Width() - 1, aRect.Right() + 2 ) );
+
+ return aRect;
+}
+
+void OCreationList::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ )
+{
+ // don't give this to the base class, it does a ReleaseMouse as very first action
+ // Though I think this is a bug (it should ReleaseMouse only if it is going to do
+ // something with the drag-event), I hesitate to fix it in the current state,
+ // since I don't overlook the consequences, and we're close to 2.0...)
+}
+
+void OCreationList::ModelHasCleared()
+{
+ SvTreeListBox::ModelHasCleared();
+ m_pLastActiveEntry = nullptr;
+ m_pMouseDownEntry = nullptr;
+}
+
+void OCreationList::GetFocus()
+{
+ SvTreeListBox::GetFocus();
+ if ( !GetCurEntry() )
+ setCurrentEntryInvalidate( m_pLastActiveEntry ? m_pLastActiveEntry : GetFirstEntryInView() );
+}
+
+void OCreationList::LoseFocus()
+{
+ SvTreeListBox::LoseFocus();
+ m_pLastActiveEntry = GetCurEntry();
+ setCurrentEntryInvalidate( nullptr );
+}
+
+void OCreationList::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ SvTreeListBox::MouseButtonDown( rMEvt );
+
+ OSL_ENSURE( !m_pMouseDownEntry, "OCreationList::MouseButtonDown: I missed some mouse event!" );
+ m_pMouseDownEntry = GetCurEntry();
+ if ( m_pMouseDownEntry )
+ {
+ InvalidateEntry( m_pMouseDownEntry );
+ CaptureMouse();
+ }
+}
+
+void OCreationList::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeaveWindow() )
+ {
+ setCurrentEntryInvalidate( nullptr );
+ }
+ else if ( !rMEvt.IsSynthetic() )
+ {
+ SvTreeListEntry* pEntry = GetEntry( rMEvt.GetPosPixel() );
+
+ if ( m_pMouseDownEntry )
+ {
+ // we're currently in a "mouse down" phase
+ OSL_ENSURE( IsMouseCaptured(), "OCreationList::MouseMove: inconsistence (1)!" );
+ if ( pEntry == m_pMouseDownEntry )
+ {
+ setCurrentEntryInvalidate( m_pMouseDownEntry );
+ }
+ else
+ {
+ OSL_ENSURE( ( GetCurEntry() == m_pMouseDownEntry ) || !GetCurEntry(),
+ "OCreationList::MouseMove: inconsistence (2)!" );
+ setCurrentEntryInvalidate( nullptr );
+ }
+ }
+ else
+ {
+ // the user is simply hovering with the mouse
+ if ( setCurrentEntryInvalidate( pEntry ) )
+ {
+ if ( !m_pMouseDownEntry )
+ updateHelpText();
+ }
+ }
+ }
+
+ SvTreeListBox::MouseMove(rMEvt);
+}
+
+void OCreationList::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ SvTreeListEntry* pEntry = GetEntry( rMEvt.GetPosPixel() );
+ bool bExecute = false;
+ // Was the mouse released over the active entry?
+ // (i.e. the entry which was under the mouse when the button went down)
+ if ( pEntry && ( m_pMouseDownEntry == pEntry ) )
+ {
+ if ( !rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() && rMEvt.IsLeft() && rMEvt.GetClicks() == 1 )
+ bExecute = true;
+ }
+
+ if ( m_pMouseDownEntry )
+ {
+ OSL_ENSURE( IsMouseCaptured(), "OCreationList::MouseButtonUp: hmmm... no mouse captured, but an active entry?" );
+ ReleaseMouse();
+
+ InvalidateEntry( m_pMouseDownEntry );
+ m_pMouseDownEntry = nullptr;
+ }
+
+ SvTreeListBox::MouseButtonUp( rMEvt );
+
+ if ( bExecute )
+ onSelected( pEntry );
+}
+
+bool OCreationList::setCurrentEntryInvalidate( SvTreeListEntry* _pEntry )
+{
+ if ( GetCurEntry() != _pEntry )
+ {
+ if ( GetCurEntry() )
+ InvalidateEntry( GetCurEntry() );
+ SetCurEntry( _pEntry );
+ if ( GetCurEntry() )
+ {
+ InvalidateEntry( GetCurEntry() );
+ CallEventListeners( VclEventId::ListboxTreeSelect, GetCurEntry() );
+ }
+ updateHelpText();
+ return true;
+ }
+ return false;
+}
+
+void OCreationList::updateHelpText()
+{
+ const char* pHelpTextId = nullptr;
+ if ( GetCurEntry() )
+ pHelpTextId = static_cast< TaskEntry* >( GetCurEntry()->GetUserData() )->pHelpID;
+ m_rTaskWindow.setHelpText(pHelpTextId);
+}
+
+void OCreationList::onSelected( SvTreeListEntry const * _pEntry ) const
+{
+ OSL_ENSURE( _pEntry, "OCreationList::onSelected: invalid entry!" );
+ URL aCommand;
+ aCommand.Complete = static_cast< TaskEntry* >( _pEntry->GetUserData() )->sUNOCommand;
+ m_rTaskWindow.getDetailView()->getBorderWin().getView()->getAppController().executeChecked( aCommand, Sequence< PropertyValue >() );
+}
+
+void OCreationList::KeyInput( const KeyEvent& rKEvt )
+{
+ const vcl::KeyCode& rCode = rKEvt.GetKeyCode();
+ if ( !rCode.IsMod1() && !rCode.IsMod2() && !rCode.IsShift() )
+ {
+ if ( rCode.GetCode() == KEY_RETURN )
+ {
+ SvTreeListEntry* pEntry = GetCurEntry() ? GetCurEntry() : FirstSelected();
+ if ( pEntry )
+ onSelected( pEntry );
+ return;
+ }
+ }
+ SvTreeListEntry* pOldCurrent = GetCurEntry();
+ SvTreeListBox::KeyInput(rKEvt);
+ SvTreeListEntry* pNewCurrent = GetCurEntry();
+
+ if ( pOldCurrent != pNewCurrent )
+ {
+ if ( pOldCurrent )
+ InvalidateEntry( pOldCurrent );
+ if ( pNewCurrent )
+ {
+ InvalidateEntry( pNewCurrent );
+ CallEventListeners( VclEventId::ListboxSelect, pNewCurrent );
+ }
+ updateHelpText();
+ }
+}
+
+OTasksWindow::OTasksWindow(vcl::Window* _pParent,OApplicationDetailView* _pDetailView)
+ : Window(_pParent,WB_DIALOGCONTROL )
+ ,m_aCreation(VclPtr<OCreationList>::Create(*this))
+ ,m_aDescription(VclPtr<FixedText>::Create(this))
+ ,m_aHelpText(VclPtr<FixedText>::Create(this,WB_WORDBREAK))
+ ,m_aFL(VclPtr<FixedLine>::Create(this,WB_VERT))
+ ,m_pDetailView(_pDetailView)
+{
+ m_aCreation->SetHelpId(HID_APP_CREATION_LIST);
+ m_aCreation->SetSelectHdl(LINK(this, OTasksWindow, OnEntrySelectHdl));
+ m_aHelpText->SetHelpId(HID_APP_HELP_TEXT);
+ m_aDescription->SetHelpId(HID_APP_DESCRIPTION_TEXT);
+ m_aDescription->SetText(DBA_RES(STR_DESCRIPTION));
+
+ Image aFolderImage = ImageProvider::getFolderImage( css::sdb::application::DatabaseObject::FORM );
+ m_aCreation->SetDefaultCollapsedEntryBmp( aFolderImage );
+ m_aCreation->SetDefaultExpandedEntryBmp( aFolderImage );
+
+ ImplInitSettings();
+}
+
+OTasksWindow::~OTasksWindow()
+{
+ disposeOnce();
+}
+
+void OTasksWindow::dispose()
+{
+ Clear();
+ m_aCreation.disposeAndClear();
+ m_aDescription.disposeAndClear();
+ m_aHelpText.disposeAndClear();
+ m_aFL.disposeAndClear();
+ m_pDetailView.clear();
+ vcl::Window::dispose();
+}
+
+void OTasksWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OTasksWindow::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+ m_aHelpText->SetTextColor( rStyleSettings.GetFieldTextColor() );
+ m_aHelpText->SetTextFillColor();
+ m_aDescription->SetTextColor( rStyleSettings.GetFieldTextColor() );
+ m_aDescription->SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+ m_aHelpText->SetBackground( rStyleSettings.GetFieldColor() );
+ m_aDescription->SetBackground( rStyleSettings.GetFieldColor() );
+ m_aFL->SetBackground( rStyleSettings.GetFieldColor() );
+
+ aFont = m_aDescription->GetControlFont();
+ aFont.SetWeight(WEIGHT_BOLD);
+ m_aDescription->SetControlFont(aFont);
+}
+
+void OTasksWindow::setHelpText(const char* pId)
+{
+ if (pId)
+ {
+ OUString sText = DBA_RES(pId);
+ m_aHelpText->SetText(sText);
+ }
+ else
+ {
+ m_aHelpText->SetText(OUString());
+}
+
+}
+
+IMPL_LINK_NOARG(OTasksWindow, OnEntrySelectHdl, SvTreeListBox*, void)
+{
+ SvTreeListEntry* pEntry = m_aCreation->GetHdlEntry();
+ if ( pEntry )
+ m_aHelpText->SetText(DBA_RES(static_cast<TaskEntry*>(pEntry->GetUserData())->pHelpID));
+}
+
+void OTasksWindow::Resize()
+{
+ // parent window dimension
+ Size aOutputSize( GetOutputSize() );
+ long nOutputWidth = aOutputSize.Width();
+ long nOutputHeight = aOutputSize.Height();
+
+ Size aFLSize = LogicToPixel(Size(2, 6), MapMode(MapUnit::MapAppFont));
+ sal_Int32 n6PPT = aFLSize.Height();
+ long nHalfOutputWidth = static_cast<long>(nOutputWidth * 0.5);
+
+ m_aCreation->SetPosSizePixel( Point(0, 0), Size(nHalfOutputWidth - n6PPT, nOutputHeight) );
+ // i77897 make the m_aHelpText a little bit smaller. (-5)
+ sal_Int32 nNewWidth = nOutputWidth - nHalfOutputWidth - aFLSize.Width() - 5;
+ m_aDescription->SetPosSizePixel( Point(nHalfOutputWidth + n6PPT, 0), Size(nNewWidth, nOutputHeight) );
+ Size aDesc = m_aDescription->CalcMinimumSize();
+ m_aHelpText->SetPosSizePixel( Point(nHalfOutputWidth + n6PPT, aDesc.Height() ), Size(nNewWidth, nOutputHeight - aDesc.Height() - n6PPT) );
+
+ m_aFL->SetPosSizePixel( Point(nHalfOutputWidth , 0), Size(aFLSize.Width(), nOutputHeight ) );
+}
+
+void OTasksWindow::fillTaskEntryList( const TaskEntryList& _rList )
+{
+ Clear();
+
+ try
+ {
+ Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
+ theModuleUIConfigurationManagerSupplier::get( getDetailView()->getBorderWin().getView()->getORB() );
+ Reference< XUIConfigurationManager > xUIConfigMgr = xModuleCfgMgrSupplier->getUIConfigurationManager(
+ "com.sun.star.sdb.OfficeDatabaseDocument"
+ );
+ Reference< XImageManager > xImageMgr( xUIConfigMgr->getImageManager(), UNO_QUERY );
+
+ // copy the commands so we can use them with the config managers
+ Sequence< OUString > aCommands( _rList.size() );
+ OUString* pCommands = aCommands.getArray();
+ for (auto const& copyTask : _rList)
+ {
+ *pCommands = copyTask.sUNOCommand;
+ ++pCommands;
+ }
+
+ Sequence< Reference< XGraphic> > aImages = xImageMgr->getImages(
+ ImageType::SIZE_DEFAULT | ImageType::COLOR_NORMAL ,
+ aCommands
+ );
+
+ const Reference< XGraphic >* pImages( aImages.getConstArray() );
+
+ for (auto const& task : _rList)
+ {
+ SvTreeListEntry* pEntry = m_aCreation->InsertEntry(task.sTitle);
+ pEntry->SetUserData( new TaskEntry(task) );
+
+ Image aImage( *pImages );
+ m_aCreation->SetExpandedEntryBmp( pEntry, aImage );
+ m_aCreation->SetCollapsedEntryBmp( pEntry, aImage );
+ ++pImages;
+ }
+ }
+ catch(Exception&)
+ {
+ }
+
+ m_aCreation->Show();
+ m_aCreation->SelectAll(false);
+ m_aHelpText->Show();
+ m_aDescription->Show();
+ m_aFL->Show();
+ m_aCreation->updateHelpText();
+ Enable(!_rList.empty());
+}
+
+void OTasksWindow::Clear()
+{
+ m_aCreation->resetLastActive();
+ SvTreeListEntry* pEntry = m_aCreation->First();
+ while ( pEntry )
+ {
+ delete static_cast< TaskEntry* >( pEntry->GetUserData() );
+ pEntry = m_aCreation->Next(pEntry);
+ }
+ m_aCreation->Clear();
+}
+
+
+OApplicationDetailView::OApplicationDetailView(OAppBorderWindow& _rParent,PreviewMode _ePreviewMode) : OSplitterView(&_rParent )
+ ,m_aHorzSplitter(VclPtr<Splitter>::Create(this))
+ ,m_aTasks(VclPtr<dbaui::OTitleWindow>::Create(this, STR_TASKS, WB_BORDER | WB_DIALOGCONTROL))
+ ,m_aContainer(VclPtr<dbaui::OTitleWindow>::Create(this, nullptr, WB_BORDER | WB_DIALOGCONTROL))
+ ,m_rBorderWin(_rParent)
+{
+ ImplInitSettings();
+
+ m_pControlHelper = VclPtr<OAppDetailPageHelper>::Create(m_aContainer.get(),m_rBorderWin,_ePreviewMode);
+ m_pControlHelper->Show();
+ m_aContainer->setChildWindow(m_pControlHelper);
+
+ VclPtrInstance<OTasksWindow> pTasks(m_aTasks.get(),this);
+ pTasks->Show();
+ pTasks->Disable(m_rBorderWin.getView()->getCommandController().isDataSourceReadOnly());
+ m_aTasks->setChildWindow(pTasks);
+ m_aTasks->Show();
+
+ m_aContainer->Show();
+
+ const long nFrameWidth = LogicToPixel(Size(3, 0), MapMode(MapUnit::MapAppFont)).Width();
+ m_aHorzSplitter->SetPosSizePixel( Point(0,50), Size(0,nFrameWidth) );
+ // now set the components at the base class
+ set(m_aContainer.get(),m_aTasks.get());
+
+ m_aHorzSplitter->Show();
+ setSplitter(m_aHorzSplitter.get());
+}
+
+OApplicationDetailView::~OApplicationDetailView()
+{
+ disposeOnce();
+}
+
+void OApplicationDetailView::dispose()
+{
+ set(nullptr);
+ setSplitter(nullptr);
+ m_aHorzSplitter.disposeAndClear();
+ m_aTasks.disposeAndClear();
+ m_aContainer.disposeAndClear();
+ m_pControlHelper.clear();
+ OSplitterView::dispose();
+}
+
+void OApplicationDetailView::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+
+ m_aHorzSplitter->SetBackground( rStyleSettings.GetDialogColor() );
+ m_aHorzSplitter->SetFillColor( rStyleSettings.GetDialogColor() );
+ m_aHorzSplitter->SetTextFillColor(rStyleSettings.GetDialogColor() );
+}
+
+void OApplicationDetailView::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ OSplitterView::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OApplicationDetailView::setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics )
+{
+ m_aExternalMnemonics = _rMnemonics;
+}
+
+bool OApplicationDetailView::interceptKeyInput( const KeyEvent& _rEvent )
+{
+ const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode();
+ if ( rKeyCode.GetModifier() == KEY_MOD2 )
+ return getTasksWindow().HandleKeyInput( _rEvent );
+
+ // not handled
+ return false;
+}
+
+void OApplicationDetailView::createTablesPage(const Reference< XConnection >& _xConnection )
+{
+ impl_createPage( E_TABLE, _xConnection, nullptr );
+}
+
+void OApplicationDetailView::createPage( ElementType _eType,const Reference< XNameAccess >& _xContainer )
+{
+ impl_createPage( _eType, nullptr, _xContainer );
+}
+
+void OApplicationDetailView::impl_createPage( ElementType _eType, const Reference< XConnection >& _rxConnection,
+ const Reference< XNameAccess >& _rxNonTableElements )
+{
+ // get the data for the pane
+ const TaskPaneData& rData = impl_getTaskPaneData( _eType );
+ getTasksWindow().fillTaskEntryList( rData.aTasks );
+
+ // enable the pane as a whole, depending on the availability of the first command
+ OSL_ENSURE( !rData.aTasks.empty(), "OApplicationDetailView::impl_createPage: no tasks at all!?" );
+ bool bEnabled = !rData.aTasks.empty()
+ && getBorderWin().getView()->getCommandController().isCommandEnabled( rData.aTasks[0].sUNOCommand );
+ getTasksWindow().Enable( bEnabled );
+ m_aContainer->setTitle(rData.pTitleId);
+
+ // let our helper create the object list
+ if ( _eType == E_TABLE )
+ m_pControlHelper->createTablesPage( _rxConnection );
+ else
+ m_pControlHelper->createPage( _eType, _rxNonTableElements );
+
+ // resize for proper window arrangements
+ Resize();
+}
+
+const TaskPaneData& OApplicationDetailView::impl_getTaskPaneData( ElementType _eType )
+{
+ if ( m_aTaskPaneData.empty() )
+ m_aTaskPaneData.resize( ELEMENT_COUNT );
+ OSL_ENSURE( ( _eType >= 0 ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OApplicationDetailView::impl_getTaskPaneData: illegal element type!" );
+ TaskPaneData& rData = m_aTaskPaneData[ _eType ];
+
+ //oj: do not check, otherwise extensions will only be visible after a reload.
+ impl_fillTaskPaneData( _eType, rData );
+
+ return rData;
+}
+
+void OApplicationDetailView::impl_fillTaskPaneData( ElementType _eType, TaskPaneData& _rData ) const
+{
+ TaskEntryList& rList( _rData.aTasks );
+ rList.clear(); rList.reserve( 4 );
+
+ switch ( _eType )
+ {
+ case E_TABLE:
+ rList.emplace_back( ".uno:DBNewTable", RID_STR_TABLES_HELP_TEXT_DESIGN, RID_STR_NEW_TABLE );
+ rList.emplace_back( ".uno:DBNewTableAutoPilot", RID_STR_TABLES_HELP_TEXT_WIZARD, RID_STR_NEW_TABLE_AUTO );
+ rList.emplace_back( ".uno:DBNewView", RID_STR_VIEWS_HELP_TEXT_DESIGN, RID_STR_NEW_VIEW, true );
+ _rData.pTitleId = RID_STR_TABLES_CONTAINER;
+ break;
+
+ case E_FORM:
+ rList.emplace_back( ".uno:DBNewForm", RID_STR_FORMS_HELP_TEXT, RID_STR_NEW_FORM );
+ rList.emplace_back( ".uno:DBNewFormAutoPilot", RID_STR_FORMS_HELP_TEXT_WIZARD, RID_STR_NEW_FORM_AUTO );
+ _rData.pTitleId = RID_STR_FORMS_CONTAINER;
+ break;
+
+ case E_REPORT:
+ rList.emplace_back( ".uno:DBNewReport", RID_STR_REPORT_HELP_TEXT, RID_STR_NEW_REPORT, true );
+ rList.emplace_back( ".uno:DBNewReportAutoPilot", RID_STR_REPORTS_HELP_TEXT_WIZARD, RID_STR_NEW_REPORT_AUTO );
+ _rData.pTitleId = RID_STR_REPORTS_CONTAINER;
+ break;
+
+ case E_QUERY:
+ rList.emplace_back( ".uno:DBNewQuery", RID_STR_QUERIES_HELP_TEXT, RID_STR_NEW_QUERY );
+ rList.emplace_back( ".uno:DBNewQueryAutoPilot", RID_STR_QUERIES_HELP_TEXT_WIZARD, RID_STR_NEW_QUERY_AUTO );
+ rList.emplace_back( ".uno:DBNewQuerySql", RID_STR_QUERIES_HELP_TEXT_SQL, RID_STR_NEW_QUERY_SQL );
+ _rData.pTitleId = RID_STR_QUERIES_CONTAINER;
+ break;
+
+ default:
+ OSL_FAIL( "OApplicationDetailView::impl_fillTaskPaneData: illegal element type!" );
+ }
+
+ MnemonicGenerator aAllMnemonics( m_aExternalMnemonics );
+
+ // remove the entries which are not enabled currently
+ for ( TaskEntryList::iterator pTask = rList.begin();
+ pTask != rList.end();
+ )
+ {
+ if ( pTask->bHideWhenDisabled
+ && !getBorderWin().getView()->getCommandController().isCommandEnabled( pTask->sUNOCommand )
+ )
+ pTask = rList.erase( pTask );
+ else
+ {
+ aAllMnemonics.RegisterMnemonic( pTask->sTitle );
+ ++pTask;
+ }
+ }
+
+ // for the remaining entries, assign mnemonics
+ for (auto const& task : rList)
+ {
+ aAllMnemonics.CreateMnemonic(task.sTitle);
+ // don't do this for now, until our task window really supports mnemonics
+ }
+}
+
+OUString OApplicationDetailView::getQualifiedName( SvTreeListEntry* _pEntry ) const
+{
+ return m_pControlHelper->getQualifiedName( _pEntry );
+}
+
+bool OApplicationDetailView::isLeaf(SvTreeListEntry const * _pEntry)
+{
+ return OAppDetailPageHelper::isLeaf(_pEntry);
+}
+
+bool OApplicationDetailView::isALeafSelected() const
+{
+ return m_pControlHelper->isALeafSelected();
+}
+
+void OApplicationDetailView::selectAll()
+{
+ m_pControlHelper->selectAll();
+}
+
+void OApplicationDetailView::sortDown()
+{
+ m_pControlHelper->sortDown();
+}
+
+void OApplicationDetailView::sortUp()
+{
+ m_pControlHelper->sortUp();
+}
+
+bool OApplicationDetailView::isFilled() const
+{
+ return m_pControlHelper->isFilled();
+}
+
+ElementType OApplicationDetailView::getElementType() const
+{
+ return m_pControlHelper->getElementType();
+}
+
+void OApplicationDetailView::clearPages(bool _bTaskAlso)
+{
+ if ( _bTaskAlso )
+ getTasksWindow().Clear();
+ m_pControlHelper->clearPages();
+}
+
+sal_Int32 OApplicationDetailView::getSelectionCount()
+{
+ return m_pControlHelper->getSelectionCount();
+}
+
+sal_Int32 OApplicationDetailView::getElementCount() const
+{
+ return m_pControlHelper->getElementCount();
+}
+
+void OApplicationDetailView::getSelectionElementNames( std::vector< OUString>& _rNames ) const
+{
+ m_pControlHelper->getSelectionElementNames( _rNames );
+}
+
+void OApplicationDetailView::describeCurrentSelectionForControl( const Control& _rControl, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ m_pControlHelper->describeCurrentSelectionForControl( _rControl, _out_rSelectedObjects );
+}
+
+void OApplicationDetailView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ m_pControlHelper->describeCurrentSelectionForType( _eType, _out_rSelectedObjects );
+}
+
+void OApplicationDetailView::selectElements(const Sequence< OUString>& _aNames)
+{
+ m_pControlHelper->selectElements( _aNames );
+}
+
+SvTreeListEntry* OApplicationDetailView::getEntry( const Point& _aPoint ) const
+{
+ return m_pControlHelper->getEntry(_aPoint);
+}
+
+bool OApplicationDetailView::isCutAllowed()
+{
+ return false;
+}
+
+bool OApplicationDetailView::isCopyAllowed()
+{
+ return true;
+}
+
+bool OApplicationDetailView::isPasteAllowed() { return true; }
+
+void OApplicationDetailView::copy() { }
+
+void OApplicationDetailView::cut() { }
+
+void OApplicationDetailView::paste() { }
+
+SvTreeListEntry* OApplicationDetailView::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject )
+{
+ return m_pControlHelper->elementAdded(_eType,_rName, _rObject );
+}
+
+void OApplicationDetailView::elementRemoved(ElementType _eType,const OUString& _rName )
+{
+ m_pControlHelper->elementRemoved(_eType,_rName );
+}
+
+void OApplicationDetailView::elementReplaced(ElementType _eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName )
+{
+ m_pControlHelper->elementReplaced( _eType, _rOldName, _rNewName );
+}
+
+PreviewMode OApplicationDetailView::getPreviewMode() const
+{
+ return m_pControlHelper->getPreviewMode();
+}
+
+bool OApplicationDetailView::isPreviewEnabled() const
+{
+ return m_pControlHelper->isPreviewEnabled();
+}
+
+void OApplicationDetailView::switchPreview(PreviewMode _eMode)
+{
+ m_pControlHelper->switchPreview(_eMode);
+}
+
+void OApplicationDetailView::showPreview(const Reference< XContent >& _xContent)
+{
+ m_pControlHelper->showPreview(_xContent);
+}
+
+void OApplicationDetailView::showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable)
+{
+ m_pControlHelper->showPreview(_sDataSourceName,_sName,_bTable);
+}
+
+bool OApplicationDetailView::isSortUp() const
+{
+ return m_pControlHelper->isSortUp();
+}
+
+vcl::Window* OApplicationDetailView::getTreeWindow() const
+{
+ return m_pControlHelper->getCurrentView();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppDetailView.hxx b/dbaccess/source/ui/app/AppDetailView.hxx
new file mode 100644
index 000000000..38bc41ab1
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailView.hxx
@@ -0,0 +1,368 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILVIEW_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILVIEW_HXX
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <vcl/split.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/mnemonic.hxx>
+#include <IClipBoardTest.hxx>
+#include "AppTitleWindow.hxx"
+#include <AppElementType.hxx>
+#include <vcl/treelistbox.hxx>
+#include <VertSplitView.hxx>
+
+#include <vector>
+
+class SvTreeListEntry;
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class OApplicationDetailView;
+ class OAppDetailPageHelper;
+ class OTasksWindow;
+
+ class OCreationList : public SvTreeListBox
+ {
+ OTasksWindow& m_rTaskWindow;
+
+ // members related to drawing the currently hovered/selected entry
+ SvTreeListEntry* m_pMouseDownEntry;
+ SvTreeListEntry* m_pLastActiveEntry;
+ Color m_aOriginalBackgroundColor;
+ vcl::Font m_aOriginalFont;
+
+ public:
+ explicit OCreationList( OTasksWindow& _rParent );
+ // Window overrides
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual void StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+ void resetLastActive() { m_pLastActiveEntry = nullptr;}
+
+ void updateHelpText();
+
+ protected:
+ virtual void PreparePaint(vcl::RenderContext& rRenderContext, SvTreeListEntry& rEntry) override;
+ virtual tools::Rectangle GetFocusRect(const SvTreeListEntry* _pEntry, long _nLine) override;
+ virtual void ModelHasCleared() override;
+
+ // IMnemonicEntryList
+ virtual void SelectSearchEntry( const void* _pEntry ) override;
+ virtual void ExecuteSearchEntry( const void* _pEntry ) const override;
+
+ private:
+ void onSelected( SvTreeListEntry const * _pEntry ) const;
+ /** sets a new current entry, and invalidates the old and the new one, if necessary
+ @return <TRUE/> if and only if the "current entry" changed
+ */
+ bool setCurrentEntryInvalidate( SvTreeListEntry* _pEntry );
+ };
+
+ struct TaskEntry
+ {
+ OUString sUNOCommand;
+ const char* pHelpID;
+ OUString sTitle;
+ bool bHideWhenDisabled;
+ // TODO: we should be consistent in the task pane and the menus/toolbars:
+ // If an entry is disabled in the latter, it should also be disabled in the former.
+ // If an entry is *hidden* in the former, it should also be hidden in the latter.
+
+ TaskEntry( const char* _pAsciiUNOCommand, const char* pHelpID, const char* pTitleResourceID, bool _bHideWhenDisabled = false );
+ };
+ typedef std::vector< TaskEntry > TaskEntryList;
+
+ struct TaskPaneData
+ {
+ /// the tasks available in the pane
+ TaskEntryList aTasks;
+ /// the resource ID for the title of the pane
+ const char* pTitleId;
+ };
+
+ class OTasksWindow : public vcl::Window
+ {
+ VclPtr<OCreationList> m_aCreation;
+ VclPtr<FixedText> m_aDescription;
+ VclPtr<FixedText> m_aHelpText;
+ VclPtr<FixedLine> m_aFL;
+ VclPtr<OApplicationDetailView> m_pDetailView;
+
+ DECL_LINK( OnEntrySelectHdl, SvTreeListBox*, void );
+ void ImplInitSettings();
+ protected:
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+ public:
+ OTasksWindow(vcl::Window* _pParent,OApplicationDetailView* _pDetailView);
+ virtual ~OTasksWindow() override;
+ virtual void dispose() override;
+
+ // Window overrides
+ virtual void Resize() override;
+
+ OApplicationDetailView* getDetailView() const { return m_pDetailView; }
+
+ /// fills the Creation listbox with the necessary strings and images
+ void fillTaskEntryList( const TaskEntryList& _rList );
+
+ bool HandleKeyInput( const KeyEvent& _rKEvt )
+ {
+ return m_aCreation->HandleKeyInput( _rKEvt );
+ }
+
+ void Clear();
+ void setHelpText(const char* pId);
+ };
+ class OApplicationDetailView : public OSplitterView
+ , public IClipboardTest
+ {
+ VclPtr<Splitter> m_aHorzSplitter;
+ VclPtr<OTitleWindow> m_aTasks;
+ VclPtr<OTitleWindow> m_aContainer;
+ OAppBorderWindow& m_rBorderWin; // my parent
+ VclPtr<OAppDetailPageHelper> m_pControlHelper;
+ std::vector< TaskPaneData > m_aTaskPaneData;
+ MnemonicGenerator m_aExternalMnemonics;
+
+ void ImplInitSettings();
+
+ protected:
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+
+ public:
+ OApplicationDetailView(OAppBorderWindow& _rParent,PreviewMode _ePreviewMode);
+ virtual ~OApplicationDetailView() override;
+ // Window overrides
+ virtual void dispose() override;
+
+ /** creates the tables page
+ @param _xConnection
+ The connection to get the table names
+ */
+ void createTablesPage(const css::uno::Reference< css::sdbc::XConnection>& _xConnection);
+
+ /** creates the page for the specific type.
+ @param _eType
+ The type which should be created. E_TABLE isn't allowed.
+ @param _xContainer
+ The container of the elements to be inserted.
+ */
+ void createPage(ElementType _eType,const css::uno::Reference< css::container::XNameAccess >& _xContainer);
+
+ void setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics );
+
+ /** called to give the window the chance to intercept key events, while it has not
+ the focus
+
+ @return <TRUE/> if and only if the event has been handled, and should not
+ not be further processed
+ */
+ bool interceptKeyInput( const KeyEvent& _rEvent );
+
+ OAppBorderWindow& getBorderWin() const { return m_rBorderWin; }
+ OTasksWindow& getTasksWindow() const { return *static_cast< OTasksWindow* >( m_aTasks->getChildWindow() ); }
+
+ bool isCutAllowed() override ;
+ bool isCopyAllowed() override ;
+ bool isPasteAllowed() override;
+ void copy() override;
+ void cut() override;
+ void paste() override;
+
+ /** return the qualified name.
+ @param _pEntry
+ The entry of a table, or query, form, report to get the qualified name.
+ If the entry is <NULL/>, the first selected is chosen.
+ @return
+ the qualified name
+ */
+ OUString getQualifiedName( SvTreeListEntry* _pEntry ) const;
+
+ /** returns if an entry is a leaf
+ @param _pEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ static bool isLeaf(SvTreeListEntry const * _pEntry);
+
+ /** returns if one of the selected entries is a leaf
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isALeafSelected() const;
+
+ /** select all entries in the detail page
+ */
+ void selectAll();
+
+ /// returns <TRUE/> if it sorts ascending
+ bool isSortUp() const;
+
+ /// sort the entries in the detail page down
+ void sortDown();
+
+ /// sort the entries in the detail page up
+ void sortUp();
+
+ /// returns <TRUE/> when a detail page was filled
+ bool isFilled() const;
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /** clears the detail pages.
+ @param _bTaskAlso
+ If <TRUE/> the task window will also be cleared.
+ */
+ void clearPages(bool _bTaskAlso = true);
+
+ /// returns the count of entries
+ sal_Int32 getElementCount() const;
+
+ /// returns the count of selected entries
+ sal_Int32 getSelectionCount();
+
+ /** returns the element names which are selected
+ @param _rNames
+ The list will be filled.
+ */
+ void getSelectionElementNames(std::vector< OUString>& _rNames ) const;
+
+ /** describes the current selection for the given control
+ */
+ void describeCurrentSelectionForControl(
+ const Control& _rControl,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** describes the current selection for the given ElementType
+ */
+ void describeCurrentSelectionForType(
+ const ElementType _eType,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** select all names on the currently selected container. Non existence names where ignored.
+ *
+ * \param _aNames the element names
+ */
+ void selectElements(const css::uno::Sequence< OUString>& _aNames);
+
+ /** adds a new object to the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the object to be inserted
+ @param _rObject
+ The object to add.
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ SvTreeListEntry* elementAdded(ElementType eType
+ ,const OUString& _rName
+ ,const css::uno::Any& _rObject );
+
+ /** replaces an objects name with a new one
+ @param _eType
+ The type where the entry should be appended.
+ @param _rOldName
+ The old name of the object to be replaced
+ @param _rNewName
+ The new name of the object to be replaced
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ @param _xObject
+ The object which was replaced
+ */
+ void elementReplaced(ElementType eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName );
+
+ /** removes an element from the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the element to be removed.
+ @param _rxConn
+ If we remove a table, the connection must be set.
+ */
+ void elementRemoved(ElementType _eType
+ ,const OUString& _rName );
+
+ /// returns the preview mode
+ PreviewMode getPreviewMode() const;
+
+ /// <TRUE/> if the preview is enabled
+ bool isPreviewEnabled() const;
+
+ /** switches to the given preview mode
+ @param _eMode
+ the mode to set for the preview
+ */
+ void switchPreview(PreviewMode _eMode);
+
+ /** shows the Preview of the content when it is enabled.
+ @param _xContent
+ The content which must support the "preview" command.
+ */
+ void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent);
+
+ /** shows the Preview of a table or query
+ @param _sDataSourceName
+ the name of the data source
+ @param _sName
+ the name of table or query
+ @param _bTable
+ <TRUE/> if it is a table, otherwise <FALSE/>
+ @return void
+ */
+ void showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable);
+
+ SvTreeListEntry* getEntry( const Point& _aPoint ) const;
+
+ vcl::Window* getTreeWindow() const;
+ private:
+ void impl_createPage(
+ ElementType _eType,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const css::uno::Reference< css::container::XNameAccess >& _rxNonTableElements
+ );
+
+ const TaskPaneData& impl_getTaskPaneData( ElementType _eType );
+ void impl_fillTaskPaneData( ElementType _eType, TaskPaneData& _rData ) const;
+ };
+}
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILVIEW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppIconControl.cxx b/dbaccess/source/ui/app/AppIconControl.cxx
new file mode 100644
index 000000000..514580014
--- /dev/null
+++ b/dbaccess/source/ui/app/AppIconControl.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppIconControl.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <vcl/image.hxx>
+#include <callbacks.hxx>
+#include <AppElementType.hxx>
+
+using namespace ::dbaui;
+OApplicationIconControl::OApplicationIconControl(vcl::Window* _pParent)
+ : SvtIconChoiceCtrl(_pParent,WB_ICON | WB_NOCOLUMNHEADER | WB_HIGHLIGHTFRAME | /*!WB_NOSELECTION |*/
+ WB_TABSTOP | WB_CLIPCHILDREN | WB_NOVSCROLL | WB_SMART_ARRANGE | WB_NOHSCROLL | WB_CENTER)
+ ,DropTargetHelper(this)
+ ,m_pActionListener(nullptr)
+{
+
+ static const struct CategoryDescriptor
+ {
+ const char* pLabelResId;
+ ElementType eType;
+ const char* aImageResId;
+ } aCategories[] = {
+ { RID_STR_TABLES_CONTAINER, E_TABLE, BMP_TABLEFOLDER_TREE_L },
+ { RID_STR_QUERIES_CONTAINER, E_QUERY, BMP_QUERYFOLDER_TREE_L },
+ { RID_STR_FORMS_CONTAINER, E_FORM, BMP_FORMFOLDER_TREE_L },
+ { RID_STR_REPORTS_CONTAINER, E_REPORT, BMP_REPORTFOLDER_TREE_L }
+ };
+ for (const CategoryDescriptor& aCategorie : aCategories)
+ {
+ SvxIconChoiceCtrlEntry* pEntry = InsertEntry(
+ DBA_RES(aCategorie.pLabelResId) ,
+ Image(StockImage::Yes, OUString::createFromAscii(aCategorie.aImageResId)));
+ if ( pEntry )
+ pEntry->SetUserData( new ElementType( aCategorie.eType ) );
+ }
+
+ SetChoiceWithCursor();
+ SetSelectionMode(SelectionMode::Single);
+}
+
+OApplicationIconControl::~OApplicationIconControl()
+{
+ disposeOnce();
+}
+
+void OApplicationIconControl::dispose()
+{
+ sal_Int32 nCount = GetEntryCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ SvxIconChoiceCtrlEntry* pEntry = GetEntry( i );
+ if ( pEntry )
+ {
+ delete static_cast<ElementType*>(pEntry->GetUserData());
+ pEntry->SetUserData(nullptr);
+ }
+ }
+ DropTargetHelper::dispose();
+ SvtIconChoiceCtrl::dispose();
+}
+
+sal_Int8 OApplicationIconControl::AcceptDrop( const AcceptDropEvent& _rEvt )
+{
+ sal_Int8 nDropOption = DND_ACTION_NONE;
+ if ( m_pActionListener )
+ {
+
+ SvxIconChoiceCtrlEntry* pEntry = GetEntry(_rEvt.maPosPixel);
+ if ( pEntry )
+ {
+ SetCursor(pEntry);
+ nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() );
+ }
+ }
+
+ return nDropOption;
+}
+
+sal_Int8 OApplicationIconControl::ExecuteDrop( const ExecuteDropEvent& _rEvt )
+{
+ if ( m_pActionListener )
+ return m_pActionListener->executeDrop( _rEvt );
+
+ return DND_ACTION_NONE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppIconControl.hxx b/dbaccess/source/ui/app/AppIconControl.hxx
new file mode 100644
index 000000000..38408af60
--- /dev/null
+++ b/dbaccess/source/ui/app/AppIconControl.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX
+
+#include <vcl/ivctrl.hxx>
+#include <vcl/transfer.hxx>
+
+namespace dbaui
+{
+ class IControlActionListener;
+ class OApplicationIconControl :public SvtIconChoiceCtrl
+ ,public DropTargetHelper
+ {
+ IControlActionListener* m_pActionListener;
+
+ public:
+ explicit OApplicationIconControl(vcl::Window* _pParent);
+ virtual ~OApplicationIconControl() override;
+ virtual void dispose() override;
+
+ void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; }
+
+ protected:
+ // DropTargetHelper overridables
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& _rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& _rEvt ) override;
+ };
+}
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppSwapWindow.cxx b/dbaccess/source/ui/app/AppSwapWindow.cxx
new file mode 100644
index 000000000..e291bdb8a
--- /dev/null
+++ b/dbaccess/source/ui/app/AppSwapWindow.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppSwapWindow.hxx"
+#include <helpids.h>
+#include "AppView.hxx"
+#include <vcl/event.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/settings.hxx>
+#include "AppController.hxx"
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+OApplicationSwapWindow::OApplicationSwapWindow( vcl::Window* _pParent, OAppBorderWindow& _rBorderWindow )
+ :Window(_pParent,WB_DIALOGCONTROL )
+ ,m_aIconControl(VclPtr<OApplicationIconControl>::Create(this))
+ ,m_eLastType(E_NONE)
+ ,m_rBorderWin( _rBorderWindow )
+{
+ ImplInitSettings();
+
+ m_aIconControl->SetClickHdl(LINK(this, OApplicationSwapWindow, OnContainerSelectHdl));
+ m_aIconControl->setControlActionListener( &m_rBorderWin.getView()->getAppController() );
+ m_aIconControl->SetHelpId(HID_APP_SWAP_ICONCONTROL);
+ m_aIconControl->Show();
+}
+
+OApplicationSwapWindow::~OApplicationSwapWindow()
+{
+ disposeOnce();
+}
+
+void OApplicationSwapWindow::dispose()
+{
+ m_aIconControl.disposeAndClear();
+ vcl::Window::dispose();
+}
+
+void OApplicationSwapWindow::Resize()
+{
+ Size aFLSize = LogicToPixel(Size(8, 0), MapMode(MapUnit::MapAppFont));
+ long nX = 0;
+ if ( m_aIconControl->GetEntryCount() != 0 )
+ nX = m_aIconControl->GetBoundingBox( m_aIconControl->GetEntry(0) ).GetWidth() + aFLSize.Width();
+
+ Size aOutputSize = GetOutputSize();
+
+ m_aIconControl->SetPosSizePixel( Point(static_cast<long>((aOutputSize.Width() - nX)*0.5), 0) ,Size(nX,aOutputSize.Height()));
+ m_aIconControl->ArrangeIcons();
+}
+
+void OApplicationSwapWindow::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+}
+
+void OApplicationSwapWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OApplicationSwapWindow::clearSelection()
+{
+ m_aIconControl->SetNoSelection();
+ SvxIconChoiceCtrlEntry* pEntry = m_aIconControl->GetSelectedEntry();
+ if ( pEntry )
+ m_aIconControl->InvalidateEntry(pEntry);
+ m_aIconControl->GetClickHdl().Call(m_aIconControl.get());
+}
+
+void OApplicationSwapWindow::createIconAutoMnemonics( MnemonicGenerator& _rMnemonics )
+{
+ m_aIconControl->CreateAutoMnemonics( _rMnemonics );
+}
+
+bool OApplicationSwapWindow::interceptKeyInput( const KeyEvent& _rEvent )
+{
+ const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode();
+ if ( rKeyCode.GetModifier() == KEY_MOD2 )
+ return m_aIconControl->DoKeyInput( _rEvent );
+
+ // not handled
+ return false;
+}
+
+ElementType OApplicationSwapWindow::getElementType() const
+{
+ SvxIconChoiceCtrlEntry* pEntry = m_aIconControl->GetSelectedEntry();
+ return pEntry ? *static_cast<ElementType*>(pEntry->GetUserData()) : E_NONE;
+}
+
+bool OApplicationSwapWindow::onContainerSelected( ElementType _eType )
+{
+ if ( m_eLastType == _eType )
+ return true;
+
+ if ( m_rBorderWin.getView()->getAppController().onContainerSelect( _eType ) )
+ {
+ if ( _eType != E_NONE )
+ m_eLastType = _eType;
+ return true;
+ }
+
+ PostUserEvent( LINK( this, OApplicationSwapWindow, ChangeToLastSelected ), nullptr, true );
+ return false;
+}
+
+IMPL_LINK(OApplicationSwapWindow, OnContainerSelectHdl, SvtIconChoiceCtrl*, _pControl, void)
+{
+ SvxIconChoiceCtrlEntry* pEntry = _pControl->GetSelectedEntry();
+ ElementType eType = E_NONE;
+ if ( pEntry )
+ {
+ eType = *static_cast<ElementType*>(pEntry->GetUserData());
+ onContainerSelected( eType ); // i87582
+ }
+}
+
+IMPL_LINK_NOARG(OApplicationSwapWindow, ChangeToLastSelected, void*, void)
+{
+ selectContainer(m_eLastType);
+}
+
+void OApplicationSwapWindow::selectContainer(ElementType _eType)
+{
+ sal_Int32 nCount = m_aIconControl->GetEntryCount();
+ SvxIconChoiceCtrlEntry* pEntry = nullptr;
+ for (sal_Int32 i=0; i < nCount; ++i)
+ {
+ pEntry = m_aIconControl->GetEntry(i);
+ if ( pEntry && *static_cast<ElementType*>(pEntry->GetUserData()) == _eType )
+ break;
+ pEntry = nullptr;
+ }
+
+ if ( pEntry )
+ m_aIconControl->SetCursor(pEntry); // this call also initiates a onContainerSelected call
+ else
+ onContainerSelected( _eType );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppSwapWindow.hxx b/dbaccess/source/ui/app/AppSwapWindow.hxx
new file mode 100644
index 000000000..62f58c152
--- /dev/null
+++ b/dbaccess/source/ui/app/AppSwapWindow.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX
+
+#include <IClipBoardTest.hxx>
+#include <vcl/vclptr.hxx>
+#include "AppIconControl.hxx"
+#include <AppElementType.hxx>
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class OApplicationSwapWindow : public vcl::Window,
+ public IClipboardTest
+ {
+ VclPtr<OApplicationIconControl> m_aIconControl;
+ ElementType m_eLastType;
+ OAppBorderWindow& m_rBorderWin;
+
+ void ImplInitSettings();
+
+ DECL_LINK( OnContainerSelectHdl, SvtIconChoiceCtrl*, void );
+ DECL_LINK( ChangeToLastSelected, void*, void );
+ protected:
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+ public:
+ OApplicationSwapWindow( vcl::Window* _pParent, OAppBorderWindow& _rBorderWindow );
+ virtual ~OApplicationSwapWindow() override;
+ // Window overrides
+ virtual void dispose() override;
+ virtual void Resize() override;
+
+ bool isCutAllowed() override { return false; }
+ bool isCopyAllowed() override { return false; }
+ bool isPasteAllowed() override { return false; }
+ void copy() override { }
+ void cut() override { }
+ void paste() override { }
+
+ sal_Int32 GetEntryCount() const { return m_aIconControl->GetEntryCount(); }
+ SvxIconChoiceCtrlEntry* GetEntry( sal_uLong nPos ) const { return m_aIconControl->GetEntry(nPos); }
+ tools::Rectangle GetBoundingBox( SvxIconChoiceCtrlEntry* pEntry ) const { return m_aIconControl->GetBoundingBox(pEntry); }
+
+ /** automatically creates mnemonics for the icon/texts in our left hand side panel
+ */
+ void createIconAutoMnemonics( MnemonicGenerator& _rMnemonics );
+
+ /** called to give the window the chance to intercept key events, while it has not
+ the focus
+
+ @return <TRUE/> if and only if the event has been handled, and should not
+ not be further processed
+ */
+ bool interceptKeyInput( const KeyEvent& _rEvent );
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /** clears the selection in the icon choice control and calls the handler
+ */
+ void clearSelection();
+
+ /** changes the container which should be displayed. The select handler will also be called.
+ @param _eType
+ Which container to show.
+ */
+ void selectContainer(ElementType _eType);
+
+ private:
+ bool onContainerSelected( ElementType _eType );
+ };
+} // namespace dbaui
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppTitleWindow.cxx b/dbaccess/source/ui/app/AppTitleWindow.cxx
new file mode 100644
index 000000000..d6d121ba4
--- /dev/null
+++ b/dbaccess/source/ui/app/AppTitleWindow.cxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppTitleWindow.hxx"
+#include <core_resource.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/event.hxx>
+
+namespace dbaui
+{
+
+OTitleWindow::OTitleWindow(vcl::Window* _pParent, const char* pTitleId, WinBits _nBits, bool _bShift)
+: Window(_pParent,_nBits | WB_DIALOGCONTROL)
+, m_aSpace1(VclPtr<FixedText>::Create(this))
+, m_aSpace2(VclPtr<FixedText>::Create(this))
+, m_aTitle(VclPtr<FixedText>::Create(this))
+, m_pChild(nullptr)
+, m_bShift(_bShift)
+{
+ setTitle(pTitleId);
+ SetBorderStyle(WindowBorderStyle::MONO);
+ ImplInitSettings();
+
+ const StyleSettings& rStyle = Application::GetSettings().GetStyleSettings();
+ vcl::Window* pWindows[] = { m_aSpace1.get(), m_aSpace2.get(), m_aTitle.get() };
+ for (vcl::Window* pWindow : pWindows)
+ {
+ vcl::Font aFont = pWindow->GetControlFont();
+ aFont.SetWeight(WEIGHT_BOLD);
+ pWindow->SetControlFont(aFont);
+ pWindow->SetControlForeground(rStyle.GetLightColor());
+ pWindow->SetControlBackground(rStyle.GetShadowColor());
+ pWindow->Show();
+ }
+}
+
+OTitleWindow::~OTitleWindow()
+{
+ disposeOnce();
+}
+
+void OTitleWindow::dispose()
+{
+ if ( m_pChild )
+ {
+ m_pChild->Hide();
+ }
+ m_pChild.disposeAndClear();
+ m_aSpace1.disposeAndClear();
+ m_aSpace2.disposeAndClear();
+ m_aTitle.disposeAndClear();
+ vcl::Window::dispose();
+}
+
+void OTitleWindow::setChildWindow(vcl::Window* _pChild)
+{
+ m_pChild = _pChild;
+}
+
+#define SPACE_BORDER 1
+void OTitleWindow::Resize()
+{
+ // parent window dimension
+ Size aOutputSize( GetOutputSize() );
+ long nOutputWidth = aOutputSize.Width();
+ long nOutputHeight = aOutputSize.Height();
+
+ Size aTextSize = LogicToPixel(Size(6, 3), MapMode(MapUnit::MapAppFont));
+ sal_Int32 nXOffset = aTextSize.Width();
+ sal_Int32 nYOffset = aTextSize.Height();
+ sal_Int32 nHeight = GetTextHeight() + 2*nYOffset;
+
+ m_aSpace1->SetPosSizePixel( Point(SPACE_BORDER, SPACE_BORDER ),
+ Size(nXOffset , nHeight - SPACE_BORDER) );
+ m_aSpace2->SetPosSizePixel( Point(nXOffset + SPACE_BORDER, SPACE_BORDER ),
+ Size(nOutputWidth - nXOffset - 2*SPACE_BORDER, nYOffset) );
+ m_aTitle->SetPosSizePixel( Point(nXOffset + SPACE_BORDER, nYOffset + SPACE_BORDER),
+ Size(nOutputWidth - nXOffset - 2*SPACE_BORDER, nHeight - nYOffset - SPACE_BORDER) );
+ if ( m_pChild )
+ {
+ m_pChild->SetPosSizePixel( Point(m_bShift ? (nXOffset+SPACE_BORDER) : sal_Int32(SPACE_BORDER), nHeight + nXOffset + SPACE_BORDER),
+ Size(nOutputWidth - ( m_bShift ? (2*nXOffset - 2*SPACE_BORDER) : sal_Int32(SPACE_BORDER) ), nOutputHeight - nHeight - 2*nXOffset - 2*SPACE_BORDER) );
+ }
+}
+
+void OTitleWindow::setTitle(const char* pTitleId)
+{
+ if (pTitleId)
+ {
+ m_aTitle->SetText(DBA_RES(pTitleId));
+ }
+}
+
+void OTitleWindow::GetFocus()
+{
+ Window::GetFocus();
+ if ( m_pChild )
+ m_pChild->GrabFocus();
+}
+
+long OTitleWindow::GetWidthPixel() const
+{
+ Size aTextSize = LogicToPixel(Size(12, 0), MapMode(MapUnit::MapAppFont));
+ sal_Int32 nWidth = GetTextWidth(m_aTitle->GetText()) + 2*aTextSize.Width();
+
+ return nWidth;
+}
+
+void OTitleWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OTitleWindow::ImplInitSettings()
+{
+ // FIXME RenderContext
+ AllSettings aAllSettings = GetSettings();
+ StyleSettings aStyle = aAllSettings.GetStyleSettings();
+ aStyle.SetMonoColor(aStyle.GetActiveBorderColor());//GetMenuBorderColor());
+ aAllSettings.SetStyleSettings(aStyle);
+ SetSettings(aAllSettings);
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+}
+
+void OTitleWindow::ApplySettings(vcl::RenderContext& rRenderContext)
+{
+ // FIXME RenderContext
+ AllSettings aAllSettings = rRenderContext.GetSettings();
+ StyleSettings aStyle = aAllSettings.GetStyleSettings();
+ aStyle.SetMonoColor(aStyle.GetActiveBorderColor());//GetMenuBorderColor());
+ aAllSettings.SetStyleSettings(aStyle);
+ rRenderContext.SetSettings(aAllSettings);
+
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor(rStyleSettings.GetWindowTextColor());
+ SetPointFont(*this, aFont);
+
+ rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor());
+ rRenderContext.SetTextFillColor();
+
+ rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
+}
+
+} // namespace dbaui
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppTitleWindow.hxx b/dbaccess/source/ui/app/AppTitleWindow.hxx
new file mode 100644
index 000000000..c6a8d417d
--- /dev/null
+++ b/dbaccess/source/ui/app/AppTitleWindow.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPTITLEWINDOW_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPTITLEWINDOW_HXX
+
+#include <vcl/fixed.hxx>
+
+namespace dbaui
+{
+ class OTitleWindow : public vcl::Window
+ {
+ VclPtr<FixedText> m_aSpace1;
+ VclPtr<FixedText> m_aSpace2;
+ VclPtr<FixedText> m_aTitle;
+ VclPtr<vcl::Window> m_pChild;
+ bool m_bShift;
+ void ImplInitSettings();
+ protected:
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+ public:
+ OTitleWindow(vcl::Window* _pParent, const char* pTitleId, WinBits _nBits, bool _bShift = true);
+ virtual ~OTitleWindow() override;
+ virtual void dispose() override;
+
+ // Window overrides
+ virtual void Resize() override;
+ virtual void GetFocus() override;
+
+ virtual void ApplySettings(vcl::RenderContext& rRenderContext) override;
+
+ /** sets the child window which should be displayed below the title. It will be destroyed at the end.
+ @param _pChild
+ The child window.
+ */
+ void setChildWindow(vcl::Window* _pChild);
+
+ /** gets the child window.
+
+ @return
+ The child window.
+ */
+ vcl::Window* getChildWindow() const { return m_pChild; }
+
+ /** sets the title text out of the resource
+ @param pTitleId
+ The resource id of the title text.
+ */
+ void setTitle(const char* pTitleId);
+
+ /** Gets the min Width in Pixel which is needed to display the whole
+
+ @return
+ the min width
+ */
+ long GetWidthPixel() const;
+ };
+} // namespace dbaui
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPTITLEWINDOW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppView.cxx b/dbaccess/source/ui/app/AppView.cxx
new file mode 100644
index 000000000..fb61be909
--- /dev/null
+++ b/dbaccess/source/ui/app/AppView.cxx
@@ -0,0 +1,524 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AppView.hxx"
+#include <strings.hrc>
+#include <tools/diagnose_ex.h>
+#include <vcl/event.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include "AppDetailView.hxx"
+#include "AppSwapWindow.hxx"
+#include <vcl/settings.hxx>
+#include "AppTitleWindow.hxx"
+#include "AppController.hxx"
+
+using namespace ::dbaui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+OAppBorderWindow::OAppBorderWindow(OApplicationView* _pParent,PreviewMode _ePreviewMode) : Window(_pParent,WB_DIALOGCONTROL)
+ ,m_pPanel(nullptr)
+ ,m_pDetailView(nullptr)
+ ,m_pView(_pParent)
+{
+
+ SetBorderStyle(WindowBorderStyle::MONO);
+
+ m_pPanel = VclPtr<OTitleWindow>::Create(this,STR_DATABASE,WB_BORDER | WB_DIALOGCONTROL, false);
+ m_pPanel->SetBorderStyle(WindowBorderStyle::MONO);
+ VclPtrInstance<OApplicationSwapWindow> pSwap( m_pPanel, *this );
+ pSwap->Show();
+
+ m_pPanel->setChildWindow(pSwap);
+ m_pPanel->Show();
+
+ m_pDetailView = VclPtr<OApplicationDetailView>::Create(*this,_ePreviewMode);
+ m_pDetailView->Show();
+
+ ImplInitSettings();
+}
+
+OAppBorderWindow::~OAppBorderWindow()
+{
+ disposeOnce();
+}
+
+void OAppBorderWindow::dispose()
+{
+ // destroy children
+ if ( m_pPanel )
+ m_pPanel->Hide();
+ m_pPanel.disposeAndClear();
+ if ( m_pDetailView )
+ m_pDetailView->Hide();
+ m_pDetailView.disposeAndClear();
+ m_pView.clear();
+ vcl::Window::dispose();
+}
+
+void OAppBorderWindow::GetFocus()
+{
+ if ( m_pPanel )
+ m_pPanel->GrabFocus();
+}
+
+void OAppBorderWindow::Resize()
+{
+ // parent window dimension
+ Size aOutputSize( GetOutputSize() );
+ long nOutputWidth = aOutputSize.Width();
+ long nOutputHeight = aOutputSize.Height();
+ long nX = 0;
+
+ Size aFLSize = LogicToPixel(Size(3, 8), MapMode(MapUnit::MapAppFont));
+ if ( m_pPanel )
+ {
+ OApplicationSwapWindow* pSwap = getPanel();
+ if ( pSwap && pSwap->GetEntryCount() != 0 )
+ nX = pSwap->GetBoundingBox( pSwap->GetEntry(0) ).GetWidth() + aFLSize.Height();
+ nX = std::max(m_pPanel->GetWidthPixel() ,nX);
+ m_pPanel->SetPosSizePixel(Point(0,0),Size(nX,nOutputHeight));
+ }
+
+ if ( m_pDetailView )
+ m_pDetailView->SetPosSizePixel(Point(nX + aFLSize.Width(),0),Size(nOutputWidth - nX - aFLSize.Width(),nOutputHeight));
+}
+
+void OAppBorderWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OAppBorderWindow::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetDialogColor() );
+}
+
+
+OApplicationSwapWindow* OAppBorderWindow::getPanel() const
+{
+ return static_cast< OApplicationSwapWindow* >( m_pPanel->getChildWindow() );
+}
+
+
+OApplicationView::OApplicationView( vcl::Window* pParent
+ ,const Reference< XComponentContext >& _rxOrb
+ ,OApplicationController& _rAppController
+ ,PreviewMode _ePreviewMode
+ ) :
+ ODataView( pParent, _rAppController, _rxOrb, WB_DIALOGCONTROL )
+ ,m_rAppController( _rAppController )
+ ,m_eChildFocus(NONE)
+{
+ m_pWin = VclPtr<OAppBorderWindow>::Create(this,_ePreviewMode);
+ m_pWin->Show();
+
+ ImplInitSettings();
+}
+
+OApplicationView::~OApplicationView()
+{
+ disposeOnce();
+}
+
+void OApplicationView::dispose()
+{
+ stopComponentListening(m_xObject);
+ m_xObject.clear();
+ m_pWin->Hide();
+ m_pWin.disposeAndClear();
+ ODataView::dispose();
+}
+
+void OApplicationView::createIconAutoMnemonics( MnemonicGenerator& _rMnemonics )
+{
+ if ( m_pWin && m_pWin->getPanel() )
+ m_pWin->getPanel()->createIconAutoMnemonics( _rMnemonics );
+}
+
+void OApplicationView::setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics )
+{
+ if ( m_pWin && m_pWin->getDetailView() )
+ m_pWin->getDetailView()->setTaskExternalMnemonics( _rMnemonics );
+}
+
+void OApplicationView::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ ODataView::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
+ (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
+ (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
+ ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
+ {
+ ImplInitSettings();
+ Invalidate();
+ }
+}
+
+void OApplicationView::resizeDocumentView(tools::Rectangle& _rPlayground)
+{
+ if ( m_pWin && !_rPlayground.IsEmpty() )
+ {
+ Size aFLSize = LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont));
+ _rPlayground.Move( aFLSize.Width(),aFLSize.Height() );
+ Size aOldSize = _rPlayground.GetSize();
+ _rPlayground.SetSize( Size(aOldSize.Width() - 2*aFLSize.Width(), aOldSize.Height() - 2*aFLSize.Height()) );
+
+ m_pWin->SetPosSizePixel(_rPlayground.TopLeft() , _rPlayground.GetSize() );
+ }
+ // just for completeness: there is no space left, we occupied it all ...
+ _rPlayground.SetPos( _rPlayground.BottomRight() );
+ _rPlayground.SetSize( Size( 0, 0 ) );
+}
+
+bool OApplicationView::PreNotify( NotifyEvent& rNEvt )
+{
+ switch(rNEvt.GetType())
+ {
+ case MouseNotifyEvent::GETFOCUS:
+ if( m_pWin && getPanel() && getPanel()->HasChildPathFocus() )
+ m_eChildFocus = PANELSWAP;
+ else if ( m_pWin && getDetailView() && getDetailView()->HasChildPathFocus() )
+ m_eChildFocus = DETAIL;
+ else
+ m_eChildFocus = NONE;
+ break;
+ case MouseNotifyEvent::KEYINPUT:
+ {
+ const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent();
+ // give the pane the chance to intercept mnemonic accelerators
+ // #i34790#
+ if ( getPanel() && getPanel()->interceptKeyInput( *pKeyEvent ) )
+ return true;
+ // and ditto the detail view
+ // #i72799#
+ if ( getDetailView() && getDetailView()->interceptKeyInput( *pKeyEvent ) )
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ODataView::PreNotify(rNEvt);
+}
+
+IClipboardTest* OApplicationView::getActiveChild() const
+{
+ IClipboardTest* pTest = nullptr;
+ if ( DETAIL == m_eChildFocus )
+ pTest = getDetailView();
+ return pTest;
+}
+
+bool OApplicationView::isCopyAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isCopyAllowed();
+}
+
+bool OApplicationView::isCutAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isCutAllowed();
+}
+
+bool OApplicationView::isPasteAllowed()
+{
+ IClipboardTest* pTest = getActiveChild();
+ return pTest && pTest->isPasteAllowed();
+}
+
+void OApplicationView::copy()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->copy();
+}
+
+void OApplicationView::cut()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->cut();
+}
+
+void OApplicationView::paste()
+{
+ IClipboardTest* pTest = getActiveChild();
+ if ( pTest )
+ pTest->paste();
+}
+
+OUString OApplicationView::getQualifiedName( SvTreeListEntry* _pEntry ) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getQualifiedName( _pEntry );
+}
+
+bool OApplicationView::isLeaf(SvTreeListEntry const * _pEntry) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return OApplicationDetailView::isLeaf(_pEntry);
+}
+
+bool OApplicationView::isALeafSelected() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isALeafSelected();
+}
+
+void OApplicationView::selectAll()
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->selectAll();
+}
+
+bool OApplicationView::isSortUp() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isSortUp();
+}
+
+void OApplicationView::sortDown()
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->sortDown();
+}
+
+void OApplicationView::sortUp()
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->sortUp();
+}
+
+bool OApplicationView::isFilled() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isFilled();
+}
+
+ElementType OApplicationView::getElementType() const
+{
+ OSL_ENSURE(m_pWin && getDetailView() && getPanel(),"Detail view is NULL! -> GPF");
+ return getDetailView()->HasChildPathFocus() ? getDetailView()->getElementType() : getPanel()->getElementType();
+}
+
+sal_Int32 OApplicationView::getSelectionCount() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getSelectionCount();
+}
+
+sal_Int32 OApplicationView::getElementCount() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getElementCount();
+}
+
+void OApplicationView::getSelectionElementNames( std::vector< OUString>& _rNames ) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->getSelectionElementNames( _rNames );
+}
+
+void OApplicationView::describeCurrentSelectionForControl( const Control& _rControl, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->describeCurrentSelectionForControl( _rControl, _out_rSelectedObjects );
+}
+
+void OApplicationView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->describeCurrentSelectionForType( _eType, _out_rSelectedObjects );
+}
+
+void OApplicationView::selectElements(const Sequence< OUString>& _aNames)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->selectElements( _aNames );
+}
+
+SvTreeListEntry* OApplicationView::elementAdded(ElementType eType,const OUString& _rName, const Any& _rObject )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->elementAdded(eType,_rName,_rObject);
+}
+
+void OApplicationView::elementRemoved(ElementType eType,const OUString& _rName )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->elementRemoved(eType,_rName);
+}
+
+void OApplicationView::elementReplaced(ElementType _eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName )
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->elementReplaced(_eType, _rOldName, _rNewName );
+}
+
+void OApplicationView::clearPages()
+{
+ OSL_ENSURE(m_pWin && getDetailView() && getPanel(),"Detail view is NULL! -> GPF");
+ getPanel()->clearSelection();
+ getDetailView()->clearPages();
+}
+
+void OApplicationView::selectContainer(ElementType _eType)
+{
+ OSL_ENSURE(m_pWin && getPanel(),"Detail view is NULL! -> GPF");
+ weld::WaitObject aWO(GetFrameWeld());
+ getPanel()->selectContainer(_eType);
+}
+
+SvTreeListEntry* OApplicationView::getEntry( const Point& _aPosPixel ) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getEntry(_aPosPixel);
+}
+
+PreviewMode OApplicationView::getPreviewMode() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getPreviewMode();
+}
+
+bool OApplicationView::isPreviewEnabled() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->isPreviewEnabled();
+}
+
+void OApplicationView::switchPreview(PreviewMode _eMode)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->switchPreview(_eMode);
+}
+
+void OApplicationView::showPreview(const Reference< XContent >& _xContent)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ stopComponentListening(m_xObject);
+ m_xObject = nullptr;
+ getDetailView()->showPreview(_xContent);
+}
+
+void OApplicationView::showPreview( const OUString& _sDataSourceName,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const OUString& _sName,
+ bool _bTable)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ if ( !isPreviewEnabled() )
+ return;
+
+ stopComponentListening(m_xObject);
+ m_xObject = nullptr;
+ try
+ {
+ Reference<XNameAccess> xNameAccess;
+ if ( _bTable )
+ {
+ Reference<XTablesSupplier> xSup(_xConnection,UNO_QUERY);
+ if ( xSup.is() )
+ xNameAccess = xSup->getTables();
+ }
+ else
+ {
+ Reference<XQueriesSupplier> xSup(_xConnection,UNO_QUERY);
+ if ( xSup.is() )
+ xNameAccess = xSup->getQueries();
+ }
+ if ( xNameAccess.is() && xNameAccess->hasByName(_sName) )
+ m_xObject.set(xNameAccess->getByName(_sName),UNO_QUERY);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ if ( m_xObject.is() )
+ startComponentListening(m_xObject);
+ getDetailView()->showPreview(_sDataSourceName,_sName,_bTable);
+}
+
+void OApplicationView::GetFocus()
+{
+ if ( m_eChildFocus == NONE && m_pWin )
+ {
+ m_pWin->GrabFocus();
+ }
+}
+
+void OApplicationView::_disposing( const css::lang::EventObject& /*_rSource*/ )
+{
+ if ( m_pWin && getDetailView() )
+ showPreview(nullptr);
+}
+
+void OApplicationView::ImplInitSettings()
+{
+ // FIXME RenderContext
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetColor( rStyleSettings.GetWindowTextColor() );
+ SetPointFont(*this, aFont);
+
+ SetTextColor( rStyleSettings.GetFieldTextColor() );
+ SetTextFillColor();
+
+ SetBackground( rStyleSettings.GetFieldColor() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/AppView.hxx b/dbaccess/source/ui/app/AppView.hxx
new file mode 100644
index 000000000..0d492953a
--- /dev/null
+++ b/dbaccess/source/ui/app/AppView.hxx
@@ -0,0 +1,297 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPVIEW_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPVIEW_HXX
+
+#include <dbaccess/dataview.hxx>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <unotools/eventlisteneradapter.hxx>
+#include <IClipBoardTest.hxx>
+#include <AppElementType.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+
+class Control;
+class SvTreeListEntry;
+class MnemonicGenerator;
+
+namespace dbaui
+{
+ class OApplicationView;
+ class OApplicationDetailView;
+ class OApplicationSwapWindow;
+ class OTitleWindow;
+ class OApplicationController;
+
+ class OAppBorderWindow : public vcl::Window
+ {
+ VclPtr<OTitleWindow> m_pPanel;
+ VclPtr<OApplicationDetailView> m_pDetailView;
+ VclPtr<OApplicationView> m_pView;
+
+ void ImplInitSettings();
+ protected:
+ // Window
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ public:
+ OAppBorderWindow(OApplicationView* _pParent,PreviewMode _ePreviewMode);
+ virtual ~OAppBorderWindow() override;
+ virtual void dispose() override;
+
+ // Window overrides
+ virtual void GetFocus() override;
+ virtual void Resize() override;
+
+ OApplicationView* getView() const { return m_pView;}
+ OApplicationSwapWindow* getPanel() const;
+ OApplicationDetailView* getDetailView() const { return m_pDetailView;}
+ };
+
+ class OApplicationView : public ODataView
+ ,public IClipboardTest
+ ,public ::utl::OEventListenerAdapter
+ {
+ enum ChildFocusState
+ {
+ PANELSWAP,
+ DETAIL,
+ NONE
+ };
+ private:
+ css::uno::Reference< css::lang::XComponent >
+ m_xObject;
+ VclPtr<OAppBorderWindow> m_pWin;
+ OApplicationController& m_rAppController;
+ ChildFocusState m_eChildFocus;
+
+ IClipboardTest* getActiveChild() const;
+
+ void ImplInitSettings();
+ protected:
+
+ // return the Rectangle where I can paint myself
+ virtual void resizeDocumentView(tools::Rectangle& rRect) override;
+
+ // OEventListenerAdapter
+ virtual void _disposing( const css::lang::EventObject& _rSource ) override;
+
+ // Window
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ public:
+ OApplicationView( vcl::Window* pParent
+ ,const css::uno::Reference< css::uno::XComponentContext >&
+ ,OApplicationController& _rAppController
+ ,PreviewMode _ePreviewMode
+ );
+ virtual ~OApplicationView() override;
+ virtual void dispose() override;
+
+ /// automatically creates mnemonics for the icon/texts in our left hand side panel
+ void createIconAutoMnemonics( MnemonicGenerator& _rMnemonics );
+
+ /// automatically creates mnemonics for the texts in our task pane
+ void setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics );
+
+ // Window overrides
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void GetFocus() override;
+
+ OApplicationController& getAppController() const { return m_rAppController; }
+
+ // IClipboardTest
+ virtual bool isCutAllowed() override;
+ virtual bool isCopyAllowed() override;
+ virtual bool isPasteAllowed() override;
+ virtual void copy() override;
+ virtual void cut() override;
+ virtual void paste() override;
+
+ /// get the left panel
+ OApplicationSwapWindow* getPanel() const { return m_pWin->getPanel(); }
+ /// get the detail page
+ OApplicationDetailView* getDetailView() const { return m_pWin->getDetailView(); }
+
+ /** return the qualified name.
+ @param _pEntry
+ The entry of a table, or query, form, report to get the qualified name.
+ If the entry is <NULL/>, the first selected is chosen.
+ @return
+ the qualified name
+ */
+ OUString getQualifiedName( SvTreeListEntry* _pEntry ) const;
+
+ /** returns if an entry is a leaf
+ @param _pEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isLeaf(SvTreeListEntry const * _pEntry) const;
+
+ /** returns if one of the selected entries is a leaf
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isALeafSelected() const;
+
+ /** select all entries in the detail page
+ */
+ void selectAll();
+
+ /// returns <TRUE/> if it sorts ascending
+ bool isSortUp() const;
+
+ /// sort the entries in the detail page down
+ void sortDown();
+
+ /// sort the entries in the detail page up
+ void sortUp();
+
+ /// returns <TRUE/> when a detail page was filled
+ bool isFilled() const;
+
+ /// return the element of currently select entry
+ ElementType getElementType() const;
+
+ /// returns the count of entries
+ sal_Int32 getElementCount() const;
+
+ /// returns the count of selected entries
+ sal_Int32 getSelectionCount() const;
+
+ /** clears the detail page and the selection on the left side.
+ The task window will also be cleared.
+ */
+ void clearPages();
+
+ /** returns the element names which are selected
+ @param _rNames
+ The list will be filled.
+ */
+ void getSelectionElementNames( std::vector< OUString>& _rNames ) const;
+
+ /** describes the current selection for the given control
+ */
+ void describeCurrentSelectionForControl(
+ const Control& _rControl,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** describes the current selection for the given ElementType
+ */
+ void describeCurrentSelectionForType(
+ const ElementType _eType,
+ css::uno::Sequence< css::sdb::application::NamedDatabaseObject >& _out_rSelectedObjects
+ );
+
+ /** select all names on the currently selected container. Non existence names where ignored.
+ *
+ * \param _aNames the element names
+ */
+ void selectElements(const css::uno::Sequence< OUString>& _aNames);
+
+ /** adds a new object to the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the object to be inserted
+ @param _rObject
+ The object to add.
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ */
+ SvTreeListEntry* elementAdded(ElementType _eType
+ ,const OUString& _rName
+ ,const css::uno::Any& _rObject );
+
+ /** replaces an objects name with a new one
+ @param _eType
+ The type where the entry should be appended.
+ @param _rOldName
+ The old name of the object to be replaced
+ @param _rNewName
+ The new name of the object to be replaced
+ @param _rxConn
+ If we insert a table, the connection must be set.
+ @param _xObject
+ The object which was replaced
+ */
+ void elementReplaced(ElementType eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName );
+
+ /** removes an element from the detail page.
+ @param _eType
+ The type where the entry should be appended.
+ @param _rName
+ The name of the element to be removed.
+ @param _rxConn
+ If we remove a table, the connection must be set.
+ */
+ void elementRemoved(ElementType _eType
+ ,const OUString& _rName );
+
+ /** changes the container which should be displayed. The select handler will also be called.
+ @param _eType
+ Which container to show.
+ */
+ void selectContainer(ElementType _eType);
+
+ /// returns the preview mode
+ PreviewMode getPreviewMode() const;
+
+ /// <TRUE/> if the preview is enabled
+ bool isPreviewEnabled() const;
+
+ /** switches to the given preview mode
+ @param _eMode
+ the mode to set for the preview
+ */
+ void switchPreview(PreviewMode _eMode);
+
+ /** shows the Preview of the content when it is enabled.
+ @param _xContent
+ The content which must support the "preview" command.
+ */
+ void showPreview(const css::uno::Reference< css::ucb::XContent >& _xContent);
+
+ /** shows the Preview of a table or query
+ @param _sDataSourceName
+ the name of the data source
+ @param _xConnection
+ the connection which will be shared
+ @param _sName
+ the name of table or query
+ @param _bTable
+ <TRUE/> if it is a table, otherwise <FALSE/>
+ @return void
+ */
+ void showPreview( const OUString& _sDataSourceName,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const OUString& _sName,
+ bool _bTable);
+
+ SvTreeListEntry* getEntry( const Point& _aPosPixel ) const;
+ };
+}
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPVIEW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/subcomponentmanager.cxx b/dbaccess/source/ui/app/subcomponentmanager.cxx
new file mode 100644
index 000000000..08df1dff0
--- /dev/null
+++ b/dbaccess/source/ui/app/subcomponentmanager.cxx
@@ -0,0 +1,555 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "subcomponentmanager.hxx"
+#include "AppController.hxx"
+#include <strings.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/embed/XComponentSupplier.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <dbaccess/dataview.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+
+#include <algorithm>
+
+namespace dbaui
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::makeAny;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::frame::XModel2;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::util::XCloseable;
+ using ::com::sun::star::awt::XTopWindow;
+ using ::com::sun::star::embed::XComponentSupplier;
+ using ::com::sun::star::ucb::XCommandProcessor;
+ using ::com::sun::star::ucb::Command;
+ using ::com::sun::star::document::XDocumentEventBroadcaster;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+
+ // helper structs
+ namespace
+ {
+ struct SubComponentDescriptor
+ {
+ /// the name of the sub component, empty if it is yet unsaved
+ OUString sName;
+ /// type of the component - an ElementType value, except for relation design
+ sal_Int32 nComponentType;
+ /// the mode in which the sub component has been opened
+ ElementOpenMode eOpenMode;
+ /// the frame which the component resides in. Must not be <NULL/>
+ Reference< XFrame > xFrame;
+ /// the controller of the sub component. Must not be <NULL/>
+ Reference< XController > xController;
+ /// the model of the sub component. Might be <NULL/>
+ Reference< XModel > xModel;
+ /// the document definition which holds the component, if any; as CommandProcessor
+ Reference< XCommandProcessor > xComponentCommandProcessor;
+ /// the document definition which holds the component, if any; as PropertySet
+ Reference< XPropertySet > xDocumentDefinitionProperties;
+
+ SubComponentDescriptor()
+ :sName()
+ ,nComponentType( -1 )
+ ,eOpenMode( E_OPEN_NORMAL )
+ ,xFrame()
+ ,xController()
+ ,xModel()
+ {
+ }
+
+ SubComponentDescriptor( const OUString& i_rName, const sal_Int32 i_nComponentType,
+ const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent )
+ :sName( i_rName )
+ ,nComponentType( i_nComponentType )
+ ,eOpenMode( i_eOpenMode )
+ {
+ if ( !impl_constructFrom( i_rComponent ) )
+ {
+ // i_rComponent is neither a model, nor a controller, nor a frame
+ // => it must be a css.sdb.DocumentDefinition
+ Reference< XComponentSupplier > xCompSupp( i_rComponent, UNO_QUERY_THROW );
+ Reference< XComponent > xComponent( xCompSupp->getComponent(), UNO_QUERY_THROW );
+ if ( !impl_constructFrom( xComponent ) )
+ throw RuntimeException("Illegal component type." );
+ xComponentCommandProcessor.set( i_rComponent, UNO_QUERY_THROW );
+ xDocumentDefinitionProperties.set( i_rComponent, UNO_QUERY_THROW );
+ }
+ }
+
+ bool is() const { return xFrame.is(); }
+
+ private:
+ bool impl_constructFrom( const Reference< XComponent >& _rxComponent )
+ {
+ // is it a model?
+ xModel.set( _rxComponent, UNO_QUERY );
+ if ( xModel.is() )
+ {
+ xController.set( xModel->getCurrentController() );
+ if ( xController.is() )
+ xFrame.set( xController->getFrame(), UNO_SET_THROW );
+ }
+ else
+ {
+ // is it a controller?
+ xController.set( _rxComponent, UNO_QUERY );
+ if ( xController.is() )
+ {
+ xFrame.set( xController->getFrame(), UNO_SET_THROW );
+ }
+ else
+ {
+ // is it a frame?
+ xFrame.set( _rxComponent, UNO_QUERY );
+ if ( !xFrame.is() )
+ return false;
+
+ // ensure we have a controller
+ xController.set( xFrame->getController(), UNO_SET_THROW );
+ }
+
+ // check whether there is a model (not required)
+ xModel.set( xController->getModel() );
+ }
+
+ return true;
+ }
+ };
+
+ struct SelectSubComponent
+ {
+ Reference< XComponent > operator()( const SubComponentDescriptor &_desc ) const
+ {
+ if ( _desc.xModel.is() )
+ return _desc.xModel.get();
+ OSL_ENSURE( _desc.xController.is(), "SelectSubComponent::operator(): illegal component!" );
+ return _desc.xController.get();
+ }
+ };
+
+ typedef std::vector< SubComponentDescriptor > SubComponents;
+
+ struct SubComponentMatch
+ {
+ public:
+ SubComponentMatch( const OUString& i_rName, const sal_Int32 i_nComponentType,
+ const ElementOpenMode i_eOpenMode )
+ :m_sName( i_rName )
+ ,m_nComponentType( i_nComponentType )
+ ,m_eOpenMode( i_eOpenMode )
+ {
+ }
+
+ bool operator()( const SubComponentDescriptor& i_rCompareWith ) const
+ {
+ return ( m_sName == i_rCompareWith.sName )
+ && ( m_nComponentType == i_rCompareWith.nComponentType )
+ && ( m_eOpenMode == i_rCompareWith.eOpenMode );
+ }
+ private:
+ const OUString m_sName;
+ const sal_Int32 m_nComponentType;
+ const ElementOpenMode m_eOpenMode;
+ };
+ }
+
+ // SubComponentManager_Data
+ struct SubComponentManager_Data
+ {
+ SubComponentManager_Data( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
+ :m_rController( _rController )
+ ,m_aMutex( _rMutex )
+ {
+ }
+
+ OApplicationController& m_rController;
+ mutable ::comphelper::SharedMutex m_aMutex;
+ SubComponents m_aComponents;
+
+ ::osl::Mutex& getMutex() const { return m_aMutex; }
+ };
+
+ // SubComponentManager
+ SubComponentManager::SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex )
+ :m_pData( new SubComponentManager_Data( _rController, _rMutex ) )
+ {
+ }
+
+ SubComponentManager::~SubComponentManager()
+ {
+ }
+
+ void SubComponentManager::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+ m_pData->m_aComponents.clear();
+ }
+
+ namespace
+ {
+ bool lcl_fallbackToAnotherController( SubComponentDescriptor& _rCompDesc )
+ {
+ Reference< XController > xFallback;
+ OSL_PRECOND( _rCompDesc.xModel.is(), "lcl_fallbackToAnotherController: illegal call!" );
+ if ( !_rCompDesc.xModel.is() )
+ return false;
+
+ xFallback.set( _rCompDesc.xModel->getCurrentController() );
+ if ( xFallback == _rCompDesc.xController )
+ // don't accept the very same controller as fallback
+ xFallback.clear();
+
+ if ( !xFallback.is() )
+ {
+ // perhaps XModel2 can be of help here
+ Reference< XModel2 > xModel2( _rCompDesc.xModel, UNO_QUERY );
+ Reference< XEnumeration > xControllerEnum;
+ if ( xModel2.is() )
+ xControllerEnum = xModel2->getControllers();
+ while ( xControllerEnum.is() && xControllerEnum->hasMoreElements() )
+ {
+ xFallback.set( xControllerEnum->nextElement(), UNO_QUERY );
+ if ( xFallback == _rCompDesc.xController )
+ xFallback.clear();
+ }
+ }
+
+ if ( xFallback.is() )
+ {
+ _rCompDesc.xController = xFallback;
+ _rCompDesc.xFrame.set( xFallback->getFrame(), UNO_SET_THROW );
+ return true;
+ }
+
+ return false;
+ }
+
+ bool lcl_closeComponent( const Reference< XCommandProcessor >& _rxCommandProcessor )
+ {
+ bool bSuccess = false;
+ try
+ {
+ sal_Int32 nCommandIdentifier = _rxCommandProcessor->createCommandIdentifier();
+
+ Command aCommand;
+ aCommand.Name = "close";
+ _rxCommandProcessor->execute( aCommand, nCommandIdentifier, nullptr );
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+ }
+
+ bool lcl_closeComponent( const SubComponentDescriptor& _rComponent )
+ {
+ if ( _rComponent.xComponentCommandProcessor.is() )
+ return lcl_closeComponent( _rComponent.xComponentCommandProcessor );
+
+ Reference< XController > xController( _rComponent.xController );
+ OSL_ENSURE( xController.is(), "lcl_closeComponent: invalid controller!" );
+
+ // suspend the controller in the document
+ if ( xController.is() )
+ if ( !xController->suspend( true ) )
+ return false;
+
+ bool bSuccess = false;
+ try
+ {
+ Reference< XCloseable > xCloseable( _rComponent.xFrame, UNO_QUERY_THROW );
+ xCloseable->close( true );
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+ }
+
+ void lcl_notifySubComponentEvent( const SubComponentManager_Data& _rData, const char* _pAsciiEventName,
+ const SubComponentDescriptor& _rComponent )
+ {
+ try
+ {
+ Reference< XDocumentEventBroadcaster > xBroadcaster( _rData.m_rController.getModel(), UNO_QUERY_THROW );
+ xBroadcaster->notifyDocumentEvent(
+ OUString::createFromAscii( _pAsciiEventName ),
+ &_rData.m_rController,
+ makeAny( _rComponent.xFrame )
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ void SAL_CALL SubComponentManager::propertyChange( const PropertyChangeEvent& i_rEvent )
+ {
+ if ( i_rEvent.PropertyName != PROPERTY_NAME )
+ // by definition, it's allowed to broadcast more than what we've registered for
+ return;
+
+ // find the sub component whose name changed
+ for (auto & component : m_pData->m_aComponents)
+ {
+ if ( component.xDocumentDefinitionProperties != i_rEvent.Source )
+ continue;
+
+ OUString sNewName;
+ OSL_VERIFY( i_rEvent.NewValue >>= sNewName );
+
+ #if OSL_DEBUG_LEVEL > 0
+ OUString sOldKnownName( component.sName );
+ OUString sOldName;
+ OSL_VERIFY( i_rEvent.OldValue >>= sOldName );
+ OSL_ENSURE( sOldName == sOldKnownName, "SubComponentManager::propertyChange: inconsistency in the old names!" );
+ #endif
+
+ component.sName = sNewName;
+ break;
+ }
+ }
+
+ void SAL_CALL SubComponentManager::disposing( const EventObject& _rSource )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
+
+ SubComponentDescriptor aClosedComponent;
+
+ for ( SubComponents::iterator comp = m_pData->m_aComponents.begin();
+ comp != m_pData->m_aComponents.end();
+ ++comp
+ )
+ {
+ bool bRemove = false;
+
+ if ( comp->xController == _rSource.Source )
+ {
+ if ( !comp->xModel.is() )
+ {
+ bRemove = true;
+ }
+ else
+ {
+ // maybe this is just one view to the sub document, and only this view is closed
+ if ( !lcl_fallbackToAnotherController( *comp ) )
+ {
+ bRemove = true;
+ }
+ }
+ }
+ else if ( comp->xModel == _rSource.Source )
+ {
+ bRemove = true;
+ }
+
+ if ( bRemove )
+ {
+ aClosedComponent = *comp;
+ m_pData->m_aComponents.erase( comp );
+ break;
+ }
+ }
+
+ if ( aClosedComponent.is() )
+ {
+ aGuard.clear();
+ lcl_notifySubComponentEvent( *m_pData, "OnSubComponentClosed", aClosedComponent );
+ }
+ }
+
+ Sequence< Reference< XComponent> > SubComponentManager::getSubComponents() const
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+
+ Sequence< Reference< XComponent > > aComponents( m_pData->m_aComponents.size() );
+ std::transform(
+ m_pData->m_aComponents.begin(),
+ m_pData->m_aComponents.end(),
+ aComponents.getArray(),
+ SelectSubComponent()
+ );
+ return aComponents;
+ }
+
+ bool SubComponentManager::closeSubComponents()
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+
+ try
+ {
+ SubComponents aWorkingCopy( m_pData->m_aComponents );
+ for (auto const& elem : aWorkingCopy)
+ {
+ lcl_closeComponent(elem);
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return empty();
+ }
+
+ bool SubComponentManager::empty() const
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+ return m_pData->m_aComponents.empty();
+ }
+
+ void SubComponentManager::onSubComponentOpened( const OUString& _rName, const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode, const Reference< XComponent >& _rxComponent )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() );
+
+#if OSL_DEBUG_LEVEL > 0
+ if ( !_rName.isEmpty() )
+ {
+ // check there does not already exist such a component
+ auto subComponentNotExists = std::none_of(
+ m_pData->m_aComponents.begin(),
+ m_pData->m_aComponents.end(),
+ SubComponentMatch( _rName, _nComponentType, _eOpenMode )
+ );
+ OSL_ENSURE( subComponentNotExists, "already existent!" );
+ }
+#endif
+ SubComponentDescriptor aElement( _rName, _nComponentType, _eOpenMode, _rxComponent );
+ ENSURE_OR_THROW( aElement.xModel.is() || aElement.xController.is(), "illegal component" );
+
+ m_pData->m_aComponents.push_back( aElement );
+
+ // add as listener
+ if ( aElement.xController.is() )
+ aElement.xController->addEventListener( this );
+ if ( aElement.xModel.is() )
+ aElement.xModel->addEventListener( this );
+ if ( aElement.xDocumentDefinitionProperties.is() )
+ aElement.xDocumentDefinitionProperties->addPropertyChangeListener( PROPERTY_NAME, this );
+
+ // notify this to interested parties
+ aGuard.clear();
+ lcl_notifySubComponentEvent( *m_pData, "OnSubComponentOpened", aElement );
+ }
+
+ bool SubComponentManager::activateSubFrame( const OUString& _rName, const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode, Reference< XComponent >& o_rComponent ) const
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+
+ SubComponents::const_iterator pos = std::find_if(
+ m_pData->m_aComponents.begin(),
+ m_pData->m_aComponents.end(),
+ SubComponentMatch( _rName, _nComponentType, _eOpenMode )
+ );
+ if ( pos == m_pData->m_aComponents.end() )
+ // no component with this name/type/open mode
+ return false;
+
+ const Reference< XFrame > xFrame( pos->xFrame, UNO_SET_THROW );
+ const Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW );
+ xTopWindow->toFront();
+
+ if ( pos->xModel.is() )
+ o_rComponent = pos->xModel.get();
+ else if ( pos->xController.is() )
+ o_rComponent = pos->xController.get();
+ else
+ o_rComponent = pos->xFrame.get();
+
+ return true;
+ }
+
+ bool SubComponentManager::closeSubFrames( const OUString& i_rName, const sal_Int32 _nComponentType )
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+ ENSURE_OR_RETURN_FALSE( !i_rName.isEmpty(), "SubComponentManager::closeSubFrames: illegal name!" );
+
+ SubComponents aWorkingCopy( m_pData->m_aComponents );
+ for (auto const& elem : aWorkingCopy)
+ {
+ if ( ( elem.sName != i_rName ) || ( elem.nComponentType != _nComponentType ) )
+ continue;
+
+ if ( !lcl_closeComponent(elem) )
+ return false;
+ }
+
+ return true;
+ }
+
+ bool SubComponentManager::lookupSubComponent( const Reference< XComponent >& i_rComponent,
+ OUString& o_rName, sal_Int32& o_rComponentType )
+ {
+ for (auto const& component : m_pData->m_aComponents)
+ {
+ if ( ( component.xModel.is()
+ && ( component.xModel == i_rComponent )
+ )
+ || ( component.xController.is()
+ && ( component.xController == i_rComponent )
+ )
+ || ( component.xFrame.is()
+ && ( component.xFrame == i_rComponent )
+ )
+ )
+ {
+ o_rName = component.sName;
+ o_rComponentType = component.nComponentType;
+ return true;
+ }
+ }
+ return false;
+ }
+
+} // namespace dbaui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/subcomponentmanager.hxx b/dbaccess/source/ui/app/subcomponentmanager.hxx
new file mode 100644
index 000000000..a2f56badc
--- /dev/null
+++ b/dbaccess/source/ui/app/subcomponentmanager.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_SUBCOMPONENTMANAGER_HXX
+#define INCLUDED_DBACCESS_SOURCE_UI_APP_SUBCOMPONENTMANAGER_HXX
+
+#include <AppElementType.hxx>
+
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+
+#include <comphelper/sharedmutex.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace dbaui
+{
+
+ struct SubComponentManager_Data;
+ class OApplicationController;
+
+ // SubComponentManager
+ typedef ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener
+ > SubComponentManager_Base;
+ class SubComponentManager : public SubComponentManager_Base
+ {
+ public:
+ SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex );
+ virtual ~SubComponentManager() override;
+
+ void disposing();
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XDatabaseDocumentUI helpers
+ css::uno::Sequence< css::uno::Reference< css::lang::XComponent> >
+ getSubComponents() const;
+ bool closeSubComponents();
+
+ // container access
+ void onSubComponentOpened(
+ const OUString& _rName,
+ const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode,
+ const css::uno::Reference< css::lang::XComponent >&
+ _rxComponent
+ );
+ bool empty() const;
+
+ /** activates (i.e. brings to top) the frame in which the given component is loaded, if any
+
+ @return
+ <TRUE/> if any only of such a frame was found, i.e. the component had already been loaded
+ previously
+ */
+ bool activateSubFrame(
+ const OUString& _rName,
+ const sal_Int32 _nComponentType,
+ const ElementOpenMode _eOpenMode,
+ css::uno::Reference< css::lang::XComponent >& o_rComponent
+ ) const;
+
+ /** closes all frames of the given component
+
+ If a view for the component (given by name and type) has been loaded into one or more
+ frames (with potentially different OpenModes), then those frames are gracefully closed.
+
+ @return
+ <TRUE/> if and only if closing those frames was successful, or frames for the given sub component
+ exist.
+ */
+ bool closeSubFrames(
+ const OUString& _rName,
+ const sal_Int32 _nComponentType
+ );
+
+ /** searches for the given sub component
+
+ @param i_rComponent
+ the sub component to look up
+ @param o_rName
+ contains, upon successful return, the name of the sub component
+ @param o_nComponentType
+ contains, upon successful return, the type of the sub component
+ @return
+ <TRUE/> if and only if the component was found
+ */
+ bool lookupSubComponent(
+ const css::uno::Reference< css::lang::XComponent >& i_rComponent,
+ OUString& o_rName,
+ sal_Int32& o_rComponentType
+ );
+
+ private:
+ std::unique_ptr< SubComponentManager_Data > m_pData;
+ };
+
+} // namespace dbaui
+
+#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_SUBCOMPONENTMANAGER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/window_layout.txt b/dbaccess/source/ui/app/window_layout.txt
new file mode 100644
index 000000000..abb15f00b
--- /dev/null
+++ b/dbaccess/source/ui/app/window_layout.txt
@@ -0,0 +1,49 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+(still unfinished)
+
+OApplicationView
+|
++-OAppBorderWindow
+ |
+ +-OTitleWindow "Database"
+ | |
+ | +-OApplicationSwapWindow
+ | |
+ | +-OApplicationIconControl
+ |
+ +-OApplicationDetailView
+ |
+ +-OTitleWindow "Tasks"
+ | |
+ | +-OTasksWindow
+ | |
+ | +-OCreationList
+ |
+ +-OTitleWindow "Forms" "Tables" "Queries" "Reports"
+ |
+ +-OAppDetailPageHelper
+ |
+ +-SvTreeListBox*
+ |
+ +-FixedLine
+ |
+ +-Window (Border)
+ |
+ +-OPreviewWindow