bump product version to 5.0.4.1
[LibreOffice.git] / dbaccess / source / filter / xml / dbloader2.cxx
blob93cf4c0b748d3824f9af227978efb7d16083f65f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "flt_reghelper.hxx"
21 #include "xmlservices.hxx"
22 #include "xmlstrings.hrc"
24 #include <com/sun/star/beans/NamedValue.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/document/XEventListener.hpp>
27 #include <com/sun/star/document/XExtendedFilterDetection.hpp>
28 #include <com/sun/star/document/XFilter.hpp>
29 #include <com/sun/star/embed/ElementModes.hpp>
30 #include <com/sun/star/embed/XStorage.hpp>
31 #include <com/sun/star/frame/Desktop.hpp>
32 #include <com/sun/star/frame/XController.hpp>
33 #include <com/sun/star/frame/XFrame.hpp>
34 #include <com/sun/star/frame/XFrameLoader.hpp>
35 #include <com/sun/star/frame/XFramesSupplier.hpp>
36 #include <com/sun/star/frame/XLoadEventListener.hpp>
37 #include <com/sun/star/frame/XModel2.hpp>
38 #include <com/sun/star/io/XInputStream.hpp>
39 #include <com/sun/star/lang/XInitialization.hpp>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/lang/XServiceInfo.hpp>
42 #include <com/sun/star/registry/XRegistryKey.hpp>
43 #include <com/sun/star/sdb/DatabaseContext.hpp>
44 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
45 #include <com/sun/star/task/XJobExecutor.hpp>
46 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
47 #include <com/sun/star/task/InteractionHandler.hpp>
48 #include <com/sun/star/util/URLTransformer.hpp>
49 #include <com/sun/star/util/XURLTransformer.hpp>
50 #include <com/sun/star/view/XSelectionSupplier.hpp>
51 #include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
52 #include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
53 #include <com/sun/star/frame/XLoadable.hpp>
55 #include <comphelper/documentconstants.hxx>
56 #include <comphelper/namedvaluecollection.hxx>
57 #include <comphelper/processfactory.hxx>
58 #include <comphelper/sequenceashashmap.hxx>
59 #include <comphelper/storagehelper.hxx>
60 #include <comphelper/types.hxx>
61 #include <cppuhelper/implbase2.hxx>
62 #include <cppuhelper/supportsservice.hxx>
63 #include <osl/file.hxx>
64 #include <sfx2/docfile.hxx>
65 #include <unotools/moduleoptions.hxx>
66 #include <toolkit/awt/vclxwindow.hxx>
67 #include <toolkit/helper/vclunohelper.hxx>
68 #include <tools/diagnose_ex.h>
69 #include <ucbhelper/commandenvironment.hxx>
70 #include <ucbhelper/content.hxx>
71 #include <vcl/msgbox.hxx>
72 #include <vcl/svapp.hxx>
74 using namespace ::ucbhelper;
75 using namespace ::com::sun::star::task;
76 using namespace ::com::sun::star::uno;
77 using namespace ::com::sun::star::ucb;
78 using namespace ::com::sun::star::io;
79 using namespace ::com::sun::star::util;
80 using namespace ::com::sun::star::frame;
81 using namespace ::com::sun::star::beans;
82 using namespace ::com::sun::star::container;
83 using namespace ::com::sun::star::lang;
84 using namespace ::com::sun::star::document;
85 using namespace ::com::sun::star::registry;
86 using namespace ::com::sun::star::sdb;
87 using namespace ::com::sun::star::embed;
88 using namespace ::com::sun::star::ui::dialogs;
89 using ::com::sun::star::awt::XWindow;
90 using ::com::sun::star::sdb::application::NamedDatabaseObject;
92 namespace dbaxml
95 class DBTypeDetection : public ::cppu::WeakImplHelper2< XExtendedFilterDetection, XServiceInfo>
97 const Reference< XComponentContext > m_aContext;
99 public:
100 DBTypeDetection(const Reference< XComponentContext >&);
102 // XServiceInfo
103 OUString SAL_CALL getImplementationName() throw(std::exception ) SAL_OVERRIDE;
104 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw(std::exception ) SAL_OVERRIDE;
105 Sequence< OUString > SAL_CALL getSupportedServiceNames() throw(std::exception ) SAL_OVERRIDE;
107 // static methods
108 static OUString getImplementationName_Static() throw( )
110 return OUString("org.openoffice.comp.dbflt.DBTypeDetection");
112 static Sequence< OUString> getSupportedServiceNames_Static() throw( );
113 static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
114 SAL_CALL Create(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >&);
116 virtual OUString SAL_CALL detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& Descriptor ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
119 DBTypeDetection::DBTypeDetection(const Reference< XComponentContext >& _rxContext)
120 :m_aContext( _rxContext )
124 OUString SAL_CALL DBTypeDetection::detect( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& Descriptor ) throw (::com::sun::star::uno::RuntimeException, std::exception)
128 ::comphelper::NamedValueCollection aMedia( Descriptor );
129 bool bStreamFromDescr = false;
130 OUString sURL = aMedia.getOrDefault( "URL", OUString() );
132 Reference< XInputStream > xInStream( aMedia.getOrDefault( "InputStream", Reference< XInputStream >() ) );
133 Reference< XPropertySet > xStorageProperties;
134 if ( xInStream.is() )
136 bStreamFromDescr = true;
137 xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromInputStream(
138 xInStream, m_aContext ), UNO_QUERY );
140 else
142 OUString sSalvagedURL( aMedia.getOrDefault( "SalvagedFile", OUString() ) );
144 OUString sFileLocation( sSalvagedURL.isEmpty() ? sURL : sSalvagedURL );
145 if ( !sFileLocation.isEmpty() )
147 xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromURL(
148 sFileLocation, ElementModes::READ, m_aContext ), UNO_QUERY );
152 if ( xStorageProperties.is() )
154 OUString sMediaType;
155 xStorageProperties->getPropertyValue( INFO_MEDIATYPE ) >>= sMediaType;
156 if ( sMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII || sMediaType == MIMETYPE_VND_SUN_XML_BASE_ASCII )
158 if ( bStreamFromDescr && !sURL.startsWith( "private:stream" ) )
160 // After fixing of the i88522 issue ( use the new file locking for database files ) the stream from the type detection can be used further
161 // for now the file should be reopened to have read/write access
162 aMedia.remove( OUString( "InputStream" ) );
163 aMedia.remove( OUString( "Stream" ) );
164 aMedia >>= Descriptor;
167 ::comphelper::disposeComponent(xStorageProperties);
168 if ( xInStream.is() )
169 xInStream->closeInput();
171 catch( Exception& )
173 DBG_UNHANDLED_EXCEPTION();
177 return OUString("StarBase");
179 ::comphelper::disposeComponent(xStorageProperties);
181 } catch(Exception&){}
182 return OUString();
185 Reference< XInterface > SAL_CALL DBTypeDetection::Create( const Reference< XMultiServiceFactory > & rSMgr )
187 return *(new DBTypeDetection( comphelper::getComponentContext(rSMgr) ));
190 // XServiceInfo
191 OUString SAL_CALL DBTypeDetection::getImplementationName() throw(std::exception )
193 return getImplementationName_Static();
196 // XServiceInfo
197 sal_Bool SAL_CALL DBTypeDetection::supportsService(const OUString& ServiceName) throw(std::exception )
199 return cppu::supportsService(this, ServiceName);
202 // XServiceInfo
203 Sequence< OUString > SAL_CALL DBTypeDetection::getSupportedServiceNames() throw(std::exception )
205 return getSupportedServiceNames_Static();
208 // ORegistryServiceManager_Static
209 Sequence< OUString > DBTypeDetection::getSupportedServiceNames_Static() throw( )
211 Sequence< OUString > aSNS( 1 );
212 aSNS[0] = "com.sun.star.document.ExtendedTypeDetection";
213 return aSNS;
216 } // namespace dbaxml
218 extern "C" void SAL_CALL createRegistryInfo_DBTypeDetection()
220 static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::DBTypeDetection > aAutoRegistration;
223 namespace dbaxml
226 class DBContentLoader : public ::cppu::WeakImplHelper2< XFrameLoader, XServiceInfo>
228 private:
229 const Reference< XComponentContext > m_aContext;
230 Reference< XFrameLoader > m_xMySelf;
231 OUString m_sCurrentURL;
232 ImplSVEvent * m_nStartWizard;
234 DECL_LINK( OnStartTableWizard, void* );
235 public:
236 DBContentLoader(const Reference< XComponentContext >&);
237 virtual ~DBContentLoader();
239 // XServiceInfo
240 OUString SAL_CALL getImplementationName() throw(std::exception ) SAL_OVERRIDE;
241 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw(std::exception ) SAL_OVERRIDE;
242 Sequence< OUString > SAL_CALL getSupportedServiceNames() throw(std::exception ) SAL_OVERRIDE;
244 // static methods
245 static OUString getImplementationName_Static() throw( )
247 return OUString("org.openoffice.comp.dbflt.DBContentLoader2");
249 static Sequence< OUString > getSupportedServiceNames_Static() throw( );
250 static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
251 SAL_CALL Create(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >&);
253 // XLoader
254 virtual void SAL_CALL load( const Reference< XFrame > & _rFrame, const OUString& _rURL,
255 const Sequence< PropertyValue >& _rArgs,
256 const Reference< XLoadEventListener > & _rListener) throw(::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
257 virtual void SAL_CALL cancel() throw(std::exception) SAL_OVERRIDE;
259 private:
260 bool impl_executeNewDatabaseWizard( Reference< XModel >& _rxModel, bool& _bShouldStartTableWizard );
264 DBContentLoader::DBContentLoader(const Reference< XComponentContext >& _rxFactory)
265 :m_aContext( _rxFactory )
266 ,m_nStartWizard(0)
271 DBContentLoader::~DBContentLoader()
276 Reference< XInterface > SAL_CALL DBContentLoader::Create( const Reference< XMultiServiceFactory > & rSMgr )
278 return *(new DBContentLoader( comphelper::getComponentContext(rSMgr) ));
281 // XServiceInfo
282 OUString SAL_CALL DBContentLoader::getImplementationName() throw(std::exception )
284 return getImplementationName_Static();
287 // XServiceInfo
288 sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName) throw(std::exception )
290 return cppu::supportsService(this, ServiceName);
293 // XServiceInfo
294 Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames() throw(std::exception )
296 return getSupportedServiceNames_Static();
299 // ORegistryServiceManager_Static
300 Sequence< OUString > DBContentLoader::getSupportedServiceNames_Static() throw( )
302 Sequence< OUString > aSNS( 1 );
303 aSNS[0] = "com.sun.star.frame.FrameLoader";
304 return aSNS;
307 namespace
309 bool lcl_urlAllowsInteraction( const Reference<XComponentContext> & _rContext, const OUString& _rURL )
311 bool bDoesAllow = false;
314 Reference< XURLTransformer > xTransformer( URLTransformer::create(_rContext) );
315 URL aURL;
316 aURL.Complete = _rURL;
317 xTransformer->parseStrict( aURL );
318 bDoesAllow = aURL.Arguments == "Interactive";
320 catch( const Exception& )
322 OSL_FAIL( "lcl_urlAllowsInteraction: caught an exception while analyzing the URL!" );
324 return bDoesAllow;
327 Reference< XWindow > lcl_getTopMostWindow( const Reference<XComponentContext> & _rxContext )
329 Reference< XWindow > xWindow;
330 // get the top most window
331 Reference < XDesktop2 > xDesktop = Desktop::create(_rxContext);
332 Reference < XFrame > xActiveFrame = xDesktop->getActiveFrame();
333 if ( xActiveFrame.is() )
335 xWindow = xActiveFrame->getContainerWindow();
336 Reference<XFrame> xFrame = xActiveFrame;
337 while ( xFrame.is() && !xFrame->isTop() )
338 xFrame.set(xFrame->getCreator(),UNO_QUERY);
340 if ( xFrame.is() )
341 xWindow = xFrame->getContainerWindow();
343 return xWindow;
347 bool DBContentLoader::impl_executeNewDatabaseWizard( Reference< XModel >& _rxModel, bool& _bShouldStartTableWizard )
349 Sequence< Any > aWizardArgs(2);
350 aWizardArgs[0] <<= PropertyValue(
351 OUString("ParentWindow"),
353 makeAny( lcl_getTopMostWindow( m_aContext ) ),
354 PropertyState_DIRECT_VALUE);
356 aWizardArgs[1] <<= PropertyValue(
357 OUString("InitialSelection"),
359 makeAny( _rxModel ),
360 PropertyState_DIRECT_VALUE);
362 // create the dialog
363 Reference< XExecutableDialog > xAdminDialog( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.sdb.DatabaseWizardDialog", aWizardArgs, m_aContext), UNO_QUERY_THROW);
365 // execute it
366 if ( RET_OK != xAdminDialog->execute() )
367 return false;
369 Reference<XPropertySet> xProp(xAdminDialog,UNO_QUERY);
370 bool bSuccess = false;
371 xProp->getPropertyValue("OpenDatabase") >>= bSuccess;
372 xProp->getPropertyValue("StartTableWizard") >>= _bShouldStartTableWizard;
373 return bSuccess;
376 void SAL_CALL DBContentLoader::load(const Reference< XFrame > & rFrame, const OUString& _rURL,
377 const Sequence< PropertyValue >& rArgs,
378 const Reference< XLoadEventListener > & rListener) throw(::com::sun::star::uno::RuntimeException, std::exception)
380 // first check if preview is true, if so return with out creating a controller. Preview is not supported
381 ::comphelper::NamedValueCollection aMediaDesc( rArgs );
382 bool bPreview = aMediaDesc.getOrDefault( "Preview", sal_False );
383 if ( bPreview )
385 if (rListener.is())
386 rListener->loadCancelled(this);
387 return;
390 Reference< XModel > xModel = aMediaDesc.getOrDefault( "Model", Reference< XModel >() );
391 OUString sSalvagedURL = aMediaDesc.getOrDefault( "SalvagedFile", _rURL );
393 bool bCreateNew = false; // does the URL denote the private:factory URL?
394 bool bStartTableWizard = false; // start the table wizard after everything was loaded successfully?
396 bool bSuccess = true;
398 // If there's no interaction handler in the media descriptor, put one.
399 // By definition, loading via loadComponentFromURL (and thus via the content loader here)
400 // is allowed to raise UI. To not burden every place inside the document with creating
401 // a default handler, we simply ensure there is one.
402 // If a handler is present in the media descriptor, even if it is NULL, we will
403 // not touch it.
404 if ( !aMediaDesc.has( "InteractionHandler" ) )
406 Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(m_aContext, 0) );
407 aMediaDesc.put( "InteractionHandler", xHandler );
410 // it's allowed to pass an existing document
411 Reference< XOfficeDatabaseDocument > xExistentDBDoc;
412 xModel.set( aMediaDesc.getOrDefault( "Model", xExistentDBDoc ), UNO_QUERY );
413 aMediaDesc.remove( "Model" );
415 // also, it's allowed to specify the type of view which should be created
416 OUString sViewName = aMediaDesc.getOrDefault( "ViewName", OUString( "Default" ) );
417 aMediaDesc.remove( "ViewName" );
419 sal_Int32 nInitialSelection = -1;
420 if ( !xModel.is() )
422 Reference< XDatabaseContext > xDatabaseContext( DatabaseContext::create(m_aContext) );
424 OUString sFactoryName = SvtModuleOptions().GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::DATABASE);
425 bCreateNew = sFactoryName.match(_rURL);
427 Reference< XDocumentDataSource > xDocumentDataSource;
428 bool bNewAndInteractive = false;
429 if ( bCreateNew )
431 bNewAndInteractive = lcl_urlAllowsInteraction( m_aContext, _rURL );
432 xDocumentDataSource.set( xDatabaseContext->createInstance(), UNO_QUERY_THROW );
434 else
436 ::comphelper::NamedValueCollection aCreationArgs;
437 aCreationArgs.put( OUString(INFO_POOLURL), sSalvagedURL );
438 xDocumentDataSource.set( xDatabaseContext->createInstanceWithArguments( aCreationArgs.getWrappedNamedValues() ), UNO_QUERY_THROW );
441 xModel.set( xDocumentDataSource->getDatabaseDocument(), UNO_QUERY );
443 if ( bCreateNew && xModel.is() )
445 if ( bNewAndInteractive )
447 bSuccess = impl_executeNewDatabaseWizard( xModel, bStartTableWizard );
449 else
453 Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
454 xLoad->initNew();
455 bSuccess = true;
457 catch( const Exception& )
459 bSuccess = false;
463 // initially select the "Tables" category (will be done below)
464 nInitialSelection = ::com::sun::star::sdb::application::DatabaseObjectContainer::TABLES;
468 if ( !xModel.is() )
470 if ( rListener.is() )
471 rListener->loadCancelled(this);
472 return;
475 if ( !bCreateNew )
477 // We need to XLoadable::load the document if it does not yet have an URL.
478 // If it already *does* have an URL, then it was either passed in the arguments, or a previous incarnation
479 // of that model existed before (which can happen if a model is closed, but an associated DataSource is kept
480 // alive 'til loading the document again).
481 bool bNeedLoad = ( xModel->getURL().isEmpty() );
484 aMediaDesc.put( "FileName", _rURL );
485 Sequence< PropertyValue > aResource( aMediaDesc.getPropertyValues() );
487 if ( bNeedLoad )
489 Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
490 xLoad->load( aResource );
493 // always attach the resource, even if the document has not been freshly loaded
494 xModel->attachResource( _rURL, aResource );
496 catch(const Exception&)
498 DBG_UNHANDLED_EXCEPTION();
499 bSuccess = false;
503 if ( bSuccess )
507 Reference< XModel2 > xModel2( xModel, UNO_QUERY_THROW );
508 Reference< XController2 > xController( xModel2->createViewController( sViewName, Sequence< PropertyValue >(), rFrame ), UNO_QUERY_THROW );
510 xController->attachModel( xModel );
511 xModel->connectController( xController.get() );
512 rFrame->setComponent( xController->getComponentWindow(), xController.get() );
513 xController->attachFrame( rFrame );
514 xModel->setCurrentController( xController.get() );
516 bSuccess = true;
518 catch( const Exception& )
520 DBG_UNHANDLED_EXCEPTION();
521 bSuccess = false;
525 if (bSuccess)
527 if ( rListener.is() )
528 rListener->loadFinished(this);
530 if ( nInitialSelection != -1 )
532 Reference< css::view::XSelectionSupplier > xDocView( xModel->getCurrentController(), UNO_QUERY );
533 if ( xDocView.is() )
535 NamedDatabaseObject aSelection;
536 aSelection.Type = nInitialSelection;
537 xDocView->select( makeAny( aSelection ) );
541 if ( bStartTableWizard )
543 // reset the data of the previous async drop (if any)
544 if ( m_nStartWizard )
545 Application::RemoveUserEvent(m_nStartWizard);
546 m_sCurrentURL = xModel->getURL();
547 m_xMySelf = this;
548 m_nStartWizard = Application::PostUserEvent(LINK(this, DBContentLoader, OnStartTableWizard));
551 else
553 if ( rListener.is() )
554 rListener->loadCancelled( this );
557 if ( !bSuccess )
558 ::comphelper::disposeComponent(xModel);
561 void DBContentLoader::cancel() throw(std::exception)
565 IMPL_LINK_NOARG( DBContentLoader, OnStartTableWizard )
567 m_nStartWizard = 0;
570 Sequence< Any > aWizArgs(1);
571 PropertyValue aValue;
572 aValue.Name = "DatabaseLocation";
573 aValue.Value <<= m_sCurrentURL;
574 aWizArgs[0] <<= aValue;
576 SolarMutexGuard aGuard;
577 Reference< XJobExecutor > xTableWizard( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.wizards.table.CallTableWizard", aWizArgs, m_aContext), UNO_QUERY);
578 if ( xTableWizard.is() )
579 xTableWizard->trigger(OUString("start"));
581 catch(const Exception&)
583 OSL_FAIL("caught an exception while starting the table wizard!");
585 m_xMySelf = NULL;
586 return 0L;
591 extern "C" void SAL_CALL createRegistryInfo_DBContentLoader2()
593 static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::DBContentLoader > aAutoRegistration;
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */