nss: upgrade to release 3.73
[LibreOffice.git] / dbaccess / source / filter / xml / dbloader2.cxx
blob60810ad0430816c5ca155b97ceb34bb9a75cb168
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 <strings.hxx>
22 #include <com/sun/star/beans/NamedValue.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/document/XExtendedFilterDetection.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/embed/XStorage.hpp>
27 #include <com/sun/star/frame/Desktop.hpp>
28 #include <com/sun/star/frame/XController2.hpp>
29 #include <com/sun/star/frame/XFrame.hpp>
30 #include <com/sun/star/frame/XFrameLoader.hpp>
31 #include <com/sun/star/frame/XLoadEventListener.hpp>
32 #include <com/sun/star/frame/XModel2.hpp>
33 #include <com/sun/star/io/XInputStream.hpp>
34 #include <com/sun/star/lang/XServiceInfo.hpp>
35 #include <com/sun/star/sdb/DatabaseContext.hpp>
36 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
37 #include <com/sun/star/task/XJobExecutor.hpp>
38 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
39 #include <com/sun/star/task/InteractionHandler.hpp>
40 #include <com/sun/star/util/URLTransformer.hpp>
41 #include <com/sun/star/util/XURLTransformer.hpp>
42 #include <com/sun/star/view/XSelectionSupplier.hpp>
43 #include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
44 #include <com/sun/star/sdb/application/NamedDatabaseObject.hpp>
45 #include <com/sun/star/frame/XLoadable.hpp>
47 #include <comphelper/documentconstants.hxx>
48 #include <comphelper/namedvaluecollection.hxx>
49 #include <comphelper/storagehelper.hxx>
50 #include <comphelper/types.hxx>
51 #include <comphelper/propertysequence.hxx>
52 #include <cppuhelper/implbase.hxx>
53 #include <cppuhelper/supportsservice.hxx>
54 #include <sfx2/docfile.hxx>
55 #include <unotools/moduleoptions.hxx>
56 #include <tools/diagnose_ex.h>
57 #include <vcl/svapp.hxx>
59 using namespace ::ucbhelper;
60 using namespace ::com::sun::star::task;
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::ucb;
63 using namespace ::com::sun::star::io;
64 using namespace ::com::sun::star::util;
65 using namespace ::com::sun::star::frame;
66 using namespace ::com::sun::star::beans;
67 using namespace ::com::sun::star::container;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::document;
70 using namespace ::com::sun::star::sdb;
71 using namespace ::com::sun::star::embed;
72 using namespace ::com::sun::star::ui::dialogs;
73 using ::com::sun::star::awt::XWindow;
74 using ::com::sun::star::sdb::application::NamedDatabaseObject;
76 namespace dbaxml
79 namespace {
81 class DBTypeDetection : public ::cppu::WeakImplHelper< XExtendedFilterDetection, XServiceInfo>
83 const Reference< XComponentContext > m_aContext;
85 public:
86 explicit DBTypeDetection(const Reference< XComponentContext >&);
88 // XServiceInfo
89 OUString SAL_CALL getImplementationName() override;
90 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
91 Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
93 virtual OUString SAL_CALL detect( css::uno::Sequence< css::beans::PropertyValue >& Descriptor ) override;
98 DBTypeDetection::DBTypeDetection(const Reference< XComponentContext >& _rxContext)
99 :m_aContext( _rxContext )
103 OUString SAL_CALL DBTypeDetection::detect( css::uno::Sequence< css::beans::PropertyValue >& Descriptor )
107 ::comphelper::NamedValueCollection aMedia( Descriptor );
108 bool bStreamFromDescr = false;
109 OUString sURL = aMedia.getOrDefault( "URL", OUString() );
111 Reference< XInputStream > xInStream( aMedia.getOrDefault( "InputStream", Reference< XInputStream >() ) );
112 Reference< XPropertySet > xStorageProperties;
113 if ( xInStream.is() )
115 bStreamFromDescr = true;
116 xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromInputStream(
117 xInStream, m_aContext ), UNO_QUERY );
119 else
121 OUString sSalvagedURL( aMedia.getOrDefault( "SalvagedFile", OUString() ) );
123 OUString sFileLocation( sSalvagedURL.isEmpty() ? sURL : sSalvagedURL );
124 if ( !sFileLocation.isEmpty() )
126 xStorageProperties.set( ::comphelper::OStorageHelper::GetStorageFromURL(
127 sFileLocation, ElementModes::READ, m_aContext ), UNO_QUERY );
131 if ( xStorageProperties.is() )
133 OUString sMediaType;
134 xStorageProperties->getPropertyValue( INFO_MEDIATYPE ) >>= sMediaType;
135 if ( sMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII || sMediaType == MIMETYPE_VND_SUN_XML_BASE_ASCII )
137 if ( bStreamFromDescr && !sURL.startsWith( "private:stream" ) )
139 // After fixing of the i88522 issue ( use the new file locking for database files ) the stream from the type detection can be used further
140 // for now the file should be reopened to have read/write access
141 aMedia.remove( OUString( "InputStream" ) );
142 aMedia.remove( OUString( "Stream" ) );
143 aMedia >>= Descriptor;
146 ::comphelper::disposeComponent(xStorageProperties);
147 if ( xInStream.is() )
148 xInStream->closeInput();
150 catch( Exception& )
152 DBG_UNHANDLED_EXCEPTION("dbaccess");
156 return "StarBase";
158 ::comphelper::disposeComponent(xStorageProperties);
160 } catch(Exception&){}
161 return OUString();
164 // XServiceInfo
165 OUString SAL_CALL DBTypeDetection::getImplementationName()
167 return "org.openoffice.comp.dbflt.DBTypeDetection";
170 // XServiceInfo
171 sal_Bool SAL_CALL DBTypeDetection::supportsService(const OUString& ServiceName)
173 return cppu::supportsService(this, ServiceName);
176 // XServiceInfo
177 Sequence< OUString > SAL_CALL DBTypeDetection::getSupportedServiceNames()
179 return { "com.sun.star.document.ExtendedTypeDetection" };
182 } // namespace dbaxml
184 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
185 org_openoffice_comp_dbflt_DBTypeDetection_get_implementation(
186 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
188 return cppu::acquire(new ::dbaxml::DBTypeDetection(context));
191 namespace dbaxml
194 namespace {
196 class DBContentLoader : public ::cppu::WeakImplHelper< XFrameLoader, XServiceInfo>
198 private:
199 const Reference< XComponentContext > m_aContext;
200 Reference< XFrameLoader > m_xMySelf;
201 OUString m_sCurrentURL;
202 ImplSVEvent * m_nStartWizard;
204 DECL_LINK( OnStartTableWizard, void*, void );
205 public:
206 explicit DBContentLoader(const Reference< XComponentContext >&);
208 // XServiceInfo
209 OUString SAL_CALL getImplementationName() override;
210 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
211 Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
213 // XLoader
214 virtual void SAL_CALL load( const Reference< XFrame > & _rFrame, const OUString& _rURL,
215 const Sequence< PropertyValue >& _rArgs,
216 const Reference< XLoadEventListener > & _rListener) override;
217 virtual void SAL_CALL cancel() override;
219 private:
220 bool impl_executeNewDatabaseWizard( Reference< XModel > const & _rxModel, bool& _bShouldStartTableWizard );
225 DBContentLoader::DBContentLoader(const Reference< XComponentContext >& _rxFactory)
226 :m_aContext( _rxFactory )
227 ,m_nStartWizard(nullptr)
232 // XServiceInfo
233 OUString SAL_CALL DBContentLoader::getImplementationName()
235 return "org.openoffice.comp.dbflt.DBContentLoader2";
238 // XServiceInfo
239 sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName)
241 return cppu::supportsService(this, ServiceName);
244 // XServiceInfo
245 Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames()
247 return { "com.sun.star.frame.FrameLoader" };
251 namespace
253 bool lcl_urlAllowsInteraction( const Reference<XComponentContext> & _rContext, const OUString& _rURL )
255 bool bDoesAllow = false;
258 Reference< XURLTransformer > xTransformer( URLTransformer::create(_rContext) );
259 URL aURL;
260 aURL.Complete = _rURL;
261 xTransformer->parseStrict( aURL );
262 bDoesAllow = aURL.Arguments == "Interactive";
264 catch( const Exception& )
266 OSL_FAIL( "lcl_urlAllowsInteraction: caught an exception while analyzing the URL!" );
268 return bDoesAllow;
271 Reference< XWindow > lcl_getTopMostWindow( const Reference<XComponentContext> & _rxContext )
273 Reference< XWindow > xWindow;
274 // get the top most window
275 Reference < XDesktop2 > xDesktop = Desktop::create(_rxContext);
276 Reference < XFrame > xActiveFrame = xDesktop->getActiveFrame();
277 if ( xActiveFrame.is() )
279 xWindow = xActiveFrame->getContainerWindow();
280 Reference<XFrame> xFrame = xActiveFrame;
281 while ( xFrame.is() && !xFrame->isTop() )
282 xFrame = xFrame->getCreator();
284 if ( xFrame.is() )
285 xWindow = xFrame->getContainerWindow();
287 return xWindow;
291 bool DBContentLoader::impl_executeNewDatabaseWizard( Reference< XModel > const & _rxModel, bool& _bShouldStartTableWizard )
293 Sequence<Any> aWizardArgs(comphelper::InitAnyPropertySequence(
295 {"ParentWindow", Any(lcl_getTopMostWindow( m_aContext ))},
296 {"InitialSelection", Any(_rxModel)}
297 }));
299 // create the dialog
300 Reference< XExecutableDialog > xAdminDialog( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.sdb.DatabaseWizardDialog", aWizardArgs, m_aContext), UNO_QUERY_THROW);
302 // execute it
303 if ( RET_OK != xAdminDialog->execute() )
304 return false;
306 Reference<XPropertySet> xProp(xAdminDialog,UNO_QUERY);
307 bool bSuccess = false;
308 xProp->getPropertyValue("OpenDatabase") >>= bSuccess;
309 xProp->getPropertyValue("StartTableWizard") >>= _bShouldStartTableWizard;
310 return bSuccess;
313 void SAL_CALL DBContentLoader::load(const Reference< XFrame > & rFrame, const OUString& _rURL,
314 const Sequence< PropertyValue >& rArgs,
315 const Reference< XLoadEventListener > & rListener)
317 // first check if preview is true, if so return without creating a controller. Preview is not supported
318 ::comphelper::NamedValueCollection aMediaDesc( rArgs );
319 bool bPreview = aMediaDesc.getOrDefault( "Preview", false );
320 if ( bPreview )
322 if (rListener.is())
323 rListener->loadCancelled(this);
324 return;
327 Reference< XModel > xModel = aMediaDesc.getOrDefault( "Model", Reference< XModel >() );
328 OUString sSalvagedURL = aMediaDesc.getOrDefault( "SalvagedFile", _rURL );
330 bool bCreateNew = false; // does the URL denote the private:factory URL?
331 bool bStartTableWizard = false; // start the table wizard after everything was loaded successfully?
333 bool bSuccess = true;
335 // If there's no interaction handler in the media descriptor, put one.
336 // By definition, loading via loadComponentFromURL (and thus via the content loader here)
337 // is allowed to raise UI. To not burden every place inside the document with creating
338 // a default handler, we simply ensure there is one.
339 // If a handler is present in the media descriptor, even if it is NULL, we will
340 // not touch it.
341 if ( !aMediaDesc.has( "InteractionHandler" ) )
343 Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(m_aContext, nullptr) );
344 aMediaDesc.put( "InteractionHandler", xHandler );
347 // it's allowed to pass an existing document
348 Reference< XOfficeDatabaseDocument > xExistentDBDoc;
349 xModel.set( aMediaDesc.getOrDefault( "Model", xExistentDBDoc ), UNO_QUERY );
350 aMediaDesc.remove( "Model" );
352 // also, it's allowed to specify the type of view which should be created
353 OUString sViewName = aMediaDesc.getOrDefault( "ViewName", OUString( "Default" ) );
354 aMediaDesc.remove( "ViewName" );
356 // this needs to stay alive for duration of this method
357 Reference< XDatabaseContext > xDatabaseContext;
359 sal_Int32 nInitialSelection = -1;
360 if ( !xModel.is() )
362 xDatabaseContext = DatabaseContext::create(m_aContext);
364 OUString sFactoryName = SvtModuleOptions().GetFactoryEmptyDocumentURL(SvtModuleOptions::EFactory::DATABASE);
365 bCreateNew = sFactoryName.match(_rURL);
367 Reference< XDocumentDataSource > xDocumentDataSource;
368 bool bNewAndInteractive = false;
369 if ( bCreateNew )
371 bNewAndInteractive = lcl_urlAllowsInteraction( m_aContext, _rURL );
372 xDocumentDataSource.set( xDatabaseContext->createInstance(), UNO_QUERY_THROW );
374 else
376 ::comphelper::NamedValueCollection aCreationArgs;
377 aCreationArgs.put( OUString(INFO_POOLURL), sSalvagedURL );
378 xDocumentDataSource.set( xDatabaseContext->createInstanceWithArguments( aCreationArgs.getWrappedNamedValues() ), UNO_QUERY_THROW );
381 xModel.set( xDocumentDataSource->getDatabaseDocument(), UNO_QUERY );
383 if ( bCreateNew && xModel.is() )
385 if ( bNewAndInteractive )
387 bSuccess = impl_executeNewDatabaseWizard( xModel, bStartTableWizard );
389 else
393 Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
394 xLoad->initNew();
395 bSuccess = true;
397 catch( const Exception& )
399 bSuccess = false;
403 // initially select the "Tables" category (will be done below)
404 nInitialSelection = css::sdb::application::DatabaseObjectContainer::TABLES;
408 if ( !xModel.is() )
410 if ( rListener.is() )
411 rListener->loadCancelled(this);
412 return;
415 if ( !bCreateNew )
417 // We need to XLoadable::load the document if it does not yet have a URL.
418 // If it already *does* have a URL, then it was either passed in the arguments, or a previous incarnation
419 // of that model existed before (which can happen if a model is closed, but an associated DataSource is kept
420 // alive 'til loading the document again).
421 bool bNeedLoad = xModel->getURL().isEmpty();
424 aMediaDesc.put( "FileName", _rURL );
425 Sequence< PropertyValue > aResource( aMediaDesc.getPropertyValues() );
427 if ( bNeedLoad )
429 Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
430 xLoad->load( aResource );
433 // always attach the resource, even if the document has not been freshly loaded
434 xModel->attachResource( _rURL, aResource );
436 catch(const Exception&)
438 DBG_UNHANDLED_EXCEPTION("dbaccess");
439 bSuccess = false;
443 if ( bSuccess )
447 Reference< XModel2 > xModel2( xModel, UNO_QUERY_THROW );
448 Reference< XController2 > xController( xModel2->createViewController( sViewName, Sequence< PropertyValue >(), rFrame ), UNO_SET_THROW );
450 xController->attachModel( xModel );
451 xModel->connectController( xController.get() );
452 rFrame->setComponent( xController->getComponentWindow(), xController.get() );
453 xController->attachFrame( rFrame );
454 xModel->setCurrentController( xController.get() );
456 bSuccess = true;
458 catch( const Exception& )
460 DBG_UNHANDLED_EXCEPTION("dbaccess");
461 bSuccess = false;
465 if (bSuccess)
467 if ( rListener.is() )
468 rListener->loadFinished(this);
470 if ( nInitialSelection != -1 )
472 Reference< css::view::XSelectionSupplier > xDocView( xModel->getCurrentController(), UNO_QUERY );
473 if ( xDocView.is() )
475 NamedDatabaseObject aSelection;
476 aSelection.Type = nInitialSelection;
477 xDocView->select( makeAny( aSelection ) );
481 if ( bStartTableWizard )
483 // reset the data of the previous async drop (if any)
484 if ( m_nStartWizard )
485 Application::RemoveUserEvent(m_nStartWizard);
486 m_sCurrentURL = xModel->getURL();
487 m_xMySelf = this;
488 m_nStartWizard = Application::PostUserEvent(LINK(this, DBContentLoader, OnStartTableWizard));
491 else
493 if ( rListener.is() )
494 rListener->loadCancelled( this );
497 if ( !bSuccess )
498 ::comphelper::disposeComponent(xModel);
501 void DBContentLoader::cancel()
505 IMPL_LINK_NOARG( DBContentLoader, OnStartTableWizard, void*, void )
507 m_nStartWizard = nullptr;
510 Sequence<Any> aWizArgs(comphelper::InitAnyPropertySequence(
512 {"DatabaseLocation", Any(m_sCurrentURL)}
513 }));
514 SolarMutexGuard aGuard;
515 Reference< XJobExecutor > xTableWizard( m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.wizards.table.CallTableWizard", aWizArgs, m_aContext), UNO_QUERY);
516 if ( xTableWizard.is() )
517 xTableWizard->trigger("start");
519 catch(const Exception&)
521 OSL_FAIL("caught an exception while starting the table wizard!");
523 m_xMySelf = nullptr;
528 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
529 org_openoffice_comp_dbflt_DBContentLoader2_get_implementation(
530 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
532 return cppu::acquire(new ::dbaxml::DBContentLoader(context));
535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */