1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
95 class DBTypeDetection
: public ::cppu::WeakImplHelper2
< XExtendedFilterDetection
, XServiceInfo
>
97 const Reference
< XComponentContext
> m_aContext
;
100 DBTypeDetection(const Reference
< XComponentContext
>&);
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
;
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
);
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() )
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();
173 DBG_UNHANDLED_EXCEPTION();
177 return OUString("StarBase");
179 ::comphelper::disposeComponent(xStorageProperties
);
181 } catch(Exception
&){}
185 Reference
< XInterface
> SAL_CALL
DBTypeDetection::Create( const Reference
< XMultiServiceFactory
> & rSMgr
)
187 return *(new DBTypeDetection( comphelper::getComponentContext(rSMgr
) ));
191 OUString SAL_CALL
DBTypeDetection::getImplementationName() throw(std::exception
)
193 return getImplementationName_Static();
197 sal_Bool SAL_CALL
DBTypeDetection::supportsService(const OUString
& ServiceName
) throw(std::exception
)
199 return cppu::supportsService(this, ServiceName
);
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";
216 } // namespace dbaxml
218 extern "C" void SAL_CALL
createRegistryInfo_DBTypeDetection()
220 static ::dbaxml::OMultiInstanceAutoRegistration
< ::dbaxml::DBTypeDetection
> aAutoRegistration
;
226 class DBContentLoader
: public ::cppu::WeakImplHelper2
< XFrameLoader
, XServiceInfo
>
229 const Reference
< XComponentContext
> m_aContext
;
230 Reference
< XFrameLoader
> m_xMySelf
;
231 OUString m_sCurrentURL
;
232 ImplSVEvent
* m_nStartWizard
;
234 DECL_LINK( OnStartTableWizard
, void* );
236 DBContentLoader(const Reference
< XComponentContext
>&);
237 virtual ~DBContentLoader();
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
;
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
>&);
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
;
260 bool impl_executeNewDatabaseWizard( Reference
< XModel
>& _rxModel
, bool& _bShouldStartTableWizard
);
264 DBContentLoader::DBContentLoader(const Reference
< XComponentContext
>& _rxFactory
)
265 :m_aContext( _rxFactory
)
271 DBContentLoader::~DBContentLoader()
276 Reference
< XInterface
> SAL_CALL
DBContentLoader::Create( const Reference
< XMultiServiceFactory
> & rSMgr
)
278 return *(new DBContentLoader( comphelper::getComponentContext(rSMgr
) ));
282 OUString SAL_CALL
DBContentLoader::getImplementationName() throw(std::exception
)
284 return getImplementationName_Static();
288 sal_Bool SAL_CALL
DBContentLoader::supportsService(const OUString
& ServiceName
) throw(std::exception
)
290 return cppu::supportsService(this, ServiceName
);
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";
309 bool lcl_urlAllowsInteraction( const Reference
<XComponentContext
> & _rContext
, const OUString
& _rURL
)
311 bool bDoesAllow
= false;
314 Reference
< XURLTransformer
> xTransformer( URLTransformer::create(_rContext
) );
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!" );
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
);
341 xWindow
= xFrame
->getContainerWindow();
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"),
360 PropertyState_DIRECT_VALUE
);
363 Reference
< XExecutableDialog
> xAdminDialog( m_aContext
->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.sdb.DatabaseWizardDialog", aWizardArgs
, m_aContext
), UNO_QUERY_THROW
);
366 if ( RET_OK
!= xAdminDialog
->execute() )
369 Reference
<XPropertySet
> xProp(xAdminDialog
,UNO_QUERY
);
370 bool bSuccess
= false;
371 xProp
->getPropertyValue("OpenDatabase") >>= bSuccess
;
372 xProp
->getPropertyValue("StartTableWizard") >>= _bShouldStartTableWizard
;
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
);
386 rListener
->loadCancelled(this);
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
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;
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;
431 bNewAndInteractive
= lcl_urlAllowsInteraction( m_aContext
, _rURL
);
432 xDocumentDataSource
.set( xDatabaseContext
->createInstance(), UNO_QUERY_THROW
);
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
);
453 Reference
< XLoadable
> xLoad( xModel
, UNO_QUERY_THROW
);
457 catch( const Exception
& )
463 // initially select the "Tables" category (will be done below)
464 nInitialSelection
= ::com::sun::star::sdb::application::DatabaseObjectContainer::TABLES
;
470 if ( rListener
.is() )
471 rListener
->loadCancelled(this);
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() );
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();
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() );
518 catch( const Exception
& )
520 DBG_UNHANDLED_EXCEPTION();
527 if ( rListener
.is() )
528 rListener
->loadFinished(this);
530 if ( nInitialSelection
!= -1 )
532 Reference
< css::view::XSelectionSupplier
> xDocView( xModel
->getCurrentController(), UNO_QUERY
);
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();
548 m_nStartWizard
= Application::PostUserEvent(LINK(this, DBContentLoader
, OnStartTableWizard
));
553 if ( rListener
.is() )
554 rListener
->loadCancelled( this );
558 ::comphelper::disposeComponent(xModel
);
561 void DBContentLoader::cancel() throw(std::exception
)
565 IMPL_LINK_NOARG( DBContentLoader
, OnStartTableWizard
)
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!");
591 extern "C" void SAL_CALL
createRegistryInfo_DBContentLoader2()
593 static ::dbaxml::OMultiInstanceAutoRegistration
< ::dbaxml::DBContentLoader
> aAutoRegistration
;
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */