summaryrefslogtreecommitdiffstats
path: root/dbaccess/source/filter/xml/dbloader2.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'dbaccess/source/filter/xml/dbloader2.cxx')
-rw-r--r--dbaccess/source/filter/xml/dbloader2.cxx535
1 files changed, 535 insertions, 0 deletions
diff --git a/dbaccess/source/filter/xml/dbloader2.cxx b/dbaccess/source/filter/xml/dbloader2.cxx
new file mode 100644
index 000000000..0513af5a2
--- /dev/null
+++ b/dbaccess/source/filter/xml/dbloader2.cxx
@@ -0,0 +1,535 @@
+/* -*- 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 <strings.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XFrameLoader.hpp>
+#include <com/sun/star/frame/XLoadEventListener.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/task/XJobExecutor.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
+#include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
+#include <com/sun/star/frame/XLoadable.hpp>
+
+#include <comphelper/documentconstants.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+using namespace ::ucbhelper;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::ui::dialogs;
+using ::com::sun::star::awt::XWindow;
+using ::com::sun::star::sdb::application::NamedDatabaseObject;
+
+namespace dbaxml
+{
+
+namespace {
+
+class DBTypeDetection : public ::cppu::WeakImplHelper< XExtendedFilterDetection, XServiceInfo>
+{
+ const Reference< XComponentContext > m_aContext;
+
+public:
+ explicit DBTypeDetection(const Reference< XComponentContext >&);
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ virtual OUString SAL_CALL detect( css::uno::Sequence< css::beans::PropertyValue >& Descriptor ) override;
+};
+
+}
+
+DBTypeDetection::DBTypeDetection(const Reference< XComponentContext >& _rxContext)
+ :m_aContext( _rxContext )
+{
+}
+
+OUString SAL_CALL DBTypeDetection::detect( css::uno::Sequence< css::beans::PropertyValue >& Descriptor )
+{
+ try
+ {
+ ::comphelper::NamedValueCollection aMedia( Descriptor );
+ bool bStreamFromDescr = false;
+ OUString sURL = aMedia.getOrDefault( "URL", OUString() );
+
+ Reference< XInputStream > xInStream( aMedia.getOrDefault( "InputStream", Reference< XInputStream >() ) );
+ Reference< XPropertySet > xStorageProperties;
+ if ( xInStream.is() )
+ {
+ bStreamFromDescr = true;
+ xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromInputStream(
+ xInStream, m_aContext ), UNO_QUERY );
+ }
+ else
+ {
+ OUString sSalvagedURL( aMedia.getOrDefault( "SalvagedFile", OUString() ) );
+
+ OUString sFileLocation( sSalvagedURL.isEmpty() ? sURL : sSalvagedURL );
+ if ( !sFileLocation.isEmpty() )
+ {
+ xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromURL(
+ sFileLocation, ElementModes::READ, m_aContext ), UNO_QUERY );
+ }
+ }
+
+ if ( xStorageProperties.is() )
+ {
+ OUString sMediaType;
+ xStorageProperties->getPropertyValue( INFO_MEDIATYPE ) >>= sMediaType;
+ if ( sMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII || sMediaType == MIMETYPE_VND_SUN_XML_BASE_ASCII )
+ {
+ if ( bStreamFromDescr && !sURL.startsWith( "private:stream" ) )
+ {
+ // After fixing of the i88522 issue ( use the new file locking for database files ) the stream from the type detection can be used further
+ // for now the file should be reopened to have read/write access
+ aMedia.remove( "InputStream" );
+ aMedia.remove( "Stream" );
+ aMedia >>= Descriptor;
+ try
+ {
+ ::comphelper::disposeComponent(xStorageProperties);
+ if ( xInStream.is() )
+ xInStream->closeInput();
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ return "StarBase";
+ }
+ ::comphelper::disposeComponent(xStorageProperties);
+ }
+ } catch(Exception&){}
+ return OUString();
+}
+
+// XServiceInfo
+OUString SAL_CALL DBTypeDetection::getImplementationName()
+{
+ return "org.openoffice.comp.dbflt.DBTypeDetection";
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL DBTypeDetection::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > SAL_CALL DBTypeDetection::getSupportedServiceNames()
+{
+ return { "com.sun.star.document.ExtendedTypeDetection" };
+}
+
+} // namespace dbaxml
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbflt_DBTypeDetection_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaxml::DBTypeDetection(context));
+}
+
+namespace dbaxml
+{
+
+namespace {
+
+class DBContentLoader : public ::cppu::WeakImplHelper< XFrameLoader, XServiceInfo>
+{
+private:
+ const Reference< XComponentContext > m_aContext;
+ Reference< XFrameLoader > m_xMySelf;
+ OUString m_sCurrentURL;
+ ImplSVEvent * m_nStartWizard;
+
+ DECL_LINK( OnStartTableWizard, void*, void );
+public:
+ explicit DBContentLoader(const Reference< XComponentContext >&);
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XLoader
+ virtual void SAL_CALL load( const Reference< XFrame > & _rFrame, const OUString& _rURL,
+ const Sequence< PropertyValue >& _rArgs,
+ const Reference< XLoadEventListener > & _rListener) override;
+ virtual void SAL_CALL cancel() override;
+
+private:
+ bool impl_executeNewDatabaseWizard( Reference< XModel > const & _rxModel, bool& _bShouldStartTableWizard );
+};
+
+}
+
+DBContentLoader::DBContentLoader(const Reference< XComponentContext >& _rxFactory)
+ :m_aContext( _rxFactory )
+ ,m_nStartWizard(nullptr)
+{
+
+}
+
+// XServiceInfo
+OUString SAL_CALL DBContentLoader::getImplementationName()
+{
+ return "org.openoffice.comp.dbflt.DBContentLoader2";
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.FrameLoader" };
+}
+
+
+namespace
+{
+ bool lcl_urlAllowsInteraction( const Reference<XComponentContext> & _rContext, const OUString& _rURL )
+ {
+ bool bDoesAllow = false;
+ try
+ {
+ Reference< XURLTransformer > xTransformer( URLTransformer::create(_rContext) );
+ URL aURL;
+ aURL.Complete = _rURL;
+ xTransformer->parseStrict( aURL );
+ bDoesAllow = aURL.Arguments == "Interactive";
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "lcl_urlAllowsInteraction: caught an exception while analyzing the URL!" );
+ }
+ return bDoesAllow;
+ }
+
+ Reference< XWindow > lcl_getTopMostWindow( const Reference<XComponentContext> & _rxContext )
+ {
+ Reference< XWindow > xWindow;
+ // get the top most window
+ Reference < XDesktop2 > xDesktop = Desktop::create(_rxContext);
+ Reference < XFrame > xActiveFrame = xDesktop->getActiveFrame();
+ if ( xActiveFrame.is() )
+ {
+ xWindow = xActiveFrame->getContainerWindow();
+ Reference<XFrame> xFrame = xActiveFrame;
+ while ( xFrame.is() && !xFrame->isTop() )
+ xFrame = xFrame->getCreator();
+
+ if ( xFrame.is() )
+ xWindow = xFrame->getContainerWindow();
+ }
+ return xWindow;
+ }
+}
+
+bool DBContentLoader::impl_executeNewDatabaseWizard( Reference< XModel > const & _rxModel, bool& _bShouldStartTableWizard )
+{
+ Sequence<Any> aWizardArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"ParentWindow", Any(lcl_getTopMostWindow( m_aContext ))},
+ {"InitialSelection", Any(_rxModel)}
+ }));
+
+ // create the dialog
+ Reference< XExecutableDialog > xAdminDialog( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.sdb.DatabaseWizardDialog", aWizardArgs, m_aContext), UNO_QUERY_THROW);
+
+ // execute it
+ if ( RET_OK != xAdminDialog->execute() )
+ return false;
+
+ Reference<XPropertySet> xProp(xAdminDialog,UNO_QUERY);
+ bool bSuccess = false;
+ xProp->getPropertyValue("OpenDatabase") >>= bSuccess;
+ xProp->getPropertyValue("StartTableWizard") >>= _bShouldStartTableWizard;
+ return bSuccess;
+}
+
+void SAL_CALL DBContentLoader::load(const Reference< XFrame > & rFrame, const OUString& _rURL,
+ const Sequence< PropertyValue >& rArgs,
+ const Reference< XLoadEventListener > & rListener)
+{
+ // first check if preview is true, if so return without creating a controller. Preview is not supported
+ ::comphelper::NamedValueCollection aMediaDesc( rArgs );
+ bool bPreview = aMediaDesc.getOrDefault( "Preview", false );
+ if ( bPreview )
+ {
+ if (rListener.is())
+ rListener->loadCancelled(this);
+ return;
+ }
+
+ Reference< XModel > xModel = aMediaDesc.getOrDefault( "Model", Reference< XModel >() );
+ OUString sSalvagedURL = aMediaDesc.getOrDefault( "SalvagedFile", _rURL );
+
+ bool bCreateNew = false; // does the URL denote the private:factory URL?
+ bool bStartTableWizard = false; // start the table wizard after everything was loaded successfully?
+
+ bool bSuccess = true;
+
+ // If there's no interaction handler in the media descriptor, put one.
+ // By definition, loading via loadComponentFromURL (and thus via the content loader here)
+ // is allowed to raise UI. To not burden every place inside the document with creating
+ // a default handler, we simply ensure there is one.
+ // If a handler is present in the media descriptor, even if it is NULL, we will
+ // not touch it.
+ if ( !aMediaDesc.has( "InteractionHandler" ) )
+ {
+ Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(m_aContext, nullptr) );
+ aMediaDesc.put( "InteractionHandler", xHandler );
+ }
+
+ // it's allowed to pass an existing document
+ Reference< XOfficeDatabaseDocument > xExistentDBDoc;
+ xModel.set( aMediaDesc.getOrDefault( "Model", xExistentDBDoc ), UNO_QUERY );
+ aMediaDesc.remove( "Model" );
+
+ // also, it's allowed to specify the type of view which should be created
+ OUString sViewName = aMediaDesc.getOrDefault( "ViewName", OUString( "Default" ) );
+ aMediaDesc.remove( "ViewName" );
+
+ // this needs to stay alive for duration of this method
+ Reference< XDatabaseContext > xDatabaseContext;
+
+ sal_Int32 nInitialSelection = -1;
+ if ( !xModel.is() )
+ {
+ xDatabaseContext = DatabaseContext::create(m_aContext);
+
+ OUString sFactoryName = SvtModuleOptions().GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::DATABASE);
+ bCreateNew = sFactoryName.match(_rURL);
+
+ Reference< XDocumentDataSource > xDocumentDataSource;
+ bool bNewAndInteractive = false;
+ if ( bCreateNew )
+ {
+ bNewAndInteractive = lcl_urlAllowsInteraction( m_aContext, _rURL );
+ xDocumentDataSource.set( xDatabaseContext->createInstance(), UNO_QUERY_THROW );
+ }
+ else
+ {
+ ::comphelper::NamedValueCollection aCreationArgs;
+ aCreationArgs.put( INFO_POOLURL, sSalvagedURL );
+ xDocumentDataSource.set( xDatabaseContext->createInstanceWithArguments( aCreationArgs.getWrappedNamedValues() ), UNO_QUERY_THROW );
+ }
+
+ xModel.set( xDocumentDataSource->getDatabaseDocument(), UNO_QUERY );
+
+ if ( bCreateNew && xModel.is() )
+ {
+ if ( bNewAndInteractive )
+ {
+ bSuccess = impl_executeNewDatabaseWizard( xModel, bStartTableWizard );
+ }
+ else
+ {
+ try
+ {
+ Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
+ xLoad->initNew();
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ bSuccess = false;
+ }
+ }
+
+ // initially select the "Tables" category (will be done below)
+ nInitialSelection = css::sdb::application::DatabaseObjectContainer::TABLES;
+ }
+ }
+
+ if ( !xModel.is() )
+ {
+ if ( rListener.is() )
+ rListener->loadCancelled(this);
+ return;
+ }
+
+ if ( !bCreateNew )
+ {
+ // We need to XLoadable::load the document if it does not yet have a URL.
+ // If it already *does* have a URL, then it was either passed in the arguments, or a previous incarnation
+ // of that model existed before (which can happen if a model is closed, but an associated DataSource is kept
+ // alive 'til loading the document again).
+ bool bNeedLoad = xModel->getURL().isEmpty();
+ try
+ {
+ aMediaDesc.put( "FileName", _rURL );
+ Sequence< PropertyValue > aResource( aMediaDesc.getPropertyValues() );
+
+ if ( bNeedLoad )
+ {
+ Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
+ xLoad->load( aResource );
+ }
+
+ // always attach the resource, even if the document has not been freshly loaded
+ xModel->attachResource( _rURL, aResource );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ bSuccess = false;
+ }
+ }
+
+ if ( bSuccess )
+ {
+ try
+ {
+ Reference< XModel2 > xModel2( xModel, UNO_QUERY_THROW );
+ Reference< XController2 > xController( xModel2->createViewController( sViewName, Sequence< PropertyValue >(), rFrame ), UNO_SET_THROW );
+
+ xController->attachModel( xModel );
+ xModel->connectController( xController );
+ rFrame->setComponent( xController->getComponentWindow(), xController );
+ xController->attachFrame( rFrame );
+ xModel->setCurrentController( xController );
+
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ bSuccess = false;
+ }
+ }
+
+ if (bSuccess)
+ {
+ if ( rListener.is() )
+ rListener->loadFinished(this);
+
+ if ( nInitialSelection != -1 )
+ {
+ Reference< css::view::XSelectionSupplier > xDocView( xModel->getCurrentController(), UNO_QUERY );
+ if ( xDocView.is() )
+ {
+ NamedDatabaseObject aSelection;
+ aSelection.Type = nInitialSelection;
+ xDocView->select( Any( aSelection ) );
+ }
+ }
+
+ if ( bStartTableWizard )
+ {
+ // reset the data of the previous async drop (if any)
+ if ( m_nStartWizard )
+ Application::RemoveUserEvent(m_nStartWizard);
+ m_sCurrentURL = xModel->getURL();
+ m_xMySelf = this;
+ m_nStartWizard = Application::PostUserEvent(LINK(this, DBContentLoader, OnStartTableWizard));
+ }
+ }
+ else
+ {
+ if ( rListener.is() )
+ rListener->loadCancelled( this );
+ }
+
+ if ( !bSuccess )
+ ::comphelper::disposeComponent(xModel);
+}
+
+void DBContentLoader::cancel()
+{
+}
+
+IMPL_LINK_NOARG( DBContentLoader, OnStartTableWizard, void*, void )
+{
+ m_nStartWizard = nullptr;
+ try
+ {
+ Sequence<Any> aWizArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"DatabaseLocation", Any(m_sCurrentURL)}
+ }));
+ SolarMutexGuard aGuard;
+ Reference< XJobExecutor > xTableWizard( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.wizards.table.CallTableWizard", aWizArgs, m_aContext), UNO_QUERY);
+ if ( xTableWizard.is() )
+ xTableWizard->trigger("start");
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "caught an exception while starting the table wizard!");
+ }
+ m_xMySelf = nullptr;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_openoffice_comp_dbflt_DBContentLoader2_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ::dbaxml::DBContentLoader(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */