From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- dbaccess/source/filter/xml/dbloader2.cxx | 535 +++++++++++++++++++++++++++++++ 1 file changed, 535 insertions(+) create mode 100644 dbaccess/source/filter/xml/dbloader2.cxx (limited to 'dbaccess/source/filter/xml/dbloader2.cxx') 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 & _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 & _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 = 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 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 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 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 const& ) +{ + return cppu::acquire(new ::dbaxml::DBContentLoader(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3