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 .
22 #include "ContentHelper.hxx"
23 #include "documentevents.hxx"
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/beans/XPropertyBag.hpp>
27 #include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
28 #include <com/sun/star/embed/XStorage.hpp>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/lang/XEventListener.hpp>
31 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
32 #include <com/sun/star/reflection/ProxyFactory.hpp>
33 #include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
34 #include <com/sun/star/sdbc/XDataSource.hpp>
35 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
38 #include <comphelper/namedvaluecollection.hxx>
39 #include <cppuhelper/weakref.hxx>
40 #include <vcl/svapp.hxx>
41 #include <sfx2/docmacromode.hxx>
42 #include <sfx2/docstoragemodifylistener.hxx>
43 #include <unotools/sharedunocomponent.hxx>
44 #include <rtl/digest.h>
45 #include <rtl/ref.hxx>
46 #include <o3tl/enumarray.hxx>
47 #include <unotools/weakref.hxx>
53 class NamedValueCollection
;
58 class OCommandContainer
;
60 typedef std::vector
< css::uno::WeakReference
< css::sdbc::XConnection
> > OWeakConnectionArray
;
62 struct DefaultPropertyValue
65 css::uno::Any DefaultValue
;
66 const css::uno::Type
& ValueType
;
68 DefaultPropertyValue(const OUString
& _aName
, const css::uno::Any
& _rDefaultValue
)
70 ,DefaultValue( _rDefaultValue
)
71 ,ValueType( _rDefaultValue
.getValueType() )
73 OSL_ENSURE( ValueType
.getTypeClass() != css::uno::TypeClass_VOID
,
74 "AsciiPropertyValue::AsciiPropertyValue: NULL values not allowed here, use the other CTOR for this!" );
76 DefaultPropertyValue(const OUString
& _aName
, const css::uno::Type
& _rValeType
)
78 ,ValueType( _rValeType
)
80 OSL_ENSURE( ValueType
.getTypeClass() != css::uno::TypeClass_VOID
,
81 "AsciiPropertyValue::AsciiPropertyValue: VOID property values not supported!" );
86 typedef ::utl::SharedUNOComponent
< css::embed::XStorage
> SharedStorage
;
88 class ODatabaseContext
;
89 class DocumentStorageAccess
;
90 class ODatabaseSource
;
91 class ODatabaseDocument
;
94 /** The class OSharedConnectionManager implements a structure to share connections.
95 It owns the master connections which will be disposed when the last connection proxy is gone.
97 // need to hold the digest
100 sal_uInt8 m_pBuffer
[RTL_DIGEST_LENGTH_SHA1
];
108 class OSharedConnectionManager
: public ::cppu::WeakImplHelper
< css::lang::XEventListener
>
110 // contains the currently used master connections
111 struct TConnectionHolder
113 css::uno::Reference
< css::sdbc::XConnection
> xMasterConnection
;
114 oslInterlockedCount nALiveCount
;
117 // the less-compare functor, used for the stl::map
120 bool operator() (const TDigestHolder
& x
, const TDigestHolder
& y
) const
123 for(i
=0;i
< RTL_DIGEST_LENGTH_SHA1
&& (x
.m_pBuffer
[i
] >= y
.m_pBuffer
[i
]); ++i
)
125 return i
< RTL_DIGEST_LENGTH_SHA1
;
129 typedef std::map
< TDigestHolder
,TConnectionHolder
,TDigestLess
> TConnectionMap
; // holds the master connections
130 typedef std::map
< css::uno::Reference
< css::sdbc::XConnection
>,TConnectionMap::iterator
> TSharedConnectionMap
;// holds the shared connections
132 ::osl::Mutex m_aMutex
;
133 TConnectionMap m_aConnections
; // remember the master connection in conjunction with the digest
134 TSharedConnectionMap m_aSharedConnection
; // the shared connections with conjunction with an iterator into the connections map
135 css::uno::Reference
< css::reflection::XProxyFactory
> m_xProxyFactory
;
138 virtual ~OSharedConnectionManager() override
;
141 explicit OSharedConnectionManager(const css::uno::Reference
< css::uno::XComponentContext
>& _rxContext
);
143 void SAL_CALL
disposing( const css::lang::EventObject
& Source
) override
;
144 css::uno::Reference
< css::sdbc::XConnection
> getConnection( const OUString
& url
,
145 const OUString
& user
,
146 const OUString
& password
,
147 const css::uno::Sequence
< css::beans::PropertyValue
>& _aInfo
,
148 ODatabaseSource
* _pDataSource
);
149 void addEventListener(const css::uno::Reference
< css::sdbc::XConnection
>& _rxConnection
, TConnectionMap::iterator
const & _rIter
);
153 class ODatabaseModelImpl
:public ::sfx2::IMacroDocumentAccess
154 ,public ::sfx2::IModifiableDocument
158 enum class ObjectType
167 enum class EmbeddedMacros
169 // the database document (storage) itself contains macros
171 // there are sub document( storage)s containing macros
173 // there are no known macro( storage)s
178 unotools::WeakReference
< ODatabaseDocument
> m_xModel
;
179 unotools::WeakReference
< ODatabaseSource
> m_xDataSource
;
181 rtl::Reference
<DocumentStorageAccess
> m_pStorageAccess
;
182 o3tl::enumarray
< ObjectType
, TContentPtr
> m_aContainer
; // one for each ObjectType
183 ::sfx2::DocumentMacroMode m_aMacroMode
;
184 sal_Int16 m_nImposedMacroExecMode
;
186 css::uno::Reference
< css::script::XStorageBasedLibraryContainer
> m_xBasicLibraries
;
187 css::uno::Reference
< css::script::XStorageBasedLibraryContainer
> m_xDialogLibraries
;
189 SharedStorage m_xDocumentStorage
;
190 ::rtl::Reference
< ::sfx2::DocumentStorageModifyListener
> m_pStorageModifyListener
;
191 ODatabaseContext
& m_rDBContext
;
192 DocumentEventsData m_aDocumentEvents
;
194 ::comphelper::NamedValueCollection m_aMediaDescriptor
;
195 /// the URL the document was loaded from
196 OUString m_sDocFileLocation
;
198 oslInterlockedCount m_refCount
;
200 /// do we have any object (forms/reports) which contains macros?
201 ::std::optional
< EmbeddedMacros
> m_aEmbeddedMacros
;
203 /// true if setting the Modified flag of the document is currently locked
204 bool m_bModificationLock
;
206 /// true if and only if a database document existed previously (though meanwhile disposed), and was already initialized
207 bool m_bDocumentInitialized
;
209 /** the URL which the document should report as its URL
211 This might differ from ->m_sDocFileLocation in case the document was loaded
212 as part of a crash recovery process. In this case, ->m_sDocFileLocation points to
213 the temporary file where the DB had been saved to, after a crash.
214 ->m_sDocumentURL then is the URL of the document which actually had
217 OUString m_sDocumentURL
;
219 SignatureState m_nScriptingSignatureState
;
222 OWeakConnectionArray m_aConnections
;
223 const css::uno::Reference
< css::uno::XComponentContext
> m_aContext
;
226 css::uno::WeakReference
< css::container::XNameAccess
> m_xCommandDefinitions
;
227 unotools::WeakReference
< ::dbaccess::OCommandContainer
> m_xTableDefinitions
;
229 css::uno::Reference
< css::util::XNumberFormatsSupplier
>
230 m_xNumberFormatsSupplier
;
231 OUString m_sConnectURL
;
232 OUString m_sName
; // transient, our creator has to tell us the title
234 OUString m_aPassword
; // transient !
235 OUString m_sFailedPassword
;
236 css::uno::Sequence
< css::beans::PropertyValue
>
237 m_aLayoutInformation
;
238 sal_Int32 m_nLoginTimeout
;
239 bool m_bReadOnly
: 1;
240 bool m_bPasswordRequired
: 1;
241 bool m_bSuppressVersionColumns
: 1;
242 bool m_bModified
: 1;
243 bool m_bDocumentReadOnly
: 1;
244 bool m_bMacroCallsSeenWhileLoading
: 1;
245 css::uno::Reference
< css::beans::XPropertyBag
>
247 css::uno::Sequence
< OUString
> m_aTableFilter
;
248 css::uno::Sequence
< OUString
> m_aTableTypeFilter
;
249 rtl::Reference
< OSharedConnectionManager
> m_xSharedConnectionManager
;
250 css::uno::Reference
<css::awt::XWindow
>
252 sal_uInt16 m_nControllerLockCount
;
256 /** determines whether the database document has an embedded data storage
258 bool isEmbeddedDatabase() const { return m_sConnectURL
.startsWith("sdbc:embedded:"); }
260 /** stores the embedded storage ("database")
262 @param _bPreventRootCommits
263 Normally, committing the embedded storage results in also committing the root storage
264 - this is an automatism for data safety reasons.
265 If you pass <TRUE/> here, committing the root storage is prevented for this particular
267 @return <TRUE/> if the storage could be committed, otherwise <FALSE/>
269 bool commitEmbeddedStorage( bool _bPreventRootCommits
= false );
271 /// commits all sub storages
272 void commitStorages();
275 const css::uno::Reference
< css::uno::XComponentContext
>& _rxContext
,
276 ODatabaseContext
& _pDBContext
278 virtual ~ODatabaseModelImpl();
281 OUString _sRegistrationName
,
282 const css::uno::Reference
< css::uno::XComponentContext
>& _rxContext
,
283 ODatabaseContext
& _rDBContext
287 /// @throws css::uno::RuntimeException
288 void disposing( const css::lang::EventObject
& Source
);
290 void setModified( bool bModified
);
294 const OUString
& getURL() const { return m_sDocumentURL
; }
295 const OUString
& getDocFileLocation() const { return m_sDocFileLocation
; }
297 css::uno::Reference
< css::embed::XStorage
>
298 getStorage( const ObjectType _eType
);
301 const css::uno::Reference
< css::util::XNumberFormatsSupplier
>&
302 getNumberFormatsSupplier();
305 getDocumentEvents() { return m_aDocumentEvents
; }
307 const ::comphelper::NamedValueCollection
&
308 getMediaDescriptor() const { return m_aMediaDescriptor
; }
311 const OUString
& _rURL
,
312 const css::uno::Sequence
< css::beans::PropertyValue
>& _rArgs
314 void setDocFileLocation(
315 const OUString
& i_rLoadedFrom
318 static ::comphelper::NamedValueCollection
319 stripLoadArguments( const ::comphelper::NamedValueCollection
& _rArguments
);
323 // disposes all elements in m_aStorages, and clears it
324 void disposeStorages();
326 /// creates a ->css::embed::StorageFactory
327 css::uno::Reference
< css::lang::XSingleServiceFactory
>
328 createStorageFactory() const;
330 /// commits our storage
331 void commitRootStorage();
333 /// commits a given storage if it's not readonly, ignoring (but asserting) all errors
334 bool commitStorageIfWriteable_ignoreErrors(
335 const css::uno::Reference
< css::embed::XStorage
>& _rxStorage
338 void clearConnections();
340 css::uno::Reference
< css::embed::XStorage
> const & getOrCreateRootStorage();
341 css::uno::Reference
< css::embed::XStorage
> const & getRootStorage() const { return m_xDocumentStorage
.getTyped(); }
342 void resetRootStorage() { impl_switchToStorage_throw( nullptr ); }
344 /** returns the data source. If it doesn't exist it will be created
346 css::uno::Reference
< css::sdbc::XDataSource
> getOrCreateDataSource();
348 /** returns the model, if there already exists one
350 rtl::Reference
< ODatabaseDocument
> getModel_noCreate() const;
352 /** returns a new ->ODatabaseDocument
355 No ->ODatabaseDocument exists so far
360 rtl::Reference
< ODatabaseDocument
> createNewModel_deliverOwnership();
362 struct ResetModelAccess
{ friend class ODatabaseDocument
; private: ResetModelAccess() { } };
364 /** resets the model to NULL
366 Only to be called when the model is being disposed
368 void modelIsDisposing( const bool _wasInitialized
, ResetModelAccess
);
370 bool hadInitializedDocument() const { return m_bDocumentInitialized
; }
372 DocumentStorageAccess
*
373 getDocumentStorageAccess();
375 css::uno::Reference
< css::document::XDocumentSubStorageSupplier
>
376 getDocumentSubStorageSupplier();
382 /// returns all known data source settings, including their default values
383 static std::span
<const DefaultPropertyValue
> getDefaultDataSourceSettings();
385 /** retrieves the requested container of objects (forms/reports/tables/queries)
387 TContentPtr
& getObjectContainer( const ObjectType _eType
);
389 /** returns the name of the storage which is used to stored objects of the given type, if applicable
392 getObjectContainerStorageName( const ObjectType _eType
);
394 /** determines whether a given object storage contains macros
396 static bool objectHasMacros(
397 const css::uno::Reference
< css::embed::XStorage
>& _rxContainerStorage
,
398 const OUString
& _rPersistentName
401 /** determines which kind of embedded macros are present in the document
403 EmbeddedMacros
determineEmbeddedMacros();
405 /** checks our document's macro execution mode, using the interaction handler as supplied with our
408 bool checkMacrosOnLoading();
410 /** adjusts our document's macro execution mode, without using any UI, assuming the user
411 would reject execution of macros, if she would have been asked.
413 If checkMacrosOnLoading has been called before (and thus the macro execution mode
414 is already adjusted), then the current execution mode is simply returned.
417 whether or not macro execution is allowed
419 bool adjustMacroMode_AutoReject();
421 /** resets our macro execute mode, so next time the checkMacrosOnLoading is called, it will
422 behave as if it has never been called before
424 void resetMacroExecutionMode();
426 /** ensures that ->m_xBasicLibraries resp. m_xDialogLibraries exists
429 the requested library container. Is never <NULL/>.
431 @throws RuntimeException
432 if something does wrong, which indicates a server error in the installation
434 css::uno::Reference
< css::script::XStorageBasedLibraryContainer
>
435 getLibraryContainer( bool _bScript
);
437 /** lets our library containers store themselves into the given root storage
439 void storeLibraryContainersTo( const css::uno::Reference
< css::embed::XStorage
>& _rxToRootStorage
);
441 /** rebases the document to the given storage
443 No actual committing, copying, saving, whatsoever happens. The storage is just remembered as the documents
444 new storage, nothing more.
446 @throws css::lang::IllegalArgumentException
447 if the given storage is <NULL/>
448 @throws css::lang::RuntimeException
449 if any of the invoked operations does so
451 css::uno::Reference
< css::embed::XStorage
>
453 const css::uno::Reference
< css::embed::XStorage
>& _rxNewRootStorage
456 /** returns the macro mode imposed by an external instance, which passed it to attachResource
458 sal_Int16
getImposedMacroExecMode() const
460 return m_nImposedMacroExecMode
;
462 void setImposedMacroExecMode( const sal_Int16 _nMacroMode
)
464 m_nImposedMacroExecMode
= _nMacroMode
;
468 // IMacroDocumentAccess overridables
469 virtual sal_Int16
getCurrentMacroExecMode() const override
;
470 virtual void setCurrentMacroExecMode( sal_uInt16
) override
;
471 virtual OUString
getDocumentLocation() const override
;
472 virtual bool documentStorageHasMacros() const override
;
473 virtual bool macroCallsSeenWhileLoading() const override
;
474 virtual css::uno::Reference
< css::document::XEmbeddedScripts
> getEmbeddedDocumentScripts() const override
;
475 virtual SignatureState
getScriptingSignatureState() override
;
476 virtual bool hasTrustedScriptingSignature(
477 const css::uno::Reference
<css::task::XInteractionHandler
>& _rxInteraction
) override
;
479 // IModifiableDocument
480 virtual void storageIsModified() override
;
482 // don't use directly, use the ModifyLock class instead
483 void lockModify() { m_bModificationLock
= true; }
484 void unlockModify() { m_bModificationLock
= false; }
485 bool isModifyLocked() const { return m_bModificationLock
; }
487 weld::Window
* GetFrameWeld();
490 void impl_construct_nothrow();
491 css::uno::Reference
< css::embed::XStorage
> const &
492 impl_switchToStorage_throw( const css::uno::Reference
< css::embed::XStorage
>& _rxNewRootStorage
);
494 /** switches to the given document URL, which denotes the logical URL of the document, not necessarily the
495 URL where the doc was loaded/recovered from
497 void impl_switchToLogicalURL(
498 const OUString
& i_rDocumentURL
503 /** a small base class for UNO components whose functionality depends on an ODatabaseModelImpl
505 class ModelDependentComponent
508 ::rtl::Reference
< ODatabaseModelImpl
> m_pImpl
;
509 ::osl::Mutex m_aMutex
; // only use this to init WeakComponentImplHelper
512 explicit ModelDependentComponent( ::rtl::Reference
< ODatabaseModelImpl
> _model
);
513 virtual ~ModelDependentComponent();
515 /** returns the component itself
517 virtual css::uno::Reference
< css::uno::XInterface
> getThis() const = 0;
519 ::osl::Mutex
& getMutex()
525 /// checks whether the component is already disposed, throws a DisposedException if so
526 void checkDisposed() const
529 throw css::lang::DisposedException( u
"Component is already disposed."_ustr
, getThis() );
534 m_pImpl
->lockModify();
539 m_pImpl
->unlockModify();
546 explicit ModifyLock( ModelDependentComponent
& _component
)
547 :m_rComponent( _component
)
549 m_rComponent
.lockModify();
554 m_rComponent
.unlockModify();
558 ModelDependentComponent
& m_rComponent
;
561 /** a guard for public methods of objects dependent on an ODatabaseModelImpl instance
563 Just put this guard onto the stack at the beginning of your method. Don't bother yourself
564 with a MutexGuard, checks for being disposed, and the like.
566 class ModelMethodGuard
569 // to avoid deadlocks, lock SolarMutex
570 SolarMutexResettableGuard m_SolarGuard
;
573 /** constructs the guard
576 the component whose functionality depends on an ODatabaseModelImpl instance
578 @throws css::lang::DisposedException
579 If the given component is already disposed
581 explicit ModelMethodGuard( const ModelDependentComponent
& _component
)
583 _component
.checkDisposed();
588 // note: this only releases *once* so may still be locked
589 m_SolarGuard
.clear();
594 m_SolarGuard
.reset();
598 } // namespace dbaccess
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */