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 <core_resource.hxx>
21 #include <strings.hrc>
22 #include "databasedocument.hxx"
23 #include "documenteventexecutor.hxx"
24 #include <databasecontext.hxx>
25 #include "documentcontainer.hxx"
26 #include <sdbcoretools.hxx>
27 #include <recovery/dbdocrecovery.hxx>
29 #include <com/sun/star/document/XExporter.hpp>
30 #include <com/sun/star/document/XFilter.hpp>
31 #include <com/sun/star/document/XImporter.hpp>
32 #include <com/sun/star/document/XGraphicStorageHandler.hpp>
33 #include <com/sun/star/document/GraphicStorageHandler.hpp>
34 #include <com/sun/star/frame/Desktop.hpp>
35 #include <com/sun/star/frame/ModuleManager.hpp>
36 #include <com/sun/star/io/IOException.hpp>
37 #include <com/sun/star/io/XSeekable.hpp>
38 #include <com/sun/star/io/XOutputStream.hpp>
39 #include <com/sun/star/io/XTruncate.hpp>
40 #include <com/sun/star/lang/NoSupportException.hpp>
41 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
42 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
43 #include <com/sun/star/sdb/DatabaseContext.hpp>
44 #include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
45 #include <com/sun/star/task/XStatusIndicator.hpp>
46 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
47 #include <com/sun/star/ui/UIConfigurationManager.hpp>
48 #include <com/sun/star/util/CloseVetoException.hpp>
49 #include <com/sun/star/view/XSelectionSupplier.hpp>
50 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
51 #include <com/sun/star/xml/sax/Writer.hpp>
53 #include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
54 #include <com/sun/star/awt/XControl.hpp>
55 #include <com/sun/star/awt/DialogProvider.hpp>
57 #include <comphelper/documentconstants.hxx>
58 #include <comphelper/enumhelper.hxx>
59 #include <comphelper/genericpropertyset.hxx>
60 #include <comphelper/namedvaluecollection.hxx>
61 #include <comphelper/numberedcollection.hxx>
62 #include <comphelper/storagehelper.hxx>
63 #include <comphelper/propertysetinfo.hxx>
64 #include <comphelper/types.hxx>
66 #include <connectivity/dbtools.hxx>
68 #include <cppuhelper/exc_hlp.hxx>
69 #include <cppuhelper/supportsservice.hxx>
70 #include <framework/titlehelper.hxx>
71 #include <unotools/saveopt.hxx>
72 #include <tools/diagnose_ex.h>
73 #include <osl/diagnose.h>
75 #include <vcl/GraphicObject.hxx>
76 #include <tools/urlobj.hxx>
78 using namespace ::com::sun::star::uno
;
79 using namespace ::com::sun::star::beans
;
80 using namespace ::com::sun::star::frame
;
81 using namespace ::com::sun::star::lang
;
82 using namespace ::com::sun::star::container
;
83 using namespace ::com::sun::star::document
;
84 using namespace ::com::sun::star::io
;
85 using namespace ::com::sun::star::util
;
86 using namespace ::com::sun::star::embed
;
87 using namespace ::com::sun::star::task
;
88 using namespace ::com::sun::star::view
;
89 using namespace ::com::sun::star::sdb
;
90 using namespace ::com::sun::star::sdbc
;
91 using namespace ::com::sun::star
;
92 using namespace ::com::sun::star::xml::sax
;
93 using namespace ::com::sun::star::script
;
94 using namespace ::com::sun::star::script::provider
;
95 using namespace ::com::sun::star::ui
;
96 using namespace ::cppu
;
103 bool ViewMonitor::onControllerConnected( const Reference
< XController
>& _rxController
)
105 bool bFirstControllerEver
= !m_bEverHadController
;
106 m_bEverHadController
= true;
108 m_xLastConnectedController
= _rxController
;
109 m_bLastIsFirstEverController
= bFirstControllerEver
;
111 return bFirstControllerEver
;
114 bool ViewMonitor::onSetCurrentController( const Reference
< XController
>& _rxController
)
116 // we interpret this as "loading the document (including UI) is finished",
117 // if and only if this is the controller which was last connected, and it was the
118 // first controller ever connected
119 bool bLoadFinished
= ( _rxController
== m_xLastConnectedController
) && m_bLastIsFirstEverController
;
121 // notify the respective events
123 m_rEventNotifier
.notifyDocumentEventAsync( m_bIsNewDocument
? "OnNew" : "OnLoad" );
125 return bLoadFinished
;
129 ODatabaseDocument::ODatabaseDocument(const ::rtl::Reference
<ODatabaseModelImpl
>& _pImpl
)
130 :ModelDependentComponent( _pImpl
)
131 ,ODatabaseDocument_OfficeDocument( getMutex() )
132 ,m_aModifyListeners( getMutex() )
133 ,m_aCloseListener( getMutex() )
134 ,m_aStorageListeners( getMutex() )
135 ,m_pEventContainer( new DocumentEvents( *this, getMutex(), _pImpl
->getDocumentEvents() ) )
136 ,m_aEventNotifier( *this, getMutex() )
137 ,m_aViewMonitor( m_aEventNotifier
)
138 ,m_eInitState( NotInitialized
)
140 ,m_bAllowDocumentScripting( false )
141 ,m_bHasBeenRecovered( false )
144 osl_atomic_increment( &m_refCount
);
146 impl_reparent_nothrow( m_xForms
);
147 impl_reparent_nothrow( m_xReports
);
148 impl_reparent_nothrow( m_pImpl
->m_xTableDefinitions
);
149 impl_reparent_nothrow( m_pImpl
->m_xCommandDefinitions
);
151 m_pEventExecutor
= new DocumentEventExecutor( m_pImpl
->m_aContext
, this );
153 osl_atomic_decrement( &m_refCount
);
155 // if there previously was a document instance for the same Impl which was already initialized,
156 // then consider ourself initialized, too.
158 if ( !m_pImpl
->hadInitializedDocument() )
161 // Note we set our init-state to "Initializing", not "Initialized". We're created from inside the ModelImpl,
162 // which is expected to call attachResource in case there was a previous incarnation of the document,
163 // so we can properly finish our initialization then.
164 impl_setInitializing();
166 if ( !m_pImpl
->getURL().isEmpty() )
168 // if the previous incarnation of the DatabaseDocument already had a URL, then creating this incarnation
169 // here is effectively loading the document.
171 m_aViewMonitor
.onLoadedDocument();
175 ODatabaseDocument::~ODatabaseDocument()
177 if ( !ODatabaseDocument_OfficeDocument::rBHelper
.bInDispose
&& !ODatabaseDocument_OfficeDocument::rBHelper
.bDisposed
)
184 Any SAL_CALL
ODatabaseDocument::queryInterface( const Type
& _rType
)
186 // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report
187 // which already contains macros. In this case, the database document itself is not
188 // allowed to contain macros, too.
189 if ( !m_bAllowDocumentScripting
190 && ( _rType
.equals( cppu::UnoType
<XEmbeddedScripts
>::get() )
191 || _rType
.equals( cppu::UnoType
<XScriptInvocationContext
>::get() )
196 Any aReturn
= ODatabaseDocument_OfficeDocument::queryInterface(_rType
);
197 if (!aReturn
.hasValue())
198 aReturn
= ODatabaseDocument_Title::queryInterface(_rType
);
202 void SAL_CALL
ODatabaseDocument::acquire( ) throw ()
204 ODatabaseDocument_OfficeDocument::acquire();
207 void SAL_CALL
ODatabaseDocument::release( ) throw ()
209 ODatabaseDocument_OfficeDocument::release();
212 Sequence
< Type
> SAL_CALL
ODatabaseDocument::getTypes( )
214 Sequence
< Type
> aTypes
= ::comphelper::concatSequences(
215 ODatabaseDocument_OfficeDocument::getTypes(),
216 ODatabaseDocument_Title::getTypes()
219 // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report
220 // which already contains macros. In this case, the database document itself is not
221 // allowed to contain macros, too.
222 if ( !m_bAllowDocumentScripting
)
224 auto newEnd
= std::remove_if( aTypes
.begin(), aTypes
.end(),
226 { return t
== cppu::UnoType
<XEmbeddedScripts
>::get() ||
227 t
== cppu::UnoType
<XScriptInvocationContext
>::get();} );
228 aTypes
.realloc( std::distance(aTypes
.begin(), newEnd
) );
234 Sequence
< sal_Int8
> SAL_CALL
ODatabaseDocument::getImplementationId( )
236 return css::uno::Sequence
<sal_Int8
>();
242 Reference
< XStatusIndicator
> lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection
& _rArguments
)
244 Reference
< XStatusIndicator
> xStatusIndicator
;
245 return _rArguments
.getOrDefault( "StatusIndicator", xStatusIndicator
);
248 void lcl_triggerStatusIndicator_throw( const ::comphelper::NamedValueCollection
& _rArguments
, DocumentGuard
& _rGuard
, const bool _bStart
)
250 Reference
< XStatusIndicator
> xStatusIndicator( lcl_extractStatusIndicator( _rArguments
) );
251 if ( !xStatusIndicator
.is() )
258 xStatusIndicator
->start( OUString(), sal_Int32(1000000) );
260 xStatusIndicator
->end();
262 catch( const Exception
& )
264 DBG_UNHANDLED_EXCEPTION("dbaccess");
267 // note that |reset| can throw a DisposedException
270 void lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection
& _rArguments
, Sequence
< Any
>& _rCallArgs
)
272 Reference
< XStatusIndicator
> xStatusIndicator( lcl_extractStatusIndicator( _rArguments
) );
273 if ( !xStatusIndicator
.is() )
276 sal_Int32 nLength
= _rCallArgs
.getLength();
277 _rCallArgs
.realloc( nLength
+ 1 );
278 _rCallArgs
[ nLength
] <<= xStatusIndicator
;
281 void lcl_extractAndStartStatusIndicator( const ::comphelper::NamedValueCollection
& _rArguments
, Reference
< XStatusIndicator
>& _rxStatusIndicator
,
282 Sequence
< Any
>& _rCallArgs
)
284 _rxStatusIndicator
= lcl_extractStatusIndicator( _rArguments
);
285 if ( !_rxStatusIndicator
.is() )
290 _rxStatusIndicator
->start( OUString(), sal_Int32(1000000) );
292 sal_Int32 nLength
= _rCallArgs
.getLength();
293 _rCallArgs
.realloc( nLength
+ 1 );
294 _rCallArgs
[ nLength
] <<= _rxStatusIndicator
;
296 catch( const Exception
& )
298 DBG_UNHANDLED_EXCEPTION("dbaccess");
302 Sequence
< PropertyValue
> lcl_appendFileNameToDescriptor( const ::comphelper::NamedValueCollection
& _rDescriptor
, const OUString
& _rURL
)
304 ::comphelper::NamedValueCollection
aMutableDescriptor( _rDescriptor
);
305 if ( !_rURL
.isEmpty() )
307 aMutableDescriptor
.put( "FileName", _rURL
);
308 aMutableDescriptor
.put( "URL", _rURL
);
310 return aMutableDescriptor
.getPropertyValues();
314 const char sPictures
[] = "Pictures";
316 // base documents seem to have a different behaviour to other documents, the
317 // root storage contents at least seem to be re-used over different saves, thus if there is a
318 // top level Picture directory it is never cleared.
319 // If we delete the 'Pictures' directory then the dialog library storage which does store
320 // any embed images will not work properly. ( this is due to the fact it will
321 // try to load the dialog which will try and access the embed images, if those images are not cached in
322 // memory it will try to read them from the Picture directory which is now gone, so... we have to use this
323 // inglorious hack below which basically will
325 // a) create a temp storage
327 // b) introspect any dialogs for any embed graphics and grab the associate URL(s)
329 // c) populate the temp storage with the associated embed images ( will be stored in a 'Pictures' folder )
331 // d) delete the 'Picture' element from the root storage
333 // e) copy the Pictures element of the temp storage to the root storage
335 // this assumes that we don't use the Pictures folder in the root of the base
336 // document for anything, I believe this is a valid assumption ( as much as
337 // I could check anyway )
339 /// @throws RuntimeException
340 static void lcl_uglyHackToStoreDialogeEmbedImages( const Reference
< XStorageBasedLibraryContainer
>& xDlgCont
, const Reference
< XStorage
>& xStorage
, const Reference
< XModel
>& rxModel
, const Reference
<XComponentContext
>& rxContext
)
342 const Sequence
< OUString
> sLibraries
= xDlgCont
->getElementNames();
343 Reference
< XStorage
> xTmpPic
= xStorage
->openStorageElement( "tempPictures", ElementModes::READWRITE
);
345 std::vector
<uno::Reference
<graphic::XGraphic
>> vxGraphicList
;
346 for ( OUString
const & sLibrary
: sLibraries
)
348 xDlgCont
->loadLibrary( sLibrary
);
349 Reference
< XNameContainer
> xLib
;
350 xDlgCont
->getByName( sLibrary
) >>= xLib
;
353 Sequence
< OUString
> sDialogs
= xLib
->getElementNames();
354 sal_Int32
nDialogs( sDialogs
.getLength() );
355 for ( sal_Int32 j
=0; j
< nDialogs
; ++j
)
357 Reference
< awt::XDialogProvider
> xDlgPrv
= awt::DialogProvider::createWithModel(rxContext
, rxModel
);
358 OUString sDialogUrl
=
359 "vnd.sun.star.script:" + sLibrary
+ "." + sDialogs
[j
] + "?location=document";
361 Reference
< css::awt::XControl
> xDialog( xDlgPrv
->createDialog( sDialogUrl
), UNO_QUERY
);
362 Reference
< XInterface
> xModel( xDialog
->getModel() );
363 vcl::graphic::SearchForGraphics(xModel
, vxGraphicList
);
367 // if we have any image urls, make sure we copy the associated images into tempPictures
368 if (!vxGraphicList
.empty())
370 // Export the images to the storage
371 uno::Reference
<document::XGraphicStorageHandler
> xGraphicStorageHandler
;
372 xGraphicStorageHandler
.set(GraphicStorageHandler::createWithStorage(rxContext
, xTmpPic
));
373 if (xGraphicStorageHandler
.is())
375 for (uno::Reference
<graphic::XGraphic
> const & rxGraphic
: vxGraphicList
)
377 xGraphicStorageHandler
->saveGraphic(rxGraphic
);
380 // delete old 'Pictures' storage and copy the contents of tempPictures into xStorage
381 xStorage
->removeElement( sPictures
);
382 xTmpPic
->copyElementTo( sPictures
, xStorage
, sPictures
);
386 // clean up an existing Pictures dir
387 if ( xStorage
->isStorageElement( sPictures
) )
388 xStorage
->removeElement( sPictures
);
392 void ODatabaseDocument::impl_setInitialized()
394 m_eInitState
= Initialized
;
396 // start event notifications
397 m_aEventNotifier
.onDocumentInitialized();
400 void ODatabaseDocument::impl_reset_nothrow()
404 m_pImpl
->clearConnections();
405 m_pImpl
->disposeStorages();
406 m_pImpl
->resetRootStorage();
408 clearObjectContainer( m_xForms
);
409 clearObjectContainer( m_xReports
);
410 clearObjectContainer( m_pImpl
->m_xTableDefinitions
);
411 clearObjectContainer( m_pImpl
->m_xCommandDefinitions
);
413 m_eInitState
= NotInitialized
;
417 catch(const Exception
&)
419 DBG_UNHANDLED_EXCEPTION("dbaccess");
421 m_pImpl
->m_bDocumentReadOnly
= false;
426 /** property map for import/export info set */
427 comphelper::PropertyMapEntry
const aExportInfoMap
[] =
429 { OUString("BaseURI"), 0, ::cppu::UnoType
<OUString
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0 },
430 { OUString("StreamName"), 0, ::cppu::UnoType
<OUString
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0 },
431 { OUString("UsePrettyPrinting"), 0, ::cppu::UnoType
<sal_Bool
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0},
432 {OUString("TargetStorage"), 0, cppu::UnoType
<embed::XStorage
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0},
433 {OUString("StreamRelPath"), 0, cppu::UnoType
<OUString
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0},
434 { OUString(), 0, css::uno::Type(), 0, 0 }
438 void ODatabaseDocument::impl_import_nolck_throw( const Reference
< XComponentContext
>& _rContext
, const Reference
< XInterface
>& _rxTargetComponent
,
439 const ::comphelper::NamedValueCollection
& _rResource
)
441 Sequence
< Any
> aFilterCreationArgs
;
442 Reference
< XStatusIndicator
> xStatusIndicator
;
443 lcl_extractAndStartStatusIndicator( _rResource
, xStatusIndicator
, aFilterCreationArgs
);
445 uno::Reference
< beans::XPropertySet
> xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap
) ) );
446 OUString sBaseURI
= _rResource
.getOrDefault("BaseURI", OUString());
447 if (sBaseURI
.isEmpty())
448 sBaseURI
= _rResource
.getOrDefault("URL",OUString());
449 assert(!sBaseURI
.isEmpty()); // needed for relative URLs
450 xInfoSet
->setPropertyValue("BaseURI", uno::makeAny(sBaseURI
));
451 xInfoSet
->setPropertyValue("StreamName", uno::makeAny(OUString("content.xml")));
453 const sal_Int32 nCount
= aFilterCreationArgs
.getLength();
454 aFilterCreationArgs
.realloc(nCount
+ 1);
455 aFilterCreationArgs
[nCount
] <<= xInfoSet
;
457 Reference
< XImporter
> xImporter(
458 _rContext
->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs
, _rContext
),
461 Reference
< XComponent
> xComponent( _rxTargetComponent
, UNO_QUERY_THROW
);
462 xImporter
->setTargetDocument( xComponent
);
464 Reference
< XFilter
> xFilter( xImporter
, UNO_QUERY_THROW
);
465 Sequence
< PropertyValue
> aFilterArgs( ODatabaseModelImpl::stripLoadArguments( _rResource
).getPropertyValues() );
466 xFilter
->filter( aFilterArgs
);
468 if ( xStatusIndicator
.is() )
469 xStatusIndicator
->end();
472 void SAL_CALL
ODatabaseDocument::initNew( )
475 DocumentGuard
aGuard( *this, DocumentGuard::InitMethod
);
477 impl_reset_nothrow();
479 impl_setInitializing();
481 // create a temporary storage
482 Reference
< XStorage
> xTempStor( ::comphelper::OStorageHelper::GetTemporaryStorage( m_pImpl
->m_aContext
) );
485 impl_storeToStorage_throw( xTempStor
, Sequence
< PropertyValue
>(), aGuard
);
487 // let the impl know we're now based on this storage
488 m_pImpl
->switchToStorage( xTempStor
);
490 // for the newly created document, allow document-wide scripting
491 m_bAllowDocumentScripting
= true;
493 impl_setInitialized();
495 m_aEventNotifier
.notifyDocumentEventAsync( "OnTitleChanged" );
497 impl_setModified_nothrow( false, aGuard
);
500 m_aEventNotifier
.notifyDocumentEvent( "OnCreate" );
502 impl_notifyStorageChange_nolck_nothrow( xTempStor
);
505 void SAL_CALL
ODatabaseDocument::load( const Sequence
< PropertyValue
>& Arguments
)
508 DocumentGuard
aGuard( *this, DocumentGuard::InitMethod
);
510 impl_reset_nothrow();
512 ::comphelper::NamedValueCollection
aResource( Arguments
);
513 if ( aResource
.has( "FileName" ) && !aResource
.has( "URL" ) )
514 // FileName is the compatibility name for URL, so we might have clients passing
515 // a FileName only. However, some of our code works with the URL only, so ensure
517 aResource
.put( "URL", aResource
.get( "FileName" ) );
518 if ( aResource
.has( "URL" ) && !aResource
.has( "FileName" ) )
519 // similar ... just in case there is legacy code which expects a FileName only
520 aResource
.put( "FileName", aResource
.get( "URL" ) );
522 // now that somebody (perhaps) told us a macro execution mode, remember it as
523 // ImposedMacroExecMode
524 m_pImpl
->setImposedMacroExecMode(
525 aResource
.getOrDefault( "MacroExecutionMode", m_pImpl
->getImposedMacroExecMode() ) );
527 impl_setInitializing();
531 impl_import_nolck_throw( m_pImpl
->m_aContext
, *this, aResource
);
534 catch( const Exception
& )
536 impl_reset_nothrow();
539 // tell our view monitor that the document has been loaded - this way it will fire the proper
540 // event (OnLoad instead of OnCreate) later on
541 m_aViewMonitor
.onLoadedDocument();
543 // note that we do *not* call impl_setInitialized() here: The initialization is only complete
544 // when the XModel::attachResource has been called, not sooner.
545 // however, in case of embedding, XModel::attachResource is already called.
547 impl_setInitialized();
549 impl_setModified_nothrow( false, aGuard
);
555 bool lcl_hasAnyModifiedSubComponent_throw( const Reference
< XController
>& i_rController
)
557 Reference
< css::sdb::application::XDatabaseDocumentUI
> xDatabaseUI( i_rController
, UNO_QUERY_THROW
);
559 const Sequence
< Reference
< XComponent
> > aComponents( xDatabaseUI
->getSubComponents() );
561 bool isAnyModified
= false;
562 for ( auto const & xComponent
: aComponents
)
564 Reference
< XModifiable
> xModify( xComponent
, UNO_QUERY
);
567 isAnyModified
= xModify
->isModified();
571 // TODO: clarify: anything else to care for? Both the sub components with and without model
572 // should support the XModifiable interface, so I think nothing more is needed here.
573 OSL_FAIL( "lcl_hasAnyModifiedSubComponent_throw: anything left to do here?" );
576 return isAnyModified
;
580 sal_Bool SAL_CALL
ODatabaseDocument::wasModifiedSinceLastSave()
582 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
584 // The implementation here is somewhat sloppy, in that it returns whether *any* part of the whole
585 // database document, including opened sub components, is modified. This is more than what is requested:
586 // We need to return <TRUE/> if the doc itself, or any of the opened sub components, has been modified
587 // since the last call to any of the save* methods, or since the document has been loaded/created.
588 // However, the API definition explicitly allows to be that sloppy ...
593 // auto recovery is an "UI feature", it is to restore the UI the user knows. Thus,
594 // we ask our connected controllers, not simply our existing form/report definitions.
595 // (There is some information which even cannot be obtained without asking the controller.
596 // For instance, newly created, but not yet saved, forms/reports are accessible via the
597 // controller only, but not via the model.)
601 for (auto const& controller
: m_aControllers
)
603 if ( lcl_hasAnyModifiedSubComponent_throw(controller
) )
607 catch( const Exception
& )
609 DBG_UNHANDLED_EXCEPTION("dbaccess");
615 void SAL_CALL
ODatabaseDocument::storeToRecoveryFile( const OUString
& i_TargetLocation
, const Sequence
< PropertyValue
>& i_MediaDescriptor
)
617 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
618 ModifyLock
aLock( *this );
622 // create a storage for the target location
623 Reference
< XStorage
> xTargetStorage( impl_createStorageFor_throw( i_TargetLocation
) );
625 // first store the document as a whole into this storage
626 impl_storeToStorage_throw( xTargetStorage
, i_MediaDescriptor
, aGuard
);
628 // save the sub components which need saving
629 DatabaseDocumentRecovery
aDocRecovery( m_pImpl
->m_aContext
);
630 aDocRecovery
.saveModifiedSubComponents( xTargetStorage
, m_aControllers
);
632 // commit the root storage
633 tools::stor::commitStorageIfWriteable( xTargetStorage
);
635 catch( const IOException
& )
639 catch( const RuntimeException
& )
643 catch( const WrappedTargetException
& )
647 catch( const Exception
& )
649 Any aError
= ::cppu::getCaughtException();
650 throw WrappedTargetException( OUString(), *this, aError
);
654 void SAL_CALL
ODatabaseDocument::recoverFromFile( const OUString
& i_SourceLocation
, const OUString
& i_SalvagedFile
, const Sequence
< PropertyValue
>& i_MediaDescriptor
)
658 DocumentGuard
aGuard( *this, DocumentGuard::InitMethod
);
660 if ( i_SourceLocation
.isEmpty() )
661 throw IllegalArgumentException( OUString(), *this, 1 );
664 // load the document itself, by simply delegating to our "load" method
666 // our load implementation expects the SalvagedFile and URL to be in the media descriptor
667 ::comphelper::NamedValueCollection
aMediaDescriptor( i_MediaDescriptor
);
668 aMediaDescriptor
.put( "SalvagedFile", i_SalvagedFile
);
669 aMediaDescriptor
.put( "URL", i_SourceLocation
);
671 aGuard
.clear(); // (load has an own guarding scheme)
672 load( aMediaDescriptor
.getPropertyValues() );
675 // Without a controller, we are unable to recover the sub components, as they're always tied to a controller.
676 // So, everything else is done when the first controller is connected.
677 m_bHasBeenRecovered
= true;
679 // tell the impl that we've been loaded from the given location
680 m_pImpl
->setDocFileLocation( i_SourceLocation
);
682 // by definition (of XDocumentRecovery), we're responsible for delivering a fully-initialized document,
683 // which includes an attachResource call.
684 const OUString
sLogicalDocumentURL( i_SalvagedFile
.isEmpty() ? i_SourceLocation
: i_SalvagedFile
);
685 impl_attachResource( sLogicalDocumentURL
, aMediaDescriptor
.getPropertyValues(), aGuard
);
688 catch( const IOException
& )
692 catch( const RuntimeException
& )
696 catch( const WrappedTargetException
& )
700 catch( const Exception
& )
702 Any aError
= ::cppu::getCaughtException();
703 throw WrappedTargetException( OUString(), *this, aError
);
708 sal_Bool SAL_CALL
ODatabaseDocument::attachResource( const OUString
& _rURL
, const Sequence
< PropertyValue
>& _rArguments
)
710 if (_rURL
.isEmpty() && _rArguments
.getLength() == 1 && _rArguments
[0].Name
== "SetEmbedded")
716 DocumentGuard
aGuard( *this, DocumentGuard::MethodUsedDuringInit
);
720 bRet
= impl_attachResource( _rURL
, _rArguments
, aGuard
);
722 catch( const RuntimeException
& )
726 catch( const Exception
& )
728 Any aError
= ::cppu::getCaughtException();
729 throw WrappedTargetRuntimeException( OUString(), *this, aError
);
734 bool ODatabaseDocument::impl_attachResource( const OUString
& i_rLogicalDocumentURL
,
735 const Sequence
< PropertyValue
>& i_rMediaDescriptor
, DocumentGuard
& _rDocGuard
)
737 if (i_rLogicalDocumentURL
== getURL())
739 ::comphelper::NamedValueCollection
aArgs(i_rMediaDescriptor
);
741 // this misuse of attachresource is a hack of the Basic importer code
742 // repurposing existing interfaces for uses it probably wasn't intended
745 // we do not support macro signatures, so we can ignore that request
746 aArgs
.remove("BreakMacroSignature");
748 bool bMacroEventRead
= false;
749 if ((aArgs
.get( "MacroEventRead" ) >>= bMacroEventRead
) && bMacroEventRead
)
750 m_pImpl
->m_bMacroCallsSeenWhileLoading
= true;
751 aArgs
.remove( "MacroEventRead" );
757 // if no URL has been provided, the caller was lazy enough to not call our getURL - which is not allowed anymore,
758 // now since getURL and getLocation both return the same, so calling one of those should be simple.
759 OUString
sDocumentURL( i_rLogicalDocumentURL
);
760 OSL_ENSURE( !sDocumentURL
.isEmpty(), "ODatabaseDocument::impl_attachResource: invalid URL!" );
761 if ( sDocumentURL
.isEmpty() )
762 sDocumentURL
= getURL();
764 m_pImpl
->setResource( sDocumentURL
, i_rMediaDescriptor
);
766 if ( impl_isInitializing() )
767 { // this means we've just been loaded, and this is the attachResource call which follows
769 impl_setInitialized();
771 // determine whether the document as a whole, or sub documents, have macros. Especially the latter
772 // controls the availability of our XEmbeddedScripts and XScriptInvocationContext interfaces, and we
773 // should know this before anybody actually uses the object.
774 m_bAllowDocumentScripting
= ( m_pImpl
->determineEmbeddedMacros() != ODatabaseModelImpl::eSubDocumentMacros
);
778 m_aEventNotifier
.notifyDocumentEvent( "OnLoadFinished" );
784 OUString SAL_CALL
ODatabaseDocument::getURL( )
786 DocumentGuard
aGuard( *this, DocumentGuard::MethodWithoutInit
);
787 return m_pImpl
->getURL();
790 Sequence
< PropertyValue
> SAL_CALL
ODatabaseDocument::getArgs( )
792 DocumentGuard
aGuard( *this, DocumentGuard::MethodWithoutInit
);
793 return m_pImpl
->getMediaDescriptor().getPropertyValues();
796 void SAL_CALL
ODatabaseDocument::setArgs(const Sequence
<beans::PropertyValue
>& /* aArgs */)
798 throw NoSupportException();
801 void SAL_CALL
ODatabaseDocument::connectController( const Reference
< XController
>& _xController
)
803 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
805 #if OSL_DEBUG_LEVEL > 0
806 for (auto const& controller
: m_aControllers
)
808 OSL_ENSURE( controller
!= _xController
, "ODatabaseDocument::connectController: this controller is already connected!" );
812 m_aControllers
.push_back( _xController
);
814 m_aEventNotifier
.notifyDocumentEventAsync( "OnViewCreated", Reference
< XController2
>( _xController
, UNO_QUERY
) );
816 bool bFirstControllerEver
= m_aViewMonitor
.onControllerConnected( _xController
);
817 if ( !bFirstControllerEver
)
820 // check/adjust our macro mode.
821 m_pImpl
->checkMacrosOnLoading();
824 void SAL_CALL
ODatabaseDocument::disconnectController( const Reference
< XController
>& _xController
)
826 bool bNotifyViewClosed
= false;
827 bool bLastControllerGone
= false;
828 bool bIsClosing
= false;
832 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
834 Controllers::iterator pos
= std::find( m_aControllers
.begin(), m_aControllers
.end(), _xController
);
835 OSL_ENSURE( pos
!= m_aControllers
.end(), "ODatabaseDocument::disconnectController: don't know this controller!" );
836 if ( pos
!= m_aControllers
.end() )
838 m_aControllers
.erase( pos
);
839 bNotifyViewClosed
= true;
842 if ( m_xCurrentController
== _xController
)
843 m_xCurrentController
= nullptr;
845 bLastControllerGone
= m_aControllers
.empty();
846 bIsClosing
= m_bClosing
;
850 if ( bNotifyViewClosed
)
851 m_aEventNotifier
.notifyDocumentEvent( "OnViewClosed", Reference
< XController2
>( _xController
, UNO_QUERY
) );
853 if ( !bLastControllerGone
|| bIsClosing
)
856 // if this was the last view, close the document as a whole
862 catch( const CloseVetoException
& )
864 // okay, somebody vetoed and took ownership
868 void SAL_CALL
ODatabaseDocument::lockControllers( )
870 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
872 ++m_pImpl
->m_nControllerLockCount
;
875 void SAL_CALL
ODatabaseDocument::unlockControllers( )
877 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
879 --m_pImpl
->m_nControllerLockCount
;
882 sal_Bool SAL_CALL
ODatabaseDocument::hasControllersLocked( )
884 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
886 return m_pImpl
->m_nControllerLockCount
!= 0;
889 Reference
< XController
> SAL_CALL
ODatabaseDocument::getCurrentController()
891 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
893 return m_xCurrentController
.is() ? m_xCurrentController
: ( m_aControllers
.empty() ? Reference
< XController
>() : *m_aControllers
.begin() );
896 void SAL_CALL
ODatabaseDocument::setCurrentController( const Reference
< XController
>& _xController
)
898 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
900 m_xCurrentController
= _xController
;
902 if ( !m_aViewMonitor
.onSetCurrentController( _xController
) )
905 // check if there are sub components to recover from our document storage
906 bool bAttemptRecovery
= m_bHasBeenRecovered
;
907 if ( !bAttemptRecovery
&& m_pImpl
->getMediaDescriptor().has( "ForceRecovery" ) )
908 // do not use getOrDefault, it will throw for invalid types, which is not desired here
909 m_pImpl
->getMediaDescriptor().get( "ForceRecovery" ) >>= bAttemptRecovery
;
911 if ( !bAttemptRecovery
)
916 DatabaseDocumentRecovery
aDocRecovery( m_pImpl
->m_aContext
);
917 aDocRecovery
.recoverSubDocuments( m_pImpl
->getRootStorage(), _xController
);
919 catch( const Exception
& )
921 DBG_UNHANDLED_EXCEPTION("dbaccess");
925 Reference
< XInterface
> SAL_CALL
ODatabaseDocument::getCurrentSelection( )
927 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
929 Reference
< XInterface
> xRet
;
930 Reference
< XSelectionSupplier
> xDocView( getCurrentController(), UNO_QUERY
);
932 xRet
.set(xDocView
->getSelection(),UNO_QUERY
);
938 sal_Bool SAL_CALL
ODatabaseDocument::hasLocation( )
940 return !getLocation().isEmpty();
943 OUString SAL_CALL
ODatabaseDocument::getLocation( )
945 DocumentGuard
aGuard( *this, DocumentGuard::MethodWithoutInit
);
946 return m_pImpl
->getURL();
947 // both XStorable::getLocation and XModel::getURL have to return the URL of the document, *not*
948 // the location of the file which the document was possibly recovered from (which would be getDocFileLocation)
951 sal_Bool SAL_CALL
ODatabaseDocument::isReadonly( )
953 DocumentGuard
aGuard( *this, DocumentGuard::MethodWithoutInit
);
954 return m_pImpl
->m_bDocumentReadOnly
;
957 void SAL_CALL
ODatabaseDocument::store( )
959 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
961 OUString
sDocumentURL( m_pImpl
->getURL() );
962 if ( !sDocumentURL
.isEmpty() )
964 if ( m_pImpl
->getDocFileLocation() == m_pImpl
->getURL() )
965 if ( m_pImpl
->m_bDocumentReadOnly
)
968 impl_storeAs_throw( m_pImpl
->getURL(), m_pImpl
->getMediaDescriptor(), SAVE
, aGuard
);
972 // if we have no URL, but did survive the DocumentGuard above, then we've been inited via XLoadable::initNew,
973 // i.e. we're based on a temporary storage
974 OSL_ENSURE( m_pImpl
->getDocFileLocation().isEmpty(), "ODatabaseDocument::store: unexpected URL inconsistency!" );
978 impl_storeToStorage_throw( m_pImpl
->getRootStorage(), m_pImpl
->getMediaDescriptor().getPropertyValues(), aGuard
);
980 catch( const Exception
& )
982 Any aError
= ::cppu::getCaughtException();
983 if ( aError
.isExtractableTo( ::cppu::UnoType
< IOException
>::get() )
984 || aError
.isExtractableTo( ::cppu::UnoType
< RuntimeException
>::get() )
990 impl_throwIOExceptionCausedBySave_throw( aError
, {} );
994 void ODatabaseDocument::impl_throwIOExceptionCausedBySave_throw( const Any
& i_rError
, std::u16string_view i_rTargetURL
) const
996 OUString sErrorMessage
= extractExceptionMessage( m_pImpl
->m_aContext
, i_rError
);
997 sErrorMessage
= ResourceManager::loadString(
998 RID_STR_ERROR_WHILE_SAVING
,
999 "$location$", i_rTargetURL
,
1000 "$message$", sErrorMessage
1002 throw IOException( sErrorMessage
, *const_cast< ODatabaseDocument
* >( this ) );
1005 void ODatabaseDocument::impl_storeAs_throw( const OUString
& _rURL
, const ::comphelper::NamedValueCollection
& _rArguments
,
1006 const StoreType _eType
, DocumentGuard
& _rGuard
)
1008 OSL_PRECOND( ( _eType
== SAVE
) || ( _eType
== SAVE_AS
),
1009 "ODatabaseDocument::impl_storeAs_throw: you introduced a new type which cannot be handled here!" );
1011 // if we're in the process of initializing the document (which effectively means it is an implicit
1012 // initialization triggered in storeAsURL), the we do not notify events, since to an observer, the SaveAs
1013 // should not be noticeable
1014 bool bIsInitializationProcess
= impl_isInitializing();
1016 if ( !bIsInitializationProcess
)
1019 m_aEventNotifier
.notifyDocumentEvent( _eType
== SAVE
? "OnSave" : "OnSaveAs", nullptr, makeAny( _rURL
) );
1023 Reference
< XStorage
> xNewRootStorage
;
1024 // will be non-NULL if our storage changed
1028 ModifyLock
aLock( *this );
1029 // ignore all changes of our "modified" state during storing
1031 bool bLocationChanged
= ( _rURL
!= m_pImpl
->getDocFileLocation() );
1032 if ( bLocationChanged
)
1034 // create storage for target URL
1035 uno::Reference
<embed::XStorage
> xTargetStorage(
1036 impl_GetStorageOrCreateFor_throw(_rArguments
, _rURL
));
1038 if ( m_pImpl
->isEmbeddedDatabase() )
1039 m_pImpl
->clearConnections();
1041 // commit everything
1042 m_pImpl
->commitEmbeddedStorage();
1043 m_pImpl
->commitStorages();
1045 // copy own storage to target storage
1046 Reference
< XStorage
> xCurrentStorage( m_pImpl
->getRootStorage() );
1047 if ( xCurrentStorage
.is() )
1048 xCurrentStorage
->copyToStorage( xTargetStorage
);
1050 m_pImpl
->disposeStorages();
1052 // each and every document definition obtained via m_xForms and m_xReports depends
1053 // on the sub storages which we just disposed. So, dispose the forms/reports collections, too.
1054 // This ensures that they're re-created when needed.
1055 clearObjectContainer( m_xForms
);
1056 clearObjectContainer( m_xReports
);
1058 xNewRootStorage
= m_pImpl
->switchToStorage( xTargetStorage
);
1060 m_pImpl
->m_bDocumentReadOnly
= false;
1063 // store to current storage
1064 Reference
< XStorage
> xCurrentStorage( m_pImpl
->getOrCreateRootStorage(), UNO_SET_THROW
);
1065 Sequence
< PropertyValue
> aMediaDescriptor( lcl_appendFileNameToDescriptor( _rArguments
, _rURL
) );
1066 impl_storeToStorage_throw( xCurrentStorage
, aMediaDescriptor
, _rGuard
);
1068 // success - tell our impl
1069 m_pImpl
->setDocFileLocation( _rURL
);
1070 m_pImpl
->setResource( _rURL
, aMediaDescriptor
);
1072 // if we are in an initialization process, then this is finished, now that we stored the document
1073 if ( bIsInitializationProcess
)
1074 impl_setInitialized();
1076 catch( const IOException
& )
1078 if ( !bIsInitializationProcess
)
1079 m_aEventNotifier
.notifyDocumentEventAsync( _eType
== SAVE
? "OnSaveFailed" : "OnSaveAsFailed", nullptr, makeAny( _rURL
) );
1082 catch( const RuntimeException
& )
1084 if ( !bIsInitializationProcess
)
1085 m_aEventNotifier
.notifyDocumentEventAsync( _eType
== SAVE
? "OnSaveFailed" : "OnSaveAsFailed", nullptr, makeAny( _rURL
) );
1088 catch( const Exception
& )
1090 Any aError
= ::cppu::getCaughtException();
1092 // notify the failure
1093 if ( !bIsInitializationProcess
)
1094 m_aEventNotifier
.notifyDocumentEventAsync( _eType
== SAVE
? "OnSaveFailed" : "OnSaveAsFailed", nullptr, makeAny( _rURL
) );
1096 impl_throwIOExceptionCausedBySave_throw( aError
, _rURL
);
1099 // notify the document event
1100 if ( !bIsInitializationProcess
)
1101 m_aEventNotifier
.notifyDocumentEventAsync( _eType
== SAVE
? "OnSaveDone" : "OnSaveAsDone", nullptr, makeAny( _rURL
) );
1103 // reset our "modified" flag, and clear the guard
1104 impl_setModified_nothrow( false, _rGuard
);
1107 // notify storage listeners
1108 if ( xNewRootStorage
.is() )
1109 impl_notifyStorageChange_nolck_nothrow( xNewRootStorage
);
1112 Reference
< XStorage
> ODatabaseDocument::impl_createStorageFor_throw( const OUString
& _rURL
) const
1114 Reference
< ucb::XSimpleFileAccess3
> xTempAccess(ucb::SimpleFileAccess::create(m_pImpl
->m_aContext
));
1115 Reference
< io::XStream
> xStream
= xTempAccess
->openFileReadWrite( _rURL
);
1116 Reference
< io::XTruncate
> xTruncate(xStream
,UNO_QUERY
);
1117 if ( xTruncate
.is() )
1119 xTruncate
->truncate();
1121 Sequence
<Any
> aParam(2);
1122 aParam
[0] <<= xStream
;
1123 aParam
[1] <<= ElementModes::READWRITE
| ElementModes::TRUNCATE
;
1125 Reference
< XSingleServiceFactory
> xStorageFactory( m_pImpl
->createStorageFactory(), UNO_SET_THROW
);
1126 return Reference
< XStorage
>( xStorageFactory
->createInstanceWithArguments( aParam
), UNO_QUERY_THROW
);
1129 css::uno::Reference
<css::embed::XStorage
> ODatabaseDocument::impl_GetStorageOrCreateFor_throw(
1130 const ::comphelper::NamedValueCollection
& _rArguments
, const OUString
& _rURL
) const
1132 // Try to get the storage from arguments, then create storage for target URL
1133 uno::Reference
<embed::XStorage
> xTargetStorage
;
1134 _rArguments
.get("TargetStorage") >>= xTargetStorage
;
1135 if (!xTargetStorage
.is())
1136 xTargetStorage
= impl_createStorageFor_throw(_rURL
);
1138 // In case we got a StreamRelPath, then xTargetStorage should reference that sub-storage.
1139 OUString sStreamRelPath
= _rArguments
.getOrDefault("StreamRelPath", OUString());
1140 if (!sStreamRelPath
.isEmpty())
1142 = xTargetStorage
->openStorageElement(sStreamRelPath
, embed::ElementModes::READWRITE
);
1144 return xTargetStorage
;
1147 void SAL_CALL
ODatabaseDocument::storeAsURL( const OUString
& _rURL
, const Sequence
< PropertyValue
>& _rArguments
)
1150 DocumentGuard
aGuard( *this, DocumentGuard::MethodWithoutInit
);
1152 // Normally, a document initialization is done via XLoadable::load or XLoadable::initNew. For convenience
1153 // reasons, and to not break existing API clients, it's allowed to call storeAsURL without having initialized
1154 // the document, in which case the initialization will be done implicitly.
1155 bool bImplicitInitialization
= !impl_isInitialized();
1156 // implicit initialization while another initialization is just running is not possible
1157 if ( bImplicitInitialization
&& impl_isInitializing() )
1158 throw RuntimeException();
1160 if ( bImplicitInitialization
)
1161 impl_setInitializing();
1165 impl_storeAs_throw( _rURL
, _rArguments
, SAVE_AS
, aGuard
);
1168 // impl_storeAs_throw cleared the lock on our mutex, but the below lines need this lock
1172 // our title might have changed, potentially at least
1173 // Sadly, we cannot check this: Calling getTitle here and now would not deliver
1174 // an up-to-date result, as the call is delegated to our TitleHelper instance, which itself
1175 // updates its title only if it gets the OnSaveAsDone event (which was sent asynchronously
1176 // by impl_storeAs_throw). So, we simply notify always, and also asynchronously
1177 m_aEventNotifier
.notifyDocumentEventAsync( "OnTitleChanged" );
1179 catch( const Exception
& )
1181 impl_reset_nothrow();
1185 if ( bImplicitInitialization
)
1186 m_bAllowDocumentScripting
= true;
1191 if ( bImplicitInitialization
)
1192 m_aEventNotifier
.notifyDocumentEvent( "OnCreate" );
1195 void ODatabaseDocument::impl_storeToStorage_throw( const Reference
< XStorage
>& _rxTargetStorage
, const Sequence
< PropertyValue
>& _rMediaDescriptor
,
1196 DocumentGuard
& _rDocGuard
) const
1198 if ( !_rxTargetStorage
.is() )
1199 throw IllegalArgumentException( OUString(), *const_cast< ODatabaseDocument
* >( this ), 1 );
1201 if ( !m_pImpl
.is() )
1202 throw DisposedException( OUString(), *const_cast< ODatabaseDocument
* >( this ) );
1206 // commit everything
1207 m_pImpl
->commitEmbeddedStorage();
1208 m_pImpl
->commitStorages();
1210 // copy own storage to target storage
1211 if ( impl_isInitialized() )
1213 Reference
< XStorage
> xCurrentStorage
= m_pImpl
->getOrCreateRootStorage();
1214 // Root storage may be empty in case of embedding.
1215 if ( xCurrentStorage
.is() && xCurrentStorage
!= _rxTargetStorage
)
1216 xCurrentStorage
->copyToStorage( _rxTargetStorage
);
1219 // write into target storage
1220 ::comphelper::NamedValueCollection
aWriteArgs( _rMediaDescriptor
);
1221 lcl_triggerStatusIndicator_throw( aWriteArgs
, _rDocGuard
, true );
1222 impl_writeStorage_throw( _rxTargetStorage
, aWriteArgs
);
1223 lcl_triggerStatusIndicator_throw( aWriteArgs
, _rDocGuard
, false );
1225 // commit target storage
1226 m_pImpl
->commitStorageIfWriteable_ignoreErrors(_rxTargetStorage
);
1228 catch( const IOException
& ) { throw; }
1229 catch( const RuntimeException
& ) { throw; }
1230 catch ( const Exception
& e
)
1232 throw IOException( e
.Message
, *const_cast< ODatabaseDocument
* >( this ) );
1236 void SAL_CALL
ODatabaseDocument::storeToURL( const OUString
& _rURL
, const Sequence
< PropertyValue
>& _rArguments
)
1238 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1239 ModifyLock
aLock( *this );
1243 m_aEventNotifier
.notifyDocumentEvent( "OnSaveTo", nullptr, makeAny( _rURL
) );
1249 const ::comphelper::NamedValueCollection
aArguments(_rArguments
);
1250 // create storage for target URL
1251 Reference
<XStorage
> xTargetStorage(impl_GetStorageOrCreateFor_throw(aArguments
, _rURL
));
1253 // extend media descriptor with URL
1254 Sequence
<PropertyValue
> aMediaDescriptor(lcl_appendFileNameToDescriptor(aArguments
, _rURL
));
1256 // store to this storage
1257 impl_storeToStorage_throw( xTargetStorage
, aMediaDescriptor
, aGuard
);
1259 catch( const Exception
& )
1261 Any aError
= ::cppu::getCaughtException();
1262 m_aEventNotifier
.notifyDocumentEventAsync( "OnSaveToFailed", nullptr, aError
);
1264 if ( aError
.isExtractableTo( ::cppu::UnoType
< IOException
>::get() )
1265 || aError
.isExtractableTo( ::cppu::UnoType
< RuntimeException
>::get() )
1272 impl_throwIOExceptionCausedBySave_throw( aError
, _rURL
);
1275 m_aEventNotifier
.notifyDocumentEventAsync( "OnSaveToDone", nullptr, makeAny( _rURL
) );
1278 // XModifyBroadcaster
1279 void SAL_CALL
ODatabaseDocument::addModifyListener( const Reference
< XModifyListener
>& _xListener
)
1281 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1282 m_aModifyListeners
.addInterface(_xListener
);
1285 void SAL_CALL
ODatabaseDocument::removeModifyListener( const Reference
< XModifyListener
>& _xListener
)
1287 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1288 m_aModifyListeners
.removeInterface(_xListener
);
1292 sal_Bool SAL_CALL
ODatabaseDocument::isModified( )
1294 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1296 return m_pImpl
->m_bModified
;
1299 void SAL_CALL
ODatabaseDocument::setModified( sal_Bool _bModified
)
1301 DocumentGuard
aGuard( *this, DocumentGuard::MethodWithoutInit
);
1302 if ( impl_isInitialized() )
1303 impl_setModified_nothrow( _bModified
, aGuard
);
1304 // it's allowed to call setModified without the document being initialized already. In this case,
1305 // we simply ignore the call - when the initialization is finished, the respective code will set
1306 // a proper "modified" flag
1309 void ODatabaseDocument::impl_setModified_nothrow( bool _bModified
, DocumentGuard
& _rGuard
)
1312 bool bModifiedChanged
= ( m_pImpl
->m_bModified
!= _bModified
) && ( !m_pImpl
->isModifyLocked() );
1314 if ( bModifiedChanged
)
1316 m_pImpl
->m_bModified
= _bModified
;
1317 m_aEventNotifier
.notifyDocumentEventAsync( "OnModifyChanged" );
1322 if ( bModifiedChanged
)
1324 lang::EventObject
aEvent( *this );
1325 m_aModifyListeners
.notifyEach( &XModifyListener::modified
, aEvent
);
1329 // css::document::XEventBroadcaster
1330 void SAL_CALL
ODatabaseDocument::addEventListener(const uno::Reference
< document::XEventListener
>& Listener
)
1332 m_aEventNotifier
.addLegacyEventListener( Listener
);
1335 void SAL_CALL
ODatabaseDocument::removeEventListener( const uno::Reference
< document::XEventListener
>& Listener
)
1337 m_aEventNotifier
.removeLegacyEventListener( Listener
);
1340 void SAL_CALL
ODatabaseDocument::addDocumentEventListener( const Reference
< XDocumentEventListener
>& Listener
)
1342 m_aEventNotifier
.addDocumentEventListener( Listener
);
1345 void SAL_CALL
ODatabaseDocument::removeDocumentEventListener( const Reference
< XDocumentEventListener
>& Listener
)
1347 m_aEventNotifier
.removeDocumentEventListener( Listener
);
1350 void SAL_CALL
ODatabaseDocument::notifyDocumentEvent( const OUString
& EventName
, const Reference
< XController2
>& ViewController
, const Any
& Supplement
)
1352 if ( EventName
.isEmpty() )
1353 throw IllegalArgumentException( OUString(), *this, 1 );
1356 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1358 if ( !DocumentEvents::needsSynchronousNotification( EventName
) )
1360 m_aEventNotifier
.notifyDocumentEventAsync( EventName
, ViewController
, Supplement
);
1366 m_aEventNotifier
.notifyDocumentEvent( EventName
, ViewController
, Supplement
);
1369 Sequence
< PropertyValue
> SAL_CALL
ODatabaseDocument::getPrinter( )
1371 OSL_FAIL( "ODatabaseDocument::getPrinter: not supported!" );
1372 return Sequence
< PropertyValue
>();
1375 void SAL_CALL
ODatabaseDocument::setPrinter( const Sequence
< PropertyValue
>& /*aPrinter*/ )
1377 OSL_FAIL( "ODatabaseDocument::setPrinter: not supported!" );
1380 void SAL_CALL
ODatabaseDocument::print( const Sequence
< PropertyValue
>& /*xOptions*/ )
1382 OSL_FAIL( "ODatabaseDocument::print: not supported!" );
1385 void ODatabaseDocument::impl_reparent_nothrow( const WeakReference
< XNameAccess
>& _rxContainer
)
1387 Reference
< XChild
> xChild( _rxContainer
.get(), UNO_QUERY
);
1389 xChild
->setParent( *this );
1392 void ODatabaseDocument::clearObjectContainer( WeakReference
< XNameAccess
>& _rxContainer
)
1394 Reference
< XNameAccess
> xContainer
= _rxContainer
;
1395 ::comphelper::disposeComponent( xContainer
);
1397 Reference
< XChild
> xChild( _rxContainer
.get(),UNO_QUERY
);
1399 xChild
->setParent( nullptr );
1400 _rxContainer
.clear();
1403 Reference
< XNameAccess
> ODatabaseDocument::impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType
)
1405 if ( ( _eType
!= ODatabaseModelImpl::E_FORM
) && ( _eType
!= ODatabaseModelImpl::E_REPORT
) )
1406 throw IllegalArgumentException();
1408 bool bFormsContainer
= _eType
== ODatabaseModelImpl::E_FORM
;
1410 WeakReference
< XNameAccess
>& rContainerRef( bFormsContainer
? m_xForms
: m_xReports
);
1411 Reference
< XNameAccess
> xContainer
= rContainerRef
;
1412 if ( !xContainer
.is() )
1415 css::uno::Reference
< css::uno::XInterface
> xMy(*this);
1416 if ( dbtools::getDataSourceSetting(xMy
,bFormsContainer
? "Forms" : "Reports",aValue
) )
1418 OUString sSupportService
;
1419 aValue
>>= sSupportService
;
1420 if ( !sSupportService
.isEmpty() )
1422 Sequence
<Any
> aArgs(1);
1423 aArgs
[0] <<= NamedValue("DatabaseDocument",makeAny(xMy
));
1425 m_pImpl
->m_aContext
->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService
, aArgs
, m_pImpl
->m_aContext
),
1427 rContainerRef
= xContainer
;
1430 if ( !xContainer
.is() )
1432 TContentPtr
& rContainerData( m_pImpl
->getObjectContainer( _eType
) );
1433 rContainerRef
= xContainer
= new ODocumentContainer( m_pImpl
->m_aContext
, *this, rContainerData
, bFormsContainer
);
1435 impl_reparent_nothrow( xContainer
);
1440 void ODatabaseDocument::impl_closeControllerFrames_nolck_throw( bool _bDeliverOwnership
)
1442 Controllers aCopy
= m_aControllers
;
1444 for (auto const& elem
: aCopy
)
1451 Reference
< XCloseable
> xFrame( elem
->getFrame(), UNO_QUERY
);
1453 xFrame
->close( _bDeliverOwnership
);
1455 catch( const CloseVetoException
& ) { throw; }
1456 catch( const Exception
& )
1458 DBG_UNHANDLED_EXCEPTION("dbaccess");
1463 void ODatabaseDocument::impl_disposeControllerFrames_nothrow()
1466 aCopy
.swap( m_aControllers
); // ensure m_aControllers is empty afterwards
1467 for( const auto& rController
: aCopy
)
1471 if( rController
.is() )
1473 Reference
< XFrame
> xFrame( rController
->getFrame() );
1474 ::comphelper::disposeComponent( xFrame
);
1477 catch( const Exception
& )
1479 DBG_UNHANDLED_EXCEPTION("dbaccess");
1484 void SAL_CALL
ODatabaseDocument::close(sal_Bool bDeliverOwnership
)
1486 // nearly everything below can/must be done without our mutex locked, the below is just for
1487 // the checks for being disposed and the like
1490 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1491 assert (!m_bClosing
);
1498 // allow listeners to veto
1499 lang::EventObject
aEvent( *this );
1500 m_aCloseListener
.forEach
< XCloseListener
>(
1501 [&aEvent
, &bDeliverOwnership
] (uno::Reference
<XCloseListener
> const& xListener
) {
1502 return xListener
->queryClosing(aEvent
, bDeliverOwnership
);
1505 // notify that we're going to unload
1506 m_aEventNotifier
.notifyDocumentEvent( "OnPrepareUnload" );
1508 impl_closeControllerFrames_nolck_throw( bDeliverOwnership
);
1510 m_aCloseListener
.notifyEach( &XCloseListener::notifyClosing
, const_cast<const lang::EventObject
&>(aEvent
) );
1514 catch ( const Exception
& )
1527 void SAL_CALL
ODatabaseDocument::addCloseListener( const Reference
< css::util::XCloseListener
>& Listener
)
1529 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1530 m_aCloseListener
.addInterface(Listener
);
1533 void SAL_CALL
ODatabaseDocument::removeCloseListener( const Reference
< css::util::XCloseListener
>& Listener
)
1535 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1536 m_aCloseListener
.removeInterface(Listener
);
1539 Reference
< XNameAccess
> SAL_CALL
ODatabaseDocument::getFormDocuments( )
1541 DocumentGuard
aGuard( *this, DocumentGuard::MethodUsedDuringInit
);
1542 return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_FORM
);
1545 Reference
< XNameAccess
> SAL_CALL
ODatabaseDocument::getReportDocuments( )
1547 DocumentGuard
aGuard( *this, DocumentGuard::MethodUsedDuringInit
);
1548 return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_REPORT
);
1551 void ODatabaseDocument::WriteThroughComponent( const Reference
< XComponent
>& xComponent
, const char* pStreamName
,
1552 const char* pServiceName
, const Sequence
< Any
>& _rArguments
, const Sequence
< PropertyValue
>& rMediaDesc
,
1553 const Reference
<XStorage
>& _xStorageToSaveTo
) const
1555 OSL_ENSURE( pStreamName
, "Need stream name!" );
1556 OSL_ENSURE( pServiceName
, "Need service name!" );
1559 OUString sStreamName
= OUString::createFromAscii( pStreamName
);
1560 Reference
< XStream
> xStream
= _xStorageToSaveTo
->openStreamElement( sStreamName
, ElementModes::READWRITE
| ElementModes::TRUNCATE
);
1561 if ( !xStream
.is() )
1564 Reference
< XOutputStream
> xOutputStream( xStream
->getOutputStream() );
1565 OSL_ENSURE( xOutputStream
.is(), "Can't create output stream in package!" );
1566 if ( !xOutputStream
.is() )
1569 Reference
< XSeekable
> xSeek( xOutputStream
, UNO_QUERY
);
1573 Reference
< XPropertySet
> xStreamProp( xOutputStream
, UNO_QUERY_THROW
);
1574 xStreamProp
->setPropertyValue( INFO_MEDIATYPE
, makeAny( OUString( "text/xml" ) ) );
1575 xStreamProp
->setPropertyValue( "Compressed", makeAny( true ) );
1578 WriteThroughComponent( xOutputStream
, xComponent
, pServiceName
, _rArguments
, rMediaDesc
);
1581 void ODatabaseDocument::WriteThroughComponent( const Reference
< XOutputStream
>& xOutputStream
,
1582 const Reference
< XComponent
>& xComponent
, const char* pServiceName
, const Sequence
< Any
>& _rArguments
,
1583 const Sequence
< PropertyValue
>& rMediaDesc
) const
1585 OSL_ENSURE( xOutputStream
.is(), "I really need an output stream!" );
1586 OSL_ENSURE( xComponent
.is(), "Need component!" );
1587 OSL_ENSURE( nullptr != pServiceName
, "Need component name!" );
1590 Reference
< XWriter
> xSaxWriter
= xml::sax::Writer::create( m_pImpl
->m_aContext
);
1592 // connect XML writer to output stream
1593 xSaxWriter
->setOutputStream( xOutputStream
);
1595 // prepare arguments (prepend doc handler to given arguments)
1596 Sequence
<Any
> aArgs( 1 + _rArguments
.getLength() );
1597 aArgs
[0] <<= xSaxWriter
;
1598 for ( sal_Int32 i
= 0; i
< _rArguments
.getLength(); ++i
)
1599 aArgs
[ i
+1 ] = _rArguments
[i
];
1601 // get filter component
1602 Reference
< XExporter
> xExporter( m_pImpl
->m_aContext
->getServiceManager()->createInstanceWithArgumentsAndContext(OUString::createFromAscii(pServiceName
), aArgs
, m_pImpl
->m_aContext
), UNO_QUERY_THROW
);
1604 // connect model and filter
1605 xExporter
->setSourceDocument( xComponent
);
1608 Reference
< XFilter
> xFilter( xExporter
, UNO_QUERY_THROW
);
1609 xFilter
->filter( rMediaDesc
);
1612 void ODatabaseDocument::impl_writeStorage_throw( const Reference
< XStorage
>& _rxTargetStorage
, const ::comphelper::NamedValueCollection
& _rMediaDescriptor
) const
1614 // extract status indicator
1615 Sequence
< Any
> aDelegatorArguments
;
1616 lcl_extractStatusIndicator( _rMediaDescriptor
, aDelegatorArguments
);
1618 uno::Reference
< beans::XPropertySet
> xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap
) ) );
1620 SvtSaveOptions aSaveOpt
;
1621 xInfoSet
->setPropertyValue("UsePrettyPrinting", uno::makeAny(aSaveOpt
.IsPrettyPrinting()));
1622 if ( aSaveOpt
.IsSaveRelFSys() )
1624 OUString sBaseURI
= _rMediaDescriptor
.getOrDefault("BaseURI", OUString());
1625 if (sBaseURI
.isEmpty())
1626 sBaseURI
= _rMediaDescriptor
.getOrDefault("URL",OUString());
1627 xInfoSet
->setPropertyValue("BaseURI", uno::makeAny(sBaseURI
));
1630 // Set TargetStorage, so it doesn't have to be re-constructed based on possibly empty URL.
1631 xInfoSet
->setPropertyValue("TargetStorage", uno::makeAny(m_pImpl
->getRootStorage()));
1633 // Set StreamRelPath, in case this document is an embedded one.
1634 OUString sStreamRelPath
;
1635 OUString sURL
= _rMediaDescriptor
.getOrDefault("URL", OUString());
1636 if (sURL
.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:"))
1638 // In this case the host contains the real path, and the path is the embedded stream name.
1639 INetURLObject
aURL(sURL
);
1640 sStreamRelPath
= aURL
.GetURLPath(INetURLObject::DecodeMechanism::WithCharset
);
1641 if (sStreamRelPath
.startsWith("/"))
1642 sStreamRelPath
= sStreamRelPath
.copy(1);
1644 if (!sStreamRelPath
.isEmpty())
1645 xInfoSet
->setPropertyValue("StreamRelPath", uno::makeAny(sStreamRelPath
));
1647 sal_Int32 nArgsLen
= aDelegatorArguments
.getLength();
1648 aDelegatorArguments
.realloc(nArgsLen
+1);
1649 aDelegatorArguments
[nArgsLen
++] <<= xInfoSet
;
1651 Reference
< XPropertySet
> xProp( _rxTargetStorage
, UNO_QUERY_THROW
);
1652 xProp
->setPropertyValue( INFO_MEDIATYPE
, makeAny( OUString(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
) ) );
1655 SvtSaveOptions::ODFSaneDefaultVersion
const nDefVersion
=
1656 aSaveOpt
.GetODFSaneDefaultVersion();
1657 // older versions can not have this property set,
1658 // it exists only starting from ODF1.2
1659 if (nDefVersion
>= SvtSaveOptions::ODFSVER_013
)
1661 aVersion
= ODFVER_013_TEXT
;
1663 else if (nDefVersion
>= SvtSaveOptions::ODFSVER_012
)
1665 aVersion
= ODFVER_012_TEXT
;
1668 if (!aVersion
.isEmpty())
1672 xProp
->setPropertyValue("Version" , uno::makeAny(aVersion
));
1674 catch (const uno::Exception
&)
1676 TOOLS_WARN_EXCEPTION("dbaccess", "exception setting Version");
1680 Reference
< XComponent
> xComponent( *const_cast< ODatabaseDocument
* >( this ), UNO_QUERY_THROW
);
1682 Sequence
< PropertyValue
> aMediaDescriptor
;
1683 _rMediaDescriptor
>>= aMediaDescriptor
;
1685 xInfoSet
->setPropertyValue("StreamName", uno::makeAny(OUString("settings.xml")));
1686 WriteThroughComponent( xComponent
, "settings.xml", "com.sun.star.comp.sdb.XMLSettingsExporter",
1687 aDelegatorArguments
, aMediaDescriptor
, _rxTargetStorage
);
1689 xInfoSet
->setPropertyValue("StreamName", uno::makeAny(OUString("content.xml")));
1690 WriteThroughComponent( xComponent
, "content.xml", "com.sun.star.comp.sdb.DBExportFilter",
1691 aDelegatorArguments
, aMediaDescriptor
, _rxTargetStorage
);
1693 if ( _rxTargetStorage
->hasByName ( sPictures
) )
1697 // Delete any previously existing Pictures folder and regenerate
1698 // any needed content if needed
1699 Reference
< XStorageBasedLibraryContainer
> xDlgs
= m_pImpl
->getLibraryContainer( false );
1702 Reference
< XModel
> xModel(const_cast< ODatabaseDocument
*>(this));
1703 lcl_uglyHackToStoreDialogeEmbedImages( m_pImpl
->getLibraryContainer(false), _rxTargetStorage
, xModel
, m_pImpl
->m_aContext
);
1706 catch ( const Exception
& )
1708 DBG_UNHANDLED_EXCEPTION("dbaccess");
1711 m_pImpl
->storeLibraryContainersTo( _rxTargetStorage
);
1714 Reference
< XUIConfigurationManager
> SAL_CALL
ODatabaseDocument::getUIConfigurationManager( )
1716 return Reference
< XUIConfigurationManager
>( getUIConfigurationManager2(), UNO_QUERY_THROW
);
1719 Reference
< XUIConfigurationManager2
> const & ODatabaseDocument::getUIConfigurationManager2( )
1721 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1723 if ( !m_xUIConfigurationManager
.is() )
1725 m_xUIConfigurationManager
= UIConfigurationManager::create( m_pImpl
->m_aContext
);
1727 OUString
aUIConfigFolderName( "Configurations2" );
1729 // First try to open with READWRITE and then READ
1730 Reference
< XStorage
> xConfigStorage
= getDocumentSubStorage( aUIConfigFolderName
, ElementModes::READWRITE
);
1731 if ( xConfigStorage
.is() )
1733 OUString aMediaType
;
1734 Reference
< XPropertySet
> xPropSet( xConfigStorage
, UNO_QUERY
);
1735 Any a
= xPropSet
->getPropertyValue( INFO_MEDIATYPE
);
1736 if ( !( a
>>= aMediaType
) || aMediaType
.isEmpty() )
1738 a
<<= OUString("application/vnd.sun.xml.ui.configuration");
1739 xPropSet
->setPropertyValue( INFO_MEDIATYPE
, a
);
1743 xConfigStorage
= getDocumentSubStorage( aUIConfigFolderName
, ElementModes::READ
);
1745 // initialize ui configuration manager with document substorage
1746 m_xUIConfigurationManager
->setStorage( xConfigStorage
);
1749 return m_xUIConfigurationManager
;
1752 Reference
< XStorage
> SAL_CALL
ODatabaseDocument::getDocumentSubStorage( const OUString
& aStorageName
, sal_Int32 nMode
)
1754 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1756 Reference
< XDocumentSubStorageSupplier
> xStorageAccess( m_pImpl
->getDocumentSubStorageSupplier() );
1757 return xStorageAccess
->getDocumentSubStorage( aStorageName
, nMode
);
1760 Sequence
< OUString
> SAL_CALL
ODatabaseDocument::getDocumentSubStoragesNames( )
1762 Reference
< XDocumentSubStorageSupplier
> xStorageAccess( m_pImpl
->getDocumentSubStorageSupplier() );
1763 return xStorageAccess
->getDocumentSubStoragesNames();
1766 void ODatabaseDocument::impl_notifyStorageChange_nolck_nothrow( const Reference
< XStorage
>& xNewRootStorage
)
1768 Reference
< XInterface
> xMe( *this );
1770 m_aStorageListeners
.forEach
< XStorageChangeListener
>(
1771 [&xMe
, &xNewRootStorage
] (uno::Reference
<XStorageChangeListener
> const& xListener
) {
1772 return xListener
->notifyStorageChange(xMe
, xNewRootStorage
);
1776 void ODatabaseDocument::disposing()
1778 if ( !m_pImpl
.is() )
1780 // this means that we're already disposed
1781 OSL_ENSURE( ODatabaseDocument_OfficeDocument::rBHelper
.bDisposed
, "ODatabaseDocument::disposing: no impl anymore, but not yet disposed!" );
1785 if ( impl_isInitialized() )
1786 m_aEventNotifier
.notifyDocumentEvent( "OnUnload" );
1788 Reference
< XModel
> xHoldAlive( this );
1790 m_aEventNotifier
.disposing();
1792 lang::EventObject
aDisposeEvent(static_cast<XWeak
*>(this));
1793 m_aModifyListeners
.disposeAndClear( aDisposeEvent
);
1794 m_aCloseListener
.disposeAndClear( aDisposeEvent
);
1795 m_aStorageListeners
.disposeAndClear( aDisposeEvent
);
1797 // this is the list of objects which we currently hold as member. Upon resetting
1798 // those members, we can (potentially) release the last reference to them, in which
1799 // case they will be deleted - if they're C++ implementations, that is :).
1800 // Some of those implementations are offending enough to require the SolarMutex, which
1801 // means we should not release the last reference while our own mutex is locked ...
1802 std::vector
< Reference
< XInterface
> > aKeepAlive
;
1806 SolarMutexGuard aGuard
;
1808 OSL_ENSURE(m_aControllers
.empty(),
1809 "ODatabaseDocument::disposing: there still are controllers!");
1810 // normally, nobody should explicitly dispose, but only XCloseable::close
1811 // the document. And upon closing, our controllers are closed, too
1814 uno::Reference
<uno::XInterface
> xUIInterface(m_xUIConfigurationManager
);
1815 aKeepAlive
.push_back(xUIInterface
);
1817 m_xUIConfigurationManager
= nullptr;
1819 clearObjectContainer(m_xForms
);
1820 clearObjectContainer(m_xReports
);
1822 // reset the macro mode: in case the our impl struct stays alive (e.g. because our DataSource
1823 // object still exists), and somebody subsequently re-opens the document, we want to have
1824 // the security warning, again.
1825 m_pImpl
->resetMacroExecutionMode();
1827 // similar arguing for our ViewMonitor
1828 m_aViewMonitor
.reset();
1830 // tell our Impl to forget us
1831 m_pImpl
->modelIsDisposing(impl_isInitialized(), ODatabaseModelImpl::ResetModelAccess());
1833 // now, at the latest, the controller array should be empty. Controllers are
1834 // expected to listen for our disposal, and disconnect then
1835 OSL_ENSURE(m_aControllers
.empty(),
1836 "ODatabaseDocument::disposing: there still are controllers!");
1837 impl_disposeControllerFrames_nothrow();
1840 uno::Reference
<uno::XInterface
> xModuleInterface(m_xModuleManager
);
1841 aKeepAlive
.push_back(xModuleInterface
);
1843 m_xModuleManager
.clear();
1846 uno::Reference
<uno::XInterface
> xTitleInterface(m_xTitleHelper
);
1847 aKeepAlive
.push_back(xTitleInterface
);
1849 m_xTitleHelper
.clear();
1859 void SAL_CALL
ODatabaseDocument::dispose( )
1861 ::cppu::WeakComponentImplHelperBase::dispose();
1864 void SAL_CALL
ODatabaseDocument::addEventListener( const Reference
< lang::XEventListener
>& _xListener
)
1866 ::cppu::WeakComponentImplHelperBase::addEventListener( _xListener
);
1869 void SAL_CALL
ODatabaseDocument::removeEventListener( const Reference
< lang::XEventListener
>& _xListener
)
1871 ::cppu::WeakComponentImplHelperBase::removeEventListener( _xListener
);
1875 OUString
ODatabaseDocument::getImplementationName()
1877 return "com.sun.star.comp.dba.ODatabaseDocument";
1880 Sequence
< OUString
> ODatabaseDocument::getSupportedServiceNames()
1882 return { "com.sun.star.sdb.OfficeDatabaseDocument", "com.sun.star.document.OfficeDocument" };
1885 sal_Bool
ODatabaseDocument::supportsService( const OUString
& _rServiceName
)
1887 return cppu::supportsService(this, _rServiceName
);
1890 Reference
< XDataSource
> SAL_CALL
ODatabaseDocument::getDataSource()
1892 DocumentGuard
aGuard( *this, DocumentGuard::MethodWithoutInit
);
1893 return m_pImpl
->getOrCreateDataSource();
1898 /// Property map for embedded import info set.
1899 comphelper::PropertyMapEntry
const aEmbeddedImportInfoMap
[] =
1901 {OUString("StreamRelPath"), 0, cppu::UnoType
<OUString
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0},
1902 {OUString("StreamName"), 0, cppu::UnoType
<OUString
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0},
1903 {OUString("SourceStorage"), 0, cppu::UnoType
<embed::XStorage
>::get(), beans::PropertyAttribute::MAYBEVOID
, 0},
1904 {OUString(), 0, css::uno::Type(), 0, 0}
1908 void SAL_CALL
ODatabaseDocument::loadFromStorage(const Reference
<XStorage
>& xStorage
, const Sequence
<PropertyValue
>& rMediaDescriptor
)
1910 DocumentGuard
aGuard(*this, DocumentGuard::InitMethod
);
1912 uno::Reference
<beans::XPropertySet
> xInfoSet(comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aEmbeddedImportInfoMap
)));
1913 comphelper::NamedValueCollection
aDescriptor(rMediaDescriptor
);
1914 xInfoSet
->setPropertyValue("StreamRelPath", uno::makeAny(aDescriptor
.getOrDefault("HierarchicalDocumentName", OUString())));
1915 xInfoSet
->setPropertyValue("StreamName", uno::makeAny(OUString("content.xml")));
1916 xInfoSet
->setPropertyValue("SourceStorage", uno::makeAny(xStorage
));
1918 uno::Sequence
<uno::Any
> aFilterCreationArgs(1);
1919 aFilterCreationArgs
[0] <<= xInfoSet
;
1921 uno::Reference
<document::XImporter
> xImporter(m_pImpl
->m_aContext
->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs
, m_pImpl
->m_aContext
), uno::UNO_QUERY_THROW
);
1923 uno::Reference
<lang::XComponent
> xComponent(*this, uno::UNO_QUERY_THROW
);
1924 xImporter
->setTargetDocument(xComponent
);
1926 uno::Reference
<document::XFilter
> xFilter(xImporter
, uno::UNO_QUERY_THROW
);
1927 uno::Sequence
<beans::PropertyValue
> aFilterArgs
;
1928 xFilter
->filter(aFilterArgs
);
1930 // In case of embedding, XModel::attachResource is already called.
1932 impl_setInitialized();
1934 impl_setModified_nothrow(false, aGuard
);
1937 void SAL_CALL
ODatabaseDocument::storeToStorage( const Reference
< XStorage
>& _rxStorage
, const Sequence
< PropertyValue
>& _rMediaDescriptor
)
1939 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1940 impl_storeToStorage_throw( _rxStorage
, _rMediaDescriptor
, aGuard
);
1943 void SAL_CALL
ODatabaseDocument::switchToStorage( const Reference
< XStorage
>& _rxNewRootStorage
)
1945 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1947 Reference
< XStorage
> xNewRootStorage( m_pImpl
->switchToStorage( _rxNewRootStorage
) );
1950 impl_notifyStorageChange_nolck_nothrow( xNewRootStorage
);
1953 Reference
< XStorage
> SAL_CALL
ODatabaseDocument::getDocumentStorage( )
1955 DocumentGuard
aGuard(*this, DocumentGuard::MethodUsedDuringInit
);
1956 return m_pImpl
->getOrCreateRootStorage();
1959 void SAL_CALL
ODatabaseDocument::addStorageChangeListener( const Reference
< XStorageChangeListener
>& Listener
)
1961 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1962 m_aStorageListeners
.addInterface( Listener
);
1965 void SAL_CALL
ODatabaseDocument::removeStorageChangeListener( const Reference
< XStorageChangeListener
>& Listener
)
1967 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1968 m_aStorageListeners
.addInterface( Listener
);
1971 Reference
< XStorageBasedLibraryContainer
> SAL_CALL
ODatabaseDocument::getBasicLibraries()
1973 DocumentGuard
aGuard( *this, DocumentGuard::MethodUsedDuringInit
);
1974 return m_pImpl
->getLibraryContainer( true );
1977 Reference
< XStorageBasedLibraryContainer
> SAL_CALL
ODatabaseDocument::getDialogLibraries()
1979 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1980 return m_pImpl
->getLibraryContainer( false );
1983 sal_Bool SAL_CALL
ODatabaseDocument::getAllowMacroExecution()
1985 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1986 return m_pImpl
->adjustMacroMode_AutoReject();
1989 Reference
< XEmbeddedScripts
> SAL_CALL
ODatabaseDocument::getScriptContainer()
1994 Reference
< provider::XScriptProvider
> SAL_CALL
ODatabaseDocument::getScriptProvider( )
1996 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
1998 Reference
< XScriptProvider
> xScriptProvider( m_xScriptProvider
);
1999 if ( !xScriptProvider
.is() )
2001 Reference
< XScriptProviderFactory
> xFactory
=
2002 theMasterScriptProviderFactory::get( m_pImpl
->m_aContext
);
2004 Any aScriptProviderContext
;
2005 if ( m_bAllowDocumentScripting
)
2006 aScriptProviderContext
<<= Reference
< XModel
>( this );
2008 xScriptProvider
.set( xFactory
->createScriptProvider( aScriptProviderContext
), UNO_SET_THROW
);
2009 m_xScriptProvider
= xScriptProvider
;
2012 return xScriptProvider
;
2015 Reference
< XNameReplace
> SAL_CALL
ODatabaseDocument::getEvents( )
2017 DocumentGuard
aGuard( *this, DocumentGuard::MethodUsedDuringInit
);
2018 return m_pEventContainer
.get();
2021 Reference
< XInterface
> ODatabaseDocument::getThis() const
2023 return *const_cast< ODatabaseDocument
* >( this );
2030 Any
operator() (const Reference
<XController
>& lhs
) const
2032 return makeAny(lhs
);
2039 Reference
< XEnumeration
> SAL_CALL
ODatabaseDocument::getControllers( )
2041 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2042 uno::Sequence
< Any
> aController( m_aControllers
.size() );
2043 std::transform( m_aControllers
.begin(), m_aControllers
.end(), aController
.getArray(), CreateAny() );
2044 return new ::comphelper::OAnyEnumeration(aController
);
2047 Sequence
< OUString
> SAL_CALL
ODatabaseDocument::getAvailableViewControllerNames( )
2049 Sequence
< OUString
> aNames
{ SERVICE_SDB_APPLICATIONCONTROLLER
};
2053 Reference
< XController2
> SAL_CALL
ODatabaseDocument::createDefaultViewController( const Reference
< XFrame
>& Frame
)
2055 return createViewController( "Default", Sequence
< PropertyValue
>(), Frame
);
2058 Reference
< XController2
> SAL_CALL
ODatabaseDocument::createViewController( const OUString
& ViewName
, const Sequence
< PropertyValue
>& Arguments
, const Reference
< XFrame
>& Frame
)
2060 if ( ViewName
!= "Default" && ViewName
!= "Preview" )
2061 throw IllegalArgumentException( OUString(), *this, 1 );
2063 throw IllegalArgumentException( OUString(), *this, 3 );
2065 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2068 Reference
< XController2
> xController(
2069 m_pImpl
->m_aContext
->getServiceManager()->createInstanceWithContext("org.openoffice.comp.dbu.OApplicationController", m_pImpl
->m_aContext
),
2072 ::comphelper::NamedValueCollection
aInitArgs( Arguments
);
2073 aInitArgs
.put( "Frame", Frame
);
2074 if ( ViewName
== "Preview" )
2075 aInitArgs
.put( "Preview", true );
2076 Reference
< XInitialization
> xInitController( xController
, UNO_QUERY_THROW
);
2077 xInitController
->initialize( aInitArgs
.getWrappedPropertyValues() );
2082 Reference
< XTitle
> const & ODatabaseDocument::impl_getTitleHelper_throw()
2084 if ( ! m_xTitleHelper
.is ())
2086 Reference
< XUntitledNumbers
> xDesktop(Desktop::create(m_pImpl
->m_aContext
), uno::UNO_QUERY_THROW
);
2087 Reference
< frame::XModel
> xThis (getThis(), uno::UNO_QUERY_THROW
);
2089 ::framework::TitleHelper
* pHelper
= new ::framework::TitleHelper(m_pImpl
->m_aContext
);
2090 m_xTitleHelper
.set(static_cast< ::cppu::OWeakObject
* >(pHelper
), uno::UNO_QUERY_THROW
);
2091 pHelper
->setOwner (xThis
);
2092 pHelper
->connectWithUntitledNumbers (xDesktop
);
2095 return m_xTitleHelper
;
2098 uno::Reference
< frame::XUntitledNumbers
> ODatabaseDocument::impl_getUntitledHelper_throw(const uno::Reference
< uno::XInterface
>& _xComponent
)
2100 if ( !m_xModuleManager
.is() )
2101 m_xModuleManager
.set( ModuleManager::create(m_pImpl
->m_aContext
) );
2106 sModuleId
= m_xModuleManager
->identify( _xComponent
);
2108 catch(const uno::Exception
&)
2111 uno::Reference
< frame::XUntitledNumbers
> xNumberedControllers
;
2113 TNumberedController::const_iterator aFind
= m_aNumberedControllers
.find(sModuleId
);
2114 if ( aFind
== m_aNumberedControllers
.end() )
2116 uno::Reference
< frame::XModel
> xThis(static_cast< frame::XModel
* >(this), uno::UNO_QUERY_THROW
);
2117 ::comphelper::NumberedCollection
* pHelper
= new ::comphelper::NumberedCollection();
2118 xNumberedControllers
.set(static_cast< ::cppu::OWeakObject
* >(pHelper
), uno::UNO_QUERY_THROW
);
2120 pHelper
->setOwner (xThis
);
2122 m_aNumberedControllers
.emplace( sModuleId
,xNumberedControllers
);
2125 xNumberedControllers
= aFind
->second
;
2127 return xNumberedControllers
;
2131 OUString SAL_CALL
ODatabaseDocument::getTitle()
2134 DocumentGuard
aGuard( *this, DocumentGuard::MethodUsedDuringInit
);
2135 return impl_getTitleHelper_throw()->getTitle();
2139 void SAL_CALL
ODatabaseDocument::setTitle( const OUString
& sTitle
)
2142 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2143 impl_getTitleHelper_throw()->setTitle( sTitle
);
2144 m_aEventNotifier
.notifyDocumentEventAsync( "OnTitleChanged" );
2148 // css.frame.XTitleChangeBroadcaster
2149 void SAL_CALL
ODatabaseDocument::addTitleChangeListener( const uno::Reference
< frame::XTitleChangeListener
>& xListener
)
2152 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2154 uno::Reference
< frame::XTitleChangeBroadcaster
> xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW
);
2155 xBroadcaster
->addTitleChangeListener( xListener
);
2158 // css.frame.XTitleChangeBroadcaster
2159 void SAL_CALL
ODatabaseDocument::removeTitleChangeListener( const uno::Reference
< frame::XTitleChangeListener
>& xListener
)
2162 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2164 uno::Reference
< frame::XTitleChangeBroadcaster
> xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW
);
2165 xBroadcaster
->removeTitleChangeListener( xListener
);
2168 // css.frame.XUntitledNumbers
2169 ::sal_Int32 SAL_CALL
ODatabaseDocument::leaseNumber( const uno::Reference
< uno::XInterface
>& xComponent
)
2171 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2172 return impl_getUntitledHelper_throw(xComponent
)->leaseNumber (xComponent
);
2175 // css.frame.XUntitledNumbers
2176 void SAL_CALL
ODatabaseDocument::releaseNumber( ::sal_Int32 nNumber
)
2178 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2179 impl_getUntitledHelper_throw()->releaseNumber (nNumber
);
2182 // css.frame.XUntitledNumbers
2183 void SAL_CALL
ODatabaseDocument::releaseNumberForComponent( const uno::Reference
< uno::XInterface
>& xComponent
)
2185 DocumentGuard
aGuard(*this, DocumentGuard::DefaultMethod
);
2186 impl_getUntitledHelper_throw(xComponent
)->releaseNumberForComponent (xComponent
);
2189 // css.frame.XUntitledNumbers
2190 OUString SAL_CALL
ODatabaseDocument::getUntitledPrefix()
2195 } // namespace dbaccess
2197 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2198 com_sun_star_comp_dba_ODatabaseDocument(css::uno::XComponentContext
* context
,
2199 css::uno::Sequence
<css::uno::Any
> const &)
2201 Reference
<XUnoTunnel
> xDBContextTunnel(DatabaseContext::create(context
), UNO_QUERY_THROW
);
2202 dbaccess::ODatabaseContext
* pContext
= reinterpret_cast<dbaccess::ODatabaseContext
*>(
2203 xDBContextTunnel
->getSomething(
2204 dbaccess::ODatabaseContext::getUnoTunnelId()));
2206 rtl::Reference
pImpl(
2207 new dbaccess::ODatabaseModelImpl(context
, *pContext
));
2208 css::uno::Reference
<XInterface
> inst(pImpl
->createNewModel_deliverOwnership());
2213 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */