/* -*- 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 "flt_reghelper.hxx" #include "xmlstrings.hrc" #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 #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::registry; 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 { class DBTypeDetection : public ::cppu::WeakImplHelper2< XExtendedFilterDetection, XServiceInfo> { const Reference< XComponentContext > m_aContext; public: DBTypeDetection(const Reference< XComponentContext >&); // XServiceInfo OUString SAL_CALL getImplementationName() throw( ); sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw( ); Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw( ); // static methods static OUString getImplementationName_Static() throw( ) { return OUString("org.openoffice.comp.dbflt.DBTypeDetection"); } static Sequence< OUString> getSupportedServiceNames_Static(void) throw( ); static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Create(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >&); virtual OUString SAL_CALL detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& Descriptor ) throw (::com::sun::star::uno::RuntimeException); }; // ------------------------------------------------------------------------- DBTypeDetection::DBTypeDetection(const Reference< XComponentContext >& _rxContext) :m_aContext( _rxContext ) { } // ------------------------------------------------------------------------- OUString SAL_CALL DBTypeDetection::detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& Descriptor ) throw (::com::sun::star::uno::RuntimeException) { try { ::comphelper::NamedValueCollection aMedia( Descriptor ); sal_Bool bStreamFromDescr = sal_False; OUString sURL = aMedia.getOrDefault( "URL", OUString() ); Reference< XInputStream > xInStream( aMedia.getOrDefault( "InputStream", Reference< XInputStream >() ) ); Reference< XPropertySet > xStorageProperties; if ( xInStream.is() ) { bStreamFromDescr = sal_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( OUString( "InputStream" ) ); aMedia.remove( OUString( "Stream" ) ); aMedia >>= Descriptor; try { ::comphelper::disposeComponent(xStorageProperties); if ( xInStream.is() ) xInStream->closeInput(); } catch( Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } return OUString("StarBase"); } ::comphelper::disposeComponent(xStorageProperties); } } catch(Exception&){} return OUString(); } // ------------------------------------------------------------------------- Reference< XInterface > SAL_CALL DBTypeDetection::Create( const Reference< XMultiServiceFactory > & rSMgr ) { return *(new DBTypeDetection( comphelper::getComponentContext(rSMgr) )); } // ------------------------------------------------------------------------- // XServiceInfo OUString SAL_CALL DBTypeDetection::getImplementationName() throw( ) { return getImplementationName_Static(); } // ------------------------------------------------------------------------- // XServiceInfo sal_Bool SAL_CALL DBTypeDetection::supportsService(const OUString& ServiceName) throw( ) { Sequence< OUString > aSNL = getSupportedServiceNames(); const OUString * pBegin = aSNL.getConstArray(); const OUString * pEnd = pBegin + aSNL.getLength(); for( ; pBegin != pEnd; ++pBegin) if( *pBegin == ServiceName ) return sal_True; return sal_False; } // ------------------------------------------------------------------------- // XServiceInfo Sequence< OUString > SAL_CALL DBTypeDetection::getSupportedServiceNames(void) throw( ) { return getSupportedServiceNames_Static(); } // ------------------------------------------------------------------------- // ORegistryServiceManager_Static Sequence< OUString > DBTypeDetection::getSupportedServiceNames_Static(void) throw( ) { Sequence< OUString > aSNS( 1 ); aSNS.getArray()[0] = OUString("com.sun.star.document.ExtendedTypeDetection"); return aSNS; } // ------------------------------------------------------------------------- extern "C" void SAL_CALL createRegistryInfo_DBTypeDetection() { static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::DBTypeDetection > aAutoRegistration; } // ----------------------------------------------------------------------------- class DBContentLoader : public ::cppu::WeakImplHelper2< XFrameLoader, XServiceInfo> { private: const Reference< XComponentContext > m_aContext; Reference< XFrameLoader > m_xMySelf; OUString m_sCurrentURL; sal_uLong m_nStartWizard; DECL_LINK( OnStartTableWizard, void* ); public: DBContentLoader(const Reference< XComponentContext >&); ~DBContentLoader(); // XServiceInfo OUString SAL_CALL getImplementationName() throw( ); sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw( ); Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw( ); // static methods static OUString getImplementationName_Static() throw( ) { return OUString("org.openoffice.comp.dbflt.DBContentLoader2"); } static Sequence< OUString > getSupportedServiceNames_Static(void) throw( ); static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Create(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >&); // XLoader virtual void SAL_CALL load( const Reference< XFrame > & _rFrame, const OUString& _rURL, const Sequence< PropertyValue >& _rArgs, const Reference< XLoadEventListener > & _rListener) throw(::com::sun::star::uno::RuntimeException); virtual void SAL_CALL cancel(void) throw(); private: sal_Bool impl_executeNewDatabaseWizard( Reference< XModel >& _rxModel, sal_Bool& _bShouldStartTableWizard ); }; DBG_NAME(DBContentLoader) DBContentLoader::DBContentLoader(const Reference< XComponentContext >& _rxFactory) :m_aContext( _rxFactory ) ,m_nStartWizard(0) { DBG_CTOR(DBContentLoader,NULL); } // ------------------------------------------------------------------------- DBContentLoader::~DBContentLoader() { DBG_DTOR(DBContentLoader,NULL); } // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- Reference< XInterface > SAL_CALL DBContentLoader::Create( const Reference< XMultiServiceFactory > & rSMgr ) { return *(new DBContentLoader( comphelper::getComponentContext(rSMgr) )); } // ------------------------------------------------------------------------- // XServiceInfo OUString SAL_CALL DBContentLoader::getImplementationName() throw( ) { return getImplementationName_Static(); } // ------------------------------------------------------------------------- // XServiceInfo sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName) throw( ) { Sequence< OUString > aSNL = getSupportedServiceNames(); const OUString * pBegin = aSNL.getConstArray(); const OUString * pEnd = pBegin + aSNL.getLength(); for( ; pBegin != pEnd; ++pBegin) if( *pBegin == ServiceName ) return sal_True; return sal_False; } // ------------------------------------------------------------------------- // XServiceInfo Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames(void) throw( ) { return getSupportedServiceNames_Static(); } // ------------------------------------------------------------------------- // ORegistryServiceManager_Static Sequence< OUString > DBContentLoader::getSupportedServiceNames_Static(void) throw( ) { Sequence< OUString > aSNS( 1 ); aSNS.getArray()[0] = OUString("com.sun.star.frame.FrameLoader"); return aSNS; } // ----------------------------------------------------------------------- namespace { // ................................................................... sal_Bool lcl_urlAllowsInteraction( const Reference & _rContext, const OUString& _rURL ) { bool bDoesAllow = sal_False; try { Reference< XURLTransformer > xTransformer( URLTransformer::create(_rContext) ); URL aURL; aURL.Complete = _rURL; xTransformer->parseStrict( aURL ); bDoesAllow = aURL.Arguments == "Interactive"; } catch( const Exception& ) { OSL_FAIL( "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.set(xFrame->getCreator(),UNO_QUERY); if ( xFrame.is() ) xWindow = xFrame->getContainerWindow(); } return xWindow; } } // ----------------------------------------------------------------------- sal_Bool DBContentLoader::impl_executeNewDatabaseWizard( Reference< XModel >& _rxModel, sal_Bool& _bShouldStartTableWizard ) { Sequence< Any > aWizardArgs(2); aWizardArgs[0] <<= PropertyValue( OUString("ParentWindow"), 0, makeAny( lcl_getTopMostWindow( m_aContext ) ), PropertyState_DIRECT_VALUE); aWizardArgs[1] <<= PropertyValue( OUString("InitialSelection"), 0, makeAny( _rxModel ), PropertyState_DIRECT_VALUE); // 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 sal_False; Reference xProp(xAdminDialog,UNO_QUERY); sal_Bool bSuccess = sal_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) throw(::com::sun::star::uno::RuntimeException) { // first check if preview is true, if so return with out creating a controller. Preview is not supported ::comphelper::NamedValueCollection aMediaDesc( rArgs ); sal_Bool bPreview = aMediaDesc.getOrDefault( "Preview", sal_False ); if ( bPreview ) { if (rListener.is()) rListener->loadCancelled(this); return; } Reference< XModel > xModel = aMediaDesc.getOrDefault( "Model", Reference< XModel >() ); OUString sSalvagedURL = aMediaDesc.getOrDefault( "SalvagedFile", _rURL ); sal_Bool bCreateNew = sal_False; // does the URL denote the private:factory URL? sal_Bool bStartTableWizard = sal_False; // start the table wizard after everything was loaded successfully? sal_Bool bSuccess = sal_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, 0) ); 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" ); sal_Int32 nInitialSelection = -1; if ( !xModel.is() ) { Reference< XDatabaseContext > xDatabaseContext( DatabaseContext::create(m_aContext) ); OUString sFactoryName = SvtModuleOptions().GetFactoryEmptyDocumentURL(SvtModuleOptions::E_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( (OUString)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 = ::com::sun::star::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 an URL. // If it already *does* have an 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(); bSuccess = sal_False; } } if ( bSuccess ) { try { Reference< XModel2 > xModel2( xModel, UNO_QUERY_THROW ); Reference< XController2 > xController( xModel2->createViewController( sViewName, Sequence< PropertyValue >(), rFrame ), UNO_QUERY_THROW ); xController->attachModel( xModel ); xModel->connectController( xController.get() ); rFrame->setComponent( xController->getComponentWindow(), xController.get() ); xController->attachFrame( rFrame ); xModel->setCurrentController( xController.get() ); bSuccess = sal_True; } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); bSuccess = sal_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( makeAny( 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(void) throw() { } // ----------------------------------------------------------------------------- IMPL_LINK( DBContentLoader, OnStartTableWizard, void*, /*NOTINTERESTEDIN*/ ) { m_nStartWizard = 0; try { Sequence< Any > aWizArgs(1); PropertyValue aValue; aValue.Name = OUString("DatabaseLocation"); aValue.Value <<= m_sCurrentURL; aWizArgs[0] <<= aValue; 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(OUString("start")); } catch(const Exception&) { OSL_FAIL("caught an exception while starting the table wizard!"); } m_xMySelf = NULL; return 0L; } } // ------------------------------------------------------------------------- extern "C" void SAL_CALL createRegistryInfo_DBContentLoader2() { static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::DBContentLoader > aAutoRegistration; } // ------------------------------------------------------------------------- extern "C" void SAL_CALL writeDBLoaderInfo2(void* pRegistryKey) { Reference< XRegistryKey> xKey(reinterpret_cast< XRegistryKey*>(pRegistryKey)); // register content loader for dispatch OUString aImpl("/"); aImpl += ::dbaxml::DBContentLoader::getImplementationName_Static(); OUString aImpltwo = aImpl + "/UNO/Loader"; Reference< XRegistryKey> xNewKey = xKey->createKey( aImpltwo ); aImpltwo = aImpl + "/Loader"; Reference< XRegistryKey > xLoaderKey = xKey->createKey( aImpltwo ); xNewKey = xLoaderKey->createKey( OUString("Pattern") ); xNewKey->setAsciiValue( OUString("private:factory/sdatabase") ); } // ----------------------------------------------------------------------------- /* vim:set shiftwidth=4 softtabstop=4 expandtab: */