summaryrefslogtreecommitdiffstats
path: root/dbaccess/source/ui/app
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /dbaccess/source/ui/app
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--dbaccess/source/ui/app/AppController.cxx2834
-rw-r--r--dbaccess/source/ui/app/AppController.hxx540
-rw-r--r--dbaccess/source/ui/app/AppControllerDnD.cxx869
-rw-r--r--dbaccess/source/ui/app/AppControllerGen.cxx736
-rw-r--r--dbaccess/source/ui/app/AppDetailPageHelper.cxx1221
-rw-r--r--dbaccess/source/ui/app/AppDetailPageHelper.hxx349
-rw-r--r--dbaccess/source/ui/app/AppDetailView.cxx510
-rw-r--r--dbaccess/source/ui/app/AppDetailView.hxx318
-rw-r--r--dbaccess/source/ui/app/AppIconControl.cxx238
-rw-r--r--dbaccess/source/ui/app/AppIconControl.hxx67
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.cxx133
-rw-r--r--dbaccess/source/ui/app/AppSwapWindow.hxx88
-rw-r--r--dbaccess/source/ui/app/AppTitleWindow.cxx65
-rw-r--r--dbaccess/source/ui/app/AppTitleWindow.hxx67
-rw-r--r--dbaccess/source/ui/app/AppView.cxx473
-rw-r--r--dbaccess/source/ui/app/AppView.hxx302
-rw-r--r--dbaccess/source/ui/app/ChildWindow.cxx25
-rw-r--r--dbaccess/source/ui/app/DocumentInfoPreview.cxx164
-rw-r--r--dbaccess/source/ui/app/DocumentInfoPreview.hxx59
-rw-r--r--dbaccess/source/ui/app/subcomponentmanager.cxx551
-rw-r--r--dbaccess/source/ui/app/subcomponentmanager.hxx120
-rw-r--r--dbaccess/source/ui/app/templwin.cxx38
-rw-r--r--dbaccess/source/ui/app/templwin.hxx28
-rw-r--r--dbaccess/source/ui/app/window_layout.txt49
24 files changed, 9844 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..06508d5c2
--- /dev/null
+++ b/dbaccess/source/ui/app/AppController.cxx
@@ -0,0 +1,2834 @@
+/* -*- 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 <dbexchange.hxx>
+#include <strings.hxx>
+#include <advancedsettingsdlg.hxx>
+#include "subcomponentmanager.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/transfer.hxx>
+#include <svtools/cliplistener.hxx>
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/interaction.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 <strings.hrc>
+#include <defaultobjectnamecheck.hxx>
+#include <databaseobjectview.hxx>
+#include <dbtreelistbox.hxx>
+#include "AppDetailView.hxx"
+#include <linkeddocuments.hxx>
+#include <UITools.hxx>
+#include <dsntypes.hxx>
+#include <dlgsave.hxx>
+#include <dbaccess_slotid.hrc>
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbu_OApplicationController_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaui::OApplicationController(context));
+}
+
+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 SERVICE_SDB_APPLICATIONCONTROLLER;
+}
+
+Sequence< OUString> SAL_CALL OApplicationController::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.application.DefaultViewController" };
+}
+
+namespace {
+
+class SelectionGuard;
+
+}
+
+// OApplicationController
+class SelectionNotifier
+{
+private:
+ ::comphelper::OInterfaceContainerHelper3<XSelectionChangeListener> 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() )
+ {
+ if ( ::comphelper::NamedValueCollection::getOrDefault( m_xModel->getArgs(), u"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( EHistoryType::PickList,
+ aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
+ aFilter,
+ getStrippedDatabaseName(),
+ std::nullopt, 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_NEWDOCDIRECT:
+ aReturn.bEnabled = true;
+ aReturn.sTitle = "private:factory/sdatabase";
+ break;
+ 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 constexpr OUStringLiteral s_sReportDesign = u"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
+ Reference< XInteractionHandler > xHandler = ::comphelper::NamedValueCollection::getOrDefault( _rxDocument->getArgs(), u"InteractionHandler", Reference< XInteractionHandler >() );
+ if ( xHandler.is() )
+ {
+ rtl::Reference pRequest( new ::comphelper::OInteractionRequest( _rException ) );
+ rtl::Reference pApprove( new ::comphelper::OInteractionApprove );
+ pRequest->addContinuation( pApprove );
+
+ try
+ {
+ xHandler->handle( pRequest );
+ }
+ 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_NEWDOCDIRECT:
+ case SID_OPENDOC:
+ {
+ Reference < XDispatchProvider > xProv( getFrame(), UNO_QUERY );
+ if ( xProv.is() )
+ {
+ URL aURL;
+ OUString aTarget;
+ if ( _nId == SID_NEWDOCDIRECT )
+ {
+ aURL.Complete = "private:factory/sdatabase?Interactive";
+ aTarget = "_default";
+ }
+ else
+ aURL.Complete = ".uno:Open";
+
+ if ( m_xUrlTransformer.is() )
+ m_xUrlTransformer->parseStrict( aURL );
+ Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, aTarget, 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();
+
+ ::sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE, getFrameWeld());
+ aFileDlg.SetContext(sfx2::FileDialogHelper::BaseSaveAs);
+ if (!sUrl.isEmpty())
+ 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( 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 );
+ insertHierarchyElement(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( 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:AddDirect", SID_NEWDOCDIRECT, CommandGroup::APPLICATION );
+ 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);
+
+ ElementType eType = getElementType(xContainer);
+ switch( eType )
+ {
+ case E_TABLE:
+ {
+ ensureConnection();
+ if ( xProp.is() && m_xMetaData.is() )
+ //TODO: tdf#133497 "OApplicationController::elementReplaced effectively does
+ // nothing":
+ (void) ::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(const weld::TreeView& rTreeView)
+{
+ OApplicationView* pContainer = getContainer();
+ if (!pContainer)
+ return false; // not handled
+
+ std::unique_ptr<weld::TreeIter> xHdlEntry = rTreeView.make_iterator();
+ if (!rTreeView.get_cursor(xHdlEntry.get()))
+ return false;
+
+ if (!pContainer->isLeaf(rTreeView, *xHdlEntry))
+ return false; // not handled
+
+ try
+ {
+ // opens a new frame with either the table or the query or report or form or view
+ openElementWithArguments(
+ getContainer()->getQualifiedName(xHdlEntry.get()),
+ 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( PROPERTY_GRAPHICAL_DESIGN, bQueryGraphicalMode );
+ }
+
+ }
+ else
+ {
+ pDesigner.reset( new ResultSetBrowser( getORB(), this, m_aCurrentFrame.getFrame(), _eType == E_TABLE ) );
+
+ if ( !aArguments.has( PROPERTY_SHOWMENU ) )
+ aArguments.put( PROPERTY_SHOWMENU, Any( 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, 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() const
+{
+ return "edit";
+}
+
+IController& OApplicationController::getCommandController()
+{
+ return *this;
+}
+
+::comphelper::OInterfaceContainerHelper2* OApplicationController::getContextMenuInterceptors()
+{
+ return &m_aContextMenuInterceptors;
+}
+
+Any OApplicationController::getCurrentSelection(weld::TreeView& rControl) const
+{
+ Sequence< NamedDatabaseObject > aSelection;
+ getContainer()->describeCurrentSelectionForControl(rControl, aSelection);
+ return Any( aSelection );
+}
+
+vcl::Window* OApplicationController::getMenuParent() const
+{
+ return getContainer()->getMenuParent();
+}
+
+void OApplicationController::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ getContainer()->adjustMenuPosition(rControl, rPos);
+}
+
+bool OApplicationController::requestQuickHelp(const void* /*pUserData*/, OUString& /*rText*/) const
+{
+ return false;
+}
+
+bool OApplicationController::requestDrag(const weld::TreeIter& /*rEntry*/)
+{
+ bool bSuccess = false;
+
+ OApplicationView* pContainer = getContainer();
+ if (pContainer && pContainer->getSelectionCount())
+ {
+ try
+ {
+ if (getContainer()->getDetailView())
+ {
+ TreeListBox* pTreeListBox = getContainer()->getDetailView()->getTreeWindow();
+
+ ElementType eType = getContainer()->getElementType();
+ if (eType == E_TABLE || eType == E_QUERY)
+ {
+ ODataClipboard& rExchange = static_cast<ODataClipboard&>(pTreeListBox->GetDataTransfer());
+ bSuccess = copySQLObject(rExchange);
+ }
+ else
+ {
+ svx::OComponentTransferable& rExchange = static_cast<svx::OComponentTransferable&>(pTreeListBox->GetDataTransfer());
+ bSuccess = copyDocObject(rExchange);
+ }
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ return bSuccess;
+}
+
+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() )
+ return DND_ACTION_NONE;
+
+ ElementType eType = pView->getElementType();
+ if ( eType == E_NONE || (eType == E_TABLE && isConnectionReadOnly()) )
+ return DND_ACTION_NONE;
+
+ // 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 )
+ return DND_ACTION_NONE;
+
+ sal_Int8 nAction = OComponentTransferable::canExtractComponentDescriptor(_rFlavors,eType == E_FORM) ? DND_ACTION_COPY : DND_ACTION_NONE;
+ if ( nAction == DND_ACTION_NONE )
+ return DND_ACTION_NONE;
+
+ auto xHitEntry = pView->getEntry(_rEvt.maPosPixel);
+ if (xHitEntry)
+ {
+ OUString sName = pView->getQualifiedName(xHitEntry.get());
+ 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;
+}
+
+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);
+ auto xHitEntry = pView->getEntry(_rEvt.maPosPixel);
+ if ( xHitEntry )
+ m_aAsyncDrop.aUrl = pView->getQualifiedName(xHitEntry.get());
+
+ 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.
+ if ( ::comphelper::NamedValueCollection::getOrDefault( m_xModel->getArgs(), u"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, Any( 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 )
+ return true;
+
+ try
+ {
+ // to get the 'modified' for the data source
+ ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) );
+ if ( aLayoutInfo.has( 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.getArray()[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);
+ auto pCurrentSelection = aCurrentSelection.getArray();
+ pCurrentSelection[0].Name = getDatabaseName();
+ switch ( eType )
+ {
+ case E_TABLE: pCurrentSelection[0].Type = DatabaseObjectContainer::TABLES; break;
+ case E_QUERY: pCurrentSelection[0].Type = DatabaseObjectContainer::QUERIES; break;
+ case E_FORM: pCurrentSelection[0].Type = DatabaseObjectContainer::FORMS; break;
+ case E_REPORT: pCurrentSelection[0].Type = DatabaseObjectContainer::REPORTS; break;
+ default:
+ OSL_FAIL( "OApplicationController::getSelection: unexpected current element type!" );
+ break;
+ }
+ }
+ }
+ return Any( 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..b7579c0cf
--- /dev/null
+++ b/dbaccess/source/ui/app/AppController.hxx
@@ -0,0 +1,540 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#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 TransferableHelper;
+class TransferableClipboardListener;
+
+namespace com::sun::star {
+ namespace container {
+ class XNameContainer;
+ class XContainer;
+ }
+ namespace ucb {
+ class XContent;
+ }
+}
+
+namespace svx
+{
+ class OComponentTransferable;
+}
+
+namespace weld
+{
+ class TreeView;
+}
+
+namespace dbaui
+{
+ class ODataClipboard;
+ class TreeListBox;
+ 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
+ rtl::Reference<TransferableHelper> copyObject();
+
+ /// fills rExchange with current object if it's a Table or Query
+ bool copySQLObject(ODataClipboard& rExchange);
+
+ /// fills rExchange with current object if it's a Form or Report
+ bool copyDocObject(svx::OComponentTransferable& rExchange);
+
+ /// 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 insertHierarchyElement( 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;
+
+ // 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(const weld::TreeView& 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 void* pUserData, OUString& rText) const override;
+ virtual bool requestDrag(const weld::TreeIter& rEntry) override;
+ virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override;
+ virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override;
+
+ // IContextMenuProvider
+ virtual OUString getContextMenuResourceName() const override;
+ virtual IController& getCommandController() override;
+ virtual ::comphelper::OInterfaceContainerHelper2*
+ getContextMenuInterceptors() override;
+ virtual css::uno::Any getCurrentSelection(weld::TreeView& rControl) const override;
+ virtual vcl::Window* getMenuParent() const override;
+ virtual void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) 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
+
+/* 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..3cc758acd
--- /dev/null
+++ b/dbaccess/source/ui/app/AppControllerDnD.cxx
@@ -0,0 +1,869 @@
+/* -*- 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 <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#
+ // 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::set< OUString > aDeleteNames(_rList.begin(), _rList.end());
+
+ 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;
+}
+
+bool OApplicationController::copySQLObject(ODataClipboard& rExchange)
+{
+ bool bSuccess = false;
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ ElementType eType = getContainer()->getElementType();
+ 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 )
+ {
+ rExchange.Update(sDataSource, CommandType::TABLE, sName, xConnection, getNumberFormatter(xConnection, getORB()), getORB());
+ }
+ else
+ {
+ rExchange.Update(sDataSource, CommandType::QUERY, sName, getNumberFormatter(xConnection, getORB()), getORB());
+ }
+ bSuccess = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+}
+
+bool OApplicationController::copyDocObject(svx::OComponentTransferable& rExchange)
+{
+ bool bSuccess = false;
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ ElementType eType = getContainer()->getElementType();
+ switch( eType )
+ {
+ 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);
+ rExchange.Update(getDatabaseName(), xContent);
+ bSuccess = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ catch(const SQLException&)
+ {
+ showError( SQLExceptionInfo( ::cppu::getCaughtException() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bSuccess;
+}
+
+rtl::Reference<TransferableHelper> OApplicationController::copyObject()
+{
+ try
+ {
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( getMutex() );
+
+ ElementType eType = getContainer()->getElementType();
+ switch( eType )
+ {
+ case E_TABLE:
+ case E_QUERY:
+ {
+ rtl::Reference<ODataClipboard> xExchange(new ODataClipboard);
+ if (copySQLObject(*xExchange))
+ return xExchange;
+ break;
+ }
+ case E_FORM:
+ case E_REPORT:
+ {
+ rtl::Reference<svx::OComponentTransferable> xExchange(new svx::OComponentTransferable);
+ if (copyDocObject(*xExchange))
+ return xExchange;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ 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,Any(sCommand));
+ xNewQuery->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,Any(bEscapeProcessing));
+ }
+ // insert
+ xDestQueries->insertByName( sTargetName, Any(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 insertHierarchyElement(_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();
+ std::u16string_view sErase = o3tl::getToken(sName,0,'/',nIndex); // we don't want to have the "private:forms" part
+ if ( nIndex != -1 )
+ {
+ aList.push_back(sName.copy(sErase.size() + 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..22dfb3663
--- /dev/null
+++ b/dbaccess/source/ui/app/AppControllerGen.cxx
@@ -0,0 +1,736 @@
+/* -*- 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/mnemonic.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/weld.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,Any(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);
+ auto pArgs = aArgs.getArray();
+ 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
+ pArgs[nArgPos++] <<= PropertyValue( "ParentWindow",
+ 0,
+ Any(xWindow),
+ PropertyState_DIRECT_VALUE);
+
+ // the initial selection
+ OUString sInitialSelection;
+ if ( getContainer() )
+ sInitialSelection = getDatabaseName();
+ if ( !sInitialSelection.isEmpty() )
+ {
+ pArgs[ nArgPos++ ] <<= PropertyValue(
+ "InitialSelection", 0,
+ Any( sInitialSelection ), PropertyState_DIRECT_VALUE );
+ }
+
+ SharedConnection xConnection( getConnection() );
+ if ( xConnection.is() )
+ {
+ pArgs[ 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, Any( 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::insertHierarchyElement(ElementType _eType, const OUString& _sParentFolder, bool _bCollection, const Reference<XContent>& _xContent, bool _bMove)
+{
+ Reference<XHierarchicalNameContainer> xNames(getElements(_eType), UNO_QUERY);
+ return dbaui::insertHierarchyElement(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 constexpr OUStringLiteral s_sStatusbar = u"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
+ if (SystemWindow* pSystemWindow = getContainer()->GetSystemWindow())
+ pSystemWindow->CollectMenuBarMnemonics(aMnemonicGenerator);
+ // - 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..b7506744d
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailPageHelper.cxx
@@ -0,0 +1,1221 @@
+/* -*- 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/PopupMenu.hpp>
+#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/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XFrames.hpp>
+#include <com/sun/star/frame/XFramesSupplier.hpp>
+#include <com/sun/star/frame/XPopupMenuController.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 <o3tl/string_view.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/cvtgrf.hxx>
+#include <tools/stream.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
+{
+ bool lcl_findEntry_impl(const TreeListBox& rTree, std::u16string_view rName, weld::TreeIter& rIter)
+ {
+ bool bReturn = false;
+ sal_Int32 nIndex = 0;
+ std::u16string_view sName( o3tl::getToken(rName,0,'/',nIndex) );
+
+ const weld::TreeView& rTreeView = rTree.GetWidget();
+ bool bEntry = true;
+ do
+ {
+ if (rTreeView.get_text(rIter) == sName)
+ {
+ if ( nIndex != -1 )
+ {
+ sName = o3tl::getToken(rName,0,'/',nIndex);
+ bEntry = rTreeView.iter_children(rIter);
+ }
+ else
+ {
+ bReturn = true;
+ break;
+ }
+ }
+ else
+ bEntry = rTreeView.iter_next_sibling(rIter);
+ }
+ while (bEntry);
+
+ return bReturn;
+ }
+
+ bool lcl_findEntry(const TreeListBox& rTree, std::u16string_view rName, weld::TreeIter& rIter)
+ {
+ sal_Int32 nIndex = 0;
+ std::u16string_view sErase = o3tl::getToken(rName,0,'/',nIndex); // we don't want to have the "private:forms" part
+ return nIndex != -1 && lcl_findEntry_impl(rTree, rName.substr(sErase.size() + 1), rIter);
+ }
+}
+
+OAppDetailPageHelper::OAppDetailPageHelper(weld::Container* pParent, OAppBorderWindow& rBorderWin, PreviewMode ePreviewMode)
+ : OChildWindow(pParent, "dbaccess/ui/detailwindow.ui", "DetailWindow")
+ , m_rBorderWin(rBorderWin)
+ , m_xBox(m_xBuilder->weld_container("box"))
+ , m_xFL(m_xBuilder->weld_widget("separator"))
+ , m_xMBPreview(m_xBuilder->weld_menu_button("disablepreview"))
+ , m_xPreview(new OPreviewWindow)
+ , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview))
+ , m_xDocumentInfo(new ODocumentInfoPreview)
+ , m_xDocumentInfoWin(new weld::CustomWeld(*m_xBuilder, "infopreview", *m_xDocumentInfo))
+ , m_xTablePreview(m_xBuilder->weld_container("tablepreview"))
+ , m_ePreviewMode(ePreviewMode)
+{
+ m_xContainer->set_stack_background();
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:DBDisablePreview",
+ "com.sun.star.sdb.OfficeDatabaseDocument");
+ m_xMBPreview->set_label(vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
+ m_xMBPreview->set_help_id(HID_APP_VIEW_PREVIEW_CB);
+
+ m_xMBPreview->connect_selected(LINK(this, OAppDetailPageHelper, MenuSelectHdl));
+ m_xMBPreview->connect_toggled(LINK(this, OAppDetailPageHelper, OnDropdownClickHdl));
+
+ m_xPreview->SetHelpId(HID_APP_VIEW_PREVIEW_1);
+
+ m_xTablePreview->set_help_id(HID_APP_VIEW_PREVIEW_2);
+ m_xDocumentInfo->SetHelpId(HID_APP_VIEW_PREVIEW_3);
+
+ m_xWindow = m_xTablePreview->CreateChildFrame();
+}
+
+OAppDetailPageHelper::~OAppDetailPageHelper()
+{
+ try
+ {
+ Reference< ::util::XCloseable> xCloseable(m_xFrame,UNO_QUERY);
+ if ( xCloseable.is() )
+ xCloseable->close(true);
+ m_xFrame.clear();
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "Exception thrown while disposing preview frame!");
+ }
+
+ for (auto& rpBox : m_aLists)
+ {
+ if (!rpBox)
+ continue;
+ rpBox.reset();
+ }
+
+ m_xWindow->dispose();
+ m_xWindow.clear();
+
+ m_xTablePreview.reset();
+ m_xDocumentInfoWin.reset();
+ m_xDocumentInfo.reset();
+ m_xPreviewWin.reset();
+ m_xPreview.reset();
+ m_xMBPreview.reset();
+ m_xFL.reset();
+ m_xBox.reset();
+}
+
+int OAppDetailPageHelper::getVisibleControlIndex() const
+{
+ int i = 0;
+ for (; i < E_ELEMENT_TYPE_COUNT ; ++i)
+ {
+ if (m_aLists[i] && m_aLists[i]->get_visible())
+ break;
+ }
+ return i;
+}
+
+void OAppDetailPageHelper::selectAll()
+{
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT)
+ {
+ m_aLists[nPos]->GetWidget().select_all();
+ }
+}
+
+void OAppDetailPageHelper::GrabFocus()
+{
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT)
+ m_aLists[nPos]->GetWidget().grab_focus();
+ else if (m_xMBPreview && m_xMBPreview->get_visible())
+ m_xMBPreview->grab_focus();
+}
+
+bool OAppDetailPageHelper::HasChildPathFocus() const
+{
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT && m_aLists[nPos]->GetWidget().has_focus())
+ return true;
+ return m_xMBPreview && m_xMBPreview->has_focus();
+}
+
+void OAppDetailPageHelper::sort(int nPos, bool bAscending)
+{
+ assert(m_aLists[nPos] && "List can not be NULL! ->GPF");
+ m_aLists[nPos]->GetWidget().set_sort_order(bAscending);
+}
+
+bool OAppDetailPageHelper::isSortUp() const
+{
+ bool bAscending = false;
+
+ int nPos = getVisibleControlIndex();
+ if (nPos < E_ELEMENT_TYPE_COUNT)
+ bAscending = m_aLists[nPos]->GetWidget().get_sort_order();
+
+ return bAscending;
+}
+
+void OAppDetailPageHelper::sortDown()
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ sort(nPos, false);
+}
+
+void OAppDetailPageHelper::sortUp()
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ sort(nPos, true);
+}
+
+void OAppDetailPageHelper::getSelectionElementNames(std::vector<OUString>& rNames) const
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return;
+
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ sal_Int32 nCount = rTreeView.n_children();
+ rNames.reserve(nCount);
+ ElementType eType = getElementType();
+
+ rTreeView.selected_foreach([this, eType, &rTreeView, &rNames](weld::TreeIter& rEntry){
+ if ( eType == E_TABLE )
+ {
+ if (!rTreeView.iter_has_child(rEntry))
+ rNames.push_back(getQualifiedName(&rEntry));
+ }
+ else
+ {
+ OUString sName = rTreeView.get_text(rEntry);
+ std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
+ bool bParent = rTreeView.iter_parent(*xParent);
+ while (bParent)
+ {
+ sName = rTreeView.get_text(*xParent) + "/" + sName;
+ bParent = rTreeView.iter_parent(*xParent);
+ }
+ rNames.push_back(sName);
+ }
+
+ return false;
+ });
+}
+
+void OAppDetailPageHelper::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence< NamedDatabaseObject >& out_rSelectedObjects)
+{
+ for (size_t i=0; i < E_ELEMENT_TYPE_COUNT; ++i)
+ {
+ if (&m_aLists[i]->GetWidget() == &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!" );
+ DBTreeViewBase* pList = ( eType < E_ELEMENT_TYPE_COUNT ) ? m_aLists[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;
+
+ weld::TreeView& rTreeView = pList->GetWidget();
+ rTreeView.selected_foreach([pList, eType, &rTreeView, &aSelected](weld::TreeIter& rEntry){
+ NamedDatabaseObject aObject;
+ switch (eType)
+ {
+ case E_TABLE:
+ {
+ OTableTreeListBox& rTableTree = static_cast<OTableTreeListBox&>(pList->getListBox());
+ aObject = rTableTree.describeObject(rEntry);
+ break;
+ }
+ case E_QUERY:
+ aObject.Type = DatabaseObject::QUERY;
+ aObject.Name = rTreeView.get_text(rEntry);
+ break;
+ case E_FORM:
+ case E_REPORT:
+ {
+ OUString sName = rTreeView.get_text(rEntry);
+ std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
+ bool bParent = rTreeView.iter_parent(*xParent);
+ while (bParent)
+ {
+ sName = rTreeView.get_text(*xParent) + "/" + sName;
+ bParent = rTreeView.iter_parent(*xParent);
+ }
+
+ if (isLeaf(rTreeView, rEntry))
+ 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);
+
+ return false;
+ });
+
+ _out_rSelectedObjects = comphelper::containerToSequence(aSelected);
+}
+
+vcl::Window* OAppDetailPageHelper::getMenuParent() const
+{
+ return &m_rBorderWin;
+}
+
+void OAppDetailPageHelper::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ int x, y, width, height;
+ if (rControl.get_extents_relative_to(m_rBorderWin.getTopLevel(), x, y, width, height))
+ {
+ rPos.AdjustX(x);
+ rPos.AdjustY(y);
+ }
+}
+
+void OAppDetailPageHelper::selectElements(const Sequence< OUString>& _aNames)
+{
+ int nPos = getVisibleControlIndex();
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return;
+
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ rTreeView.unselect_all();
+ const OUString* pIter = _aNames.getConstArray();
+ const OUString* pEnd = pIter + _aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ auto xEntry = rTree.getListBox().GetEntryPosByName(*pIter);
+ if (!xEntry)
+ continue;
+ rTreeView.select(*xEntry);
+ }
+}
+
+OUString OAppDetailPageHelper::getQualifiedName(const weld::TreeIter* _pEntry) const
+{
+ int nPos = getVisibleControlIndex();
+ OUString sComposedName;
+
+ if ( nPos >= E_ELEMENT_TYPE_COUNT )
+ return sComposedName;
+
+ OSL_ENSURE(m_aLists[nPos],"Tables tree view is NULL! -> GPF");
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(_pEntry));
+ if (!_pEntry)
+ {
+ if (!rTreeView.get_selected(xEntry.get()))
+ xEntry.reset();
+ }
+
+ if (!xEntry)
+ return sComposedName;
+
+ if ( getElementType() == E_TABLE )
+ {
+ const OTableTreeListBox& rTableTreeListBox = static_cast<const OTableTreeListBox&>(m_aLists[nPos]->getListBox());
+ sComposedName = rTableTreeListBox.getQualifiedTableName(*xEntry);
+ }
+ else
+ {
+ sComposedName = rTreeView.get_text(*xEntry);
+ bool bParent = rTreeView.iter_parent(*xEntry);
+ while (bParent)
+ {
+ sComposedName = rTreeView.get_text(*xEntry) + "/" + sComposedName;
+ bParent = rTreeView.iter_parent(*xEntry);
+ }
+ }
+
+ 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 )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ nCount = rTreeView.count_selected_rows();
+ }
+ return nCount;
+}
+
+sal_Int32 OAppDetailPageHelper::getElementCount() const
+{
+ sal_Int32 nCount = 0;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ nCount = rTreeView.n_children();
+ }
+ return nCount;
+}
+
+bool OAppDetailPageHelper::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry)
+{
+ sal_Int32 nEntryType = rTreeView.get_id(rEntry).toInt32();
+ 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 )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ rTreeView.selected_foreach([&rTreeView, &bLeafSelected](weld::TreeIter& rEntry){
+ bLeafSelected = isLeaf(rTreeView, rEntry);
+ return bLeafSelected;
+ });
+ }
+ return bLeafSelected;
+}
+
+std::unique_ptr<weld::TreeIter> OAppDetailPageHelper::getEntry( const Point& _aPosPixel) const
+{
+ std::unique_ptr<weld::TreeIter> xReturn;
+ int nPos = getVisibleControlIndex();
+ if ( nPos < E_ELEMENT_TYPE_COUNT )
+ {
+ DBTreeViewBase& rTree = *m_aLists[nPos];
+ weld::TreeView& rTreeView = rTree.GetWidget();
+ xReturn = rTreeView.make_iterator();
+ if (!rTreeView.get_dest_row_at_pos(_aPosPixel, xReturn.get(), false))
+ xReturn.reset();
+ }
+ return xReturn;
+}
+
+void OAppDetailPageHelper::createTablesPage(const Reference< XConnection>& _xConnection)
+{
+ OSL_ENSURE(_xConnection.is(),"Connection is NULL! -> GPF");
+
+ if ( !m_aLists[E_TABLE] )
+ {
+ m_aLists[E_TABLE].reset(new DBTableTreeView(m_xBox.get()));
+ setupTree(*m_aLists[E_TABLE]);
+ m_aLists[E_TABLE]->GetWidget().set_help_id(HID_APP_TABLE_TREE);
+ }
+
+ weld::TreeView& rTreeView = m_aLists[E_TABLE]->GetWidget();
+ if (!rTreeView.n_children())
+ {
+ static_cast<OTableTreeListBox&>(m_aLists[E_TABLE]->getListBox()).UpdateTableList(_xConnection);
+
+ std::unique_ptr<weld::TreeIter> xFirst(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xFirst))
+ rTreeView.expand_row(*xFirst);
+ rTreeView.unselect_all();
+ }
+
+ setDetailPage(*m_aLists[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;
+ switch( _eType )
+ {
+ case E_FORM:
+ sHelpId = HID_APP_FORM_TREE;
+ break;
+ case E_REPORT:
+ sHelpId = HID_APP_REPORT_TREE;
+ break;
+ case E_QUERY:
+ sHelpId = HID_APP_QUERY_TREE;
+ break;
+ default:
+ OSL_FAIL("Illegal call!");
+ }
+ OUString sImageId = getElementIcons(_eType);
+
+ if ( !m_aLists[_eType] )
+ {
+ m_aLists[_eType] = createSimpleTree(sHelpId, _eType);
+ }
+
+ if ( !m_aLists[_eType] )
+ return;
+
+ weld::TreeView& rTreeView = m_aLists[_eType]->GetWidget();
+ if (!rTreeView.n_children() && _xContainer.is())
+ {
+ rTreeView.make_unsorted();
+ fillNames( _xContainer, _eType, sImageId, nullptr );
+ rTreeView.make_sorted();
+
+ rTreeView.unselect_all();
+ }
+ setDetailPage(*m_aLists[_eType]);
+}
+
+void OAppDetailPageHelper::setDetailPage(DBTreeViewBase& rTreeView)
+{
+ bool bHasFocus = false;
+
+ DBTreeViewBase* pCurrent = getCurrentView();
+ if (pCurrent)
+ {
+ weld::Widget& rCurrent = pCurrent->GetWidget();
+ bHasFocus = rCurrent.has_focus();
+ pCurrent->hide();
+ }
+
+ showPreview(nullptr);
+ m_xFL->show();
+ rTreeView.show();
+ m_xMBPreview->show();
+ switchPreview(m_ePreviewMode,true);
+
+ if (bHasFocus)
+ rTreeView.GetWidget().grab_focus();
+}
+
+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, const weld::TreeIter* _pParent )
+{
+ OSL_ENSURE(_xContainer.is(),"Data source is NULL! -> GPF");
+ OSL_ENSURE( ( _eType >= E_TABLE ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OAppDetailPageHelper::fillNames: invalid type!" );
+
+ DBTreeViewBase* pList = m_aLists[_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;
+
+ weld::TreeView& rTreeView = pList->GetWidget();
+
+ std::unique_ptr<weld::TreeIter> xRet = rTreeView.make_iterator();
+ 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)
+ {
+ Reference<XNameAccess> xSubElements(_xContainer->getByName(*pIter),UNO_QUERY);
+ if ( xSubElements.is() )
+ {
+ OUString sId(OUString::number(nFolderIndicator));
+
+ rTreeView.insert(_pParent, -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, *pIter, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ getBorderWin().getView()->getAppController().containerFound( Reference< XContainer >( xSubElements, UNO_QUERY ) );
+ fillNames( xSubElements, _eType, rImageId, xRet.get());
+ }
+ else
+ {
+ rTreeView.insert(_pParent, -1, nullptr, nullptr, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, *pIter, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ rTreeView.set_image(*xRet, rImageId);
+ }
+ }
+}
+
+std::unique_ptr<DBTreeViewBase> OAppDetailPageHelper::createSimpleTree(const OString& rHelpId, ElementType eType)
+{
+ const bool bSQLType = eType == E_TABLE || eType == E_QUERY;
+ std::unique_ptr<DBTreeViewBase> xTreeView(new DBTreeView(m_xBox.get(), bSQLType));
+ xTreeView->GetWidget().set_help_id(rHelpId);
+ setupTree(*xTreeView);
+ return xTreeView;
+}
+
+void OAppDetailPageHelper::setupTree(DBTreeViewBase& rDBTreeView)
+{
+ weld::WaitObject aWaitCursor(m_rBorderWin.GetFrameWeld());
+
+ rDBTreeView.getListBox().setCopyHandler(LINK(this, OAppDetailPageHelper, OnCopyEntry));
+ rDBTreeView.getListBox().setPasteHandler(LINK(this, OAppDetailPageHelper, OnPasteEntry));
+ rDBTreeView.getListBox().setDeleteHandler(LINK(this, OAppDetailPageHelper, OnDeleteEntry));
+
+ weld::TreeView& rTreeView = rDBTreeView.GetWidget();
+ rTreeView.make_sorted();
+ rTreeView.set_selection_mode(SelectionMode::Multiple);
+ // an arbitrary small size it's allowed to shrink to
+ rTreeView.set_size_request(42, 42);
+
+ rTreeView.connect_row_activated(LINK(this, OAppDetailPageHelper, OnEntryDoubleClick));
+
+ rDBTreeView.getListBox().SetSelChangeHdl(LINK(this, OAppDetailPageHelper, OnEntrySelChange));
+
+ rDBTreeView.getListBox().setControlActionListener(&getBorderWin().getView()->getAppController());
+ rDBTreeView.getListBox().setContextMenuProvider(&getBorderWin().getView()->getAppController());
+}
+
+void OAppDetailPageHelper::clearPages()
+{
+ showPreview(nullptr);
+ for (auto& rpBox : m_aLists)
+ {
+ if ( rpBox )
+ rpBox->GetWidget().clear();
+ }
+}
+
+bool OAppDetailPageHelper::isFilled() const
+{
+ size_t i = 0;
+ for (; i < E_ELEMENT_TYPE_COUNT && !m_aLists[i]; ++i)
+ ;
+ return i != E_ELEMENT_TYPE_COUNT;
+}
+
+void OAppDetailPageHelper::elementReplaced(ElementType eType,
+ const OUString& rOldName,
+ const OUString& rNewName)
+{
+ DBTreeViewBase* pTreeView = getCurrentView();
+ if (!pTreeView)
+ return;
+
+ weld::TreeView& rTreeView = pTreeView->GetWidget();
+ rTreeView.make_unsorted();
+
+ switch (eType)
+ {
+ case E_TABLE:
+ static_cast<OTableTreeListBox&>(pTreeView->getListBox()).removedTable(rOldName);
+ static_cast<OTableTreeListBox&>(pTreeView->getListBox()).addedTable(rNewName);
+ break;
+ case E_QUERY:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry_impl(pTreeView->getListBox(), rOldName, *xIter))
+ rTreeView.set_text(*xIter, rNewName);
+ break;
+ }
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), rOldName, *xIter))
+ rTreeView.set_text(*xIter, rNewName);
+ break;
+ }
+ default:
+ OSL_FAIL("Invalid element type");
+ }
+
+ rTreeView.make_sorted();
+}
+
+std::unique_ptr<weld::TreeIter> OAppDetailPageHelper::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject )
+{
+ std::unique_ptr<weld::TreeIter> xRet;
+ DBTreeViewBase* pTreeView = m_aLists[_eType].get();
+ if (!pTreeView)
+ return xRet;
+ weld::TreeView& rTreeView = pTreeView->GetWidget();
+ rTreeView.make_unsorted();
+ if (_eType == E_TABLE)
+ {
+ xRet = static_cast<OTableTreeListBox&>(pTreeView->getListBox()).addedTable( _rName );
+ }
+ else
+ {
+ std::unique_ptr<weld::TreeIter> xEntry;
+ 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();
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), sName, *xIter))
+ xEntry = std::move(xIter);
+ }
+ }
+
+ OUString sImageId = getElementIcons(_eType);
+ Reference<XNameAccess> xContainer(_rObject,UNO_QUERY);
+ if ( xContainer.is() )
+ {
+ const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType );
+ OUString sId(OUString::number(nFolderIndicator));
+
+ xRet = rTreeView.make_iterator();
+ rTreeView.insert(xEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, _rName, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ fillNames(xContainer, _eType, sImageId, xRet.get());
+ }
+ else
+ {
+ xRet = rTreeView.make_iterator();
+ rTreeView.insert(xEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xRet.get());
+ rTreeView.set_text(*xRet, _rName, 0);
+ rTreeView.set_text_emphasis(*xRet, false, 0);
+ rTreeView.set_image(*xRet, sImageId);
+ }
+ }
+ rTreeView.make_sorted();
+ return xRet;
+}
+
+void OAppDetailPageHelper::elementRemoved( ElementType _eType,const OUString& _rName )
+{
+ DBTreeViewBase* pTreeView = getCurrentView();
+ if ( !pTreeView )
+ return;
+
+ weld::TreeView& rTreeView = pTreeView->GetWidget();
+
+ 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->getListBox()).removedTable(_rName);
+ break;
+ case E_QUERY:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry_impl(pTreeView->getListBox(), _rName, *xIter))
+ rTreeView.remove(*xIter);
+ break;
+ }
+ case E_FORM:
+ case E_REPORT:
+ {
+ std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xIter) && lcl_findEntry(pTreeView->getListBox(), _rName, *xIter))
+ rTreeView.remove(*xIter);
+ break;
+ }
+ default:
+ OSL_FAIL("Invalid element type");
+ }
+ if (!rTreeView.n_children())
+ showPreview(nullptr);
+}
+
+IMPL_LINK(OAppDetailPageHelper, OnEntryDoubleClick, weld::TreeView&, rTreeView, bool)
+{
+ return getBorderWin().getView()->getAppController().onEntryDoubleClick(rTreeView);
+}
+
+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();
+}
+
+bool OAppDetailPageHelper::isPreviewEnabled() const
+{
+ return m_ePreviewMode != E_PREVIEWNONE;
+}
+
+namespace
+{
+ OUString stripTrailingDots(std::u16string_view rStr)
+ {
+ return OUString(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_xMBPreview->set_label(stripTrailingDots(aCommandLabel));
+
+ // simulate a selectionChanged event at the controller, to force the preview to be updated
+ if ( isPreviewEnabled() )
+ {
+ DBTreeViewBase* pCurrent = getCurrentView();
+ if (pCurrent && pCurrent->GetWidget().get_selected(nullptr))
+ {
+ getBorderWin().getView()->getAppController().onSelectionChanged();
+ }
+ }
+ else
+ {
+ m_xTablePreview->hide();
+ m_xPreview->Hide();
+ m_xDocumentInfo->Hide();
+ }
+}
+
+void OAppDetailPageHelper::showPreview(const Reference< XContent >& _xContent)
+{
+ if ( !isPreviewEnabled() )
+ return;
+
+ m_xTablePreview->hide();
+
+ weld::WaitObject aWaitCursor(m_rBorderWin.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_xDocumentInfo->Hide();
+ m_xPreview->Show();
+
+ Graphic aGraphic;
+ Sequence < sal_Int8 > aBmpSequence;
+ if ( aPreview >>= aBmpSequence )
+ {
+ SvMemoryStream aData( aBmpSequence.getArray(),
+ aBmpSequence.getLength(),
+ StreamMode::READ );
+
+ GraphicConverter::Import(aData,aGraphic);
+ }
+ m_xPreview->setGraphic( aGraphic );
+ m_xPreview->Invalidate();
+ }
+ else
+ {
+ m_xPreview->Hide();
+ m_xDocumentInfo->clear();
+ m_xDocumentInfo->Show();
+ Reference<document::XDocumentProperties> xProp(
+ aPreview, UNO_QUERY);
+ if ( xProp.is() )
+ m_xDocumentInfo->fill(xProp);
+ }
+ }
+ else
+ {
+ m_xPreview->Hide();
+ m_xDocumentInfo->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(m_rBorderWin.GetFrameWeld());
+ m_xPreview->Hide();
+ m_xDocumentInfo->Hide();
+ m_xTablePreview->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( PROPERTY_SHOWMENU, false );
+
+ Reference< XController > xPreview( pDispatcher->openExisting( Any( _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);
+}
+
+namespace
+{
+ class MenuStatusListener final : public ::cppu::WeakImplHelper<css::frame::XStatusListener>
+ {
+ weld::MenuButton& m_rMBPreview;
+ public:
+ MenuStatusListener(weld::MenuButton& rMBPreview)
+ : m_rMBPreview(rMBPreview)
+ {
+ }
+
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent &rEvent) override
+ {
+ if (!rEvent.IsEnabled)
+ {
+ const OUString &rURL = rEvent.FeatureURL.Complete;
+ m_rMBPreview.remove_item(rURL.toUtf8());
+ }
+ }
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& /*rSource*/) override
+ {
+ }
+ };
+};
+
+IMPL_LINK_NOARG(OAppDetailPageHelper, OnDropdownClickHdl, weld::Toggleable&, void)
+{
+ if (!m_xMBPreview->get_active())
+ return;
+
+ m_xMBPreview->clear();
+
+ // 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;
+
+ auto xFrame = getBorderWin().getView()->getAppController().getFrame();
+
+ css::uno::Sequence<css::uno::Any> aArgs {
+ css::uno::Any(comphelper::makePropertyValue("InToolbar", true)),
+ css::uno::Any(comphelper::makePropertyValue("ModuleIdentifier", OUString("com.sun.star.sdb.OfficeDatabaseDocument"))),
+ css::uno::Any(comphelper::makePropertyValue("Frame", xFrame)) };
+
+ css::uno::Reference<css::frame::XPopupMenuController> xPopupController
+ (xPopupMenuFactory->createInstanceWithArgumentsAndContext(".uno:DBPreview", aArgs, xContext), css::uno::UNO_QUERY);
+
+ if (!xPopupController.is())
+ return;
+
+ css::uno::Reference<css::awt::XPopupMenu> xPopupMenu(css::awt::PopupMenu::create(xContext));
+ xPopupController->setPopupMenu(xPopupMenu);
+
+ css::util::URL aTargetURL;
+ Reference<XDispatchProvider> xDispatchProvider(xFrame, css::uno::UNO_QUERY);
+
+ css::uno::Reference<css::frame::XStatusListener> xStatusListener(new MenuStatusListener(*m_xMBPreview));
+
+ for (int i = 0, nCount = xPopupMenu->getItemCount(); i < nCount; ++i)
+ {
+ auto nItemId = xPopupMenu->getItemId(i);
+ // in practice disabled items are initially enabled so this doesn't have an effect and
+ // an status update is needed to query the enabled/disabled state
+ if (!xPopupMenu->isItemEnabled(nItemId))
+ continue;
+
+ aTargetURL.Complete = xPopupMenu->getCommand(nItemId);
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aTargetURL.Complete,
+ "com.sun.star.sdb.OfficeDatabaseDocument");
+ m_xMBPreview->append_item(aTargetURL.Complete, vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
+
+ // Add/remove status listener to get a status update once so we can remove any disabled items from the menu
+ auto xDispatch = xDispatchProvider->queryDispatch(aTargetURL, "_self",
+ css::frame::FrameSearchFlag::SELF);
+ if (xDispatch.is())
+ {
+ xDispatch->addStatusListener(xStatusListener, aTargetURL);
+ xDispatch->removeStatusListener(xStatusListener, aTargetURL);
+ }
+ }
+
+ css::uno::Reference<css::lang::XComponent> xComponent(xPopupController, css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose();
+}
+
+IMPL_LINK(OAppDetailPageHelper, MenuSelectHdl, const OString&, rIdent, void)
+{
+ if (rIdent.isEmpty())
+ return;
+
+ css::util::URL aURL;
+ aURL.Complete = OUString::fromUtf8(rIdent);
+
+ Reference<XDispatchProvider> xProvider(getBorderWin().getView()->getAppController().getFrame(), UNO_QUERY);
+ Reference<XDispatch> xDisp = xProvider->queryDispatch(aURL, "_self", 0);
+ xDisp->dispatch(aURL, css::uno::Sequence<css::beans::PropertyValue>());
+
+ m_xMBPreview->set_label(stripTrailingDots(m_xMBPreview->get_item_label(rIdent)));
+}
+
+OPreviewWindow::OPreviewWindow()
+{
+}
+
+bool OPreviewWindow::ImplGetGraphicCenterRect(const vcl::RenderContext& rRenderContext, const Graphic& rGraphic, tools::Rectangle& rResultRect) const
+{
+ const Size aWinSize( GetOutputSizePixel() );
+ Size aNewSize(rRenderContext.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<tools::Long>( aWinSize.Height() * fGrfWH ) );
+ aNewSize.setHeight( aWinSize.Height() );
+ }
+ else
+ {
+ aNewSize.setWidth( aWinSize.Width() );
+ aNewSize.setHeight( static_cast<tools::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*/)
+{
+ if (ImplGetGraphicCenterRect(rRenderContext, 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);
+ }
+}
+
+/* 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..25cc3229a
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailPageHelper.hxx
@@ -0,0 +1,349 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#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 <vcl/graph.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+#include <AppElementType.hxx>
+#include <ChildWindow.hxx>
+#include "DocumentInfoPreview.hxx"
+
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::frame { class XFrame2; }
+namespace com::sun::star::io { class XPersist; }
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class ODocumentInfoPreview;
+ class DBTreeViewBase;
+ class TreeListBox;
+
+ class OPreviewWindow final : public weld::CustomWidgetController
+ {
+ GraphicObject m_aGraphicObj;
+ tools::Rectangle m_aPreviewRect;
+
+ /** gets the graphic center rect
+ @param rRenderContext
+ the context to which we are drawing
+ @param rGraphic
+ the graphic
+ @param rResultRect
+ the resulting rectangle
+
+ @return
+ <TRUE/> when successful
+ */
+ bool ImplGetGraphicCenterRect(const vcl::RenderContext& rRenderContext, const Graphic& rGraphic, tools::Rectangle& rResultRect) const;
+
+ public:
+ OPreviewWindow();
+
+ 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 final : public OChildWindow
+ {
+ std::unique_ptr<DBTreeViewBase> m_aLists[size_t(E_ELEMENT_TYPE_COUNT)];
+ OAppBorderWindow& m_rBorderWin;
+ std::unique_ptr<weld::Container> m_xBox;
+ std::unique_ptr<weld::Widget> m_xFL;
+ std::unique_ptr<weld::MenuButton> m_xMBPreview;
+
+ std::unique_ptr<OPreviewWindow> m_xPreview;
+ std::unique_ptr<weld::CustomWeld> m_xPreviewWin;
+
+ std::unique_ptr<ODocumentInfoPreview> m_xDocumentInfo;
+ std::unique_ptr<weld::CustomWeld> m_xDocumentInfoWin;
+
+ std::unique_ptr<weld::Container> m_xTablePreview;
+
+ 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 bAscending
+ If sort should be Ascending of Descending
+ */
+ void sort(int nPos, bool bAscending);
+
+ /** 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,
+ const weld::TreeIter* _pParent );
+
+ /** sets the detail page
+ @param rTreeView
+ The control which should be visible.
+ */
+ void setDetailPage(DBTreeViewBase& rTreeView);
+
+ /** sets all HandleCallbacks
+ @param rTreeView
+ The newly created DBTreeViewBase
+ */
+ void setupTree(DBTreeViewBase& rTreeView);
+
+ /** creates the tree and sets all HandleCallbacks
+ @param nHelpId
+ The help id of the control
+ @param eType
+ The element type of the control
+ @return
+ The new tree.
+ */
+ std::unique_ptr<DBTreeViewBase> createSimpleTree(const OString& rHelpId, ElementType eType);
+
+ DECL_LINK( OnEntryDoubleClick, weld::TreeView&, bool );
+ DECL_LINK( OnEntrySelChange, LinkParamNone*, void );
+
+ DECL_LINK( OnCopyEntry, LinkParamNone*, void );
+ DECL_LINK( OnPasteEntry, LinkParamNone*, void );
+ DECL_LINK( OnDeleteEntry, LinkParamNone*, void );
+
+ DECL_LINK(OnDropdownClickHdl, weld::Toggleable&, void);
+ DECL_LINK(MenuSelectHdl, const OString&, void);
+
+ OAppBorderWindow& getBorderWin() const { return m_rBorderWin; }
+
+ public:
+ OAppDetailPageHelper(weld::Container* pParent, OAppBorderWindow& rBorderWin, PreviewMode ePreviewMode);
+ virtual ~OAppDetailPageHelper() override;
+
+ virtual void GrabFocus() override;
+ virtual bool HasChildPathFocus() const 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
+ */
+ DBTreeViewBase* getCurrentView() const
+ {
+ ElementType eType = getElementType();
+ return (eType != E_NONE ) ? m_aLists[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 weld::TreeView& 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
+ );
+
+ /** get the menu parent window for the given control
+ */
+ vcl::Window* getMenuParent() const;
+ void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const;
+
+ /** 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( const weld::TreeIter* _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 rTreeView
+ The TreeView rEntry belongs to
+ @param rEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry);
+
+ /** returns if one of the selected entries is a leaf
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isALeafSelected() const;
+
+ std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) 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.
+ */
+ std::unique_ptr<weld::TreeIter> 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);
+ };
+}
+
+/* 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..63a9f7f39
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailView.cxx
@@ -0,0 +1,510 @@
+/* -*- 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/svapp.hxx>
+#include "AppDetailPageHelper.hxx"
+#include <dbaccess/IController.hxx>
+#include <algorithm>
+#include <dbtreelistbox.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;
+
+TaskEntry::TaskEntry( const char* _pAsciiUNOCommand, TranslateId _pHelpID, TranslateId pTitleResourceID, bool _bHideWhenDisabled )
+ :sUNOCommand( OUString::createFromAscii( _pAsciiUNOCommand ) )
+ ,pHelpID( _pHelpID )
+ ,sTitle( DBA_RES(pTitleResourceID) )
+ ,bHideWhenDisabled( _bHideWhenDisabled )
+{
+}
+
+void OTasksWindow::updateHelpText()
+{
+ TranslateId pHelpTextId;
+ int nCurEntry = m_xTreeView->get_selected_index();
+ if (nCurEntry != -1)
+ pHelpTextId = weld::fromId<TaskEntry*>(m_xTreeView->get_id(nCurEntry))->pHelpID;
+ setHelpText(pHelpTextId);
+}
+
+IMPL_LINK(OTasksWindow, onSelected, weld::TreeView&, rTreeView, bool)
+{
+ m_nCursorIndex = rTreeView.get_cursor_index();
+ if (m_nCursorIndex != -1)
+ {
+ URL aCommand;
+ aCommand.Complete = weld::fromId<TaskEntry*>(rTreeView.get_id(m_nCursorIndex))->sUNOCommand;
+ getDetailView()->getBorderWin().getView()->getAppController().executeChecked( aCommand, Sequence< PropertyValue >() );
+ }
+ return true;
+}
+
+void OTasksWindow::GrabFocus()
+{
+ if (!m_xTreeView)
+ return;
+ m_xTreeView->grab_focus();
+}
+
+bool OTasksWindow::HasChildPathFocus() const
+{
+ return m_xTreeView && m_xTreeView->has_focus();
+}
+
+IMPL_LINK_NOARG(OTasksWindow, FocusInHdl, weld::Widget&, void)
+{
+ m_xTreeView->select(m_nCursorIndex != -1 ? m_nCursorIndex : 0);
+}
+
+IMPL_LINK_NOARG(OTasksWindow, FocusOutHdl, weld::Widget&, void)
+{
+ m_nCursorIndex = m_xTreeView->get_cursor_index();
+ m_xTreeView->unselect_all();
+}
+
+IMPL_LINK_NOARG(OTasksWindow, OnEntrySelectHdl, weld::TreeView&, void)
+{
+ m_nCursorIndex = m_xTreeView->get_cursor_index();
+ updateHelpText();
+}
+
+OTasksWindow::OTasksWindow(weld::Container* pParent, OApplicationDetailView* pDetailView)
+ : OChildWindow(pParent, "dbaccess/ui/taskwindow.ui", "TaskWindow")
+ , m_xTreeView(m_xBuilder->weld_tree_view("treeview"))
+ , m_xDescription(m_xBuilder->weld_label("description"))
+ , m_xHelpText(m_xBuilder->weld_text_view("helptext"))
+ , m_pDetailView(pDetailView)
+ , m_nCursorIndex(-1)
+{
+ m_xContainer->set_stack_background();
+
+ m_xTreeView->set_help_id(HID_APP_CREATION_LIST);
+ m_xTreeView->connect_row_activated(LINK(this, OTasksWindow, onSelected));
+ m_xTreeView->connect_changed(LINK(this, OTasksWindow, OnEntrySelectHdl));
+ m_xTreeView->connect_focus_in(LINK(this, OTasksWindow, FocusInHdl));
+ m_xTreeView->connect_focus_out(LINK(this, OTasksWindow, FocusOutHdl));
+ // an arbitrary small size it's allowed to shrink to
+ m_xTreeView->set_size_request(42, 42);
+
+ m_xHelpText->set_help_id(HID_APP_HELP_TEXT);
+ m_xDescription->set_help_id(HID_APP_DESCRIPTION_TEXT);
+}
+
+OTasksWindow::~OTasksWindow()
+{
+ Clear();
+}
+
+void OTasksWindow::setHelpText(TranslateId pId)
+{
+ if (pId)
+ m_xHelpText->set_text(DBA_RES(pId));
+ else
+ m_xHelpText->set_text(OUString());
+}
+
+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() );
+
+ size_t nIndex = 0;
+ for (auto const& task : _rList)
+ {
+ OUString sId = weld::toId(new TaskEntry(task));
+ m_xTreeView->append(sId, task.sTitle);
+ m_xTreeView->set_image(nIndex++, *pImages++);
+ }
+ }
+ catch(Exception&)
+ {
+ }
+
+ m_xTreeView->unselect_all();
+ updateHelpText();
+ Enable(!_rList.empty());
+}
+
+void OTasksWindow::Clear()
+{
+ m_xTreeView->all_foreach([this](weld::TreeIter& rEntry){
+ TaskEntry* pUserData = weld::fromId<TaskEntry*>(m_xTreeView->get_id(rEntry));
+ delete pUserData;
+ return false;
+ });
+
+ m_xTreeView->clear();
+}
+
+OApplicationDetailView::OApplicationDetailView(weld::Container* pParent, OAppBorderWindow& rBorder,
+ PreviewMode ePreviewMode)
+ : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/appdetailwindow.ui"))
+ , m_xContainer(m_xBuilder->weld_container("AppDetailWindow"))
+ , m_xHorzSplitter(m_xBuilder->weld_paned("splitter"))
+ , m_xTasksParent(m_xBuilder->weld_container("tasks"))
+ , m_xContainerParent(m_xBuilder->weld_container("container"))
+ , m_xTasks(new dbaui::OTitleWindow(m_xTasksParent.get(), STR_TASKS))
+ , m_xTitleContainer(new dbaui::OTitleWindow(m_xContainerParent.get(), TranslateId()))
+ , m_rBorderWin(rBorder)
+{
+ m_xControlHelper = std::make_shared<OAppDetailPageHelper>(m_xTitleContainer->getChildContainer(), m_rBorderWin, ePreviewMode);
+ m_xTitleContainer->setChildWindow(m_xControlHelper);
+
+ std::shared_ptr<OChildWindow> xTasks = std::make_shared<OTasksWindow>(m_xTasks->getChildContainer(), this);
+ xTasks->Enable(!m_rBorderWin.getView()->getCommandController().isDataSourceReadOnly());
+ m_xTasks->setChildWindow(xTasks);
+}
+
+OApplicationDetailView::~OApplicationDetailView()
+{
+}
+
+void OApplicationDetailView::setTaskExternalMnemonics( MnemonicGenerator const & rMnemonics )
+{
+ m_aExternalMnemonics = rMnemonics;
+}
+
+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_xTitleContainer->setTitle(rData.pTitleId);
+
+ // let our helper create the object list
+ if ( _eType == E_TABLE )
+ GetControlHelper()->createTablesPage( _rxConnection );
+ else
+ GetControlHelper()->createPage( _eType, _rxNonTableElements );
+}
+
+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!" );
+ }
+
+ // 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
+ {
+ ++pTask;
+ }
+ }
+}
+
+const TaskPaneData& OApplicationDetailView::impl_getTaskPaneData( ElementType _eType )
+{
+ if ( m_aTaskPaneData.empty() )
+ m_aTaskPaneData.resize( size_t(E_ELEMENT_TYPE_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;
+}
+
+OUString OApplicationDetailView::getQualifiedName(const weld::TreeIter* _pEntry) const
+{
+ return GetControlHelper()->getQualifiedName( _pEntry );
+}
+
+bool OApplicationDetailView::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry)
+{
+ return OAppDetailPageHelper::isLeaf(rTreeView, rEntry);
+}
+
+bool OApplicationDetailView::isALeafSelected() const
+{
+ return GetControlHelper()->isALeafSelected();
+}
+
+void OApplicationDetailView::selectAll()
+{
+ GetControlHelper()->selectAll();
+}
+
+void OApplicationDetailView::sortDown()
+{
+ GetControlHelper()->sortDown();
+}
+
+void OApplicationDetailView::sortUp()
+{
+ GetControlHelper()->sortUp();
+}
+
+bool OApplicationDetailView::isFilled() const
+{
+ return GetControlHelper()->isFilled();
+}
+
+ElementType OApplicationDetailView::getElementType() const
+{
+ return GetControlHelper()->getElementType();
+}
+
+void OApplicationDetailView::clearPages(bool _bTaskAlso)
+{
+ if ( _bTaskAlso )
+ getTasksWindow().Clear();
+ GetControlHelper()->clearPages();
+}
+
+sal_Int32 OApplicationDetailView::getSelectionCount()
+{
+ return GetControlHelper()->getSelectionCount();
+}
+
+sal_Int32 OApplicationDetailView::getElementCount() const
+{
+ return GetControlHelper()->getElementCount();
+}
+
+void OApplicationDetailView::getSelectionElementNames( std::vector< OUString>& _rNames ) const
+{
+ GetControlHelper()->getSelectionElementNames( _rNames );
+}
+
+void OApplicationDetailView::describeCurrentSelectionForControl(const weld::TreeView& rControl, Sequence< NamedDatabaseObject >& out_rSelectedObjects)
+{
+ GetControlHelper()->describeCurrentSelectionForControl(rControl, out_rSelectedObjects);
+}
+
+void OApplicationDetailView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects )
+{
+ GetControlHelper()->describeCurrentSelectionForType( _eType, _out_rSelectedObjects );
+}
+
+vcl::Window* OApplicationDetailView::getMenuParent() const
+{
+ return GetControlHelper()->getMenuParent();
+}
+
+void OApplicationDetailView::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ return GetControlHelper()->adjustMenuPosition(rControl, rPos);
+}
+
+void OApplicationDetailView::selectElements(const Sequence< OUString>& _aNames)
+{
+ GetControlHelper()->selectElements( _aNames );
+}
+
+std::unique_ptr<weld::TreeIter> OApplicationDetailView::getEntry(const Point& rPoint) const
+{
+ return GetControlHelper()->getEntry(rPoint);
+}
+
+bool OApplicationDetailView::isCutAllowed()
+{
+ return false;
+}
+
+bool OApplicationDetailView::isCopyAllowed()
+{
+ return true;
+}
+
+bool OApplicationDetailView::isPasteAllowed() { return true; }
+
+void OApplicationDetailView::copy() { }
+
+void OApplicationDetailView::cut() { }
+
+void OApplicationDetailView::paste() { }
+
+std::unique_ptr<weld::TreeIter> OApplicationDetailView::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject )
+{
+ return GetControlHelper()->elementAdded(_eType, _rName, _rObject);
+}
+
+void OApplicationDetailView::elementRemoved(ElementType _eType,const OUString& _rName )
+{
+ GetControlHelper()->elementRemoved(_eType,_rName );
+}
+
+void OApplicationDetailView::elementReplaced(ElementType _eType
+ ,const OUString& _rOldName
+ ,const OUString& _rNewName )
+{
+ GetControlHelper()->elementReplaced( _eType, _rOldName, _rNewName );
+}
+
+PreviewMode OApplicationDetailView::getPreviewMode() const
+{
+ return GetControlHelper()->getPreviewMode();
+}
+
+bool OApplicationDetailView::isPreviewEnabled() const
+{
+ return GetControlHelper()->isPreviewEnabled();
+}
+
+void OApplicationDetailView::switchPreview(PreviewMode _eMode)
+{
+ GetControlHelper()->switchPreview(_eMode);
+}
+
+void OApplicationDetailView::showPreview(const Reference< XContent >& _xContent)
+{
+ GetControlHelper()->showPreview(_xContent);
+}
+
+void OApplicationDetailView::showPreview( const OUString& _sDataSourceName,
+ const OUString& _sName,
+ bool _bTable)
+{
+ GetControlHelper()->showPreview(_sDataSourceName,_sName,_bTable);
+}
+
+bool OApplicationDetailView::isSortUp() const
+{
+ return GetControlHelper()->isSortUp();
+}
+
+TreeListBox* OApplicationDetailView::getTreeWindow() const
+{
+ DBTreeViewBase* pCurrent = GetControlHelper()->getCurrentView();
+ if (!pCurrent)
+ return nullptr;
+ return &pCurrent->getListBox();
+}
+
+OAppDetailPageHelper* OApplicationDetailView::GetControlHelper()
+{
+ return static_cast<OAppDetailPageHelper*>(m_xControlHelper.get());
+}
+
+const OAppDetailPageHelper* OApplicationDetailView::GetControlHelper() const
+{
+ return static_cast<const OAppDetailPageHelper*>(m_xControlHelper.get());
+}
+
+bool OApplicationDetailView::HasChildPathFocus() const
+{
+ return m_xHorzSplitter->has_focus() ||
+ m_xTasks->HasChildPathFocus() ||
+ m_xTitleContainer->HasChildPathFocus();
+}
+
+/* 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..f074df440
--- /dev/null
+++ b/dbaccess/source/ui/app/AppDetailView.hxx
@@ -0,0 +1,318 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#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/mnemonic.hxx>
+#include <IClipBoardTest.hxx>
+#include "AppTitleWindow.hxx"
+#include <AppElementType.hxx>
+
+#include <vector>
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class OApplicationDetailView;
+ class OAppDetailPageHelper;
+ class OTasksWindow;
+ class TreeListBox;
+
+ struct TaskEntry
+ {
+ OUString sUNOCommand;
+ TranslateId 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, TranslateId pHelpID, TranslateId 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
+ TranslateId pTitleId;
+ };
+
+ class OTasksWindow final : public OChildWindow
+ {
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ std::unique_ptr<weld::Label> m_xDescription;
+ std::unique_ptr<weld::TextView> m_xHelpText;
+ OApplicationDetailView* m_pDetailView;
+
+ int m_nCursorIndex;
+
+ DECL_LINK(onSelected, weld::TreeView&, bool);
+ DECL_LINK(OnEntrySelectHdl, weld::TreeView&, void);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+
+ void updateHelpText();
+
+ public:
+ OTasksWindow(weld::Container* pParent, OApplicationDetailView* pDetailView);
+ ~OTasksWindow();
+
+ virtual void GrabFocus() override;
+
+ virtual bool HasChildPathFocus() const override;
+
+ OApplicationDetailView* getDetailView() const { return m_pDetailView; }
+
+ /// fills the Creation listbox with the necessary strings and images
+ void fillTaskEntryList( const TaskEntryList& _rList );
+
+ void Clear();
+ void setHelpText(TranslateId pId);
+ };
+
+ class OApplicationDetailView final : public IClipboardTest
+ {
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Paned> m_xHorzSplitter;
+ std::unique_ptr<weld::Container> m_xTasksParent;
+ std::unique_ptr<weld::Container> m_xContainerParent;
+ std::unique_ptr<OTitleWindow> m_xTasks;
+ std::unique_ptr<OTitleWindow> m_xTitleContainer;
+ OAppBorderWindow& m_rBorderWin; // my parent
+ std::shared_ptr<OChildWindow> m_xControlHelper;
+ std::vector< TaskPaneData > m_aTaskPaneData;
+ MnemonicGenerator m_aExternalMnemonics;
+
+ const OAppDetailPageHelper* GetControlHelper() const;
+ OAppDetailPageHelper* GetControlHelper();
+
+ public:
+ OApplicationDetailView(weld::Container* pParent, OAppBorderWindow& rBorder, PreviewMode ePreviewMode);
+ ~OApplicationDetailView();
+
+ /** 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 );
+
+ OAppBorderWindow& getBorderWin() const { return m_rBorderWin; }
+ OTasksWindow& getTasksWindow() const { return *static_cast< OTasksWindow* >( m_xTasks->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(const weld::TreeIter* _pEntry) const;
+
+ /** returns if an entry is a leaf
+ @param rTreeView
+ The TreeView pEntry belongs to
+ @param rEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry);
+
+ /** 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 weld::TreeView& 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
+ );
+
+ /** get the menu parent window for the given control
+ */
+ vcl::Window* getMenuParent() const;
+ void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const;
+
+ /** 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.
+ */
+ std::unique_ptr<weld::TreeIter> 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);
+
+ std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const;
+
+ TreeListBox* getTreeWindow() const;
+
+ bool HasChildPathFocus() 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;
+ };
+}
+
+/* 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..1448c4015
--- /dev/null
+++ b/dbaccess/source/ui/app/AppIconControl.cxx
@@ -0,0 +1,238 @@
+/* -*- 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 <sfx2/thumbnailviewitem.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/event.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <callbacks.hxx>
+#include <AppElementType.hxx>
+
+namespace dbaui
+{
+class OApplicationIconControlDropTarget final : public DropTargetHelper
+{
+private:
+ OApplicationIconControl& m_rControl;
+
+public:
+ OApplicationIconControlDropTarget(OApplicationIconControl& rControl)
+ : DropTargetHelper(rControl.GetDrawingArea()->get_drop_target())
+ , m_rControl(rControl)
+ {
+ }
+
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
+ {
+ return m_rControl.AcceptDrop(rEvt);
+ }
+
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
+ {
+ return m_rControl.ExecuteDrop(rEvt);
+ }
+};
+
+OApplicationIconControl::OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll)
+ : ThumbnailView(std::move(xScroll), nullptr)
+ , m_pActionListener(nullptr)
+ , m_nMaxWidth(0)
+ , m_nMaxHeight(0)
+{
+ mnVItemSpace = 6; // row spacing
+ mbSelectOnFocus = false;
+ DrawMnemonics(true);
+}
+
+void OApplicationIconControl::Fill()
+{
+ static const struct CategoryDescriptor
+ {
+ TranslateId pLabelResId;
+ ElementType eType;
+ rtl::OUStringConstExpr 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)
+ {
+ // E_TABLE is 0, but 0 means void so use id of enum + 1
+ std::unique_ptr<ThumbnailViewItem> xItem(
+ new ThumbnailViewItem(*this, aCategorie.eType + 1));
+ xItem->mbBorder = false;
+ xItem->maPreview1 = BitmapEx(aCategorie.aImageResId);
+ const Size& rSize = xItem->maPreview1.GetSizePixel();
+ m_nMaxWidth = std::max(m_nMaxWidth, rSize.Width());
+ m_nMaxHeight = std::max(m_nMaxHeight, rSize.Height());
+ xItem->maTitle = DBA_RES(aCategorie.pLabelResId);
+ m_nMaxWidth = std::max<tools::Long>(m_nMaxWidth, GetTextWidth(xItem->maTitle));
+ AppendItem(std::move(xItem));
+ }
+
+ const int nMargin = 12;
+ const int nWidthRequest = m_nMaxWidth + 2 * nMargin;
+ set_size_request(nWidthRequest, -1);
+ // we expect a Resize at which point we'll set the item sizes based on our final size
+}
+
+ElementType OApplicationIconControl::GetSelectedItem() const
+{
+ for (const auto& rItem : mItemList)
+ {
+ if (!rItem->mbSelected)
+ continue;
+ return static_cast<ElementType>(rItem->mnId - 1);
+ }
+ return E_NONE;
+}
+
+void OApplicationIconControl::createIconAutoMnemonics(MnemonicGenerator& rMnemonics)
+{
+ for (const auto& rItem : mItemList)
+ rMnemonics.RegisterMnemonic(rItem->maTitle);
+
+ // exchange texts with generated mnemonics
+ for (auto& rItem : mItemList)
+ rItem->maTitle = rMnemonics.CreateMnemonic(rItem->maTitle);
+}
+
+void OApplicationIconControl::Resize()
+{
+ // fill the full width of the allocated area and give two lines of space to
+ // center the title in
+ setItemDimensions(GetOutputSizePixel().Width(), m_nMaxHeight, GetTextHeight() * 2, 0);
+ ThumbnailView::Resize();
+}
+
+bool OApplicationIconControl::IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const
+{
+ bool bRet = false;
+
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+ for (const auto& rItem : mItemList)
+ {
+ if (rI18nHelper.MatchMnemonic(rItem->maTitle, cChar))
+ {
+ bRet = true;
+ rType = static_cast<ElementType>(rItem->mnId - 1);
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+bool OApplicationIconControl::DoKeyShortCut(const KeyEvent& rKEvt)
+{
+ bool bMod2 = rKEvt.GetKeyCode().IsMod2();
+ sal_Unicode cChar = rKEvt.GetCharCode();
+ ElementType eType(E_NONE);
+ if (bMod2 && cChar && IsMnemonicChar(cChar, eType))
+ {
+ // shortcut is clicked
+ deselectItems();
+ SelectItem(eType + 1);
+ return true;
+ }
+
+ return false;
+}
+
+bool OApplicationIconControl::KeyInput(const KeyEvent& rKEvt)
+{
+ return DoKeyShortCut(rKEvt) || ThumbnailView::KeyInput(rKEvt);
+}
+
+void OApplicationIconControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ThumbnailView::SetDrawingArea(pDrawingArea);
+ m_xDropTarget.reset(new OApplicationIconControlDropTarget(*this));
+}
+
+sal_Int8 OApplicationIconControl::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ sal_Int8 nDropOption = DND_ACTION_NONE;
+ if (m_pActionListener)
+ {
+ sal_uInt16 nEntry = GetItemId(rEvt.maPosPixel);
+ if (nEntry)
+ {
+ deselectItems();
+ SelectItem(nEntry);
+ nDropOption
+ = m_pActionListener->queryDrop(rEvt, m_xDropTarget->GetDataFlavorExVector());
+ }
+ }
+ return nDropOption;
+}
+
+sal_Int8 OApplicationIconControl::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ if (m_pActionListener)
+ m_pActionListener->executeDrop(rEvt);
+ return DND_ACTION_NONE;
+}
+
+OApplicationIconControl::~OApplicationIconControl() {}
+
+void OApplicationIconControl::GetFocus()
+{
+ ThumbnailView::GetFocus();
+ Invalidate(); // redraw focus rect
+}
+
+void OApplicationIconControl::LoseFocus()
+{
+ ThumbnailView::LoseFocus();
+ Invalidate(); // redraw focus rect
+}
+
+tools::Rectangle OApplicationIconControl::GetFocusRect()
+{
+ if (HasFocus())
+ {
+ // Get the last selected item in the list
+ for (tools::Long i = mFilteredItemList.size() - 1; i >= 0; --i)
+ {
+ ThumbnailViewItem* pItem = mFilteredItemList[i];
+ if (pItem->isSelected())
+ {
+ tools::Rectangle aRet(pItem->getDrawArea());
+ aRet.AdjustLeft(THUMBNAILVIEW_ITEM_CORNER);
+ aRet.AdjustTop(1);
+ aRet.AdjustRight(-THUMBNAILVIEW_ITEM_CORNER);
+ aRet.AdjustBottom(-2);
+ return aRet;
+ }
+ }
+ }
+ return tools::Rectangle();
+}
+}
+
+/* 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..1146a77a1
--- /dev/null
+++ b/dbaccess/source/ui/app/AppIconControl.hxx
@@ -0,0 +1,67 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <sfx2/thumbnailview.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/weld.hxx>
+#include <AppElementType.hxx>
+
+class MnemonicGenerator;
+
+namespace dbaui
+{
+ class IControlActionListener;
+ class IconControl;
+ class OApplicationIconControlDropTarget;
+
+ class OApplicationIconControl final : public ThumbnailView
+ {
+ std::unique_ptr<OApplicationIconControlDropTarget> m_xDropTarget;
+ IControlActionListener* m_pActionListener;
+
+ tools::Long m_nMaxWidth;
+ tools::Long m_nMaxHeight;
+
+ bool IsMnemonicChar(sal_Unicode cChar, ElementType& rType) const;
+
+ public:
+ explicit OApplicationIconControl(std::unique_ptr<weld::ScrolledWindow> xScroll);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual void Resize() override;
+ virtual tools::Rectangle GetFocusRect() override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+ bool DoKeyShortCut(const KeyEvent& rKEvt);
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual ~OApplicationIconControl() override;
+
+ ElementType GetSelectedItem() const;
+
+ void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; }
+ void Fill();
+
+ void createIconAutoMnemonics(MnemonicGenerator& rMnemonics);
+
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
+ };
+}
+
+/* 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..ea2066c72
--- /dev/null
+++ b/dbaccess/source/ui/app/AppSwapWindow.cxx
@@ -0,0 +1,133 @@
+/* -*- 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 <sfx2/thumbnailviewitem.hxx>
+#include <vcl/event.hxx>
+#include <vcl/mnemonic.hxx>
+#include <vcl/svapp.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(weld::Container* pParent,
+ OAppBorderWindow& rBorderWindow)
+ : OChildWindow(pParent, "dbaccess/ui/appswapwindow.ui", "AppSwapWindow")
+ , m_xIconControl(new OApplicationIconControl(m_xBuilder->weld_scrolled_window("scroll", true)))
+ , m_xIconControlWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xIconControl))
+ , m_eLastType(E_NONE)
+ , m_rBorderWin(rBorderWindow)
+ , m_nChangeEvent(nullptr)
+{
+ m_xContainer->set_stack_background();
+
+ m_xIconControl->SetHelpId(HID_APP_SWAP_ICONCONTROL);
+ m_xIconControl->Fill();
+ m_xIconControl->setItemStateHdl(LINK(this, OApplicationSwapWindow, OnContainerSelectHdl));
+ m_xIconControl->setControlActionListener(&m_rBorderWin.getView()->getAppController());
+}
+
+void OApplicationSwapWindow::GrabFocus()
+{
+ if (m_xIconControl)
+ m_xIconControl->GrabFocus();
+}
+
+bool OApplicationSwapWindow::HasChildPathFocus() const
+{
+ return m_xIconControl && m_xIconControl->HasFocus();
+}
+
+OApplicationSwapWindow::~OApplicationSwapWindow()
+{
+ if (m_nChangeEvent)
+ Application::RemoveUserEvent(m_nChangeEvent);
+}
+
+void OApplicationSwapWindow::clearSelection()
+{
+ m_xIconControl->deselectItems();
+ onContainerSelected(E_NONE);
+}
+
+void OApplicationSwapWindow::createIconAutoMnemonics(MnemonicGenerator& rMnemonics)
+{
+ m_xIconControl->createIconAutoMnemonics(rMnemonics);
+}
+
+bool OApplicationSwapWindow::interceptKeyInput(const KeyEvent& _rEvent)
+{
+ const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode();
+ if (rKeyCode.GetModifier() == KEY_MOD2)
+ return m_xIconControl->DoKeyShortCut(_rEvent);
+ // not handled
+ return false;
+}
+
+ElementType OApplicationSwapWindow::getElementType() const
+{
+ return m_xIconControl->GetSelectedItem();
+}
+
+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;
+ }
+
+ if (!m_nChangeEvent)
+ m_nChangeEvent
+ = Application::PostUserEvent(LINK(this, OApplicationSwapWindow, ChangeToLastSelected));
+ return false;
+}
+
+IMPL_LINK(OApplicationSwapWindow, OnContainerSelectHdl, const ThumbnailViewItem*, pEntry, void)
+{
+ if (pEntry->mbSelected)
+ {
+ ElementType eType = static_cast<ElementType>(pEntry->mnId - 1);
+ onContainerSelected(eType); // i87582
+ }
+}
+
+IMPL_LINK_NOARG(OApplicationSwapWindow, ChangeToLastSelected, void*, void)
+{
+ m_nChangeEvent = nullptr;
+ selectContainer(m_eLastType);
+}
+
+void OApplicationSwapWindow::selectContainer(ElementType eType)
+{
+ m_xIconControl->deselectItems();
+ m_xIconControl->SelectItem(eType + 1); // will trigger onContainerSelected
+}
+
+/* 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..1ce972e3b
--- /dev/null
+++ b/dbaccess/source/ui/app/AppSwapWindow.hxx
@@ -0,0 +1,88 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <IClipBoardTest.hxx>
+#include "AppIconControl.hxx"
+#include <AppElementType.hxx>
+#include <ChildWindow.hxx>
+
+struct ImplSVEvent;
+class MnemonicGenerator;
+
+namespace dbaui
+{
+ class OAppBorderWindow;
+ class OApplicationSwapWindow : public OChildWindow
+ , public IClipboardTest
+ {
+ std::unique_ptr<OApplicationIconControl> m_xIconControl;
+ std::unique_ptr<weld::CustomWeld> m_xIconControlWin;
+ ElementType m_eLastType;
+ OAppBorderWindow& m_rBorderWin;
+ ImplSVEvent* m_nChangeEvent;
+
+ DECL_LINK( OnContainerSelectHdl, const ThumbnailViewItem*, void );
+ DECL_LINK( ChangeToLastSelected, void*, void );
+
+ public:
+ OApplicationSwapWindow(weld::Container* pParent, OAppBorderWindow& rBorderWindow);
+ virtual ~OApplicationSwapWindow() override;
+
+ virtual void GrabFocus() override;
+ virtual bool HasChildPathFocus() const 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 { }
+
+ /** 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
+
+/* 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..d5e604394
--- /dev/null
+++ b/dbaccess/source/ui/app/AppTitleWindow.cxx
@@ -0,0 +1,65 @@
+/* -*- 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 <core_resource.hxx>
+#include <vcl/svapp.hxx>
+#include "AppTitleWindow.hxx"
+
+namespace dbaui
+{
+OTitleWindow::OTitleWindow(weld::Container* pParent, TranslateId pTitleId)
+ : m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/titlewindow.ui"))
+ , m_xContainer(m_xBuilder->weld_container("TitleWindow"))
+ , m_xTitleFrame(m_xBuilder->weld_container("titleparent"))
+ , m_xTitle(m_xBuilder->weld_label("title"))
+ , m_xChildContainer(m_xBuilder->weld_container("box"))
+{
+ setTitle(pTitleId);
+
+ m_xContainer->set_stack_background();
+ m_xTitleFrame->set_title_background();
+ m_xTitle->set_label_type(weld::LabelType::Title);
+}
+
+OTitleWindow::~OTitleWindow() {}
+
+weld::Container* OTitleWindow::getChildContainer() { return m_xChildContainer.get(); }
+
+void OTitleWindow::setChildWindow(const std::shared_ptr<OChildWindow>& rChild)
+{
+ m_xChild = rChild;
+}
+
+void OTitleWindow::setTitle(TranslateId pTitleId)
+{
+ if (!pTitleId)
+ return;
+ m_xTitle->set_label(DBA_RES(pTitleId));
+}
+
+void OTitleWindow::GrabFocus()
+{
+ if (m_xChild)
+ m_xChild->GrabFocus();
+}
+
+bool OTitleWindow::HasChildPathFocus() const { return m_xChild && m_xChild->HasChildPathFocus(); }
+
+} // 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..d57f52416
--- /dev/null
+++ b/dbaccess/source/ui/app/AppTitleWindow.hxx
@@ -0,0 +1,67 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <ChildWindow.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace dbaui
+{
+ class OTitleWindow final
+ {
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Container> m_xTitleFrame;
+ std::unique_ptr<weld::Label> m_xTitle;
+ std::unique_ptr<weld::Container> m_xChildContainer;
+ std::shared_ptr<OChildWindow> m_xChild;
+
+ public:
+ OTitleWindow(weld::Container* pParent, TranslateId pTitleId);
+ ~OTitleWindow();
+
+ void GrabFocus();
+
+ bool HasChildPathFocus() const;
+
+ /** gets the window which should be used as a child's parent */
+ weld::Container* getChildContainer();
+
+ /** 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(const std::shared_ptr<OChildWindow>& rChild);
+
+ /** gets the child window.
+
+ @return
+ The child window.
+ */
+ OChildWindow* getChildWindow() const { return m_xChild.get(); }
+
+ /** sets the title text out of the resource
+ @param pTitleId
+ The resource id of the title text.
+ */
+ void setTitle(TranslateId pTitleId);
+ };
+} // namespace dbaui
+
+/* 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..b300df8df
--- /dev/null
+++ b/dbaccess/source/ui/app/AppView.cxx
@@ -0,0 +1,473 @@
+/* -*- 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)
+ : InterimItemWindow(pParent, "dbaccess/ui/appborderwindow.ui", "AppBorderWindow", false)
+ , m_xPanelParent(m_xBuilder->weld_container("panel"))
+ , m_xDetailViewParent(m_xBuilder->weld_container("detail"))
+ , m_xView(pParent)
+{
+ SetStyle(GetStyle() | WB_DIALOGCONTROL);
+
+ m_xPanel.reset(new OTitleWindow(m_xPanelParent.get(), STR_DATABASE));
+ std::shared_ptr<OChildWindow> xSwap = std::make_shared<OApplicationSwapWindow>(m_xPanel->getChildContainer(), *this);
+
+ m_xPanel->setChildWindow(xSwap);
+
+ m_xDetailView.reset(new OApplicationDetailView(m_xDetailViewParent.get(), *this, ePreviewMode));
+
+ ImplInitSettings();
+}
+
+OAppBorderWindow::~OAppBorderWindow()
+{
+ disposeOnce();
+}
+
+void OAppBorderWindow::dispose()
+{
+ // destroy children
+ m_xPanel.reset();
+ m_xDetailView.reset();
+ m_xPanelParent.reset();
+ m_xDetailViewParent.reset();
+ m_xView.clear();
+ InterimItemWindow::dispose();
+}
+
+void OAppBorderWindow::GetFocus()
+{
+ if (m_xPanel)
+ m_xPanel->GrabFocus();
+}
+
+OApplicationSwapWindow* OAppBorderWindow::getPanel() const
+{
+ return static_cast<OApplicationSwapWindow*>(m_xPanel->getChildWindow());
+}
+
+OApplicationView::OApplicationView( vcl::Window* pParent
+ ,const Reference< XComponentContext >& _rxOrb
+ ,OApplicationController& _rAppController
+ ,PreviewMode _ePreviewMode
+ ) :
+ ODataView( pParent, _rAppController, _rxOrb, WB_DIALOGCONTROL )
+ ,m_rAppController( _rAppController )
+{
+ 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 ) );
+}
+
+OApplicationView::ChildFocusState OApplicationView::getChildFocus() const
+{
+ ChildFocusState eChildFocus;
+ if( m_pWin && getPanel() && getPanel()->HasChildPathFocus() )
+ eChildFocus = PANELSWAP;
+ else if ( m_pWin && getDetailView() && getDetailView()->HasChildPathFocus() )
+ eChildFocus = DETAIL;
+ else
+ eChildFocus = NONE;
+ return eChildFocus;
+}
+
+bool OApplicationView::PreNotify( NotifyEvent& rNEvt )
+{
+ switch(rNEvt.GetType())
+ {
+ 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;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ODataView::PreNotify(rNEvt);
+}
+
+IClipboardTest* OApplicationView::getActiveChild() const
+{
+ IClipboardTest* pTest = nullptr;
+ if (getChildFocus() == DETAIL)
+ 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(const weld::TreeIter* _pEntry) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getQualifiedName( _pEntry );
+}
+
+bool OApplicationView::isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return OApplicationDetailView::isLeaf(rTreeView, rEntry);
+}
+
+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 weld::TreeView& rControl, Sequence<NamedDatabaseObject>& out_rSelectedObjects)
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ getDetailView()->describeCurrentSelectionForControl(rControl, out_rSelectedObjects);
+}
+
+vcl::Window* OApplicationView::getMenuParent() const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getMenuParent();
+}
+
+void OApplicationView::adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->adjustMenuPosition(rControl, rPos);
+}
+
+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 );
+}
+
+std::unique_ptr<weld::TreeIter> 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);
+}
+
+std::unique_ptr<weld::TreeIter> OApplicationView::getEntry(const Point& rPosPixel) const
+{
+ OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF");
+ return getDetailView()->getEntry(rPosPixel);
+}
+
+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_pWin && getChildFocus() == NONE)
+ 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(*GetOutDev(), 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..59a6d477a
--- /dev/null
+++ b/dbaccess/source/ui/app/AppView.hxx
@@ -0,0 +1,302 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#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 <vcl/InterimItemWindow.hxx>
+#include <vcl/weld.hxx>
+#include <IClipBoardTest.hxx>
+#include <AppElementType.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+
+class MnemonicGenerator;
+
+namespace dbaui
+{
+ class OApplicationView;
+ class OApplicationDetailView;
+ class OApplicationSwapWindow;
+ class OTitleWindow;
+ class OApplicationController;
+
+ class OAppBorderWindow final : public InterimItemWindow
+ {
+ std::unique_ptr<weld::Container> m_xPanelParent;
+ std::unique_ptr<weld::Container> m_xDetailViewParent;
+ std::unique_ptr<OTitleWindow> m_xPanel;
+ std::unique_ptr<OApplicationDetailView> m_xDetailView;
+ VclPtr<OApplicationView> m_xView;
+
+ public:
+ OAppBorderWindow(OApplicationView* pParent, PreviewMode ePreviewMode);
+ virtual ~OAppBorderWindow() override;
+ virtual void dispose() override;
+
+ // Window overrides
+ virtual void GetFocus() override;
+
+ OApplicationView* getView() const { return m_xView.get(); }
+ OApplicationSwapWindow* getPanel() const;
+ OApplicationDetailView* getDetailView() const { return m_xDetailView.get(); }
+ weld::Container& getTopLevel() { return *m_xContainer; }
+ };
+
+ 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 getChildFocus() const;
+ 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(const weld::TreeIter* _pEntry) const;
+
+ /** returns if an entry is a leaf
+ @param rTreeView
+ The TreeView rEntry belongs to
+ @param rEntry
+ The entry to check
+ @return
+ <TRUE/> if the entry is a leaf, otherwise <FALSE/>
+ */
+ bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) 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 weld::TreeView& 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
+ );
+
+ /** get the menu parent window for the given control
+ */
+ vcl::Window* getMenuParent() const;
+
+ /** adjust rPos relative to rControl to instead relative to getMenuParent */
+ void adjustMenuPosition(const weld::TreeView& rControl, ::Point& rPos) const;
+
+ /** 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.
+ */
+ std::unique_ptr<weld::TreeIter> 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);
+
+ std::unique_ptr<weld::TreeIter> getEntry(const Point& rPosPixel) const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/ChildWindow.cxx b/dbaccess/source/ui/app/ChildWindow.cxx
new file mode 100644
index 000000000..a8091c863
--- /dev/null
+++ b/dbaccess/source/ui/app/ChildWindow.cxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#include <vcl/svapp.hxx>
+#include <ChildWindow.hxx>
+
+namespace dbaui
+{
+OChildWindow::OChildWindow(weld::Container* pParent, const OUString& rUIXMLDescription,
+ const OString& rID)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , m_xContainer(m_xBuilder->weld_container(rID))
+{
+}
+
+OChildWindow::~OChildWindow() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/dbaccess/source/ui/app/DocumentInfoPreview.cxx b/dbaccess/source/ui/app/DocumentInfoPreview.cxx
new file mode 100644
index 000000000..7220eb2bd
--- /dev/null
+++ b/dbaccess/source/ui/app/DocumentInfoPreview.cxx
@@ -0,0 +1,164 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <rtl/ustring.hxx>
+#include "DocumentInfoPreview.hxx"
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itemset.hxx>
+#include <tools/datetime.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/localedatawrapper.hxx>
+
+#include <templwin.hrc>
+#include "templwin.hxx"
+
+namespace dbaui {
+
+ODocumentInfoPreview::ODocumentInfoPreview()
+{
+}
+
+void ODocumentInfoPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ WeldEditView::SetDrawingArea(pDrawingArea);
+ m_xEditView->HideCursor();
+ m_xEditView->SetReadOnly(true);
+}
+
+ODocumentInfoPreview::~ODocumentInfoPreview()
+{
+}
+
+void ODocumentInfoPreview::clear() {
+ m_xEditEngine->SetText(OUString());
+}
+
+void ODocumentInfoPreview::fill(
+ css::uno::Reference< css::document::XDocumentProperties > const & xDocProps)
+{
+ assert(xDocProps.is());
+
+ insertNonempty(DI_TITLE, xDocProps->getTitle());
+ insertNonempty(DI_FROM, xDocProps->getAuthor());
+ insertDateTime(DI_DATE, xDocProps->getCreationDate());
+ insertNonempty(DI_MODIFIEDBY, xDocProps->getModifiedBy());
+ insertDateTime(DI_MODIFIEDDATE, xDocProps->getModificationDate());
+ insertNonempty(DI_PRINTBY, xDocProps->getPrintedBy());
+ insertDateTime(DI_PRINTDATE, xDocProps->getPrintDate());
+ insertNonempty(DI_THEME, xDocProps->getSubject());
+ insertNonempty(
+ DI_KEYWORDS,
+ comphelper::string::convertCommaSeparated(xDocProps->getKeywords()));
+ insertNonempty(DI_DESCRIPTION, xDocProps->getDescription());
+
+ // User-defined (custom) properties:
+ css::uno::Reference< css::beans::XPropertySet > user(
+ xDocProps->getUserDefinedProperties(), css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::beans::XPropertySetInfo > info(
+ user->getPropertySetInfo());
+ const css::uno::Sequence< css::beans::Property > props(info->getProperties());
+ for (const auto& rProp : props) {
+ OUString name(rProp.Name);
+ css::uno::Any aAny(user->getPropertyValue(name));
+ css::uno::Reference< css::script::XTypeConverter > conv(
+ css::script::Converter::create(
+ comphelper::getProcessComponentContext()));
+ OUString value;
+ try {
+ value = conv->convertToSimpleType(aAny, css::uno::TypeClass_STRING).
+ get< OUString >();
+ } catch (css::script::CannotConvertException &) {
+ TOOLS_INFO_EXCEPTION("svtools.contnr", "ignored");
+ }
+ if (!value.isEmpty()) {
+ insertEntry(name, value);
+ }
+ }
+
+ m_xEditView->SetSelection(ESelection(0, 0, 0, 0));
+}
+
+namespace
+{
+ ESelection InsertAtEnd(const EditEngine& rEditEngine)
+ {
+ const sal_uInt32 nPara = rEditEngine.GetParagraphCount() -1;
+ sal_Int32 nLastLen = rEditEngine.GetText(nPara).getLength();
+ return ESelection(nPara, nLastLen, nPara, nLastLen);
+ }
+}
+
+void ODocumentInfoPreview::insertEntry(
+ std::u16string_view title, OUString const & value)
+{
+ if (!m_xEditEngine->GetText().isEmpty()) {
+ m_xEditEngine->QuickInsertText("\n\n", InsertAtEnd(*m_xEditEngine));
+ }
+
+ OUString caption(OUString::Concat(title) + ":\n");
+ m_xEditEngine->QuickInsertText(caption, InsertAtEnd(*m_xEditEngine));
+
+ SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT));
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CJK));
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CTL));
+ int nCaptionPara = m_xEditEngine->GetParagraphCount() - 2;
+ m_xEditEngine->QuickSetAttribs(aSet, ESelection(nCaptionPara, 0, nCaptionPara, caption.getLength() - 1));
+
+ m_xEditEngine->QuickInsertText(value, InsertAtEnd(*m_xEditEngine));
+}
+
+void ODocumentInfoPreview::insertNonempty(tools::Long id, OUString const & value)
+{
+ if (!value.isEmpty()) {
+ insertEntry(SvtDocInfoTable_Impl::GetString(id), value);
+ }
+}
+
+void ODocumentInfoPreview::insertDateTime(
+ tools::Long id, css::util::DateTime const & value)
+{
+ DateTime aToolsDT(
+ Date(value.Day, value.Month, value.Year),
+ tools::Time(
+ value.Hours, value.Minutes, value.Seconds, value.NanoSeconds));
+ if (aToolsDT.IsValidAndGregorian()) {
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ OUString buf = rLocaleWrapper.getDate(aToolsDT) +
+ ", " +
+ rLocaleWrapper.getTime(aToolsDT);
+ insertEntry(SvtDocInfoTable_Impl::GetString(id), buf);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/DocumentInfoPreview.hxx b/dbaccess/source/ui/app/DocumentInfoPreview.hxx
new file mode 100644
index 000000000..0c9548d0a
--- /dev/null
+++ b/dbaccess/source/ui/app/DocumentInfoPreview.hxx
@@ -0,0 +1,59 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <svx/weldeditview.hxx>
+
+namespace com :: sun :: star :: uno { template <typename > class Reference; }
+
+namespace com::sun::star {
+ namespace document { class XDocumentProperties; }
+ namespace util { struct DateTime; }
+}
+
+namespace dbaui {
+
+class ODocumentInfoPreview final : public WeldEditView {
+public:
+ ODocumentInfoPreview();
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual ~ODocumentInfoPreview() override;
+
+ void clear();
+
+ void fill(css::uno::Reference< css::document::XDocumentProperties > const & xDocProps);
+
+private:
+ void insertEntry(std::u16string_view title, OUString const & value);
+
+ void insertNonempty(tools::Long id, OUString const & value);
+
+ void insertDateTime(tools::Long id, css::util::DateTime const & value);
+};
+
+}
+
+/* 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..bf92f2400
--- /dev/null
+++ b/dbaccess/source/ui/app/subcomponentmanager.cxx
@@ -0,0 +1,551 @@
+/* -*- 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::Any;
+ 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()
+ :nComponentType( -1 )
+ ,eOpenMode( E_OPEN_NORMAL )
+ {
+ }
+
+ 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;
+ OSL_ENSURE( _desc.xController.is(), "SelectSubComponent::operator(): illegal component!" );
+ return _desc.xController;
+ }
+ };
+
+ 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,
+ Any( _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( std::u16string_view i_rName, const sal_Int32 _nComponentType )
+ {
+ ::osl::MutexGuard aGuard( m_pData->getMutex() );
+ ENSURE_OR_RETURN_FALSE( !i_rName.empty(), "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..402a3d593
--- /dev/null
+++ b/dbaccess/source/ui/app/subcomponentmanager.hxx
@@ -0,0 +1,120 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#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(
+ std::u16string_view _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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/templwin.cxx b/dbaccess/source/ui/app/templwin.cxx
new file mode 100644
index 000000000..e9940782d
--- /dev/null
+++ b/dbaccess/source/ui/app/templwin.cxx
@@ -0,0 +1,38 @@
+/* -*- 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 <core_resource.hxx>
+#include <templwin.hrc>
+#include "templwin.hxx"
+
+namespace SvtDocInfoTable_Impl
+{
+ OUString GetString(int nId)
+ {
+ for (size_t i = 0; i < SAL_N_ELEMENTS(STRARY_SVT_DOCINFO); ++i)
+ {
+ if (STRARY_SVT_DOCINFO[i].second == nId)
+ return DBA_RES(STRARY_SVT_DOCINFO[i].first);
+ }
+
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/ui/app/templwin.hxx b/dbaccess/source/ui/app/templwin.hxx
new file mode 100644
index 000000000..8978a6ea3
--- /dev/null
+++ b/dbaccess/source/ui/app/templwin.hxx
@@ -0,0 +1,28 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+namespace SvtDocInfoTable_Impl
+{
+OUString GetString(int nId);
+};
+
+/* 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