1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include "commandcontainer.hxx"
21 #include "connection.hxx"
22 #include <databasecontext.hxx>
23 #include "databasedocument.hxx"
24 #include "datasource.hxx"
25 #include <stringconstants.hxx>
26 #include <ModelImpl.hxx>
27 #include <sdbcoretools.hxx>
28 
29 #include <com/sun/star/beans/PropertyBag.hpp>
30 #include <com/sun/star/container/XSet.hpp>
31 #include <com/sun/star/document/MacroExecMode.hpp>
32 #include <com/sun/star/embed/XTransactedObject.hpp>
33 #include <com/sun/star/embed/XTransactionBroadcaster.hpp>
34 #include <com/sun/star/embed/StorageFactory.hpp>
35 #include <com/sun/star/form/XLoadable.hpp>
36 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
37 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
38 #include <com/sun/star/sdb/BooleanComparisonMode.hpp>
39 #include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
40 #include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
41 #include <com/sun/star/util/NumberFormatsSupplier.hpp>
42 
43 #include <connectivity/dbexception.hxx>
44 #include <cppuhelper/exc_hlp.hxx>
45 #include <cppuhelper/implbase.hxx>
46 #include <cppuhelper/typeprovider.hxx>
47 #include <comphelper/types.hxx>
48 #include <rtl/digest.h>
49 #include <sfx2/signaturestate.hxx>
50 #include <tools/debug.hxx>
51 #include <tools/diagnose_ex.h>
52 #include <osl/diagnose.h>
53 #include <sal/log.hxx>
54 #include <vcl/errcode.hxx>
55 #include <tools/urlobj.hxx>
56 #include <unotools/sharedunocomponent.hxx>
57 #include <unotools/configmgr.hxx>
58 #include <i18nlangtag/languagetag.hxx>
59 
60 #include <algorithm>
61 
62 using namespace ::com::sun::star::document;
63 using namespace ::com::sun::star::sdbc;
64 using namespace ::com::sun::star::sdbcx;
65 using namespace ::com::sun::star::sdb;
66 using namespace ::com::sun::star::beans;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::embed;
70 using namespace ::com::sun::star::container;
71 using namespace ::com::sun::star::util;
72 using namespace ::com::sun::star::io;
73 using namespace ::com::sun::star::ucb;
74 using namespace ::com::sun::star::frame;
75 using namespace ::com::sun::star::view;
76 using namespace ::com::sun::star::task;
77 using namespace ::com::sun::star::script;
78 using namespace ::cppu;
79 using namespace ::osl;
80 using namespace ::dbtools;
81 using namespace ::comphelper;
82 
83 namespace dbaccess
84 {
85 
86 // DocumentStorageAccess
87 class DocumentStorageAccess : public ::cppu::WeakImplHelper<   XDocumentSubStorageSupplier
88                                                            ,   XTransactionListener >
89 {
90     typedef std::map< OUString, Reference< XStorage > >    NamedStorages;
91 
92     ::osl::Mutex        m_aMutex;
93     /// all sub storages which we ever gave to the outer world
94     NamedStorages       m_aExposedStorages;
95     ODatabaseModelImpl* m_pModelImplementation;
96     bool                m_bPropagateCommitToRoot;
97     bool                m_bDisposingSubStorages;
98 
99 public:
100     explicit DocumentStorageAccess( ODatabaseModelImpl& _rModelImplementation )
101         :m_pModelImplementation( &_rModelImplementation )
102         ,m_bPropagateCommitToRoot( true )
103         ,m_bDisposingSubStorages( false )
104     {
105     }
106 
107 protected:
108     virtual ~DocumentStorageAccess() override
109     {
110     }
111 
112 public:
113     void dispose();
114 
115     // XDocumentSubStorageSupplier
116     virtual Reference< XStorage > SAL_CALL getDocumentSubStorage( const OUString& aStorageName, ::sal_Int32 _nMode ) override;
117     virtual Sequence< OUString > SAL_CALL getDocumentSubStoragesNames(  ) override;
118 
119     // XTransactionListener
120     virtual void SAL_CALL preCommit( const css::lang::EventObject& aEvent ) override;
121     virtual void SAL_CALL commited( const css::lang::EventObject& aEvent ) override;
122     virtual void SAL_CALL preRevert( const css::lang::EventObject& aEvent ) override;
123     virtual void SAL_CALL reverted( const css::lang::EventObject& aEvent ) override;
124 
125     // XEventListener
126     virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
127 
128     /// disposes all storages managed by this instance
129     void disposeStorages();
130 
131     /// disposes all known sub storages
132     void commitStorages();
133 
134     /// commits the dedicated "database" storage
135     bool commitEmbeddedStorage( bool _bPreventRootCommits );
136 
137 private:
138     /** opens the sub storage with the given name, in the given mode
139     */
140     Reference< XStorage > impl_openSubStorage_nothrow( const OUString& _rStorageName, sal_Int32 _nMode );
141 
142     void impl_suspendCommitPropagation()
143     {
144         OSL_ENSURE( m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_suspendCommitPropagation: already suspended" );
145         m_bPropagateCommitToRoot = false;
146     }
147     void impl_resumeCommitPropagation()
148     {
149         OSL_ENSURE( !m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_resumeCommitPropagation: not suspended" );
150         m_bPropagateCommitToRoot = true;
151     }
152 
153 };
154 
155 void DocumentStorageAccess::dispose()
156 {
157     ::osl::MutexGuard aGuard( m_aMutex );
158 
159     for (auto const& exposedStorage : m_aExposedStorages)
160     {
161         try
162         {
163             Reference< XTransactionBroadcaster > xBroadcaster(exposedStorage.second, UNO_QUERY);
164             if ( xBroadcaster.is() )
165                 xBroadcaster->removeTransactionListener( this );
166         }
167         catch( const Exception& )
168         {
169             DBG_UNHANDLED_EXCEPTION("dbaccess");
170         }
171     }
172 
173     m_aExposedStorages.clear();
174 
175     m_pModelImplementation = nullptr;
176 }
177 
178 Reference< XStorage > DocumentStorageAccess::impl_openSubStorage_nothrow( const OUString& _rStorageName, sal_Int32 _nDesiredMode )
179 {
180     OSL_ENSURE( !_rStorageName.isEmpty(),"ODatabaseModelImpl::impl_openSubStorage_nothrow: Invalid storage name!" );
181 
182     Reference< XStorage > xStorage;
183     try
184     {
185         Reference< XStorage > xRootStorage( m_pModelImplementation->getOrCreateRootStorage() );
186         if ( xRootStorage.is() )
187         {
188             sal_Int32 nRealMode = m_pModelImplementation->m_bDocumentReadOnly ? ElementModes::READ : _nDesiredMode;
189             if ( nRealMode == ElementModes::READ )
190             {
191                 if ( xRootStorage.is() && !xRootStorage->hasByName( _rStorageName ) )
192                     return xStorage;
193             }
194 
195             xStorage = xRootStorage->openStorageElement( _rStorageName, nRealMode );
196 
197             Reference< XTransactionBroadcaster > xBroad( xStorage, UNO_QUERY );
198             if ( xBroad.is() )
199                 xBroad->addTransactionListener( this );
200         }
201     }
202     catch( const Exception& )
203     {
204         DBG_UNHANDLED_EXCEPTION("dbaccess");
205     }
206 
207     return xStorage;
208 }
209 
210 void DocumentStorageAccess::disposeStorages()
211 {
212     m_bDisposingSubStorages = true;
213 
214     for (auto & exposedStorage : m_aExposedStorages)
215     {
216         try
217         {
218             ::comphelper::disposeComponent( exposedStorage.second );
219         }
220         catch( const Exception& )
221         {
222             DBG_UNHANDLED_EXCEPTION("dbaccess");
223         }
224     }
225     m_aExposedStorages.clear();
226 
227     m_bDisposingSubStorages = false;
228 }
229 
230 void DocumentStorageAccess::commitStorages()
231 {
232     try
233     {
234         for (auto const& exposedStorage : m_aExposedStorages)
235         {
236             tools::stor::commitStorageIfWriteable( exposedStorage.second );
237         }
238     }
239     catch(const WrappedTargetException&)
240     {
241         // WrappedTargetException not allowed to leave
242         throw IOException();
243     }
244 }
245 
246 bool DocumentStorageAccess::commitEmbeddedStorage( bool _bPreventRootCommits )
247 {
248     if ( _bPreventRootCommits )
249         impl_suspendCommitPropagation();
250 
251     bool bSuccess = false;
252     try
253     {
254         NamedStorages::const_iterator pos = m_aExposedStorages.find( "database" );
255         if ( pos != m_aExposedStorages.end() )
256             bSuccess = tools::stor::commitStorageIfWriteable( pos->second );
257     }
258     catch( Exception& )
259     {
260         DBG_UNHANDLED_EXCEPTION("dbaccess");
261     }
262 
263     if ( _bPreventRootCommits )
264         impl_resumeCommitPropagation();
265 
266     return bSuccess;
267 
268 }
269 
270 Reference< XStorage > SAL_CALL DocumentStorageAccess::getDocumentSubStorage( const OUString& aStorageName, ::sal_Int32 _nDesiredMode )
271 {
272     ::osl::MutexGuard aGuard( m_aMutex );
273     NamedStorages::const_iterator pos = m_aExposedStorages.find( aStorageName );
274     if ( pos == m_aExposedStorages.end() )
275     {
276         Reference< XStorage > xResult = impl_openSubStorage_nothrow( aStorageName, _nDesiredMode );
277         pos = m_aExposedStorages.emplace( aStorageName, xResult ).first;
278     }
279 
280     return pos->second;
281 }
282 
283 Sequence< OUString > SAL_CALL DocumentStorageAccess::getDocumentSubStoragesNames(  )
284 {
285     Reference< XStorage > xRootStor( m_pModelImplementation->getRootStorage() );
286     if ( !xRootStor.is() )
287         return Sequence< OUString >();
288 
289     std::vector< OUString > aNames;
290 
291     Sequence< OUString > aElementNames( xRootStor->getElementNames() );
292     for ( sal_Int32 i=0; i<aElementNames.getLength(); ++i )
293     {
294         if ( xRootStor->isStorageElement( aElementNames[i] ) )
295             aNames.push_back( aElementNames[i] );
296     }
297     return aNames.empty()
298         ?  Sequence< OUString >()
299         :  Sequence< OUString >( &aNames[0], aNames.size() );
300 }
301 
302 void SAL_CALL DocumentStorageAccess::preCommit( const css::lang::EventObject& /*aEvent*/ )
303 {
304     // not interested in
305 }
306 
307 void SAL_CALL DocumentStorageAccess::commited( const css::lang::EventObject& aEvent )
308 {
309     ::osl::MutexGuard aGuard( m_aMutex );
310 
311     if ( m_pModelImplementation )
312         m_pModelImplementation->setModified( true );
313 
314     if ( m_pModelImplementation && m_bPropagateCommitToRoot )
315     {
316         Reference< XStorage > xStorage( aEvent.Source, UNO_QUERY );
317 
318         // check if this is the dedicated "database" sub storage
319         NamedStorages::const_iterator pos = m_aExposedStorages.find( "database" );
320         if  (   ( pos != m_aExposedStorages.end() )
321             &&  ( pos->second == xStorage )
322             )
323         {
324             // if so, also commit the root storage
325             m_pModelImplementation->commitRootStorage();
326         }
327     }
328 }
329 
330 void SAL_CALL DocumentStorageAccess::preRevert( const css::lang::EventObject& /*aEvent*/ )
331 {
332     // not interested in
333 }
334 
335 void SAL_CALL DocumentStorageAccess::reverted( const css::lang::EventObject& /*aEvent*/ )
336 {
337     // not interested in
338 }
339 
340 void SAL_CALL DocumentStorageAccess::disposing( const css::lang::EventObject& Source )
341 {
342     OSL_ENSURE( Reference< XStorage >( Source.Source, UNO_QUERY ).is(), "DocumentStorageAccess::disposing: No storage? What's this?" );
343 
344     if ( m_bDisposingSubStorages )
345         return;
346 
347     auto find = std::find_if(m_aExposedStorages.begin(), m_aExposedStorages.end(),
348         [&Source](const NamedStorages::value_type& rEntry) { return rEntry.second == Source.Source; });
349     if (find != m_aExposedStorages.end())
350         m_aExposedStorages.erase( find );
351 }
352 
353 // ODatabaseModelImpl
354 
355 ODatabaseModelImpl::ODatabaseModelImpl( const Reference< XComponentContext >& _rxContext, ODatabaseContext& _rDBContext )
356             :m_xModel()
357             ,m_xDataSource()
358             ,m_aContainer(4)
359             ,m_aMacroMode( *this )
360             ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE )
361             ,m_rDBContext( _rDBContext )
362             ,m_refCount(0)
363             ,m_aEmbeddedMacros()
364             ,m_bModificationLock( false )
365             ,m_bDocumentInitialized( false )
366             ,m_aContext( _rxContext )
367             ,m_nLoginTimeout(0)
368             ,m_bReadOnly(false)
369             ,m_bPasswordRequired(false)
370             ,m_bSuppressVersionColumns(true)
371             ,m_bModified(false)
372             ,m_bDocumentReadOnly(false)
373             ,m_pSharedConnectionManager(nullptr)
374             ,m_nControllerLockCount(0)
375 {
376     // some kind of default
377     m_sConnectURL = "jdbc:";
378     m_aTableFilter.realloc(1);
379     m_aTableFilter[0] = "%";
380     impl_construct_nothrow();
381 }
382 
383 ODatabaseModelImpl::ODatabaseModelImpl(
384                     const OUString& _rRegistrationName,
385                     const Reference< XComponentContext >& _rxContext,
386                     ODatabaseContext& _rDBContext
387                     )
388             :m_xModel()
389             ,m_xDataSource()
390             ,m_aContainer(4)
391             ,m_aMacroMode( *this )
392             ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE )
393             ,m_rDBContext( _rDBContext )
394             ,m_refCount(0)
395             ,m_aEmbeddedMacros()
396             ,m_bModificationLock( false )
397             ,m_bDocumentInitialized( false )
398             ,m_aContext( _rxContext )
399             ,m_sName(_rRegistrationName)
400             ,m_nLoginTimeout(0)
401             ,m_bReadOnly(false)
402             ,m_bPasswordRequired(false)
403             ,m_bSuppressVersionColumns(true)
404             ,m_bModified(false)
405             ,m_bDocumentReadOnly(false)
406             ,m_pSharedConnectionManager(nullptr)
407             ,m_nControllerLockCount(0)
408 {
409     impl_construct_nothrow();
410 }
411 
412 ODatabaseModelImpl::~ODatabaseModelImpl()
413 {
414 }
415 
416 void ODatabaseModelImpl::impl_construct_nothrow()
417 {
418     // create the property bag to hold the settings (also known as "Info" property)
419     try
420     {
421         // the set of property value types in the bag is limited:
422         Sequence< Type > aAllowedTypes({
423              cppu::UnoType<sal_Bool>::get(),
424              cppu::UnoType<double>::get(),
425              cppu::UnoType<OUString>::get(),
426              cppu::UnoType<sal_Int32>::get(),
427              cppu::UnoType<sal_Int16>::get(),
428              cppu::UnoType<Sequence< Any >>::get(),
429         });
430 
431         m_xSettings = PropertyBag::createWithTypes( m_aContext, aAllowedTypes, false/*AllowEmptyPropertyName*/, true/*AutomaticAddition*/ );
432 
433         // insert the default settings
434         Reference< XPropertyContainer > xContainer( m_xSettings, UNO_QUERY_THROW );
435         Reference< XSet > xSettingsSet( m_xSettings, UNO_QUERY_THROW );
436         const AsciiPropertyValue* pSettings = getDefaultDataSourceSettings();
437         for ( ; pSettings->AsciiName; ++pSettings )
438         {
439             if ( !pSettings->DefaultValue.hasValue() )
440             {
441                 Property aProperty(
442                     OUString::createFromAscii( pSettings->AsciiName ),
443                     -1,
444                     pSettings->ValueType,
445                     PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT | PropertyAttribute::MAYBEVOID
446                 );
447                 xSettingsSet->insert( makeAny( aProperty ) );
448             }
449             else
450             {
451                 xContainer->addProperty(
452                     OUString::createFromAscii( pSettings->AsciiName ),
453                     PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
454                     pSettings->DefaultValue
455                 );
456             }
457         }
458     }
459     catch( const Exception& )
460     {
461         DBG_UNHANDLED_EXCEPTION("dbaccess");
462     }
463     m_rDBContext.appendAtTerminateListener(*this);
464 }
465 
466 namespace
467 {
468     OUString lcl_getContainerStorageName_throw( ODatabaseModelImpl::ObjectType _eType )
469     {
470         const sal_Char* pAsciiName( nullptr );
471         switch ( _eType )
472         {
473         case ODatabaseModelImpl::E_FORM:   pAsciiName = "forms"; break;
474         case ODatabaseModelImpl::E_REPORT: pAsciiName = "reports"; break;
475         case ODatabaseModelImpl::E_QUERY:  pAsciiName = "queries"; break;
476         case ODatabaseModelImpl::E_TABLE:  pAsciiName = "tables"; break;
477         default:
478             throw RuntimeException();
479         }
480         return OUString::createFromAscii( pAsciiName );
481     }
482 
483     bool lcl_hasObjectWithMacros_throw( const ODefinitionContainer_Impl& _rObjectDefinitions, const Reference< XStorage >& _rxContainerStorage )
484     {
485         bool bSomeDocHasMacros = false;
486 
487         for (auto const& objectDefinition : _rObjectDefinitions)
488         {
489             const TContentPtr& rDefinition( objectDefinition.second );
490             const OUString& rPersistentName( rDefinition->m_aProps.sPersistentName );
491 
492             if ( rPersistentName.isEmpty() )
493             {   // it's a logical sub folder used to organize the real objects
494                 const ODefinitionContainer_Impl& rSubFoldersObjectDefinitions( dynamic_cast< const ODefinitionContainer_Impl& >( *rDefinition ) );
495                 bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rSubFoldersObjectDefinitions, _rxContainerStorage );
496                 if (bSomeDocHasMacros)
497                     break;
498                 continue;
499             }
500 
501             bSomeDocHasMacros = ODatabaseModelImpl::objectHasMacros( _rxContainerStorage, rPersistentName );
502             if (bSomeDocHasMacros)
503                 break;
504         }
505         return bSomeDocHasMacros;
506     }
507 
508     bool lcl_hasObjectsWithMacros_nothrow( ODatabaseModelImpl& _rModel, const ODatabaseModelImpl::ObjectType _eType )
509     {
510         bool bSomeDocHasMacros = false;
511 
512         const OContentHelper_Impl& rContainerData( *_rModel.getObjectContainer( _eType ).get() );
513         const ODefinitionContainer_Impl& rObjectDefinitions = dynamic_cast< const ODefinitionContainer_Impl& >( rContainerData );
514 
515         try
516         {
517             Reference< XStorage > xContainerStorage( _rModel.getStorage( _eType ) );
518             // note the READWRITE here: If the storage already existed before, then the OpenMode will
519             // be ignored, anyway.
520             // If the storage did not yet exist, then it will be created. If the database document
521             // is read-only, the OpenMode will be automatically downgraded to READ. Otherwise,
522             // the storage will in fact be created as READWRITE. While this is not strictly necessary
523             // for this particular use case here, it is required since the storage is *cached*, and
524             // later use cases will need the READWRITE mode.
525 
526             if ( xContainerStorage.is() )
527                 bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rObjectDefinitions, xContainerStorage );
528         }
529         catch( const Exception& )
530         {
531             DBG_UNHANDLED_EXCEPTION("dbaccess");
532             // be on the safe side: If we can't reliably determine whether there are macros,
533             // assume there actually are. Better this way, than the other way round.
534             bSomeDocHasMacros = true;
535         }
536 
537         return bSomeDocHasMacros;
538     }
539 }
540 
541 bool ODatabaseModelImpl::objectHasMacros( const Reference< XStorage >& _rxContainerStorage, const OUString& _rPersistentName )
542 {
543     OSL_PRECOND( _rxContainerStorage.is(), "ODatabaseModelImpl::objectHasMacros: this will crash!" );
544 
545     bool bHasMacros = true;
546     try
547     {
548         if ( !_rxContainerStorage->hasByName( _rPersistentName ) )
549             return false;
550 
551         Reference< XStorage > xObjectStor( _rxContainerStorage->openStorageElement(
552             _rPersistentName, ElementModes::READ ) );
553 
554         bHasMacros = ::sfx2::DocumentMacroMode::storageHasMacros( xObjectStor );
555     }
556     catch( const Exception& )
557     {
558         DBG_UNHANDLED_EXCEPTION("dbaccess");
559     }
560     return bHasMacros;
561 }
562 
563 void ODatabaseModelImpl::reset()
564 {
565     m_bReadOnly = false;
566     std::vector< TContentPtr > aEmptyContainers( 4 );
567     m_aContainer.swap( aEmptyContainers );
568 
569     if ( m_pStorageAccess.is() )
570     {
571         m_pStorageAccess->dispose();
572         m_pStorageAccess.clear();
573     }
574 }
575 
576 void ODatabaseModelImpl::disposing( const css::lang::EventObject& Source )
577 {
578     Reference<XConnection> xCon(Source.Source,UNO_QUERY);
579     if ( xCon.is() )
580     {
581         bool bStore = false;
582         for (OWeakConnectionArray::iterator i = m_aConnections.begin(); i != m_aConnections.end(); )
583         {
584             css::uno::Reference< css::sdbc::XConnection > xIterConn ( *i );
585             if ( !xIterConn.is())
586             {
587                 i = m_aConnections.erase(i);
588             }
589             else if ( xCon == xIterConn )
590             {
591                 *i = css::uno::WeakReference< css::sdbc::XConnection >();
592                 bStore = true;
593                 break;
594             } else
595                 ++i;
596         }
597 
598         if ( bStore )
599             commitRootStorage();
600     }
601     else
602     {
603         OSL_FAIL( "ODatabaseModelImpl::disposing: where does this come from?" );
604     }
605 }
606 
607 void ODatabaseModelImpl::clearConnections()
608 {
609     OWeakConnectionArray aConnections;
610     aConnections.swap( m_aConnections );
611 
612     Reference< XConnection > xConn;
613     for (auto const& connection : aConnections)
614     {
615         xConn = connection;
616         if ( xConn.is() )
617         {
618             try
619             {
620                 xConn->close();
621             }
622             catch(const Exception&)
623             {
624                 DBG_UNHANDLED_EXCEPTION("dbaccess");
625             }
626         }
627     }
628 
629     m_pSharedConnectionManager = nullptr;
630     m_xSharedConnectionManager = nullptr;
631 }
632 
633 void ODatabaseModelImpl::dispose()
634 {
635     // dispose the data source and the model
636     try
637     {
638         Reference< XDataSource > xDS( m_xDataSource );
639         ::comphelper::disposeComponent( xDS );
640 
641         Reference< XModel > xModel( m_xModel );
642         ::comphelper::disposeComponent( xModel );
643     }
644     catch( const Exception& )
645     {
646         DBG_UNHANDLED_EXCEPTION("dbaccess");
647     }
648     m_xDataSource = WeakReference<XDataSource>();
649     m_xModel = WeakReference< XModel >();
650 
651     for (auto const& elem : m_aContainer)
652     {
653         if ( elem.get() )
654             elem->m_pDataSource = nullptr;
655     }
656     m_aContainer.clear();
657 
658     clearConnections();
659 
660     m_xNumberFormatsSupplier = nullptr;
661 
662     try
663     {
664         bool bCouldStore = commitEmbeddedStorage( true );
665             // "true" means that committing the embedded storage should not trigger committing the root
666             // storage. This is because we are going to commit the root storage ourself, anyway
667         disposeStorages();
668         if ( bCouldStore )
669             commitRootStorage();
670 
671         impl_switchToStorage_throw( nullptr );
672     }
673     catch( const Exception& )
674     {
675         DBG_UNHANDLED_EXCEPTION("dbaccess");
676     }
677 
678     if ( m_pStorageAccess.is() )
679     {
680         m_pStorageAccess->dispose();
681         m_pStorageAccess.clear();
682     }
683 }
684 
685 const Reference< XNumberFormatsSupplier > & ODatabaseModelImpl::getNumberFormatsSupplier()
686 {
687     if (!m_xNumberFormatsSupplier.is())
688     {
689         // the arguments : the work locale of the current user
690         Locale aLocale( LanguageTag::convertToLocale( utl::ConfigManager::getWorkLocale(), false));
691 
692         m_xNumberFormatsSupplier.set( NumberFormatsSupplier::createWithLocale( m_aContext, aLocale ) );
693     }
694     return m_xNumberFormatsSupplier;
695 }
696 
697 void ODatabaseModelImpl::setDocFileLocation( const OUString& i_rLoadedFrom )
698 {
699     ENSURE_OR_THROW( !i_rLoadedFrom.isEmpty(), "invalid URL" );
700     m_sDocFileLocation = i_rLoadedFrom;
701 }
702 
703 void ODatabaseModelImpl::setResource( const OUString& i_rDocumentURL, const Sequence< PropertyValue >& _rArgs )
704 {
705     ENSURE_OR_THROW( !i_rDocumentURL.isEmpty(), "invalid URL" );
706 
707     ::comphelper::NamedValueCollection aMediaDescriptor( _rArgs );
708 #if OSL_DEBUG_LEVEL > 0
709     if ( aMediaDescriptor.has( "SalvagedFile" ) )
710     {
711         OUString sSalvagedFile( aMediaDescriptor.getOrDefault( "SalvagedFile", OUString() ) );
712         // If SalvagedFile is an empty string, this indicates "the document is being recovered, but i_rDocumentURL already
713         // is the real document URL, not the temporary document location"
714         if ( sSalvagedFile.isEmpty() )
715             sSalvagedFile = i_rDocumentURL;
716 
717         OSL_ENSURE( sSalvagedFile == i_rDocumentURL, "ODatabaseModelImpl::setResource: inconsistency!" );
718             // nowadays, setResource should only be called with the logical URL of the document
719     }
720 #endif
721 
722     m_aMediaDescriptor = stripLoadArguments( aMediaDescriptor );
723 
724     impl_switchToLogicalURL( i_rDocumentURL );
725 }
726 
727 ::comphelper::NamedValueCollection ODatabaseModelImpl::stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments )
728 {
729     OSL_ENSURE( !_rArguments.has( "Model" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (1)!" );
730     OSL_ENSURE( !_rArguments.has( "ViewName" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (2)!" );
731 
732     ::comphelper::NamedValueCollection aMutableArgs( _rArguments );
733     aMutableArgs.remove( "Model" );
734     aMutableArgs.remove( "ViewName" );
735     return aMutableArgs;
736 }
737 
738 void ODatabaseModelImpl::disposeStorages()
739 {
740     getDocumentStorageAccess()->disposeStorages();
741 }
742 
743 Reference< XSingleServiceFactory > ODatabaseModelImpl::createStorageFactory() const
744 {
745     return StorageFactory::create( m_aContext );
746 }
747 
748 void ODatabaseModelImpl::commitRootStorage()
749 {
750     Reference< XStorage > xStorage( getOrCreateRootStorage() );
751     bool bSuccess = commitStorageIfWriteable_ignoreErrors( xStorage );
752     SAL_WARN_IF(!bSuccess && xStorage.is(), "dbaccess",
753         "ODatabaseModelImpl::commitRootStorage: could not commit the storage!");
754 }
755 
756 Reference< XStorage > const & ODatabaseModelImpl::getOrCreateRootStorage()
757 {
758     if ( !m_xDocumentStorage.is() )
759     {
760         Reference< XSingleServiceFactory> xStorageFactory = StorageFactory::create( m_aContext );
761         Any aSource;
762         aSource = m_aMediaDescriptor.get( "Stream" );
763         if ( !aSource.hasValue() )
764             aSource = m_aMediaDescriptor.get( "InputStream" );
765         if ( !aSource.hasValue() && !m_sDocFileLocation.isEmpty() )
766             aSource <<= m_sDocFileLocation;
767         // TODO: shouldn't we also check URL?
768 
769         OSL_ENSURE( aSource.hasValue(), "ODatabaseModelImpl::getOrCreateRootStorage: no source to create the storage from!" );
770 
771         if ( aSource.hasValue() )
772         {
773             Sequence< Any > aStorageCreationArgs(2);
774             aStorageCreationArgs[0] = aSource;
775             aStorageCreationArgs[1] <<= ElementModes::READWRITE;
776 
777             Reference< XStorage > xDocumentStorage;
778             OUString sURL;
779             aSource >>= sURL;
780             // Don't try to load a meta-URL as-is.
781             if (!sURL.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:"))
782             {
783                 try
784                 {
785                     xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW );
786                 }
787                 catch( const Exception& )
788                 {
789                     m_bDocumentReadOnly = true;
790                     aStorageCreationArgs[1] <<= ElementModes::READ;
791                     try
792                     {
793                         xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW );
794                     }
795                     catch( const Exception& )
796                     {
797                         DBG_UNHANDLED_EXCEPTION("dbaccess");
798                     }
799                 }
800             }
801 
802             impl_switchToStorage_throw( xDocumentStorage );
803         }
804     }
805     return m_xDocumentStorage.getTyped();
806 }
807 
808 DocumentStorageAccess* ODatabaseModelImpl::getDocumentStorageAccess()
809 {
810     if ( !m_pStorageAccess.is() )
811     {
812         m_pStorageAccess = new DocumentStorageAccess( *this );
813     }
814     return m_pStorageAccess.get();
815 }
816 
817 void ODatabaseModelImpl::modelIsDisposing( const bool _wasInitialized, ResetModelAccess )
818 {
819     m_xModel.clear();
820 
821     // Basic libraries and Dialog libraries are a model facet, though held at this impl class.
822     // They automatically dispose themself when the model they belong to is being disposed.
823     // So, to not be tempted to do anything with them, again, we reset them.
824     m_xBasicLibraries.clear();
825     m_xDialogLibraries.clear();
826 
827     m_bDocumentInitialized = _wasInitialized;
828 }
829 
830 Reference< XDocumentSubStorageSupplier > ODatabaseModelImpl::getDocumentSubStorageSupplier()
831 {
832     return getDocumentStorageAccess();
833 }
834 
835 bool ODatabaseModelImpl::commitEmbeddedStorage( bool _bPreventRootCommits )
836 {
837     return getDocumentStorageAccess()->commitEmbeddedStorage( _bPreventRootCommits );
838 }
839 
840 bool ODatabaseModelImpl::commitStorageIfWriteable_ignoreErrors( const Reference< XStorage >& _rxStorage )
841 {
842     bool bSuccess = false;
843     try
844     {
845         bSuccess = tools::stor::commitStorageIfWriteable( _rxStorage );
846     }
847     catch( const Exception& )
848     {
849         DBG_UNHANDLED_EXCEPTION("dbaccess");
850     }
851     return bSuccess;
852 }
853 
854 void ODatabaseModelImpl::setModified( bool _bModified )
855 {
856     if ( isModifyLocked() )
857         return;
858 
859     try
860     {
861         Reference< XModifiable > xModi( m_xModel.get(), UNO_QUERY );
862         if ( xModi.is() )
863             xModi->setModified( _bModified );
864         else
865             m_bModified = _bModified;
866     }
867     catch( const Exception& )
868     {
869         DBG_UNHANDLED_EXCEPTION("dbaccess");
870     }
871 }
872 
873 Reference<XDataSource> ODatabaseModelImpl::getOrCreateDataSource()
874 {
875     Reference<XDataSource> xDs = m_xDataSource;
876     if ( !xDs.is() )
877     {
878         xDs = new ODatabaseSource(this);
879         m_xDataSource = xDs;
880     }
881     return xDs;
882 }
883 
884 Reference< XModel> ODatabaseModelImpl::getModel_noCreate() const
885 {
886     return m_xModel;
887 }
888 
889 Reference< XModel > ODatabaseModelImpl::createNewModel_deliverOwnership()
890 {
891     Reference< XModel > xModel( m_xModel );
892     OSL_PRECOND( !xModel.is(), "ODatabaseModelImpl::createNewModel_deliverOwnership: not to be called if there already is a model!" );
893     if ( !xModel.is() )
894     {
895         bool bHadModelBefore = m_bDocumentInitialized;
896 
897         xModel = ODatabaseDocument::createDatabaseDocument( this, ODatabaseDocument::FactoryAccess() );
898         m_xModel = xModel;
899 
900         try
901         {
902             Reference< XGlobalEventBroadcaster > xModelCollection = theGlobalEventBroadcaster::get( m_aContext );
903             xModelCollection->insert( makeAny( xModel ) );
904         }
905         catch( const Exception& )
906         {
907             DBG_UNHANDLED_EXCEPTION("dbaccess");
908         }
909 
910         if ( bHadModelBefore )
911         {
912             // do an attachResources
913             // In case the document is loaded regularly, this is not necessary, as our loader will do it.
914             // However, in case that the document is implicitly created by asking the data source for the document,
915             // then nobody would call the doc's attachResource. So, we do it here, to ensure it's in a proper
916             // state, fires all events, and so on.
917             // #i105505#
918             xModel->attachResource( xModel->getURL(), m_aMediaDescriptor.getPropertyValues() );
919         }
920     }
921     return xModel;
922 }
923 
924 void ODatabaseModelImpl::acquire()
925 {
926     osl_atomic_increment(&m_refCount);
927 }
928 
929 void ODatabaseModelImpl::release()
930 {
931     if ( osl_atomic_decrement(&m_refCount) == 0 )
932     {
933         acquire();  // prevent multiple releases
934         m_rDBContext.removeFromTerminateListener(*this);
935         dispose();
936         m_rDBContext.storeTransientProperties(*this);
937         if (!m_sDocumentURL.isEmpty())
938             m_rDBContext.revokeDatabaseDocument(*this);
939         delete this;
940     }
941 }
942 
943 void ODatabaseModelImpl::commitStorages()
944 {
945     getDocumentStorageAccess()->commitStorages();
946 }
947 
948 Reference< XStorage > ODatabaseModelImpl::getStorage( const ObjectType _eType )
949 {
950     return getDocumentStorageAccess()->getDocumentSubStorage( getObjectContainerStorageName( _eType ),
951                     css::embed::ElementModes::READWRITE );
952 }
953 
954 const AsciiPropertyValue* ODatabaseModelImpl::getDefaultDataSourceSettings()
955 {
956     static const AsciiPropertyValue aKnownSettings[] =
957     {
958         // known JDBC settings
959         AsciiPropertyValue( "JavaDriverClass",            makeAny( OUString() ) ),
960         AsciiPropertyValue( "JavaDriverClassPath",        makeAny( OUString() ) ),
961         AsciiPropertyValue( "IgnoreCurrency",             makeAny( false ) ),
962         // known settings for file-based drivers
963         AsciiPropertyValue( "Extension",                  makeAny( OUString() ) ),
964         AsciiPropertyValue( "CharSet",                    makeAny( OUString() ) ),
965         AsciiPropertyValue( "HeaderLine",                 makeAny( true ) ),
966         AsciiPropertyValue( "FieldDelimiter",             makeAny( OUString( "," ) ) ),
967         AsciiPropertyValue( "StringDelimiter",            makeAny( OUString( "\"" ) ) ),
968         AsciiPropertyValue( "DecimalDelimiter",           makeAny( OUString( "." ) ) ),
969         AsciiPropertyValue( "ThousandDelimiter",          makeAny( OUString() ) ),
970         AsciiPropertyValue( "ShowDeleted",                makeAny( false ) ),
971         // known ODBC settings
972         AsciiPropertyValue( "SystemDriverSettings",       makeAny( OUString() ) ),
973         AsciiPropertyValue( "UseCatalog",                 makeAny( false ) ),
974         AsciiPropertyValue( "TypeInfoSettings",           makeAny( Sequence< Any >()) ),
975         // settings related to auto increment handling
976         AsciiPropertyValue( "AutoIncrementCreation",      makeAny( OUString() ) ),
977         AsciiPropertyValue( "AutoRetrievingStatement",    makeAny( OUString() ) ),
978         AsciiPropertyValue( "IsAutoRetrievingEnabled",    makeAny( false ) ),
979         // known LDAP driver settings
980         AsciiPropertyValue( "HostName",                   makeAny( OUString() ) ),
981         AsciiPropertyValue( "PortNumber",                 makeAny( sal_Int32(389) ) ),
982         AsciiPropertyValue( "BaseDN",                     makeAny( OUString() ) ),
983         AsciiPropertyValue( "MaxRowCount",                makeAny( sal_Int32(100) ) ),
984         // known MySQLNative driver settings
985         AsciiPropertyValue( "LocalSocket",                makeAny( OUString() ) ),
986         AsciiPropertyValue( "NamedPipe",                  makeAny( OUString() ) ),
987         // misc known driver settings
988         AsciiPropertyValue( "ParameterNameSubstitution",  makeAny( false ) ),
989         AsciiPropertyValue( "AddIndexAppendix",           makeAny( true ) ),
990         AsciiPropertyValue( "IgnoreDriverPrivileges",     makeAny( true ) ),
991         AsciiPropertyValue( "ImplicitCatalogRestriction", ::cppu::UnoType< OUString >::get() ),
992         AsciiPropertyValue( "ImplicitSchemaRestriction",  ::cppu::UnoType< OUString >::get() ),
993         AsciiPropertyValue( "PrimaryKeySupport",          ::cppu::UnoType< sal_Bool >::get() ),
994         AsciiPropertyValue( "ShowColumnDescription",      makeAny( false ) ),
995         // known SDB level settings
996         AsciiPropertyValue( "NoNameLengthLimit",          makeAny( false ) ),
997         AsciiPropertyValue( "AppendTableAliasName",       makeAny( false ) ),
998         AsciiPropertyValue( "GenerateASBeforeCorrelationName",  makeAny( false ) ),
999         AsciiPropertyValue( "ColumnAliasInOrderBy",       makeAny( true ) ),
1000         AsciiPropertyValue( "EnableSQL92Check",           makeAny( false ) ),
1001         AsciiPropertyValue( "BooleanComparisonMode",      makeAny( BooleanComparisonMode::EQUAL_INTEGER ) ),
1002         AsciiPropertyValue( "TableTypeFilterMode",        makeAny( sal_Int32(3) ) ),
1003         AsciiPropertyValue( "RespectDriverResultSetType", makeAny( false ) ),
1004         AsciiPropertyValue( "UseSchemaInSelect",          makeAny( true ) ),
1005         AsciiPropertyValue( "UseCatalogInSelect",         makeAny( true ) ),
1006         AsciiPropertyValue( "EnableOuterJoinEscape",      makeAny( true ) ),
1007         AsciiPropertyValue( "PreferDosLikeLineEnds",      makeAny( false ) ),
1008         AsciiPropertyValue( "FormsCheckRequiredFields",   makeAny( true ) ),
1009         AsciiPropertyValue( "EscapeDateTime",             makeAny( true ) ),
1010 
1011         // known services to handle database tasks
1012         AsciiPropertyValue( "TableAlterationServiceName", makeAny( OUString() ) ),
1013         AsciiPropertyValue( "TableRenameServiceName",     makeAny( OUString() ) ),
1014         AsciiPropertyValue( "ViewAlterationServiceName",  makeAny( OUString() ) ),
1015         AsciiPropertyValue( "ViewAccessServiceName",      makeAny( OUString() ) ),
1016         AsciiPropertyValue( "CommandDefinitions",         makeAny( OUString() ) ),
1017         AsciiPropertyValue( "Forms",                      makeAny( OUString() ) ),
1018         AsciiPropertyValue( "Reports",                    makeAny( OUString() ) ),
1019         AsciiPropertyValue( "KeyAlterationServiceName",   makeAny( OUString() ) ),
1020         AsciiPropertyValue( "IndexAlterationServiceName", makeAny( OUString() ) ),
1021 
1022         AsciiPropertyValue()
1023     };
1024     return aKnownSettings;
1025 }
1026 
1027 TContentPtr& ODatabaseModelImpl::getObjectContainer( ObjectType _eType )
1028 {
1029     OSL_PRECOND( _eType >= E_FORM && _eType <= E_TABLE, "ODatabaseModelImpl::getObjectContainer: illegal index!" );
1030     TContentPtr& rContentPtr = m_aContainer[ _eType ];
1031 
1032     if ( !rContentPtr.get() )
1033     {
1034         rContentPtr = TContentPtr( new ODefinitionContainer_Impl );
1035         rContentPtr->m_pDataSource = this;
1036         rContentPtr->m_aProps.aTitle = lcl_getContainerStorageName_throw( _eType );
1037     }
1038     return rContentPtr;
1039 }
1040 
1041 bool ODatabaseModelImpl::adjustMacroMode_AutoReject()
1042 {
1043     return m_aMacroMode.adjustMacroMode( nullptr );
1044 }
1045 
1046 bool ODatabaseModelImpl::checkMacrosOnLoading()
1047 {
1048     Reference< XInteractionHandler > xInteraction;
1049     xInteraction = m_aMediaDescriptor.getOrDefault( "InteractionHandler", xInteraction );
1050     return m_aMacroMode.checkMacrosOnLoading( xInteraction );
1051 }
1052 
1053 void ODatabaseModelImpl::resetMacroExecutionMode()
1054 {
1055     m_aMacroMode = ::sfx2::DocumentMacroMode( *this );
1056 }
1057 
1058 Reference< XStorageBasedLibraryContainer > ODatabaseModelImpl::getLibraryContainer( bool _bScript )
1059 {
1060     Reference< XStorageBasedLibraryContainer >& rxContainer( _bScript ? m_xBasicLibraries : m_xDialogLibraries );
1061     if ( rxContainer.is() )
1062         return rxContainer;
1063 
1064     Reference< XStorageBasedDocument > xDocument( getModel_noCreate(), UNO_QUERY_THROW );
1065         // this is only to be called if there already exists a document model - in fact, it is
1066         // to be called by the document model only
1067 
1068     try
1069     {
1070         Reference< XStorageBasedLibraryContainer > (*Factory)( const Reference< XComponentContext >&, const Reference< XStorageBasedDocument >&)
1071             = _bScript ? &DocumentScriptLibraryContainer::create : &DocumentDialogLibraryContainer::create;
1072 
1073         rxContainer.set(
1074             (*Factory)( m_aContext, xDocument ),
1075             UNO_QUERY_THROW
1076         );
1077     }
1078     catch( const RuntimeException& )
1079     {
1080         throw;
1081     }
1082     catch( const Exception& )
1083     {
1084         throw WrappedTargetRuntimeException(
1085             OUString(),
1086             xDocument,
1087             ::cppu::getCaughtException()
1088         );
1089     }
1090     return rxContainer;
1091 }
1092 
1093 void ODatabaseModelImpl::storeLibraryContainersTo( const Reference< XStorage >& _rxToRootStorage )
1094 {
1095     if ( m_xBasicLibraries.is() )
1096         m_xBasicLibraries->storeLibrariesToStorage( _rxToRootStorage );
1097 
1098     if ( m_xDialogLibraries.is() )
1099         m_xDialogLibraries->storeLibrariesToStorage( _rxToRootStorage );
1100 }
1101 
1102 Reference< XStorage > ODatabaseModelImpl::switchToStorage( const Reference< XStorage >& _rxNewRootStorage )
1103 {
1104     if ( !_rxNewRootStorage.is() )
1105         throw IllegalArgumentException();
1106 
1107     return impl_switchToStorage_throw( _rxNewRootStorage );
1108 }
1109 
1110 namespace
1111 {
1112     void lcl_modifyListening( ::sfx2::IModifiableDocument& _rDocument,
1113         const Reference< XStorage >& _rxStorage, ::rtl::Reference< ::sfx2::DocumentStorageModifyListener >& _inout_rListener,
1114         comphelper::SolarMutex& _rMutex, bool _bListen )
1115     {
1116         Reference< XModifiable > xModify( _rxStorage, UNO_QUERY );
1117         OSL_ENSURE( xModify.is() || !_rxStorage.is(), "lcl_modifyListening: storage can't notify us!" );
1118 
1119         if ( xModify.is() && !_bListen && _inout_rListener.is() )
1120         {
1121             xModify->removeModifyListener( _inout_rListener.get() );
1122         }
1123 
1124         if ( _inout_rListener.is() )
1125         {
1126             _inout_rListener->dispose();
1127             _inout_rListener = nullptr;
1128         }
1129 
1130         if ( xModify.is() && _bListen )
1131         {
1132             _inout_rListener = new ::sfx2::DocumentStorageModifyListener( _rDocument, _rMutex );
1133             xModify->addModifyListener( _inout_rListener.get() );
1134         }
1135     }
1136 }
1137 
1138 namespace
1139 {
1140     void lcl_rebaseScriptStorage_throw( const Reference< XStorageBasedLibraryContainer >& _rxContainer,
1141         const Reference< XStorage >& _rxNewRootStorage )
1142     {
1143         if ( _rxContainer.is() )
1144         {
1145             if ( _rxNewRootStorage.is() )
1146                 _rxContainer->setRootStorage( _rxNewRootStorage );
1147 //            else
1148                    // TODO: what to do here? dispose the container?
1149         }
1150     }
1151 }
1152 
1153 Reference< XStorage > const & ODatabaseModelImpl::impl_switchToStorage_throw( const Reference< XStorage >& _rxNewRootStorage )
1154 {
1155     // stop listening for modifications at the old storage
1156     lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), false );
1157 
1158     // set new storage
1159     m_xDocumentStorage.reset( _rxNewRootStorage, SharedStorage::TakeOwnership );
1160 
1161     // start listening for modifications
1162     lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), true );
1163 
1164     // forward new storage to Basic and Dialog library containers
1165     lcl_rebaseScriptStorage_throw( m_xBasicLibraries, m_xDocumentStorage.getTyped() );
1166     lcl_rebaseScriptStorage_throw( m_xDialogLibraries, m_xDocumentStorage.getTyped() );
1167 
1168     m_bReadOnly = !tools::stor::storageIsWritable_nothrow( m_xDocumentStorage.getTyped() );
1169     // TODO: our data source, if it exists, must broadcast the change of its ReadOnly property
1170 
1171     return m_xDocumentStorage.getTyped();
1172 }
1173 
1174 void ODatabaseModelImpl::impl_switchToLogicalURL( const OUString& i_rDocumentURL )
1175 {
1176     if ( i_rDocumentURL == m_sDocumentURL )
1177         return;
1178 
1179     const OUString sOldURL( m_sDocumentURL );
1180     // update our name, if necessary
1181     if  (   ( m_sName == m_sDocumentURL )   // our name is our old URL
1182         ||  ( m_sName.isEmpty() )        // we do not have a name, yet (i.e. are not registered at the database context)
1183         )
1184     {
1185         INetURLObject aURL( i_rDocumentURL );
1186         if ( aURL.GetProtocol() != INetProtocol::NotValid )
1187         {
1188             m_sName = i_rDocumentURL;
1189             // TODO: our data source must broadcast the change of the Name property
1190         }
1191     }
1192 
1193     // remember URL
1194     m_sDocumentURL = i_rDocumentURL;
1195 
1196     // update our location, if necessary
1197     if  ( m_sDocFileLocation.isEmpty() )
1198         m_sDocFileLocation = m_sDocumentURL;
1199 
1200     // register at the database context, or change registration
1201     if (!sOldURL.isEmpty())
1202         m_rDBContext.databaseDocumentURLChange( sOldURL, m_sDocumentURL );
1203     else
1204         m_rDBContext.registerDatabaseDocument( *this );
1205 }
1206 
1207 OUString ODatabaseModelImpl::getObjectContainerStorageName( const ObjectType _eType )
1208 {
1209     return lcl_getContainerStorageName_throw( _eType );
1210 }
1211 
1212 sal_Int16 ODatabaseModelImpl::getCurrentMacroExecMode() const
1213 {
1214     sal_Int16 nCurrentMode = MacroExecMode::NEVER_EXECUTE;
1215     try
1216     {
1217         nCurrentMode = m_aMediaDescriptor.getOrDefault( "MacroExecutionMode", nCurrentMode );
1218     }
1219     catch( const Exception& )
1220     {
1221         DBG_UNHANDLED_EXCEPTION("dbaccess");
1222     }
1223     return nCurrentMode;
1224 }
1225 
1226 void ODatabaseModelImpl::setCurrentMacroExecMode( sal_uInt16 nMacroMode )
1227 {
1228     m_aMediaDescriptor.put( "MacroExecutionMode", nMacroMode );
1229 }
1230 
1231 OUString ODatabaseModelImpl::getDocumentLocation() const
1232 {
1233     return getURL();
1234     // formerly, we returned getDocFileLocation here, which is the location of the file from which we
1235     // recovered the "real" document.
1236     // However, during CWS autorecovery evolving, we clarified (with MAV/MT) the role of XModel::getURL and
1237     // XStorable::getLocation. In this course, we agreed that for a macro security check, the *document URL*
1238     // (not the recovery file URL) is to be used: The recovery file lies in the backup folder, and by definition,
1239     // this folder is considered to be secure. So, the document URL needs to be used to decide about the security.
1240 }
1241 
1242 ODatabaseModelImpl::EmbeddedMacros ODatabaseModelImpl::determineEmbeddedMacros()
1243 {
1244     if ( !m_aEmbeddedMacros )
1245     {
1246         if ( ::sfx2::DocumentMacroMode::storageHasMacros( getOrCreateRootStorage() ) )
1247         {
1248             m_aEmbeddedMacros.reset( eDocumentWideMacros );
1249         }
1250         else if (   lcl_hasObjectsWithMacros_nothrow( *this, E_FORM )
1251                 ||  lcl_hasObjectsWithMacros_nothrow( *this, E_REPORT )
1252                 )
1253         {
1254             m_aEmbeddedMacros.reset( eSubDocumentMacros );
1255         }
1256         else
1257         {
1258             m_aEmbeddedMacros.reset( eNoMacros );
1259         }
1260     }
1261     return *m_aEmbeddedMacros;
1262 }
1263 
1264 bool ODatabaseModelImpl::documentStorageHasMacros() const
1265 {
1266     const_cast< ODatabaseModelImpl* >( this )->determineEmbeddedMacros();
1267     return ( *m_aEmbeddedMacros != eNoMacros );
1268 }
1269 
1270 Reference< XEmbeddedScripts > ODatabaseModelImpl::getEmbeddedDocumentScripts() const
1271 {
1272     return Reference< XEmbeddedScripts >( getModel_noCreate(), UNO_QUERY );
1273 }
1274 
1275 SignatureState ODatabaseModelImpl::getScriptingSignatureState()
1276 {
1277     // no support for signatures at the moment
1278     return SignatureState::NOSIGNATURES;
1279 }
1280 
1281 bool ODatabaseModelImpl::hasTrustedScriptingSignature( bool /*bAllowUIToAddAuthor*/ )
1282 {
1283     // no support for signatures at the moment
1284     return false;
1285 }
1286 
1287 void ODatabaseModelImpl::storageIsModified()
1288 {
1289     setModified( true );
1290 }
1291 
1292 ModelDependentComponent::ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model )
1293     :m_pImpl( _model )
1294 {
1295 }
1296 
1297 ModelDependentComponent::~ModelDependentComponent()
1298 {
1299 }
1300 
1301 }   // namespace dbaccess
1302 
1303 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1304