xref: /core/sfx2/source/doc/sfxbasemodel.cxx (revision badc9c68dcbb12b358a81999618c57befcb411ed)
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 <sal/config.h>
21 
22 #include <algorithm>
23 #include <chrono>
24 #include <memory>
25 #include <optional>
26 #include <config_features.h>
27 
28 #include <sfx2/sfxbasemodel.hxx>
29 
30 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
31 #include <com/sun/star/task/XInteractionHandler.hpp>
32 #include <com/sun/star/task/ErrorCodeIOException.hpp>
33 #include <com/sun/star/task/ErrorCodeRequest2.hpp>
34 #include <com/sun/star/view/XSelectionSupplier.hpp>
35 #include <com/sun/star/view/XPrintJobListener.hpp>
36 #include <com/sun/star/lang/DisposedException.hpp>
37 #include <com/sun/star/lang/IllegalArgumentException.hpp>
38 #include <com/sun/star/lang/NoSupportException.hpp>
39 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
40 #include <com/sun/star/lang/NotInitializedException.hpp>
41 #include <com/sun/star/frame/Desktop.hpp>
42 #include <com/sun/star/frame/IllegalArgumentIOException.hpp>
43 #include <com/sun/star/frame/XUntitledNumbers.hpp>
44 #include <com/sun/star/frame/DoubleInitializationException.hpp>
45 #include <com/sun/star/embed/XStorage.hpp>
46 #include <com/sun/star/document/XStorageChangeListener.hpp>
47 #include <com/sun/star/beans/StringPair.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/beans/XPropertySetInfo.hpp>
50 #include <com/sun/star/container/XIndexContainer.hpp>
51 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
52 #include <com/sun/star/script/provider/XScriptProvider.hpp>
53 #include <com/sun/star/ui/UIConfigurationManager.hpp>
54 #include <com/sun/star/embed/ElementModes.hpp>
55 #include <com/sun/star/embed/Aspects.hpp>
56 #include <com/sun/star/document/DocumentProperties.hpp>
57 #include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
58 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
59 #include <com/sun/star/ucb/ContentCreationException.hpp>
60 #include <com/sun/star/ucb/CommandAbortedException.hpp>
61 #include <com/sun/star/util/XCloneable.hpp>
62 #include <com/sun/star/util/InvalidStateException.hpp>
63 #include <com/sun/star/util/CloseVetoException.hpp>
64 #include <comphelper/enumhelper.hxx>
65 #include <comphelper/indexedpropertyvalues.hxx>
66 #include <comphelper/interfacecontainer3.hxx>
67 #include <comphelper/string.hxx>
68 
69 #include <cppuhelper/implbase.hxx>
70 #include <comphelper/lok.hxx>
71 #include <comphelper/multicontainer2.hxx>
72 #include <cppuhelper/exc_hlp.hxx>
73 #include <comphelper/processfactory.hxx>
74 #include <comphelper/propertyvalue.hxx>
75 #include <comphelper/sequenceashashmap.hxx>
76 #include <comphelper/namedvaluecollection.hxx>
77 #include <o3tl/deleter.hxx>
78 #include <o3tl/safeint.hxx>
79 #include <o3tl/string_view.hxx>
80 #include <svl/itemset.hxx>
81 #include <svl/stritem.hxx>
82 #include <svl/eitem.hxx>
83 #include <svl/grabbagitem.hxx>
84 #include <tools/urlobj.hxx>
85 #include <tools/debug.hxx>
86 #include <comphelper/diagnose_ex.hxx>
87 #include <tools/svborder.hxx>
88 #include <unotools/tempfile.hxx>
89 #include <osl/mutex.hxx>
90 #include <comphelper/errcode.hxx>
91 #include <vcl/filter/SvmWriter.hxx>
92 #include <vcl/salctype.hxx>
93 #include <vcl/gdimtf.hxx>
94 #include <comphelper/fileformat.h>
95 #include <comphelper/servicehelper.hxx>
96 #include <comphelper/storagehelper.hxx>
97 #include <toolkit/helper/vclunohelper.hxx>
98 #include <vcl/transfer.hxx>
99 #include <svtools/ehdl.hxx>
100 #include <svtools/sfxecode.hxx>
101 #include <sal/log.hxx>
102 #include <framework/configimporter.hxx>
103 #include <framework/titlehelper.hxx>
104 #include <comphelper/numberedcollection.hxx>
105 #include <unotools/ucbhelper.hxx>
106 #include <ucbhelper/content.hxx>
107 
108 #include <sfx2/sfxbasecontroller.hxx>
109 #include <sfx2/viewfac.hxx>
110 #include <workwin.hxx>
111 #include <sfx2/signaturestate.hxx>
112 #include <sfx2/sfxuno.hxx>
113 #include <objshimp.hxx>
114 #include <sfx2/viewfrm.hxx>
115 #include <sfx2/viewsh.hxx>
116 #include <sfx2/docfile.hxx>
117 #include <sfx2/docfilt.hxx>
118 #include <sfx2/dispatch.hxx>
119 #include <sfx2/module.hxx>
120 #include <basic/basmgr.hxx>
121 #include <sfx2/event.hxx>
122 #include <eventsupplier.hxx>
123 #include <sfx2/sfxsids.hrc>
124 #include <sfx2/strings.hrc>
125 #include <sfx2/app.hxx>
126 #include <sfx2/docfac.hxx>
127 #include <sfx2/fcontnr.hxx>
128 #include <sfx2/docstoragemodifylistener.hxx>
129 #include <sfx2/brokenpackageint.hxx>
130 #include "graphhelp.hxx"
131 #include <docundomanager.hxx>
132 #include <openurlhint.hxx>
133 #include <sfx2/msgpool.hxx>
134 #include <sfx2/DocumentMetadataAccess.hxx>
135 #include "printhelper.hxx"
136 #include <sfx2/sfxresid.hxx>
137 #include <sfx2/filedlghelper.hxx>
138 #include <comphelper/profilezone.hxx>
139 #include <vcl/threadex.hxx>
140 #include <unotools/mediadescriptor.hxx>
141 
142 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
143 
144 //  namespaces
145 
146 
147 using namespace ::com::sun::star;
148 using namespace ::com::sun::star::uno;
149 using ::com::sun::star::beans::PropertyValue;
150 using ::com::sun::star::document::CmisProperty;
151 using ::com::sun::star::frame::XFrame;
152 using ::com::sun::star::frame::XController;
153 using ::com::sun::star::frame::XController2;
154 using ::com::sun::star::lang::IllegalArgumentException;
155 using ::com::sun::star::io::IOException;
156 using ::com::sun::star::uno::Sequence;
157 using ::com::sun::star::document::XDocumentRecovery;
158 using ::com::sun::star::document::XUndoManager;
159 using ::com::sun::star::document::XUndoAction;
160 using ::com::sun::star::frame::XModel;
161 
162 namespace {
163 
164 /** This Listener is used to get notified when the XDocumentProperties of the
165     XModel change.
166  */
167 class SfxDocInfoListener_Impl : public ::cppu::WeakImplHelper<
168     util::XModifyListener >
169 {
170 
171 public:
172     SfxObjectShell& m_rShell;
173 
SfxDocInfoListener_Impl(SfxObjectShell & i_rDoc)174     explicit SfxDocInfoListener_Impl( SfxObjectShell& i_rDoc )
175         : m_rShell(i_rDoc)
176     { };
177 
178     virtual void SAL_CALL disposing( const lang::EventObject& ) override;
179     virtual void SAL_CALL modified( const lang::EventObject& ) override;
180 };
181 
182 }
183 
modified(const lang::EventObject &)184 void SAL_CALL SfxDocInfoListener_Impl::modified( const lang::EventObject& )
185 {
186     SolarMutexGuard aSolarGuard;
187 
188     // notify changes to the SfxObjectShell
189     m_rShell.FlushDocInfo();
190 }
191 
disposing(const lang::EventObject &)192 void SAL_CALL SfxDocInfoListener_Impl::disposing( const lang::EventObject& )
193 {
194 }
195 
196 
197 //  impl. declarations
198 
199 
200 struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument
201 {
202     // counter for SfxBaseModel instances created.
203     inline static std::atomic<sal_Int64>                       g_nInstanceCounter = 0   ;
204     SfxObjectShellRef                                          m_pObjectShell           ;
205     OUString                                                   m_sURL                   ;
206     OUString                                                   m_sRuntimeUID            ;
207     OUString                                                   m_aPreusedFilterName     ;
208     comphelper::OInterfaceContainerHelper3<view::XPrintJobListener>  m_aPrintJobListeners;
209     comphelper::OInterfaceContainerHelper3<lang::XEventListener>  m_aEventListeners;
210     comphelper::OInterfaceContainerHelper3<util::XModifyListener>  m_aModifyListeners;
211     comphelper::OInterfaceContainerHelper3<document::XEventListener>  m_aDocumentEventListeners1;
212     comphelper::OInterfaceContainerHelper3<document::XDocumentEventListener>  m_aDocumentEventListeners2;
213     comphelper::OInterfaceContainerHelper3<document::XStorageChangeListener>  m_aStorageChangeListeners;
214     comphelper::OInterfaceContainerHelper3<util::XCloseListener>  m_aCloseListeners;
215     std::unordered_map<css::uno::Reference< css::drawing::XShape >,
216                        std::vector<css::uno::Reference< css::document::XShapeEventListener >>> maShapeListeners;
217     Reference< XInterface >                                    m_xParent                ;
218     Reference< frame::XController >                            m_xCurrent               ;
219     Reference< document::XDocumentProperties >                 m_xDocumentProperties    ;
220     Reference< script::XStarBasicAccess >                      m_xStarBasicAccess       ;
221     rtl::Reference< SfxEvents_Impl >                           m_xEvents                ;
222     Sequence< beans::PropertyValue>                            m_seqArguments           ;
223     std::vector< Reference< frame::XController > >             m_seqControllers         ;
224     Reference< container::XIndexAccess >                       m_contViewData           ;
225     sal_uInt16                                                 m_nControllerLockCount   ;
226     bool                                                       m_bClosed                ;
227     bool                                                       m_bClosing               ;
228     bool                                                       m_bSaving                ;
229     bool                                                       m_bSuicide               ;
230     bool                                                       m_bExternalTitle         ;
231     bool                                                       m_bDisposing             ;
232     rtl::Reference< SfxPrintHelper>                            m_xPrintable             ;
233     Reference< ui::XUIConfigurationManager2 >                  m_xUIConfigurationManager;
234     ::rtl::Reference< ::sfx2::DocumentStorageModifyListener >  m_pStorageModifyListen   ;
235     OUString                                                   m_sModuleIdentifier      ;
236     rtl::Reference< ::framework::TitleHelper >                 m_xTitleHelper           ;
237     rtl::Reference< ::comphelper::NumberedCollection >         m_xNumberedControllers   ;
238     rtl::Reference<::sfx2::DocumentMetadataAccess>             m_xDocumentMetadata      ;
239     ::rtl::Reference< ::sfx2::DocumentUndoManager >            m_pDocumentUndoManager   ;
240     Sequence< document::CmisProperty>                          m_cmisProperties         ;
241     std::shared_ptr<SfxGrabBagItem>                            m_xGrabBagItem           ;
242     std::optional<std::chrono::steady_clock::time_point>       m_oDirtyTimestamp        ;
243 
IMPL_SfxBaseModel_DataContainerIMPL_SfxBaseModel_DataContainer244     IMPL_SfxBaseModel_DataContainer( ::osl::Mutex& rMutex, SfxObjectShell* pObjectShell )
245             :   m_pObjectShell          ( pObjectShell  )
246             ,   m_aPrintJobListeners    ( rMutex    )
247             ,   m_aEventListeners       ( rMutex    )
248             ,   m_aModifyListeners      ( rMutex    )
249             ,   m_aDocumentEventListeners1( rMutex  )
250             ,   m_aDocumentEventListeners2( rMutex  )
251             ,   m_aStorageChangeListeners ( rMutex  )
252             ,   m_aCloseListeners       ( rMutex    )
253             ,   m_nControllerLockCount  ( 0         )
254             ,   m_bClosed               ( false     )
255             ,   m_bClosing              ( false     )
256             ,   m_bSaving               ( false     )
257             ,   m_bSuicide              ( false     )
258             ,   m_bExternalTitle        ( false     )
259             ,   m_bDisposing            ( false     )
260     {
261         // increase global instance counter, and set own Runtime UID
262         m_sRuntimeUID = OUString::number(++g_nInstanceCounter);
263     }
264 
~IMPL_SfxBaseModel_DataContainerIMPL_SfxBaseModel_DataContainer265     virtual ~IMPL_SfxBaseModel_DataContainer()
266     {
267     }
268 
269     // ::sfx2::IModifiableDocument
storageIsModifiedIMPL_SfxBaseModel_DataContainer270     virtual void storageIsModified() override
271     {
272         if ( m_pObjectShell.is() && !m_pObjectShell->IsModified() )
273             m_pObjectShell->SetModified();
274     }
275 
276     void impl_setDocumentProperties(
277             const Reference< document::XDocumentProperties >& );
278 
GetDMAIMPL_SfxBaseModel_DataContainer279     Reference<rdf::XDocumentMetadataAccess> GetDMA()
280     {
281         if (!m_xDocumentMetadata.is())
282         {
283             OSL_ENSURE(m_pObjectShell.is(), "GetDMA: no object shell?");
284             if (!m_pObjectShell.is())
285             {
286                 return nullptr;
287             }
288 
289             const Reference<XComponentContext>& xContext(
290                 ::comphelper::getProcessComponentContext());
291             const Reference<frame::XModel> xModel(
292                 m_pObjectShell->GetModel());
293             const Reference<lang::XMultiComponentFactory> xMsf(
294                 xContext->getServiceManager());
295             const Reference<frame::
296                 XTransientDocumentsDocumentContentFactory> xTDDCF(
297                     xMsf->createInstanceWithContext(
298                         u"com.sun.star.frame.TransientDocumentsDocumentContentFactory"_ustr,
299                     xContext),
300                 UNO_QUERY_THROW);
301             const Reference<ucb::XContent> xContent(
302                 xTDDCF->createDocumentContent(xModel) );
303             OSL_ENSURE(xContent.is(), "GetDMA: cannot create DocumentContent");
304             if (!xContent.is())
305             {
306                 return nullptr;
307             }
308             OUString uri = xContent->getIdentifier()->getContentIdentifier();
309             OSL_ENSURE(!uri.isEmpty(), "GetDMA: empty uri?");
310             if (!uri.isEmpty() && !uri.endsWith("/"))
311             {
312                 uri += "/";
313             }
314 
315             m_xDocumentMetadata = new ::sfx2::DocumentMetadataAccess(
316                 xContext, *m_pObjectShell, uri);
317         }
318         return m_xDocumentMetadata;
319     }
320 
CreateDMAUninitializedIMPL_SfxBaseModel_DataContainer321     rtl::Reference<::sfx2::DocumentMetadataAccess> CreateDMAUninitialized()
322     {
323         return (m_pObjectShell.is())
324             ? new ::sfx2::DocumentMetadataAccess(
325                 ::comphelper::getProcessComponentContext(), *m_pObjectShell)
326             : nullptr;
327     }
328 
setModifiedForAutoSaveIMPL_SfxBaseModel_DataContainer329     void setModifiedForAutoSave(bool val)
330     {
331         if (val)
332         {
333             if (!m_oDirtyTimestamp)
334                 m_oDirtyTimestamp.emplace(std::chrono::steady_clock::now());
335         }
336         else
337         {
338             m_oDirtyTimestamp.reset();
339         }
340     }
341 };
342 
343 namespace {
344 
345 // Listener that forwards notifications from the PrintHelper to the "real" listeners
346 class SfxPrintHelperListener_Impl : public ::cppu::WeakImplHelper< view::XPrintJobListener >
347 {
348 public:
349     IMPL_SfxBaseModel_DataContainer* m_pData;
SfxPrintHelperListener_Impl(IMPL_SfxBaseModel_DataContainer * pData)350     explicit SfxPrintHelperListener_Impl( IMPL_SfxBaseModel_DataContainer* pData )
351         : m_pData( pData )
352     {}
353 
354     virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override ;
355     virtual void SAL_CALL printJobEvent( const view::PrintJobEvent& rEvent ) override;
356 };
357 
358 }
359 
disposing(const lang::EventObject &)360 void SAL_CALL SfxPrintHelperListener_Impl::disposing( const lang::EventObject& )
361 {
362     m_pData->m_xPrintable = nullptr;
363 }
364 
printJobEvent(const view::PrintJobEvent & rEvent)365 void SAL_CALL SfxPrintHelperListener_Impl::printJobEvent( const view::PrintJobEvent& rEvent )
366 {
367     if ( m_pData->m_aPrintJobListeners.getLength() )
368     {
369         m_pData->m_aPrintJobListeners.notifyEach(&view::XPrintJobListener::printJobEvent, rEvent);
370     }
371 }
372 
373 namespace {
374 
375 // SfxOwnFramesLocker ====================================================================================
376 // allows to lock all the frames related to the provided SfxObjectShell
377 class SfxOwnFramesLocker
378 {
379     Sequence< Reference< frame::XFrame > > m_aLockedFrames;
380 
381     static vcl::Window* GetVCLWindow( const Reference< frame::XFrame >& xFrame );
382 public:
383     explicit SfxOwnFramesLocker( SfxObjectShell const * ObjechShell );
384     ~SfxOwnFramesLocker();
385 };
386 
387 }
388 
SfxOwnFramesLocker(SfxObjectShell const * pObjectShell)389 SfxOwnFramesLocker::SfxOwnFramesLocker( SfxObjectShell const * pObjectShell )
390 {
391     if ( !pObjectShell )
392         return;
393 
394     if ( comphelper::LibreOfficeKit::isForkedChild() )
395         return; // no need to tweak UI when in the background
396 
397     for (   SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pObjectShell );
398             pFrame;
399             pFrame = SfxViewFrame::GetNext( *pFrame, pObjectShell )
400         )
401     {
402         SfxFrame& rSfxFrame = pFrame->GetFrame();
403         try
404         {
405             // get vcl window related to the frame and lock it if it is still not locked
406             const Reference< frame::XFrame >& xFrame = rSfxFrame.GetFrameInterface();
407             vcl::Window* pWindow = GetVCLWindow( xFrame );
408             if ( !pWindow )
409                 throw RuntimeException();
410 
411             if ( pWindow->IsEnabled() )
412             {
413                 pWindow->Disable();
414 
415                 try
416                 {
417                     sal_Int32 nLen = m_aLockedFrames.getLength();
418                     m_aLockedFrames.realloc( nLen + 1 );
419                     m_aLockedFrames.getArray()[nLen] = xFrame;
420                 }
421                 catch( Exception& )
422                 {
423                     pWindow->Enable();
424                     throw;
425                 }
426             }
427         }
428         catch( Exception& )
429         {
430             OSL_FAIL( "Not possible to lock the frame window!" );
431         }
432     }
433 }
434 
~SfxOwnFramesLocker()435 SfxOwnFramesLocker::~SfxOwnFramesLocker()
436 {
437     for ( auto& rFrame : asNonConstRange(m_aLockedFrames) )
438     {
439         try
440         {
441             if ( rFrame.is() )
442             {
443                 // get vcl window related to the frame and unlock it
444                 vcl::Window* pWindow = GetVCLWindow( rFrame );
445                 if ( !pWindow )
446                     throw RuntimeException();
447 
448                 pWindow->Enable();
449 
450                 rFrame.clear();
451             }
452         }
453         catch( Exception& )
454         {
455             OSL_FAIL( "Can't unlock the frame window!" );
456         }
457     }
458 }
459 
GetVCLWindow(const Reference<frame::XFrame> & xFrame)460 vcl::Window* SfxOwnFramesLocker::GetVCLWindow( const Reference< frame::XFrame >& xFrame )
461 {
462     VclPtr<vcl::Window> pWindow;
463 
464     if ( xFrame.is() )
465     {
466         Reference< awt::XWindow > xWindow = xFrame->getContainerWindow();
467         if ( xWindow.is() )
468                pWindow = VCLUnoHelper::GetWindow( xWindow );
469     }
470 
471     return pWindow;
472 }
473 
474 namespace {
475 
476 // SfxSaveGuard ====================================================================================
477 class SfxSaveGuard
478 {
479     private:
480         Reference< frame::XModel > m_xModel;
481         IMPL_SfxBaseModel_DataContainer* m_pData;
482         std::unique_ptr<SfxOwnFramesLocker> m_pFramesLock;
483 
484         SfxSaveGuard(SfxSaveGuard const &) = delete;
485         void operator =(const SfxSaveGuard&) = delete;
486 
487     public:
488         SfxSaveGuard(const Reference< frame::XModel >&             xModel                      ,
489                            IMPL_SfxBaseModel_DataContainer* pData);
490         ~SfxSaveGuard();
491 };
492 
493 }
494 
SfxSaveGuard(const Reference<frame::XModel> & xModel,IMPL_SfxBaseModel_DataContainer * pData)495 SfxSaveGuard::SfxSaveGuard(const Reference< frame::XModel >&             xModel                      ,
496                                  IMPL_SfxBaseModel_DataContainer* pData)
497     : m_xModel     ( xModel )
498     , m_pData      ( pData )
499 {
500     if ( m_pData->m_bClosed )
501         throw lang::DisposedException(u"Object already disposed."_ustr);
502 
503     m_pData->m_bSaving = true;
504     m_pFramesLock.reset(new SfxOwnFramesLocker( m_pData->m_pObjectShell.get() ));
505 }
506 
~SfxSaveGuard()507 SfxSaveGuard::~SfxSaveGuard()
508 {
509     m_pFramesLock.reset();
510 
511     m_pData->m_bSaving = false;
512 
513     // m_bSuicide was set e.g. in case someone tried to close a document, while it was used for
514     // storing at the same time. Further m_bSuicide was set to sal_True only if close(sal_True) was called.
515     // So the ownership was delegated to the place where a veto exception was thrown.
516     // Now we have to call close() again and delegate the ownership to the next one, which
517     // can't accept that. Close(sal_False) can't work in this case. Because then the document will may be never closed...
518 
519     if ( !m_pData->m_bSuicide )
520         return;
521 
522     // Reset this state. In case the new close() request is not accepted by someone else...
523     // it's not a good idea to have two "owners" for close.-)
524     m_pData->m_bSuicide = false;
525     try
526     {
527         Reference< util::XCloseable > xClose(m_xModel, UNO_QUERY);
528         if (xClose.is())
529             xClose->close(true);
530     }
531     catch(const util::CloseVetoException&)
532     {}
533 }
534 
SfxBaseModel(SfxObjectShell * pObjectShell)535 SfxBaseModel::SfxBaseModel( SfxObjectShell *pObjectShell )
536 : BaseMutex()
537 , m_pData( std::make_shared<IMPL_SfxBaseModel_DataContainer>( m_aMutex, pObjectShell ) )
538 , m_bSupportEmbeddedScripts( pObjectShell && pObjectShell->Get_Impl() && !pObjectShell->Get_Impl()->m_bNoBasicCapabilities )
539 , m_bSupportDocRecovery( pObjectShell && pObjectShell->Get_Impl() && pObjectShell->Get_Impl()->m_bDocRecoverySupport )
540 {
541     if ( pObjectShell != nullptr )
542     {
543         StartListening( *pObjectShell ) ;
544     }
545 }
546 
547 //  destructor
~SfxBaseModel()548 SfxBaseModel::~SfxBaseModel()
549 {
550 }
551 
552 //  XInterface
queryInterface(const uno::Type & rType)553 Any SAL_CALL SfxBaseModel::queryInterface( const uno::Type& rType )
554 {
555     if  (   ( !m_bSupportEmbeddedScripts && rType.equals( cppu::UnoType<document::XEmbeddedScripts>::get() ) )
556         ||  ( !m_bSupportDocRecovery && (rType.equals( cppu::UnoType<XDocumentRecovery>::get() ) || rType.equals( cppu::UnoType<XDocumentRecovery2>::get() )) )
557         )
558         return Any();
559 
560     return SfxBaseModel_Base::queryInterface( rType );
561 }
562 
563 
564 //  XTypeProvider
565 
566 
567 namespace
568 {
lcl_stripType(Sequence<uno::Type> & io_rTypes,const uno::Type & i_rTypeToStrip)569     void lcl_stripType( Sequence< uno::Type >& io_rTypes, const uno::Type& i_rTypeToStrip )
570     {
571         Sequence< uno::Type > aStrippedTypes( io_rTypes.getLength() - 1 );
572         ::std::remove_copy_if(
573             std::cbegin(io_rTypes),
574             std::cend(io_rTypes),
575             aStrippedTypes.getArray(),
576             [&i_rTypeToStrip](const uno::Type& aType) { return aType == i_rTypeToStrip; }
577         );
578         io_rTypes = std::move(aStrippedTypes);
579     }
580 }
581 
getTypes()582 Sequence< uno::Type > SAL_CALL SfxBaseModel::getTypes()
583 {
584     Sequence< uno::Type > aTypes( SfxBaseModel_Base::getTypes() );
585 
586     if ( !m_bSupportEmbeddedScripts )
587         lcl_stripType( aTypes, cppu::UnoType<document::XEmbeddedScripts>::get() );
588 
589     if ( !m_bSupportDocRecovery )
590         lcl_stripType( aTypes, cppu::UnoType<XDocumentRecovery2>::get() );
591 
592     return aTypes;
593 }
594 
595 
596 //  XTypeProvider
597 
598 
getImplementationId()599 Sequence< sal_Int8 > SAL_CALL SfxBaseModel::getImplementationId()
600 {
601     return css::uno::Sequence<sal_Int8>();
602 }
603 
604 
605 //  XStarBasicAccess
606 
607 #if HAVE_FEATURE_SCRIPTING
608 
implGetStarBasicAccess(SfxObjectShell const * pObjectShell)609 static Reference< script::XStarBasicAccess > implGetStarBasicAccess( SfxObjectShell const * pObjectShell )
610 {
611     Reference< script::XStarBasicAccess > xRet;
612 
613 #if !HAVE_FEATURE_SCRIPTING
614     (void) pObjectShell;
615 #else
616     if( pObjectShell )
617     {
618         BasicManager* pMgr = pObjectShell->GetBasicManager();
619         xRet = getStarBasicAccess( pMgr );
620     }
621 #endif
622     return xRet;
623 }
624 
625 #endif
626 
getLibraryContainer()627 Reference< container::XNameContainer > SAL_CALL SfxBaseModel::getLibraryContainer()
628 {
629 #if !HAVE_FEATURE_SCRIPTING
630     Reference< container::XNameContainer > dummy;
631 
632     return dummy;
633 #else
634     SfxModelGuard aGuard( *this );
635 
636     Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
637     if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
638         rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
639 
640     Reference< container::XNameContainer > xRet;
641     if( rxAccess.is() )
642         xRet = rxAccess->getLibraryContainer();
643     return xRet;
644 #endif
645 }
646 
647 /**___________________________________________________________________________________________________
648     @seealso    XStarBasicAccess
649 */
createLibrary(const OUString & LibName,const OUString & Password,const OUString & ExternalSourceURL,const OUString & LinkTargetURL)650 void SAL_CALL SfxBaseModel::createLibrary( const OUString& LibName, const OUString& Password,
651     const OUString& ExternalSourceURL, const OUString& LinkTargetURL )
652 {
653 #if !HAVE_FEATURE_SCRIPTING
654     (void) LibName;
655     (void) Password;
656     (void) ExternalSourceURL;
657     (void) LinkTargetURL;
658 #else
659     SfxModelGuard aGuard( *this );
660 
661     Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
662     if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
663         rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
664 
665     if( rxAccess.is() )
666         rxAccess->createLibrary( LibName, Password, ExternalSourceURL, LinkTargetURL );
667 #endif
668 }
669 
670 /**___________________________________________________________________________________________________
671     @seealso    XStarBasicAccess
672 */
addModule(const OUString & LibraryName,const OUString & ModuleName,const OUString & Language,const OUString & Source)673 void SAL_CALL SfxBaseModel::addModule( const OUString& LibraryName, const OUString& ModuleName,
674     const OUString& Language, const OUString& Source )
675 {
676 #if !HAVE_FEATURE_SCRIPTING
677     (void) LibraryName;
678     (void) ModuleName;
679     (void) Language;
680     (void) Source;
681 #else
682     SfxModelGuard aGuard( *this );
683 
684     Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
685     if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
686         rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
687 
688     if( rxAccess.is() )
689         rxAccess->addModule( LibraryName, ModuleName, Language, Source );
690 #endif
691 }
692 
693 /**___________________________________________________________________________________________________
694     @seealso    XStarBasicAccess
695 */
addDialog(const OUString & LibraryName,const OUString & DialogName,const Sequence<sal_Int8> & Data)696 void SAL_CALL SfxBaseModel::addDialog( const OUString& LibraryName, const OUString& DialogName,
697     const Sequence< sal_Int8 >& Data )
698 {
699 #if !HAVE_FEATURE_SCRIPTING
700     (void) LibraryName;
701     (void) DialogName;
702     (void) Data;
703 #else
704     SfxModelGuard aGuard( *this );
705 
706     Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
707     if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
708         rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
709 
710     if( rxAccess.is() )
711         rxAccess->addDialog( LibraryName, DialogName, Data );
712 #endif
713 }
714 
715 
716 //  XChild
717 
718 
getParent()719 Reference< XInterface > SAL_CALL SfxBaseModel::getParent()
720 {
721     SfxModelGuard aGuard( *this );
722 
723     return m_pData->m_xParent;
724 }
725 
726 
727 //  XChild
728 
729 
setParent(const Reference<XInterface> & Parent)730 void SAL_CALL SfxBaseModel::setParent(const Reference< XInterface >& Parent)
731 {
732     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
733     m_pData->m_xParent = Parent;
734 }
735 
736 
737 //  XComponent
738 
739 
dispose()740 void SAL_CALL SfxBaseModel::dispose()
741 {
742     SolarMutexGuard aGuard;
743     if (impl_isDisposed())
744         return;
745 
746     if  ( !m_pData->m_bClosed )
747     {
748         // gracefully accept wrong dispose calls instead of close call
749         // and try to make it work (may be really disposed later!)
750         try
751         {
752             close( true );
753         }
754         catch ( util::CloseVetoException& )
755         {
756         }
757 
758         return;
759     }
760 
761     if  ( m_pData->m_bDisposing )
762         return;
763     m_pData->m_bDisposing = true;
764 
765     if ( m_pData->m_pStorageModifyListen.is() )
766     {
767         m_pData->m_pStorageModifyListen->dispose();
768         m_pData->m_pStorageModifyListen = nullptr;
769     }
770 
771     if ( m_pData->m_pDocumentUndoManager.is() )
772     {
773         m_pData->m_pDocumentUndoManager->disposing();
774         m_pData->m_pDocumentUndoManager = nullptr;
775     }
776 
777     lang::EventObject aEvent( static_cast<frame::XModel *>(this) );
778     m_pData->m_aPrintJobListeners.disposeAndClear( aEvent );
779     m_pData->m_aEventListeners.disposeAndClear( aEvent );
780     m_pData->m_aModifyListeners.disposeAndClear( aEvent );
781     m_pData->m_aDocumentEventListeners1.disposeAndClear( aEvent );
782     m_pData->m_aDocumentEventListeners2.disposeAndClear( aEvent );
783     m_pData->m_aStorageChangeListeners.disposeAndClear( aEvent );
784     m_pData->m_aCloseListeners.disposeAndClear( aEvent );
785 
786     m_pData->m_xDocumentProperties.clear();
787 
788     m_pData->m_xDocumentMetadata.clear();
789 
790     if ( m_pData->m_pObjectShell.is() )
791     {
792         EndListening( *m_pData->m_pObjectShell );
793     }
794 
795     m_pData->m_xCurrent.clear();
796     m_pData->m_seqControllers.clear();
797 
798     // m_pData member must be set to zero before delete is called to
799     // force disposed exception whenever someone tries to access our
800     // instance while in the dtor.
801     m_pData.reset();
802 }
803 
804 
805 //  XComponent
806 
807 
addEventListener(const Reference<lang::XEventListener> & aListener)808 void SAL_CALL SfxBaseModel::addEventListener( const Reference< lang::XEventListener >& aListener )
809 {
810     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
811     m_pData->m_aEventListeners.addInterface( aListener );
812 }
813 
814 
815 //  XComponent
816 
817 
removeEventListener(const Reference<lang::XEventListener> & aListener)818 void SAL_CALL SfxBaseModel::removeEventListener( const Reference< lang::XEventListener >& aListener )
819 {
820     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
821     m_pData->m_aEventListeners.removeInterface( aListener );
822 }
823 
824 void
impl_setDocumentProperties(const Reference<document::XDocumentProperties> & rxNewDocProps)825 IMPL_SfxBaseModel_DataContainer::impl_setDocumentProperties(
826         const Reference< document::XDocumentProperties >& rxNewDocProps)
827 {
828     m_xDocumentProperties.set(rxNewDocProps, UNO_SET_THROW);
829     if (m_pObjectShell.is())
830     {
831         Reference<util::XModifyBroadcaster> const xMB(
832             m_xDocumentProperties, UNO_QUERY_THROW);
833         xMB->addModifyListener(new SfxDocInfoListener_Impl(*m_pObjectShell));
834     }
835 }
836 
837 // document::XDocumentPropertiesSupplier:
838 Reference< document::XDocumentProperties > SAL_CALL
getDocumentProperties()839 SfxBaseModel::getDocumentProperties()
840 {
841     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
842     if ( !m_pData->m_xDocumentProperties.is() )
843     {
844         Reference< document::XDocumentProperties > xDocProps(
845             document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
846         m_pData->impl_setDocumentProperties(xDocProps);
847     }
848 
849     return m_pData->m_xDocumentProperties;
850 }
851 
852 
853 //  lang::XEventListener
854 
855 
disposing(const lang::EventObject & aObject)856 void SAL_CALL SfxBaseModel::disposing( const lang::EventObject& aObject )
857 {
858     SolarMutexGuard aGuard;
859     if ( impl_isDisposed() )
860         return;
861 
862     Reference< util::XModifyListener >  xMod( aObject.Source, UNO_QUERY );
863     Reference< lang::XEventListener >  xListener( aObject.Source, UNO_QUERY );
864     Reference< document::XEventListener >  xDocListener( aObject.Source, UNO_QUERY );
865 
866     if ( xMod.is() )
867         m_pData->m_aModifyListeners.removeInterface( xMod );
868     else if ( xListener.is() )
869         m_pData->m_aEventListeners.removeInterface( xListener );
870     else if ( xDocListener.is() )
871         m_pData->m_aDocumentEventListeners1.removeInterface( xDocListener );
872 }
873 
874 
875 //  frame::XModel
876 
877 
attachResource(const OUString & rURL,const Sequence<beans::PropertyValue> & rArgs)878 sal_Bool SAL_CALL SfxBaseModel::attachResource( const   OUString&                   rURL    ,
879                                                 const   Sequence< beans::PropertyValue >&  rArgs   )
880 {
881     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
882     if ( rURL.isEmpty() && rArgs.getLength() == 1 && rArgs[0].Name == "SetEmbedded" )
883     {
884         // allows to set a windowless document to EMBEDDED state
885         // but _only_ before load() or initNew() methods
886         if ( m_pData->m_pObjectShell.is() && !m_pData->m_pObjectShell->GetMedium() )
887         {
888             bool bEmb(false);
889             if ( ( rArgs[0].Value >>= bEmb ) && bEmb )
890                 m_pData->m_pObjectShell->SetCreateMode_Impl( SfxObjectCreateMode::EMBEDDED );
891         }
892 
893         return true;
894     }
895 
896     if ( m_pData->m_pObjectShell.is() )
897     {
898         m_pData->m_sURL = rURL;
899 
900         SfxObjectShell* pObjectShell = m_pData->m_pObjectShell.get();
901 
902         Sequence< sal_Int32 > aWinExtent;
903         for (const beans::PropertyValue & rProp : rArgs)
904         {
905             if (rProp.Name == "WinExtent" && (rProp.Value >>= aWinExtent) && ( aWinExtent.getLength() == 4 ) )
906             {
907                 tools::Rectangle aVisArea( aWinExtent[0], aWinExtent[1], aWinExtent[2], aWinExtent[3] );
908                 aVisArea = OutputDevice::LogicToLogic(aVisArea, MapMode(MapUnit::Map100thMM), MapMode(pObjectShell->GetMapUnit()));
909                 pObjectShell->SetVisArea( aVisArea );
910             }
911             bool bBreakMacroSign = false;
912             if ( rProp.Name == "BreakMacroSignature" && (rProp.Value >>= bBreakMacroSign) )
913             {
914                 pObjectShell->BreakMacroSign_Impl( bBreakMacroSign );
915             }
916             bool bMacroEventRead = false;
917             if ( rProp.Name == "MacroEventRead" && (rProp.Value >>= bMacroEventRead) && bMacroEventRead)
918             {
919                 pObjectShell->SetMacroCallsSeenWhileLoading();
920             }
921         }
922         Sequence<beans::PropertyValue> aStrippedArgs(rArgs.getLength());
923         beans::PropertyValue* pStripped = aStrippedArgs.getArray();
924         for (const beans::PropertyValue & rProp : rArgs)
925         {
926             if (rProp.Name == "WinExtent"
927                 || rProp.Name == "BreakMacroSignature"
928                 || rProp.Name == "MacroEventRead"
929                 || rProp.Name == "Stream"
930                 || rProp.Name == "InputStream"
931                 || rProp.Name == "URL"
932                 || rProp.Name == "Frame"
933                 || rProp.Name == "Password"
934                 || rProp.Name == "EncryptionData")
935                 continue;
936             *pStripped++ = rProp;
937         }
938         aStrippedArgs.realloc(pStripped - aStrippedArgs.getArray());
939 
940         // TODO/LATER: all the parameters that are accepted by ItemSet of the DocShell must be removed here
941 
942         m_pData->m_seqArguments = std::move(aStrippedArgs);
943 
944         SfxMedium* pMedium = pObjectShell->GetMedium();
945         if ( pMedium )
946         {
947             SfxAllItemSet aSet( pObjectShell->GetPool() );
948             TransformParameters( SID_OPENDOC, rArgs, aSet );
949 
950             // the arguments are not allowed to reach the medium
951             aSet.ClearItem( SID_FILE_NAME );
952             aSet.ClearItem( SID_FILLFRAME );
953 
954             pMedium->GetItemSet().Put( aSet );
955             const SfxStringItem* pItem = aSet.GetItem<SfxStringItem>(SID_FILTER_NAME, false);
956             if ( pItem )
957                 pMedium->SetFilter(
958                     pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( pItem->GetValue() ) );
959 
960             const SfxStringItem* pTitleItem = aSet.GetItem<SfxStringItem>(SID_DOCINFO_TITLE, false);
961             if ( pTitleItem )
962             {
963                 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pObjectShell );
964                 if ( pFrame )
965                     pFrame->UpdateTitle();
966             }
967         }
968     }
969 
970     return true ;
971 }
972 
973 
974 //  frame::XModel
975 
976 
getURL()977 OUString SAL_CALL SfxBaseModel::getURL()
978 {
979     SfxModelGuard aGuard( *this );
980     return m_pData->m_sURL ;
981 }
982 
983 
984 //  frame::XModel
985 
getArgs()986 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs()
987 {
988     return getArgs2({});
989 }
990 
991 //  frame::XModel3
992 
getArgs2(const Sequence<OUString> & requestedArgsSeq)993 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs2(const Sequence<OUString> & requestedArgsSeq )
994 {
995     SfxModelGuard aGuard( *this );
996 
997     if (!SfxApplication::Get()) // tdf#113755
998     {
999         SAL_WARN("sfx.appl", "Unexpected operations on model");
1000         return m_pData->m_seqArguments;
1001     }
1002 
1003     std::set<std::u16string_view> requestedArgs;
1004     for (OUString const & s : requestedArgsSeq)
1005         requestedArgs.insert(s);
1006 
1007     if ( m_pData->m_pObjectShell.is() )
1008     {
1009         Sequence< beans::PropertyValue > seqArgsNew;
1010         Sequence< beans::PropertyValue > seqArgsOld;
1011         SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );
1012 
1013         // we need to know which properties are supported by the transformer
1014         // hopefully it is a temporary solution, I guess nonconvertable properties
1015         // should not be supported so then there will be only ItemSet from medium
1016 
1017         TransformItems( SID_OPENDOC, m_pData->m_pObjectShell->GetMedium()->GetItemSet(), seqArgsNew );
1018         TransformParameters( SID_OPENDOC, m_pData->m_seqArguments, aSet );
1019         TransformItems( SID_OPENDOC, aSet, seqArgsOld );
1020 
1021         sal_Int32 nNewLength = seqArgsNew.getLength();
1022 
1023         if (requestedArgs.empty() || requestedArgs.count(u"WinExtent"))
1024         {
1025             // "WinExtent" property should be updated always.
1026             // We can store it now to overwrite an old value
1027             // since it is not from ItemSet
1028             tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
1029             aTmpRect = OutputDevice::LogicToLogic(aTmpRect, MapMode(m_pData->m_pObjectShell->GetMapUnit()), MapMode(MapUnit::Map100thMM));
1030 
1031             Sequence< sal_Int32 > aRectSeq
1032             {
1033                 o3tl::narrowing<int>(aTmpRect.Left()),
1034                 o3tl::narrowing<int>(aTmpRect.Top()),
1035                 o3tl::narrowing<int>(aTmpRect.IsWidthEmpty() ? aTmpRect.Left() : aTmpRect.Right()),
1036                 o3tl::narrowing<int>(aTmpRect.IsHeightEmpty() ? aTmpRect.Top() : aTmpRect.Bottom())
1037             };
1038 
1039             seqArgsNew.realloc( ++nNewLength );
1040             auto pseqArgsNew = seqArgsNew.getArray();
1041             pseqArgsNew[ nNewLength - 1 ].Name = "WinExtent";
1042             pseqArgsNew[ nNewLength - 1 ].Value <<= aRectSeq;
1043         }
1044 
1045         if (requestedArgs.empty() || requestedArgs.count(u"PreusedFilterName"))
1046         {
1047             if ( !m_pData->m_aPreusedFilterName.isEmpty() )
1048             {
1049                 seqArgsNew.realloc( ++nNewLength );
1050                 auto pseqArgsNew = seqArgsNew.getArray();
1051                 pseqArgsNew[ nNewLength - 1 ].Name = "PreusedFilterName";
1052                 pseqArgsNew[ nNewLength - 1 ].Value <<= m_pData->m_aPreusedFilterName;
1053             }
1054         }
1055 
1056         if (requestedArgs.empty() || requestedArgs.count(u"DocumentBorder"))
1057         {
1058             SfxViewFrame* pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
1059             if ( pFrame )
1060             {
1061                 SvBorder aBorder = pFrame->GetBorderPixelImpl();
1062 
1063                 Sequence< sal_Int32 > aBorderSeq
1064                 {
1065                     o3tl::narrowing<int>(aBorder.Left()),
1066                     o3tl::narrowing<int>(aBorder.Top()),
1067                     o3tl::narrowing<int>(aBorder.Right()),
1068                     o3tl::narrowing<int>(aBorder.Bottom())
1069                 };
1070 
1071                 seqArgsNew.realloc( ++nNewLength );
1072                 auto pseqArgsNew = seqArgsNew.getArray();
1073                 pseqArgsNew[ nNewLength - 1 ].Name = "DocumentBorder";
1074                 pseqArgsNew[ nNewLength - 1 ].Value <<= aBorderSeq;
1075             }
1076         }
1077 
1078         if (requestedArgs.empty())
1079         {
1080             // only the values that are not supported by the ItemSet must be cached here
1081             Sequence< beans::PropertyValue > aFinalCache;
1082             sal_Int32 nFinalLength = 0;
1083 
1084             for (const auto& rOrg : m_pData->m_seqArguments)
1085             {
1086                 auto bNew = std::none_of(std::cbegin(seqArgsOld), std::cend(seqArgsOld),
1087                     [&rOrg](const beans::PropertyValue& rOld){ return rOld.Name == rOrg.Name; });
1088                 if ( bNew )
1089                 {
1090                     // the entity with this name should be new for seqArgsNew
1091                     // since it is not supported by transformer
1092 
1093                     seqArgsNew.realloc( ++nNewLength );
1094                     seqArgsNew.getArray()[ nNewLength - 1 ] = rOrg;
1095 
1096                     aFinalCache.realloc( ++nFinalLength );
1097                     aFinalCache.getArray()[ nFinalLength - 1 ] = rOrg;
1098                 }
1099             }
1100 
1101             m_pData->m_seqArguments = std::move(aFinalCache);
1102         }
1103 
1104         return seqArgsNew;
1105     }
1106 
1107     return m_pData->m_seqArguments;
1108 }
1109 
setArgs(const Sequence<beans::PropertyValue> & aArgs)1110 void SAL_CALL SfxBaseModel::setArgs(const Sequence<beans::PropertyValue>& aArgs)
1111 {
1112     SfxModelGuard aGuard( *this );
1113 
1114     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
1115     if (!pMedium)
1116     {
1117         throw util::InvalidStateException(
1118             u"Medium could not be retrieved, unable to execute setArgs"_ustr);
1119     }
1120 
1121     for (const auto& rArg : aArgs)
1122     {
1123         OUString sValue;
1124         bool bValue;
1125         bool ok = false;
1126         if (rArg.Name == "SuggestedSaveAsName")
1127         {
1128             if (rArg.Value >>= sValue)
1129             {
1130                 pMedium->GetItemSet().Put(SfxStringItem(SID_SUGGESTEDSAVEASNAME, sValue));
1131                 ok = true;
1132             }
1133         }
1134         else if (rArg.Name == "SuggestedSaveAsDir")
1135         {
1136             if (rArg.Value >>= sValue)
1137             {
1138                 pMedium->GetItemSet().Put(SfxStringItem(SID_SUGGESTEDSAVEASDIR, sValue));
1139                 ok = true;
1140             }
1141         }
1142         else if (rArg.Name == "ExportDirectory")
1143         {
1144             if (rArg.Value >>= sValue)
1145             {
1146                 pMedium->GetItemSet().Put(SfxStringItem(SID_EXPORTDIRECTORY, sValue));
1147                 ok = true;
1148             }
1149         }
1150         else if (rArg.Name == "LockContentExtraction")
1151         {
1152             if (rArg.Value >>= bValue)
1153             {
1154                 pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_CONTENT_EXTRACTION, bValue));
1155                 ok = true;
1156             }
1157         }
1158         else if (rArg.Name == "LockExport")
1159         {
1160             if (rArg.Value >>= bValue)
1161             {
1162                 pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_EXPORT, bValue));
1163                 ok = true;
1164             }
1165         }
1166         else if (rArg.Name == "LockPrint")
1167         {
1168             if (rArg.Value >>= bValue)
1169             {
1170                 pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_PRINT, bValue));
1171                 ok = true;
1172             }
1173         }
1174         else if (rArg.Name == "LockSave")
1175         {
1176             if (rArg.Value >>= bValue)
1177             {
1178                 pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_SAVE, bValue));
1179                 ok = true;
1180             }
1181         }
1182         else if (rArg.Name == "LockEditDoc")
1183         {
1184             if (rArg.Value >>= bValue)
1185             {
1186                 pMedium->GetItemSet().Put(SfxBoolItem(SID_LOCK_EDITDOC, bValue));
1187                 ok = true;
1188             }
1189         }
1190         else if (rArg.Name == "Replaceable")
1191         {
1192             if (rArg.Value >>= bValue)
1193             {
1194                 pMedium->GetItemSet().Put(SfxBoolItem(SID_REPLACEABLE, bValue));
1195                 ok = true;
1196             }
1197         }
1198         else if (rArg.Name == "EncryptionData")
1199         {
1200             pMedium->GetItemSet().Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, rArg.Value));
1201             ok = true;
1202         }
1203         else if (rArg.Name == "EmbeddedFonts")
1204         {
1205             if (uno::Sequence<beans::StringPair> fonts; rArg.Value >>= fonts)
1206             {
1207                 pMedium->AddEmbeddedFonts(fonts);
1208                 ok = true;
1209             }
1210         }
1211 
1212         if (!ok)
1213         {
1214             throw lang::IllegalArgumentException("Setting property not supported: " + rArg.Name,
1215                                                  comphelper::getProcessComponentContext(), 0);
1216         }
1217     }
1218 }
1219 
1220 //  frame::XModel
1221 
1222 
connectController(const Reference<frame::XController> & xController)1223 void SAL_CALL SfxBaseModel::connectController( const Reference< frame::XController >& xController )
1224 {
1225     SfxModelGuard aGuard( *this );
1226     OSL_PRECOND( xController.is(), "SfxBaseModel::connectController: invalid controller!" );
1227     if ( !xController.is() )
1228         return;
1229 
1230     m_pData->m_seqControllers.push_back(xController);
1231 
1232     if ( m_pData->m_seqControllers.size() == 1 )
1233     {
1234         SfxViewFrame* pViewFrame = SfxViewFrame::Get( xController, GetObjectShell() );
1235         ENSURE_OR_THROW( pViewFrame, "SFX document without SFX view!?" );
1236         pViewFrame->UpdateDocument_Impl();
1237         const OUString sDocumentURL = GetObjectShell()->GetMedium()->GetName();
1238         if ( !sDocumentURL.isEmpty() )
1239             SfxGetpApp()->Broadcast( SfxOpenUrlHint( sDocumentURL ) );
1240     }
1241 }
1242 
1243 
1244 //  frame::XModel
1245 
1246 
disconnectController(const Reference<frame::XController> & xController)1247 void SAL_CALL SfxBaseModel::disconnectController( const Reference< frame::XController >& xController )
1248 {
1249     SfxModelGuard aGuard( *this );
1250 
1251     if ( m_pData->m_seqControllers.empty() )
1252         return;
1253 
1254     auto& vec = m_pData->m_seqControllers;
1255     std::erase(vec, xController);
1256 
1257     if ( xController == m_pData->m_xCurrent )
1258         m_pData->m_xCurrent.clear();
1259 }
1260 
1261 namespace
1262 {
1263     class ControllerLockUndoAction : public ::cppu::WeakImplHelper< XUndoAction >
1264     {
1265     public:
ControllerLockUndoAction(const Reference<XModel> & i_model,const bool i_undoIsUnlock)1266         ControllerLockUndoAction( const Reference< XModel >& i_model, const bool i_undoIsUnlock )
1267             :m_xModel( i_model )
1268             ,m_bUndoIsUnlock( i_undoIsUnlock )
1269         {
1270         }
1271 
1272         // XUndoAction
1273         virtual OUString SAL_CALL getTitle() override;
1274         virtual void SAL_CALL undo(  ) override;
1275         virtual void SAL_CALL redo(  ) override;
1276 
1277     private:
1278         const Reference< XModel >   m_xModel;
1279         const bool                  m_bUndoIsUnlock;
1280     };
1281 
getTitle()1282     OUString SAL_CALL ControllerLockUndoAction::getTitle()
1283     {
1284         // this action is intended to be used within an UndoContext only, so nobody will ever see this title ...
1285         return OUString();
1286     }
1287 
undo()1288     void SAL_CALL ControllerLockUndoAction::undo(  )
1289     {
1290         if ( m_bUndoIsUnlock )
1291             m_xModel->unlockControllers();
1292         else
1293             m_xModel->lockControllers();
1294     }
1295 
redo()1296     void SAL_CALL ControllerLockUndoAction::redo(  )
1297     {
1298         if ( m_bUndoIsUnlock )
1299             m_xModel->lockControllers();
1300         else
1301             m_xModel->unlockControllers();
1302     }
1303 }
1304 
1305 
1306 //  frame::XModel
1307 
1308 
lockControllers()1309 void SAL_CALL SfxBaseModel::lockControllers()
1310 {
1311     SfxModelGuard aGuard( *this );
1312 
1313     ++m_pData->m_nControllerLockCount ;
1314 
1315     if  (   m_pData->m_pDocumentUndoManager.is()
1316         &&  m_pData->m_pDocumentUndoManager->isInContext()
1317         &&  !m_pData->m_pDocumentUndoManager->isLocked()
1318         )
1319     {
1320         m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( this, true ) );
1321     }
1322 }
1323 
1324 
1325 //  frame::XModel
1326 
1327 
unlockControllers()1328 void SAL_CALL SfxBaseModel::unlockControllers()
1329 {
1330     SfxModelGuard aGuard( *this );
1331 
1332     --m_pData->m_nControllerLockCount ;
1333 
1334     if  (   m_pData->m_pDocumentUndoManager.is()
1335         &&  m_pData->m_pDocumentUndoManager->isInContext()
1336         &&  !m_pData->m_pDocumentUndoManager->isLocked()
1337         )
1338     {
1339         m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( this, false ) );
1340     }
1341 }
1342 
1343 
1344 //  frame::XModel
1345 
1346 
hasControllersLocked()1347 sal_Bool SAL_CALL SfxBaseModel::hasControllersLocked()
1348 {
1349     SfxModelGuard aGuard( *this );
1350     return ( m_pData->m_nControllerLockCount != 0 ) ;
1351 }
1352 
1353 
1354 //  frame::XModel
1355 
1356 
getCurrentController()1357 Reference< frame::XController > SAL_CALL SfxBaseModel::getCurrentController()
1358 {
1359     SfxModelGuard aGuard( *this );
1360 
1361     // get the last active controller of this model
1362     if ( m_pData->m_xCurrent.is() )
1363         return m_pData->m_xCurrent;
1364 
1365     // get the first controller of this model
1366     return !m_pData->m_seqControllers.empty() ? m_pData->m_seqControllers.front() : m_pData->m_xCurrent;
1367 }
1368 
1369 
1370 //  frame::XModel
1371 
1372 
setCurrentController(const Reference<frame::XController> & xCurrentController)1373 void SAL_CALL SfxBaseModel::setCurrentController( const Reference< frame::XController >& xCurrentController )
1374 {
1375     SfxModelGuard aGuard( *this );
1376 
1377     m_pData->m_xCurrent = xCurrentController;
1378 }
1379 
1380 
1381 //  frame::XModel
1382 
1383 
getCurrentSelection()1384 Reference< XInterface > SAL_CALL SfxBaseModel::getCurrentSelection()
1385 {
1386     SfxModelGuard aGuard( *this );
1387 
1388     Reference< XInterface >     xReturn;
1389     Reference< frame::XController >    xController =   getCurrentController()      ;
1390 
1391     if ( xController.is() )
1392     {
1393         Reference< view::XSelectionSupplier >  xDocView( xController, UNO_QUERY );
1394         if ( xDocView.is() )
1395         {
1396             Any aSel = xDocView->getSelection();
1397             aSel >>= xReturn ;
1398         }
1399     }
1400 
1401     return xReturn ;
1402 }
1403 
1404 
1405 //  XModifiable2
1406 
1407 
disableSetModified()1408 sal_Bool SAL_CALL SfxBaseModel::disableSetModified()
1409 {
1410     SfxModelGuard aGuard( *this );
1411 
1412     if ( !m_pData->m_pObjectShell.is() )
1413         throw RuntimeException();
1414 
1415     bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
1416     m_pData->m_pObjectShell->EnableSetModified( false );
1417 
1418     return bResult;
1419 }
1420 
enableSetModified()1421 sal_Bool SAL_CALL SfxBaseModel::enableSetModified()
1422 {
1423     SfxModelGuard aGuard( *this );
1424 
1425     if ( !m_pData->m_pObjectShell.is() )
1426         throw RuntimeException();
1427 
1428     bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
1429     m_pData->m_pObjectShell->EnableSetModified();
1430 
1431     return bResult;
1432 }
1433 
isSetModifiedEnabled()1434 sal_Bool SAL_CALL SfxBaseModel::isSetModifiedEnabled()
1435 {
1436     SfxModelGuard aGuard( *this );
1437 
1438     if ( !m_pData->m_pObjectShell.is() )
1439         throw RuntimeException();
1440 
1441     return m_pData->m_pObjectShell->IsEnableSetModified();
1442 }
1443 
1444 
1445 //  XModifiable
1446 
1447 
isModified()1448 sal_Bool SAL_CALL SfxBaseModel::isModified()
1449 {
1450     SfxModelGuard aGuard( *this );
1451 
1452     return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->IsModified();
1453 }
1454 
1455 
1456 //  XModifiable
1457 
1458 
setModified(sal_Bool bModified)1459 void SAL_CALL SfxBaseModel::setModified( sal_Bool bModified )
1460 {
1461     SfxModelGuard aGuard( *this );
1462 
1463     if ( m_pData->m_pObjectShell.is() )
1464         m_pData->m_pObjectShell->SetModified(bModified);
1465 }
1466 
1467 
1468 //  XModifiable
1469 
1470 
addModifyListener(const Reference<util::XModifyListener> & xListener)1471 void SAL_CALL SfxBaseModel::addModifyListener(const Reference< util::XModifyListener >& xListener)
1472 {
1473     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1474 
1475     m_pData->m_aModifyListeners.addInterface( xListener );
1476 }
1477 
1478 
1479 //  XModifiable
1480 
1481 
removeModifyListener(const Reference<util::XModifyListener> & xListener)1482 void SAL_CALL SfxBaseModel::removeModifyListener(const Reference< util::XModifyListener >& xListener)
1483 {
1484     SfxModelGuard aGuard( *this );
1485 
1486     m_pData->m_aModifyListeners.removeInterface( xListener );
1487 }
1488 
1489 
1490 //  XCloseable
1491 
1492 
close(sal_Bool bDeliverOwnership)1493 void SAL_CALL SfxBaseModel::close( sal_Bool bDeliverOwnership )
1494 {
1495     SolarMutexGuard aGuard;
1496     if ( impl_isDisposed() || m_pData->m_bClosed || m_pData->m_bClosing )
1497         return;
1498 
1499     Reference< XInterface > xSelfHold( getXWeak() );
1500     lang::EventObject       aSource  ( getXWeak() );
1501     if (m_pData->m_aCloseListeners.getLength())
1502     {
1503         comphelper::OInterfaceIteratorHelper3 pIterator(m_pData->m_aCloseListeners);
1504         while (pIterator.hasMoreElements())
1505         {
1506             try
1507             {
1508                 pIterator.next()->queryClosing( aSource, bDeliverOwnership );
1509             }
1510             catch( RuntimeException& )
1511             {
1512                 pIterator.remove();
1513             }
1514         }
1515     }
1516 
1517     if ( m_pData->m_bSaving )
1518     {
1519         if (bDeliverOwnership)
1520             m_pData->m_bSuicide = true;
1521         throw util::CloseVetoException(
1522                 u"Can not close while saving."_ustr,
1523                 static_cast< util::XCloseable* >(this));
1524     }
1525 
1526     // no own objections against closing!
1527     m_pData->m_bClosing = true;
1528     if (m_pData->m_aCloseListeners.getLength())
1529     {
1530         comphelper::OInterfaceIteratorHelper3 pCloseIterator(m_pData->m_aCloseListeners);
1531         while (pCloseIterator.hasMoreElements())
1532         {
1533             try
1534             {
1535                 pCloseIterator.next()->notifyClosing( aSource );
1536             }
1537             catch( RuntimeException& )
1538             {
1539                 pCloseIterator.remove();
1540             }
1541         }
1542     }
1543 
1544     m_pData->m_bClosed = true;
1545     m_pData->m_bClosing = false;
1546 
1547     dispose();
1548 }
1549 
1550 
1551 //  XCloseBroadcaster
1552 
1553 
addCloseListener(const Reference<util::XCloseListener> & xListener)1554 void SAL_CALL SfxBaseModel::addCloseListener( const Reference< util::XCloseListener >& xListener )
1555 {
1556     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1557 
1558     m_pData->m_aCloseListeners.addInterface( xListener );
1559 }
1560 
1561 
1562 //  XCloseBroadcaster
1563 
1564 
removeCloseListener(const Reference<util::XCloseListener> & xListener)1565 void SAL_CALL SfxBaseModel::removeCloseListener( const Reference< util::XCloseListener >& xListener )
1566 {
1567     SfxModelGuard aGuard( *this );
1568 
1569     m_pData->m_aCloseListeners.removeInterface( xListener );
1570 }
1571 
1572 
1573 //  XPrintable
1574 
1575 
getPrinter()1576 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getPrinter()
1577 {
1578     SfxModelGuard aGuard( *this );
1579 
1580     impl_getPrintHelper();
1581     return m_pData->m_xPrintable->getPrinter();
1582 }
1583 
setPrinter(const Sequence<beans::PropertyValue> & rPrinter)1584 void SAL_CALL SfxBaseModel::setPrinter(const Sequence< beans::PropertyValue >& rPrinter)
1585 {
1586     SfxModelGuard aGuard( *this );
1587 
1588     impl_getPrintHelper();
1589     m_pData->m_xPrintable->setPrinter( rPrinter );
1590 }
1591 
print(const Sequence<beans::PropertyValue> & rOptions)1592 void SAL_CALL SfxBaseModel::print(const Sequence< beans::PropertyValue >& rOptions)
1593 {
1594     SfxModelGuard aGuard( *this );
1595 
1596     impl_getPrintHelper();
1597 
1598     // tdf#123728 Always print on main thread to avoid deadlocks
1599     vcl::solarthread::syncExecute([this, &rOptions]() { m_pData->m_xPrintable->print(rOptions); });
1600 }
1601 
1602 //  XStorable
1603 
1604 
hasLocation()1605 sal_Bool SAL_CALL SfxBaseModel::hasLocation()
1606 {
1607     SfxModelGuard aGuard( *this );
1608 
1609     return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->HasName();
1610 }
1611 
1612 
1613 //  XStorable
1614 
1615 
getLocation()1616 OUString SAL_CALL SfxBaseModel::getLocation()
1617 {
1618     SfxModelGuard aGuard( *this );
1619 
1620     if ( m_pData->m_pObjectShell.is() )
1621     {
1622         // TODO/LATER: is it correct that the shared document returns shared file location?
1623         if ( m_pData->m_pObjectShell->IsDocShared() )
1624             return m_pData->m_pObjectShell->GetSharedFileURL();
1625         else
1626             return m_pData->m_pObjectShell->GetMedium()->GetName();
1627     }
1628 
1629     return m_pData->m_sURL;
1630 }
1631 
1632 
1633 //  XStorable
1634 
1635 
isReadonly()1636 sal_Bool SAL_CALL SfxBaseModel::isReadonly()
1637 {
1638     SfxModelGuard aGuard( *this );
1639 
1640     return !m_pData->m_pObjectShell.is() || m_pData->m_pObjectShell->IsReadOnly();
1641 }
1642 
1643 //  XStorable2
1644 
1645 
storeSelf(const Sequence<beans::PropertyValue> & aSeqArgs)1646 void SAL_CALL SfxBaseModel::storeSelf( const    Sequence< beans::PropertyValue >&  aSeqArgs )
1647 {
1648     SfxModelGuard aGuard( *this );
1649 
1650     if ( !m_pData->m_pObjectShell.is() )
1651         return;
1652 
1653     SfxSaveGuard aSaveGuard(this, m_pData.get());
1654 
1655     bool bCheckIn = false;
1656     bool bOnMainThread = false;
1657     for ( const auto& rArg : aSeqArgs )
1658     {
1659         // check that only acceptable parameters are provided here
1660         if ( rArg.Name != "VersionComment" && rArg.Name != "Author"
1661           && rArg.Name != "DontTerminateEdit"
1662           && rArg.Name != "InteractionHandler" && rArg.Name != "StatusIndicator"
1663           && rArg.Name != "VersionMajor"
1664           && rArg.Name != "FailOnWarning"
1665           && rArg.Name != "CheckIn"
1666           && rArg.Name != "NoFileSync"
1667           && rArg.Name != "OnMainThread" )
1668         {
1669             const OUString aMessage( "Unexpected MediaDescriptor parameter: " + rArg.Name );
1670             throw lang::IllegalArgumentException( aMessage, Reference< XInterface >(), 1 );
1671         }
1672         else if ( rArg.Name == "CheckIn" )
1673         {
1674             rArg.Value >>= bCheckIn;
1675         }
1676         else if (rArg.Name == "OnMainThread")
1677         {
1678             rArg.Value >>= bOnMainThread;
1679         }
1680     }
1681 
1682     // Remove CheckIn property if needed
1683     sal_uInt16 nSlotId = SID_SAVEDOC;
1684     Sequence< beans::PropertyValue >  aArgs = aSeqArgs;
1685     if ( bCheckIn )
1686     {
1687         nSlotId = SID_CHECKIN;
1688         sal_Int32 nLength = aSeqArgs.getLength( );
1689         aArgs = Sequence< beans::PropertyValue >( nLength - 1 );
1690         std::copy_if(aSeqArgs.begin(), aSeqArgs.end(), aArgs.getArray(),
1691             [](const beans::PropertyValue& rProp) { return rProp.Name != "CheckIn"; });
1692     }
1693 
1694     std::optional<SfxAllItemSet> pParams(SfxGetpApp()->GetPool() );
1695     TransformParameters( nSlotId, aArgs, *pParams );
1696 
1697     SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDoc, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOC), m_pData->m_pObjectShell.get() ) );
1698 
1699     bool bRet = false;
1700 
1701     // TODO/LATER: let the embedded case of saving be handled more careful
1702     if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1703     {
1704         // If this is an embedded object that has no URL based location it should be stored to own storage.
1705         // An embedded object can have a location based on URL in case it is a link, then it should be
1706         // stored in normal way.
1707         if ( !hasLocation() || getLocation().startsWith("private:") )
1708         {
1709             // actually in this very rare case only UI parameters have sense
1710             // TODO/LATER: should be done later, after integration of sb19
1711             bRet = m_pData->m_pObjectShell->DoSave()
1712                 && m_pData->m_pObjectShell->DoSaveCompleted();
1713         }
1714         else
1715         {
1716             bRet = m_pData->m_pObjectShell->Save_Impl( &*pParams );
1717         }
1718     }
1719     else
1720     {
1721         // Tell the SfxMedium if we are in checkin instead of normal save
1722         m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId == SID_CHECKIN );
1723         if (bOnMainThread)
1724             bRet = vcl::solarthread::syncExecute(
1725                 [this, &pParams] { return m_pData->m_pObjectShell->Save_Impl(&*pParams); });
1726         else
1727             bRet = m_pData->m_pObjectShell->Save_Impl(&*pParams);
1728         m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId != SID_CHECKIN );
1729     }
1730 
1731     pParams.reset();
1732 
1733     ErrCodeMsg nErrCode = m_pData->m_pObjectShell->GetErrorIgnoreWarning();
1734     m_pData->m_pObjectShell->ResetError();
1735 
1736     if ( bRet )
1737     {
1738         m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();
1739 
1740         SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCDONE), m_pData->m_pObjectShell.get() ) );
1741     }
1742     else
1743     {
1744         if (!nErrCode)
1745             nErrCode = ERRCODE_IO_CANTWRITE;
1746         // write the contents of the logger to the file
1747         SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocFailed, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCFAILED), m_pData->m_pObjectShell.get() ) );
1748 
1749         throw task::ErrorCodeIOException(
1750             "SfxBaseModel::storeSelf: " + nErrCode.toString(),
1751             Reference< XInterface >(), sal_uInt32(nErrCode.GetCode()));
1752     }
1753 }
1754 
1755 
1756 //  XStorable
1757 
1758 
store()1759 void SAL_CALL SfxBaseModel::store()
1760 {
1761     comphelper::ProfileZone aZone("store");
1762     storeSelf( Sequence< beans::PropertyValue >() );
1763 }
1764 
1765 
1766 //  XStorable
1767 
1768 
storeAsURL(const OUString & rURL,const Sequence<beans::PropertyValue> & rArgs)1769 void SAL_CALL SfxBaseModel::storeAsURL( const   OUString&                   rURL    ,
1770                                         const   Sequence< beans::PropertyValue >&  rArgs   )
1771 {
1772     SfxModelGuard aGuard( *this );
1773     comphelper::ProfileZone aZone("storeAs");
1774 
1775     if ( !m_pData->m_pObjectShell.is() )
1776         return;
1777 
1778     SfxSaveGuard aSaveGuard(this, m_pData.get());
1779 
1780     utl::MediaDescriptor aDescriptor(rArgs);
1781     bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault(u"OnMainThread"_ustr, false);
1782     if (bOnMainThread)
1783     {
1784         vcl::solarthread::syncExecute([this, rURL, rArgs]() { impl_store(rURL, rArgs, false); });
1785     }
1786     else
1787     {
1788         impl_store(rURL, rArgs, false);
1789     }
1790 
1791     Sequence< beans::PropertyValue > aSequence ;
1792     TransformItems( SID_OPENDOC, m_pData->m_pObjectShell->GetMedium()->GetItemSet(), aSequence );
1793     attachResource( rURL, aSequence );
1794 
1795     loadCmisProperties( );
1796 
1797 #if OSL_DEBUG_LEVEL > 0
1798     const SfxStringItem* pPasswdItem = m_pData->m_pObjectShell->GetMedium()->GetItemSet().GetItem(SID_PASSWORD, false);
1799     OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
1800 #endif
1801 }
1802 
1803 
1804 //  XUndoManagerSupplier
1805 
getUndoManager()1806 Reference< XUndoManager > SAL_CALL SfxBaseModel::getUndoManager(  )
1807 {
1808     SfxModelGuard aGuard( *this );
1809     if ( !m_pData->m_pDocumentUndoManager.is() )
1810         m_pData->m_pDocumentUndoManager.set( new ::sfx2::DocumentUndoManager( *this ) );
1811     return m_pData->m_pDocumentUndoManager;
1812 }
1813 
1814 
1815 //  XStorable
1816 
1817 
storeToURL(const OUString & rURL,const Sequence<beans::PropertyValue> & rArgs)1818 void SAL_CALL SfxBaseModel::storeToURL( const   OUString&                   rURL    ,
1819                                         const   Sequence< beans::PropertyValue >&  rArgs   )
1820 {
1821     SfxModelGuard aGuard( *this );
1822     comphelper::ProfileZone aZone("storeToURL");
1823 
1824     if ( !m_pData->m_pObjectShell.is() )
1825         return;
1826 
1827     SfxSaveGuard aSaveGuard(this, m_pData.get());
1828     try {
1829         utl::MediaDescriptor aDescriptor(rArgs);
1830         bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault(u"OnMainThread"_ustr, false);
1831         if (bOnMainThread)
1832             vcl::solarthread::syncExecute([this, rURL, rArgs]() { impl_store(rURL, rArgs, true); });
1833         else
1834             impl_store(rURL, rArgs, true);
1835     }
1836     catch (const uno::Exception &e)
1837     {
1838         // convert to the exception we announce in the throw
1839         // (eg. neon likes to throw InteractiveAugmentedIOException which
1840         // is not an io::IOException)
1841         throw io::IOException(e.Message, e.Context);
1842     }
1843 }
1844 
wasModifiedSinceLastSave()1845 sal_Bool SAL_CALL SfxBaseModel::wasModifiedSinceLastSave()
1846 {
1847     SfxModelGuard aGuard( *this );
1848     return m_pData->m_oDirtyTimestamp.has_value();
1849 }
1850 
storeToRecoveryFile(const OUString & i_TargetLocation,const Sequence<PropertyValue> & i_MediaDescriptor)1851 void SAL_CALL SfxBaseModel::storeToRecoveryFile( const OUString& i_TargetLocation, const Sequence< PropertyValue >& i_MediaDescriptor )
1852 {
1853     SfxModelGuard aGuard( *this );
1854 
1855     // delegate
1856     SfxSaveGuard aSaveGuard( this, m_pData.get() );
1857     impl_store( i_TargetLocation, i_MediaDescriptor, true );
1858 
1859     // no need for subsequent calls to storeToRecoveryFile, unless we're modified, again
1860     m_pData->setModifiedForAutoSave(false);
1861 }
1862 
getModifiedStateDuration()1863 sal_Int64 SAL_CALL SfxBaseModel::getModifiedStateDuration()
1864 {
1865     SfxModelGuard aGuard(*this);
1866     if (!m_pData->m_oDirtyTimestamp)
1867         return -1;
1868     auto ms = std::chrono::ceil<std::chrono::milliseconds>(std::chrono::steady_clock::now()
1869                                                            - *m_pData->m_oDirtyTimestamp);
1870     return ms.count();
1871 }
1872 
recoverFromFile(const OUString & i_SourceLocation,const OUString & i_SalvagedFile,const Sequence<PropertyValue> & i_MediaDescriptor)1873 void SAL_CALL SfxBaseModel::recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor )
1874 {
1875     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1876 
1877     // delegate to our "load" method
1878     ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor );
1879 
1880     // our load implementation expects the SalvagedFile to be in the media descriptor
1881     OSL_ENSURE( !aMediaDescriptor.has( u"SalvagedFile"_ustr ) || ( aMediaDescriptor.getOrDefault( u"SalvagedFile"_ustr, OUString() ) == i_SalvagedFile ),
1882         "SfxBaseModel::recoverFromFile: inconsistent information!" );
1883     aMediaDescriptor.put( u"SalvagedFile"_ustr, i_SalvagedFile );
1884 
1885     // similar for the to-be-loaded file
1886     OSL_ENSURE( !aMediaDescriptor.has( u"URL"_ustr ) || ( aMediaDescriptor.getOrDefault( u"URL"_ustr, OUString() ) == i_SourceLocation ),
1887         "SfxBaseModel::recoverFromFile: inconsistent information!" );
1888     aMediaDescriptor.put( u"URL"_ustr, i_SourceLocation );
1889 
1890     load( aMediaDescriptor.getPropertyValues() );
1891 
1892     // Note: The XDocumentRecovery interface specification requires us to do an attachResource after loading.
1893     // However, we will not do this here, as we know that our load implementation (respectively some method
1894     // called from there) already did so.
1895     // In particular, the load process might already have modified some elements of the media
1896     // descriptor, for instance the MacroExecMode (in case the user was involved to decide about it), and we do
1897     // not want to overwrite it with the "old" elements passed to this method here.
1898 }
1899 
1900 
1901 // XLoadable
1902 
1903 
initNew()1904 void SAL_CALL SfxBaseModel::initNew()
1905 {
1906     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1907     if ( IsInitialized() )
1908         throw frame::DoubleInitializationException( OUString(), *this );
1909 
1910     // the object shell should exist always
1911     DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );
1912     if ( !m_pData->m_pObjectShell.is() )
1913         return;
1914 
1915     if( m_pData->m_pObjectShell->GetMedium() )
1916         throw frame::DoubleInitializationException();
1917 
1918     bool bRes = m_pData->m_pObjectShell->DoInitNew();
1919     ErrCodeMsg nErrCode = m_pData->m_pObjectShell->GetErrorIgnoreWarning() ?
1920                        m_pData->m_pObjectShell->GetErrorIgnoreWarning() : ERRCODE_IO_CANTCREATE;
1921     m_pData->m_pObjectShell->ResetError();
1922 
1923     if ( !bRes )
1924         throw task::ErrorCodeIOException(
1925             "SfxBaseModel::initNew: " + nErrCode.toString(),
1926             Reference< XInterface >(), sal_uInt32(nErrCode.GetCode()));
1927 }
1928 
1929 namespace {
1930 
getFilterProvider(SfxMedium const & rMedium)1931 OUString getFilterProvider( SfxMedium const & rMedium )
1932 {
1933     const std::shared_ptr<const SfxFilter>& pFilter = rMedium.GetFilter();
1934     if (!pFilter)
1935         return OUString();
1936 
1937     return pFilter->GetProviderName();
1938 }
1939 
setUpdatePickList(SfxMedium * pMedium)1940 void setUpdatePickList( SfxMedium* pMedium )
1941 {
1942     if (!pMedium)
1943         return;
1944 
1945     bool bHidden = false;
1946     const SfxBoolItem* pHidItem = pMedium->GetItemSet().GetItem(SID_HIDDEN, false);
1947     if (pHidItem)
1948         bHidden = pHidItem->GetValue();
1949 
1950     pMedium->SetUpdatePickList(!bHidden);
1951 }
1952 
1953 }
1954 
load(const Sequence<beans::PropertyValue> & seqArguments)1955 void SAL_CALL SfxBaseModel::load(   const Sequence< beans::PropertyValue >& seqArguments )
1956 {
1957     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1958     if ( IsInitialized() )
1959         throw frame::DoubleInitializationException( OUString(), *this );
1960 
1961     // the object shell should exist always
1962     DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );
1963 
1964     if (!m_pData->m_pObjectShell.is())
1965         return;
1966 
1967     if( m_pData->m_pObjectShell->GetMedium() )
1968         // if a Medium is present, the document is already initialized
1969         throw frame::DoubleInitializationException();
1970 
1971     SfxMedium* pMedium = new SfxMedium( seqArguments );
1972 
1973     ErrCodeMsg nError = ERRCODE_NONE;
1974     if (!getFilterProvider(*pMedium).isEmpty())
1975     {
1976         if (!m_pData->m_pObjectShell->DoLoadExternal(pMedium))
1977             nError = ERRCODE_IO_GENERAL;
1978 
1979         pMedium = handleLoadError(nError, pMedium);
1980         setUpdatePickList(pMedium);
1981         return;
1982     }
1983 
1984     OUString aFilterName;
1985     const SfxStringItem* pFilterNameItem = pMedium->GetItemSet().GetItem(SID_FILTER_NAME, false);
1986     if( pFilterNameItem )
1987         aFilterName = pFilterNameItem->GetValue();
1988     if( !m_pData->m_pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) )
1989     {
1990         // filtername is not valid
1991         delete pMedium;
1992         throw frame::IllegalArgumentIOException();
1993     }
1994 
1995     const SfxStringItem* pSalvageItem = pMedium->GetItemSet().GetItem(SID_DOC_SALVAGE, false);
1996     bool bSalvage = pSalvageItem != nullptr;
1997 
1998     // load document
1999     if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
2000         nError=ERRCODE_IO_GENERAL;
2001 
2002     // QUESTION: if the following happens outside of DoLoad, something important is missing there!
2003     Reference< task::XInteractionHandler > xHandler = pMedium->GetInteractionHandler();
2004     if( m_pData->m_pObjectShell->GetErrorCode() )
2005     {
2006         nError = m_pData->m_pObjectShell->GetErrorCode();
2007         if ( nError == ERRCODE_IO_BROKENPACKAGE && xHandler.is() )
2008         {
2009             const OUString aDocName( pMedium->GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ) );
2010             if (!pMedium->IsRepairPackage())
2011             {
2012                 RequestPackageReparation aRequest( aDocName );
2013                 xHandler->handle( aRequest.GetRequest() );
2014                 if( aRequest.isApproved() )
2015                 {
2016                     // lok: we want to overwrite file in jail, so don't use template flag
2017                     bool bIsLOK = comphelper::LibreOfficeKit::isActive();
2018                     // broken package: try second loading and allow repair
2019                     pMedium->GetItemSet().Put( SfxBoolItem( SID_REPAIRPACKAGE, true ) );
2020                     pMedium->GetItemSet().Put( SfxBoolItem( SID_TEMPLATE, !bIsLOK ) );
2021                     pMedium->GetItemSet().Put( SfxStringItem( SID_DOCINFO_TITLE, aDocName ) );
2022 
2023                     // the error must be reset and the storage must be reopened in new mode
2024                     pMedium->ResetError();
2025                     pMedium->CloseStorage();
2026                     m_pData->m_pObjectShell->PrepareSecondTryLoad_Impl();
2027                     nError = ERRCODE_NONE;
2028                     if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
2029                         nError=ERRCODE_IO_GENERAL;
2030                     if (m_pData->m_pObjectShell->GetErrorCode())
2031                         nError = m_pData->m_pObjectShell->GetErrorCode();
2032                 }
2033             }
2034 
2035             if ( nError == ERRCODE_IO_BROKENPACKAGE )
2036             {
2037                 // repair either not allowed or not successful
2038                 NotifyBrokenPackage aRequest( aDocName );
2039                 xHandler->handle( aRequest.GetRequest() );
2040             }
2041         }
2042     }
2043 
2044     if( m_pData->m_pObjectShell->IsAbortingImport() )
2045         nError = ERRCODE_ABORT;
2046 
2047     if (bSalvage && nError == ERRCODE_NONE)
2048     {
2049         // file recovery: restore original filter
2050         const SfxStringItem* pFilterItem = pMedium->GetItemSet().GetItem(SID_FILTER_NAME, false);
2051         assert(pFilterItem && "this will exist");
2052         SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
2053         std::shared_ptr<const SfxFilter> pSetFilter = rMatcher.GetFilter4FilterName( pFilterItem->GetValue() );
2054         pMedium->SetFilter( pSetFilter );
2055         m_pData->m_pObjectShell->SetModified();
2056     }
2057 
2058     // TODO/LATER: maybe the mode should be retrieved from outside and the preused filter should not be set
2059     if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
2060     {
2061         const SfxStringItem* pFilterItem = pMedium->GetItemSet().GetItem(SID_FILTER_NAME, false);
2062         if ( pFilterItem )
2063             m_pData->m_aPreusedFilterName = pFilterItem->GetValue();
2064     }
2065 
2066     if ( !nError )
2067         nError = pMedium->GetErrorIgnoreWarning();
2068 
2069     m_pData->m_pObjectShell->ResetError();
2070 
2071     pMedium = handleLoadError(nError, pMedium);
2072     loadCmisProperties();
2073     setUpdatePickList(pMedium);
2074 
2075 #if OSL_DEBUG_LEVEL > 0
2076     const SfxStringItem* pPasswdItem = pMedium->GetItemSet().GetItem(SID_PASSWORD, false);
2077     OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
2078 #endif
2079 }
2080 
2081 
2082 // XTransferable
2083 
2084 
getTransferData(const datatransfer::DataFlavor & aFlavor)2085 Any SAL_CALL SfxBaseModel::getTransferData( const datatransfer::DataFlavor& aFlavor )
2086 {
2087     SfxModelGuard aGuard( *this );
2088 
2089     Any aAny;
2090 
2091     if ( m_pData->m_pObjectShell.is() )
2092     {
2093         if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
2094         {
2095             if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2096                 throw datatransfer::UnsupportedFlavorException();
2097 
2098             TransferableObjectDescriptor aDesc;
2099 
2100             aDesc.maClassName = m_pData->m_pObjectShell->GetClassName();
2101             aDesc.maTypeName = aFlavor.HumanPresentableName;
2102 
2103             // TODO/LATER: ViewAspect needs to be sal_Int64
2104             aDesc.mnViewAspect = sal::static_int_cast< sal_uInt16 >( embed::Aspects::MSOLE_CONTENT );
2105 
2106             Size aSize = m_pData->m_pObjectShell->GetVisArea().GetSize();
2107 
2108             MapUnit aMapUnit = m_pData->m_pObjectShell->GetMapUnit();
2109             aDesc.maSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
2110             aDesc.maDragStartPos = Point();
2111             aDesc.maDisplayName.clear();
2112 
2113             SvMemoryStream aMemStm( 1024, 1024 );
2114             WriteTransferableObjectDescriptor( aMemStm, aDesc );
2115             aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
2116         }
2117         else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
2118         {
2119             if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2120                 throw datatransfer::UnsupportedFlavorException();
2121 
2122             try
2123             {
2124                 utl::TempFileNamed aTmp;
2125                 aTmp.EnableKillingFile();
2126                 storeToURL( aTmp.GetURL(), Sequence < beans::PropertyValue >() );
2127                 std::unique_ptr<SvStream> pStream(aTmp.GetStream( StreamMode::READ ));
2128                 const sal_uInt32 nLen = pStream->TellEnd();
2129                 Sequence< sal_Int8 > aSeq( nLen );
2130                 pStream->ReadBytes(aSeq.getArray(), nLen);
2131                 if( aSeq.hasElements() )
2132                     aAny <<= aSeq;
2133             }
2134             catch ( Exception& )
2135             {
2136             }
2137         }
2138         else if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2139         {
2140             if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2141                 throw datatransfer::UnsupportedFlavorException();
2142 
2143 
2144             std::shared_ptr<GDIMetaFile> xMetaFile =
2145                 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2146 
2147             if (xMetaFile)
2148             {
2149                 SvMemoryStream aMemStm( 65535, 65535 );
2150                 aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2151 
2152                 SvmWriter aWriter( aMemStm );
2153                 aWriter.Write( *xMetaFile );
2154                 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
2155                                                 aMemStm.TellEnd() );
2156             }
2157         }
2158         else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2159         {
2160             if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2161                 throw datatransfer::UnsupportedFlavorException();
2162 
2163             std::shared_ptr<GDIMetaFile> xMetaFile =
2164                 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2165 
2166             if (xMetaFile)
2167             {
2168                 SvMemoryStream aMemStm( 65535, 65535 );
2169                 aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2170 
2171                 SvmWriter aWriter( aMemStm );
2172                 aWriter.Write( *xMetaFile );
2173                 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
2174                                                 aMemStm.TellEnd() );
2175             }
2176         }
2177         else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
2178         {
2179             if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2180             {
2181                 std::shared_ptr<GDIMetaFile> xMetaFile =
2182                     m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2183 
2184                 if (xMetaFile)
2185                 {
2186                     std::unique_ptr<SvMemoryStream> xStream(
2187                         GraphicHelper::getFormatStrFromGDI_Impl(
2188                             xMetaFile.get(), ConvertDataFormat::EMF ) );
2189                     if (xStream)
2190                     {
2191                         xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2192                         aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2193                                                         xStream->TellEnd() );
2194                     }
2195                 }
2196             }
2197             else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2198               && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2199             {
2200                 std::shared_ptr<GDIMetaFile> xMetaFile =
2201                     m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2202 
2203                 if (xMetaFile)
2204                 {
2205                     aAny <<= reinterpret_cast< sal_uInt64 >(
2206                         GraphicHelper::getEnhMetaFileFromGDI_Impl( xMetaFile.get() ) );
2207                 }
2208             }
2209             else
2210                 throw datatransfer::UnsupportedFlavorException();
2211         }
2212         else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
2213         {
2214             if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2215             {
2216                 std::shared_ptr<GDIMetaFile> xMetaFile =
2217                     m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2218 
2219                 if (xMetaFile)
2220                 {
2221                     std::unique_ptr<SvMemoryStream> xStream(
2222                         GraphicHelper::getFormatStrFromGDI_Impl(
2223                             xMetaFile.get(), ConvertDataFormat::WMF ) );
2224 
2225                     if (xStream)
2226                     {
2227                         xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2228                         aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2229                                                         xStream->TellEnd() );
2230                     }
2231                 }
2232             }
2233             else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2234               && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2235             {
2236                 // means HGLOBAL handler to memory storage containing METAFILEPICT structure
2237 
2238                 std::shared_ptr<GDIMetaFile> xMetaFile =
2239                     m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2240 
2241                 if (xMetaFile)
2242                 {
2243                     Size aMetaSize = xMetaFile->GetPrefSize();
2244                     aAny <<= reinterpret_cast< sal_uInt64 >(
2245                         GraphicHelper::getWinMetaFileFromGDI_Impl(
2246                             xMetaFile.get(), aMetaSize ) );
2247                 }
2248             }
2249             else
2250                 throw datatransfer::UnsupportedFlavorException();
2251         }
2252         else if ( aFlavor.MimeType == "image/svg+xml" )
2253         {
2254             if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2255                 throw datatransfer::UnsupportedFlavorException();
2256 
2257             std::shared_ptr<GDIMetaFile> xMetaFile =
2258                 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2259 
2260             if (xMetaFile)
2261             {
2262                 std::unique_ptr<SvMemoryStream> xStream(
2263                     GraphicHelper::getFormatStrFromGDI_Impl(
2264                         xMetaFile.get(), ConvertDataFormat::SVG ) );
2265 
2266                 if (xStream)
2267                 {
2268                     xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2269                     aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2270                                                     xStream->TellEnd() );
2271                 }
2272             }
2273         }
2274         else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
2275         {
2276             if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2277                 throw datatransfer::UnsupportedFlavorException();
2278 
2279             std::shared_ptr<GDIMetaFile> xMetaFile =
2280                 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2281 
2282             if (xMetaFile)
2283             {
2284                 std::unique_ptr<SvMemoryStream> xStream(
2285                     GraphicHelper::getFormatStrFromGDI_Impl(
2286                         xMetaFile.get(), ConvertDataFormat::BMP ) );
2287 
2288                 if (xStream)
2289                 {
2290                     xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2291                     aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2292                                                     xStream->TellEnd() );
2293                 }
2294             }
2295         }
2296         else if ( aFlavor.MimeType == "image/png" )
2297         {
2298             if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2299                 throw datatransfer::UnsupportedFlavorException();
2300 
2301             std::shared_ptr<GDIMetaFile> xMetaFile =
2302                 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2303 
2304             if (xMetaFile)
2305             {
2306                 std::unique_ptr<SvMemoryStream> xStream(
2307                     GraphicHelper::getFormatStrFromGDI_Impl(
2308                         xMetaFile.get(), ConvertDataFormat::PNG ) );
2309 
2310                 if (xStream)
2311                 {
2312                     xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2313                     aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2314                                                     xStream->TellEnd() );
2315                 }
2316             }
2317         }
2318         else
2319             throw datatransfer::UnsupportedFlavorException();
2320     }
2321 
2322     return aAny;
2323 }
2324 
2325 
2326 // XTransferable
2327 
2328 
getTransferDataFlavors()2329 Sequence< datatransfer::DataFlavor > SAL_CALL SfxBaseModel::getTransferDataFlavors()
2330 {
2331     SfxModelGuard aGuard( *this );
2332 
2333     const sal_Int32 nSuppFlavors = GraphicHelper::supportsMetaFileHandle_Impl() ? 11 : 9;
2334     Sequence< datatransfer::DataFlavor > aFlavorSeq( nSuppFlavors );
2335     auto pFlavorSeq = aFlavorSeq.getArray();
2336 
2337     pFlavorSeq[0].MimeType =
2338         "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
2339     pFlavorSeq[0].HumanPresentableName =  "GDIMetaFile";
2340     pFlavorSeq[0].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2341 
2342     pFlavorSeq[1].MimeType =
2343         "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"";
2344     pFlavorSeq[1].HumanPresentableName = "GDIMetaFile";
2345     pFlavorSeq[1].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2346 
2347     pFlavorSeq[2].MimeType =
2348         "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ;
2349     pFlavorSeq[2].HumanPresentableName = "Enhanced Windows MetaFile";
2350     pFlavorSeq[2].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2351 
2352     pFlavorSeq[3].MimeType =
2353         "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
2354     pFlavorSeq[3].HumanPresentableName = "Windows MetaFile";
2355     pFlavorSeq[3].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2356 
2357     pFlavorSeq[4].MimeType =
2358         "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
2359     pFlavorSeq[4].HumanPresentableName = "Star Object Descriptor (XML)";
2360     pFlavorSeq[4].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2361 
2362     pFlavorSeq[5].MimeType =
2363         "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
2364     pFlavorSeq[5].HumanPresentableName = "Star Embed Source (XML)";
2365     pFlavorSeq[5].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2366 
2367     pFlavorSeq[6].MimeType =
2368         "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"";
2369     pFlavorSeq[6].HumanPresentableName = "Bitmap";
2370     pFlavorSeq[6].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2371 
2372     pFlavorSeq[7].MimeType = "image/png";
2373     pFlavorSeq[7].HumanPresentableName = "PNG";
2374     pFlavorSeq[7].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2375 
2376     pFlavorSeq[8].MimeType = "image/svg+xml";
2377     pFlavorSeq[8].HumanPresentableName = "SVG";
2378     pFlavorSeq[8].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2379 
2380     if ( nSuppFlavors == 11 )
2381     {
2382         pFlavorSeq[9].MimeType =
2383             "application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
2384         pFlavorSeq[9].HumanPresentableName = "Enhanced Windows MetaFile";
2385         pFlavorSeq[9].DataType = cppu::UnoType<sal_uInt64>::get();
2386 
2387         pFlavorSeq[10].MimeType =
2388             "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
2389         pFlavorSeq[10].HumanPresentableName = "Windows MetaFile";
2390         pFlavorSeq[10].DataType = cppu::UnoType<sal_uInt64>::get();
2391     }
2392 
2393     return aFlavorSeq;
2394 }
2395 
2396 
2397 // XTransferable
2398 
2399 
isDataFlavorSupported(const datatransfer::DataFlavor & aFlavor)2400 sal_Bool SAL_CALL SfxBaseModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
2401 {
2402     SfxModelGuard aGuard( *this );
2403 
2404     if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2405     {
2406         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2407             return true;
2408     }
2409     else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2410     {
2411         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2412             return true;
2413     }
2414     else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
2415     {
2416         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2417             return true;
2418         else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2419           && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2420             return true;
2421     }
2422     else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
2423     {
2424         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2425             return true;
2426         else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2427           && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2428             return true;
2429     }
2430     else if ( aFlavor.MimeType == "image/svg+xml" )
2431     {
2432         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2433             return true;
2434     }
2435     else if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
2436     {
2437         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2438             return true;
2439     }
2440     else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
2441     {
2442         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2443             return true;
2444     }
2445     else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
2446     {
2447         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2448             return true;
2449     }
2450     else if ( aFlavor.MimeType == "image/png" )
2451     {
2452         if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2453             return true;
2454     }
2455 
2456     return false;
2457 }
2458 
2459 
2460 //  XEventsSupplier
2461 
2462 
getEvents()2463 Reference< container::XNameReplace > SAL_CALL SfxBaseModel::getEvents()
2464 {
2465     SfxModelGuard aGuard( *this );
2466 
2467     if ( ! m_pData->m_xEvents.is() )
2468     {
2469         m_pData->m_xEvents = new SfxEvents_Impl( m_pData->m_pObjectShell.get(), this );
2470     }
2471 
2472     return m_pData->m_xEvents;
2473 }
2474 
2475 
2476 //  XEmbeddedScripts
2477 
2478 
getBasicLibraries()2479 Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getBasicLibraries()
2480 {
2481     SfxModelGuard aGuard( *this );
2482 
2483     Reference< script::XStorageBasedLibraryContainer > xBasicLibraries;
2484     if ( m_pData->m_pObjectShell.is() )
2485         xBasicLibraries.set(m_pData->m_pObjectShell->GetBasicContainer());
2486     return xBasicLibraries;
2487 }
2488 
getDialogLibraries()2489 Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getDialogLibraries()
2490 {
2491     SfxModelGuard aGuard( *this );
2492 
2493     Reference< script::XStorageBasedLibraryContainer > xDialogLibraries;
2494     if ( m_pData->m_pObjectShell.is() )
2495         xDialogLibraries.set(m_pData->m_pObjectShell->GetDialogContainer());
2496     return xDialogLibraries;
2497 }
2498 
getAllowMacroExecution()2499 sal_Bool SAL_CALL SfxBaseModel::getAllowMacroExecution()
2500 {
2501     SfxModelGuard aGuard( *this );
2502 
2503     if ( m_pData->m_pObjectShell.is() )
2504         return m_pData->m_pObjectShell->AdjustMacroMode();
2505     return false;
2506 }
2507 
2508 
2509 //  XScriptInvocationContext
2510 
2511 
getScriptContainer()2512 Reference< document::XEmbeddedScripts > SAL_CALL SfxBaseModel::getScriptContainer()
2513 {
2514     SfxModelGuard aGuard( *this );
2515 
2516     Reference< document::XEmbeddedScripts > xDocumentScripts;
2517 
2518     try
2519     {
2520         Reference< frame::XModel > xDocument( this );
2521         xDocumentScripts.set( xDocument, UNO_QUERY );
2522         while ( !xDocumentScripts.is() && xDocument.is() )
2523         {
2524             Reference< container::XChild > xDocAsChild( xDocument, UNO_QUERY );
2525             if ( !xDocAsChild.is() )
2526             {
2527                 xDocument = nullptr;
2528                 break;
2529             }
2530 
2531             xDocument.set( xDocAsChild->getParent(), UNO_QUERY );
2532             xDocumentScripts.set( xDocument, UNO_QUERY );
2533         }
2534     }
2535     catch( const Exception& )
2536     {
2537         DBG_UNHANDLED_EXCEPTION("sfx.doc");
2538         xDocumentScripts = nullptr;
2539     }
2540 
2541     return xDocumentScripts;
2542 }
2543 
2544 
2545 //  XEventBroadcaster
2546 
2547 
addEventListener(const Reference<document::XEventListener> & aListener)2548 void SAL_CALL SfxBaseModel::addEventListener( const Reference< document::XEventListener >& aListener )
2549 {
2550     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2551 
2552     m_pData->m_aDocumentEventListeners1.addInterface( aListener );
2553 }
2554 
2555 
2556 //  XEventBroadcaster
2557 
2558 
removeEventListener(const Reference<document::XEventListener> & aListener)2559 void SAL_CALL SfxBaseModel::removeEventListener( const Reference< document::XEventListener >& aListener )
2560 {
2561     SfxModelGuard aGuard( *this );
2562 
2563     m_pData->m_aDocumentEventListeners1.removeInterface( aListener );
2564 }
2565 
2566 //  XShapeEventBroadcaster
2567 
addShapeEventListener(const css::uno::Reference<css::drawing::XShape> & xShape,const Reference<document::XShapeEventListener> & xListener)2568 void SAL_CALL SfxBaseModel::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
2569 {
2570     assert(xShape.is() && "no shape?");
2571     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2572 
2573     m_pData->maShapeListeners[xShape].push_back(xListener);
2574 }
2575 
2576 
2577 //  XShapeEventBroadcaster
2578 
2579 
removeShapeEventListener(const css::uno::Reference<css::drawing::XShape> & xShape,const Reference<document::XShapeEventListener> & xListener)2580 void SAL_CALL SfxBaseModel::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
2581 {
2582     SfxModelGuard aGuard( *this );
2583 
2584     auto it = m_pData->maShapeListeners.find(xShape);
2585     if (it != m_pData->maShapeListeners.end())
2586     {
2587         auto rVec = it->second;
2588         auto it2 = std::find(rVec.begin(), rVec.end(), xListener);
2589         if (it2 != rVec.end())
2590         {
2591             rVec.erase(it2);
2592             if (rVec.empty())
2593                 m_pData->maShapeListeners.erase(it);
2594         }
2595     }
2596 }
2597 
2598 //  XDocumentEventBroadcaster
2599 
2600 
addDocumentEventListener(const Reference<document::XDocumentEventListener> & aListener)2601 void SAL_CALL SfxBaseModel::addDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
2602 {
2603     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2604     m_pData->m_aDocumentEventListeners2.addInterface( aListener );
2605 }
2606 
2607 
removeDocumentEventListener(const Reference<document::XDocumentEventListener> & aListener)2608 void SAL_CALL SfxBaseModel::removeDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
2609 {
2610     SfxModelGuard aGuard( *this );
2611     m_pData->m_aDocumentEventListeners2.removeInterface( aListener );
2612 }
2613 
2614 
notifyDocumentEvent(const OUString &,const Reference<frame::XController2> &,const Any &)2615 void SAL_CALL SfxBaseModel::notifyDocumentEvent( const OUString&, const Reference< frame::XController2 >&, const Any& )
2616 {
2617     throw lang::NoSupportException(u"SfxBaseModel controls all the sent notifications itself!"_ustr );
2618 }
2619 
getCmisProperties()2620 Sequence<document::CmisProperty> SAL_CALL SfxBaseModel::getCmisProperties()
2621 {
2622     if (impl_isDisposed())
2623         return Sequence<document::CmisProperty>();
2624     return m_pData->m_cmisProperties;
2625 }
2626 
setCmisProperties(const Sequence<document::CmisProperty> & _cmisproperties)2627 void SAL_CALL SfxBaseModel::setCmisProperties( const Sequence< document::CmisProperty >& _cmisproperties )
2628 {
2629     m_pData->m_cmisProperties = _cmisproperties;
2630 }
2631 
updateCmisProperties(const Sequence<document::CmisProperty> & aProperties)2632 void SAL_CALL SfxBaseModel::updateCmisProperties( const Sequence< document::CmisProperty >& aProperties )
2633 {
2634     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2635     if ( !pMedium )
2636         return;
2637 
2638     try
2639     {
2640         ::ucbhelper::Content aContent( pMedium->GetName( ),
2641             Reference<ucb::XCommandEnvironment>(),
2642             comphelper::getProcessComponentContext() );
2643 
2644         aContent.executeCommand( u"updateProperties"_ustr, uno::Any( aProperties ) );
2645         loadCmisProperties( );
2646     }
2647     catch (const Exception & e)
2648     {
2649         css::uno::Any anyEx = cppu::getCaughtException();
2650         throw lang::WrappedTargetRuntimeException( e.Message,
2651                         e.Context, anyEx );
2652     }
2653 
2654 }
2655 
checkOut()2656 void SAL_CALL SfxBaseModel::checkOut(  )
2657 {
2658     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2659     if ( !pMedium )
2660         return;
2661 
2662     try
2663     {
2664         ::ucbhelper::Content aContent( pMedium->GetName(),
2665             Reference<ucb::XCommandEnvironment>(),
2666             comphelper::getProcessComponentContext() );
2667 
2668         Any aResult = aContent.executeCommand( u"checkout"_ustr, Any( ) );
2669         OUString sURL;
2670         aResult >>= sURL;
2671 
2672         m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
2673         m_pData->m_pObjectShell->GetMedium( )->GetMedium_Impl( );
2674         m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
2675         Sequence< beans::PropertyValue > aSequence ;
2676         TransformItems( SID_OPENDOC, pMedium->GetItemSet(), aSequence );
2677         attachResource( sURL, aSequence );
2678 
2679         // Reload the CMIS properties
2680         loadCmisProperties( );
2681     }
2682     catch ( const Exception & e )
2683     {
2684         css::uno::Any anyEx = cppu::getCaughtException();
2685         throw lang::WrappedTargetRuntimeException( e.Message,
2686                         e.Context, anyEx );
2687     }
2688 }
2689 
cancelCheckOut()2690 void SAL_CALL SfxBaseModel::cancelCheckOut(  )
2691 {
2692     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2693     if ( !pMedium )
2694         return;
2695 
2696     try
2697     {
2698         ::ucbhelper::Content aContent( pMedium->GetName(),
2699             Reference<ucb::XCommandEnvironment>(),
2700             comphelper::getProcessComponentContext() );
2701 
2702         Any aResult = aContent.executeCommand( u"cancelCheckout"_ustr, Any( ) );
2703         OUString sURL;
2704         aResult >>= sURL;
2705 
2706         m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
2707     }
2708     catch ( const Exception & e )
2709     {
2710         css::uno::Any anyEx = cppu::getCaughtException();
2711         throw lang::WrappedTargetRuntimeException( e.Message,
2712                         e.Context, anyEx );
2713     }
2714 }
2715 
checkIn(sal_Bool bIsMajor,const OUString & rMessage)2716 void SAL_CALL SfxBaseModel::checkIn( sal_Bool bIsMajor, const OUString& rMessage )
2717 {
2718     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2719     if ( !pMedium )
2720         return;
2721 
2722     try
2723     {
2724         Sequence< beans::PropertyValue > aProps{
2725             comphelper::makePropertyValue(u"VersionMajor"_ustr, bIsMajor),
2726             comphelper::makePropertyValue(u"VersionComment"_ustr, rMessage),
2727             comphelper::makePropertyValue(u"CheckIn"_ustr, true)
2728         };
2729 
2730         const OUString sName( pMedium->GetName( ) );
2731         storeSelf( aProps );
2732 
2733         // Refresh pMedium as it has probably changed during the storeSelf call
2734         pMedium = m_pData->m_pObjectShell->GetMedium( );
2735         const OUString sNewName( pMedium->GetName( ) );
2736 
2737         // URL has changed, update the document
2738         if ( sName != sNewName )
2739         {
2740             m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
2741             Sequence< beans::PropertyValue > aSequence ;
2742             TransformItems( SID_OPENDOC, pMedium->GetItemSet(), aSequence );
2743             attachResource( sNewName, aSequence );
2744 
2745             // Reload the CMIS properties
2746             loadCmisProperties( );
2747         }
2748     }
2749     catch ( const Exception & e )
2750     {
2751         css::uno::Any anyEx = cppu::getCaughtException();
2752         throw lang::WrappedTargetRuntimeException( e.Message,
2753                         e.Context, anyEx );
2754     }
2755 }
2756 
getAllVersions()2757 uno::Sequence< document::CmisVersion > SAL_CALL SfxBaseModel::getAllVersions( )
2758 {
2759     uno::Sequence<document::CmisVersion> aVersions;
2760     if (impl_isDisposed())
2761         return aVersions;
2762     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2763     if ( pMedium )
2764     {
2765         try
2766         {
2767             ::ucbhelper::Content aContent( pMedium->GetName(),
2768                 Reference<ucb::XCommandEnvironment>(),
2769                 comphelper::getProcessComponentContext() );
2770 
2771             Any aResult = aContent.executeCommand( u"getAllVersions"_ustr, Any( ) );
2772             aResult >>= aVersions;
2773         }
2774         catch ( const Exception & e )
2775         {
2776             css::uno::Any anyEx = cppu::getCaughtException();
2777             throw lang::WrappedTargetRuntimeException( e.Message,
2778                             e.Context, anyEx );
2779         }
2780     }
2781     return aVersions;
2782 }
2783 
getBoolPropertyValue(const OUString & rName)2784 bool SfxBaseModel::getBoolPropertyValue( const OUString& rName )
2785 {
2786     bool bValue = false;
2787     if ( m_pData->m_pObjectShell.is() )
2788     {
2789         SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2790         if ( pMedium )
2791         {
2792             try
2793             {
2794                 ::ucbhelper::Content aContent( pMedium->GetName( ),
2795                     utl::UCBContentHelper::getDefaultCommandEnvironment(),
2796                     comphelper::getProcessComponentContext() );
2797                 Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
2798                 if ( xProps->hasPropertyByName( rName ) )
2799                 {
2800                     aContent.getPropertyValue( rName ) >>= bValue;
2801                 }
2802             }
2803             catch ( const Exception & )
2804             {
2805                 // Simply ignore it: it's likely the document isn't versionable in that case
2806                 bValue = false;
2807             }
2808         }
2809     }
2810     return bValue;
2811 }
2812 
isVersionable()2813 sal_Bool SAL_CALL SfxBaseModel::isVersionable( )
2814 {
2815     return getBoolPropertyValue( u"IsVersionable"_ustr );
2816 }
2817 
canCheckOut()2818 sal_Bool SAL_CALL SfxBaseModel::canCheckOut( )
2819 {
2820     return getBoolPropertyValue( u"CanCheckOut"_ustr );
2821 }
2822 
canCancelCheckOut()2823 sal_Bool SAL_CALL SfxBaseModel::canCancelCheckOut( )
2824 {
2825     return getBoolPropertyValue( u"CanCancelCheckOut"_ustr );
2826 }
2827 
canCheckIn()2828 sal_Bool SAL_CALL SfxBaseModel::canCheckIn( )
2829 {
2830     return getBoolPropertyValue( u"CanCheckIn"_ustr );
2831 }
2832 
loadCmisProperties()2833 void SfxBaseModel::loadCmisProperties( )
2834 {
2835     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2836     if ( !pMedium )
2837         return;
2838 
2839     try
2840     {
2841         ::ucbhelper::Content aContent( pMedium->GetName( ),
2842             utl::UCBContentHelper::getDefaultCommandEnvironment(),
2843             comphelper::getProcessComponentContext() );
2844         Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
2845         static constexpr OUString aCmisProps( u"CmisProperties"_ustr );
2846         if ( xProps->hasPropertyByName( aCmisProps ) )
2847         {
2848             Sequence< document::CmisProperty> aCmisProperties;
2849             aContent.getPropertyValue( aCmisProps ) >>= aCmisProperties;
2850             setCmisProperties( aCmisProperties );
2851         }
2852     }
2853     catch (const ucb::ContentCreationException &)
2854     {
2855     }
2856     catch (const ucb::CommandAbortedException &)
2857     {
2858     }
2859 }
2860 
handleLoadError(const ErrCodeMsg & rError,SfxMedium * pMedium)2861 SfxMedium* SfxBaseModel::handleLoadError( const ErrCodeMsg& rError, SfxMedium* pMedium )
2862 {
2863     if (!rError)
2864     {
2865         // No error condition.
2866         return pMedium;
2867     }
2868 
2869     ErrCodeMsg nError = rError;
2870     bool bSilent = false;
2871     const SfxBoolItem* pSilentItem = pMedium->GetItemSet().GetItem(SID_SILENT, false);
2872     if( pSilentItem )
2873         bSilent = pSilentItem->GetValue();
2874 
2875     bool bWarning = nError.IsWarning();
2876     if ( nError != ERRCODE_IO_BROKENPACKAGE && !bSilent )
2877     {
2878         // broken package was handled already
2879         if ( SfxObjectShell::UseInteractionToHandleError(pMedium->GetInteractionHandler(), nError) && !bWarning)
2880         {
2881             // abort loading (except for warnings)
2882             nError = ERRCODE_IO_ABORT;
2883         }
2884     }
2885 
2886     if ( m_pData->m_pObjectShell->GetMedium() != pMedium )
2887     {
2888         // for whatever reason document now has another medium
2889         OSL_FAIL("Document has rejected the medium?!");
2890         delete pMedium;
2891         pMedium = nullptr;
2892     }
2893 
2894     if ( !bWarning )    // #i30711# don't abort loading if it's only a warning
2895     {
2896         nError = nError ? nError : ERRCODE_IO_CANTREAD;
2897         throw task::ErrorCodeIOException(
2898             "SfxBaseModel::handleLoadError: 0x" + nError.toString(),
2899             Reference< XInterface >(), sal_uInt32(nError.GetCode()));
2900     }
2901     else
2902         pMedium->SetWarningError(nError);
2903 
2904     return pMedium;
2905 }
2906 
2907 
2908 //  SfxListener
2909 
2910 
addTitle_Impl(Sequence<beans::PropertyValue> & rSeq,const OUString & rTitle)2911 static void addTitle_Impl( Sequence < beans::PropertyValue >& rSeq, const OUString& rTitle )
2912 {
2913     auto [begin, end] = asNonConstRange(rSeq);
2914     auto pProp = std::find_if(begin, end,
2915         [](const beans::PropertyValue& rProp) { return rProp.Name == "Title"; });
2916     if (pProp != end)
2917     {
2918         pProp->Value <<= rTitle;
2919     }
2920     else
2921     {
2922         sal_Int32 nCount = rSeq.getLength();
2923         rSeq.realloc( nCount+1 );
2924         auto& el = rSeq.getArray()[nCount];
2925         el.Name = "Title";
2926         el.Value <<= rTitle;
2927     }
2928 }
2929 
Notify(SfxBroadcaster & rBC,const SfxHint & rHint)2930 void SfxBaseModel::Notify(          SfxBroadcaster& rBC     ,
2931                              const  SfxHint&        rHint   )
2932 {
2933     if ( !m_pData )
2934         return;
2935 
2936     if ( &rBC != m_pData->m_pObjectShell.get() )
2937         return;
2938 
2939     if ( rHint.GetId() == SfxHintId::DocChanged )
2940         changing();
2941     else if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
2942     {
2943         const SfxEventHint& rNamedHint = static_cast<const SfxEventHint&>(rHint);
2944         switch (rNamedHint.GetEventId())
2945         {
2946         case SfxEventHintId::StorageChanged:
2947         {
2948             if ( m_pData->m_xUIConfigurationManager.is()
2949               && m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
2950             {
2951                 Reference< embed::XStorage > xConfigStorage;
2952                 static constexpr OUString aUIConfigFolderName( u"Configurations2"_ustr );
2953 
2954                 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
2955                 if ( !xConfigStorage.is() )
2956                     xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
2957 
2958                 if ( xConfigStorage.is() || !m_pData->m_pObjectShell->GetStorage()->hasByName( aUIConfigFolderName ) )
2959                 {
2960                     // the storage is different, since otherwise it could not be opened, so it must be exchanged
2961                     m_pData->m_xUIConfigurationManager->setStorage( xConfigStorage );
2962                 }
2963                 else
2964                 {
2965                     OSL_FAIL( "Unexpected scenario!" );
2966                 }
2967             }
2968 
2969             ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
2970         }
2971         break;
2972 
2973         case SfxEventHintId::LoadFinished:
2974         {
2975             impl_getPrintHelper();
2976             ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
2977             m_pData->setModifiedForAutoSave(false);
2978         }
2979         break;
2980 
2981         case SfxEventHintId::SaveAsDocDone:
2982         {
2983             m_pData->m_sURL = m_pData->m_pObjectShell->GetMedium()->GetName();
2984 
2985             Sequence< beans::PropertyValue > aArgs;
2986             TransformItems( SID_SAVEASDOC, m_pData->m_pObjectShell->GetMedium()->GetItemSet(), aArgs );
2987             addTitle_Impl( aArgs, m_pData->m_pObjectShell->GetTitle() );
2988             attachResource( m_pData->m_pObjectShell->GetMedium()->GetName(), aArgs );
2989         }
2990         break;
2991 
2992         case SfxEventHintId::DocCreated:
2993         {
2994             impl_getPrintHelper();
2995             m_pData->setModifiedForAutoSave(false);
2996         }
2997         break;
2998 
2999         case SfxEventHintId::ModifyChanged:
3000         {
3001             m_pData->setModifiedForAutoSave(isModified());
3002         }
3003         break;
3004         default: break;
3005         }
3006 
3007         Any aSupplement;
3008         if (rNamedHint.GetEventId() == SfxEventHintId::PrintDoc)
3009             aSupplement <<= static_cast<const SfxPrintingHint*>(&rHint)->GetWhich();
3010         const SfxViewEventHint* pViewHint = dynamic_cast<const SfxViewEventHint*>(&rHint);
3011         postEvent_Impl( rNamedHint.GetEventName(), pViewHint ? pViewHint->GetController() : Reference< frame::XController2 >(), aSupplement );
3012     }
3013     else if ( rHint.GetId() == SfxHintId::TitleChanged )
3014     {
3015         addTitle_Impl( m_pData->m_seqArguments, m_pData->m_pObjectShell->GetTitle() );
3016         postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::TITLECHANGED ) );
3017     }
3018     else if ( rHint.GetId() == SfxHintId::ModeChanged )
3019     {
3020         postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::MODECHANGED ) );
3021     }
3022 }
3023 
3024 
3025 //  public impl.
3026 
3027 
NotifyModifyListeners_Impl() const3028 void SfxBaseModel::NotifyModifyListeners_Impl() const
3029 {
3030     if ( m_pData->m_aModifyListeners.getLength() )
3031     {
3032         lang::EventObject aEvent( static_cast<frame::XModel *>(const_cast<SfxBaseModel *>(this)) );
3033         m_pData->m_aModifyListeners.notifyEach( &util::XModifyListener::modified, aEvent );
3034     }
3035 
3036     // this notification here is done too generously, we cannot simply assume that we're really modified
3037     // now, but we need to check it ...
3038     m_pData->setModifiedForAutoSave(const_cast<SfxBaseModel*>(this)->isModified());
3039 }
3040 
changing()3041 void SfxBaseModel::changing()
3042 {
3043     SfxModelGuard aGuard( *this );
3044 
3045     // the notification should not be sent if the document can not be modified
3046     if ( !m_pData->m_pObjectShell.is() || !m_pData->m_pObjectShell->IsEnableSetModified() )
3047         return;
3048 
3049     NotifyModifyListeners_Impl();
3050 }
3051 
3052 
3053 //  public impl.
3054 
3055 
GetObjectShell() const3056 SfxObjectShell* SfxBaseModel::GetObjectShell() const
3057 {
3058     return m_pData ? m_pData->m_pObjectShell.get() : nullptr;
3059 }
3060 
3061 
3062 //  public impl.
3063 
3064 
IsInitialized() const3065 bool SfxBaseModel::IsInitialized() const
3066 {
3067     if ( !m_pData || !m_pData->m_pObjectShell.is() )
3068     {
3069         OSL_FAIL( "SfxBaseModel::IsInitialized: this should have been caught earlier!" );
3070         return false;
3071     }
3072 
3073     return m_pData->m_pObjectShell->GetMedium() != nullptr;
3074 }
3075 
MethodEntryCheck(const bool i_mustBeInitialized) const3076 void SfxBaseModel::MethodEntryCheck( const bool i_mustBeInitialized ) const
3077 {
3078     if ( impl_isDisposed() )
3079         throw lang::DisposedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
3080     if ( i_mustBeInitialized && !IsInitialized() )
3081         throw lang::NotInitializedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
3082 }
3083 
impl_isDisposed() const3084 bool SfxBaseModel::impl_isDisposed() const
3085 {
3086     return ( m_pData == nullptr ) ;
3087 }
3088 
3089 
3090 //  private impl.
3091 
3092 
GetMediumFilterName_Impl() const3093 OUString SfxBaseModel::GetMediumFilterName_Impl() const
3094 {
3095     std::shared_ptr<const SfxFilter> pFilter;
3096     SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
3097     if ( pMedium )
3098         pFilter = pMedium->GetFilter();
3099 
3100     if ( pFilter )
3101         return pFilter->GetName();
3102 
3103     return OUString();
3104 }
3105 
impl_store(const OUString & sURL,const Sequence<beans::PropertyValue> & seqArguments,bool bSaveTo)3106 void SfxBaseModel::impl_store(  const   OUString&                   sURL            ,
3107                                 const   Sequence< beans::PropertyValue >&  seqArguments    ,
3108                                         bool                        bSaveTo         )
3109 {
3110     if( sURL.isEmpty() )
3111         throw frame::IllegalArgumentIOException();
3112 
3113     if (!m_pData->m_pObjectShell)
3114         return;
3115 
3116     ::comphelper::SequenceAsHashMap aArgHash(seqArguments);
3117     if ( !bSaveTo && !sURL.isEmpty()
3118       && !sURL.startsWith( "private:stream" )
3119       && ::utl::UCBContentHelper::EqualURLs( getLocation(), sURL ) )
3120     {
3121         // this is the same file URL as the current document location, try to use storeOwn if possible
3122 
3123         static constexpr OUString aFilterString( u"FilterName"_ustr  );
3124         const OUString aFilterName( aArgHash.getUnpackedValueOrDefault( aFilterString, OUString() ) );
3125         if ( !aFilterName.isEmpty() )
3126         {
3127             SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
3128             if ( pMedium )
3129             {
3130                 const std::shared_ptr<const SfxFilter>& pFilter = pMedium->GetFilter();
3131                 if ( pFilter && aFilterName == pFilter->GetFilterName() )
3132                 {
3133                     // #i119366# - If the former file saving with password, do not trying in StoreSelf anyway...
3134                     bool bFormerPassword = false;
3135                     {
3136                         uno::Sequence< beans::NamedValue > aOldEncryptionData;
3137                         if (GetEncryptionData_Impl( &pMedium->GetItemSet(), aOldEncryptionData ))
3138                         {
3139                             bFormerPassword = true;
3140                         }
3141                     }
3142                     if ( !bFormerPassword )
3143                     {
3144                         aArgHash.erase( aFilterString );
3145                         aArgHash.erase( u"URL"_ustr );
3146 
3147                         try
3148                         {
3149                             storeSelf( aArgHash.getAsConstPropertyValueList() );
3150                             return;
3151                         }
3152                         catch( const lang::IllegalArgumentException& )
3153                         {
3154 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
3155                             // some additional arguments do not allow to use saving, SaveAs should be done
3156                             // but only for normal documents, the shared documents would be overwritten in this case
3157                             // that would mean an information loss
3158                             // TODO/LATER: need a new interaction for this case
3159                             if ( m_pData->m_pObjectShell->IsDocShared() )
3160                             {
3161                                 uno::Sequence< beans::NamedValue > aNewEncryptionData = aArgHash.getUnpackedValueOrDefault(u"EncryptionData"_ustr, uno::Sequence< beans::NamedValue >() );
3162                                 if ( !aNewEncryptionData.hasElements() )
3163                                 {
3164                                     aNewEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( aArgHash.getUnpackedValueOrDefault(u"Password"_ustr, OUString()) );
3165                                 }
3166 
3167                                 uno::Sequence< beans::NamedValue > aOldEncryptionData;
3168                                 (void)GetEncryptionData_Impl( &pMedium->GetItemSet(), aOldEncryptionData );
3169 
3170                                 if ( !aOldEncryptionData.hasElements() && !aNewEncryptionData.hasElements() )
3171                                     throw;
3172                                 else
3173                                 {
3174                                     // if the password is changed a special error should be used in case of shared document
3175                                     throw task::ErrorCodeIOException(u"Can not change password for shared document."_ustr, uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_SFX_SHARED_NOPASSWORDCHANGE) );
3176                                 }
3177                             }
3178 #endif
3179                         }
3180                     }
3181                 }
3182             }
3183         }
3184     }
3185 
3186     SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDoc : SfxEventHintId::SaveAsDoc, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOC : GlobalEventId::SAVEASDOC ),
3187                                             m_pData->m_pObjectShell.get() ) );
3188 
3189     const OUString aFilterName(aArgHash.getUnpackedValueOrDefault(u"FilterName"_ustr, OUString()));
3190     OUString aPassword, aPasswordToModify;
3191     if (!aArgHash.getUnpackedValueOrDefault(u"EncryptionData"_ustr, Sequence<beans::NamedValue>())
3192              .hasElements())
3193         aPassword = aArgHash.getUnpackedValueOrDefault(u"Password"_ustr, OUString());
3194     if (!aArgHash.getUnpackedValueOrDefault(u"ModifyPasswordInfo"_ustr, Sequence<beans::PropertyValue>())
3195              .hasElements()
3196         && aArgHash.getUnpackedValueOrDefault(u"ModifyPasswordInfo"_ustr, static_cast<sal_Int32>(0)) == 0)
3197         aPasswordToModify = aArgHash.getUnpackedValueOrDefault(u"PasswordToModify"_ustr, OUString());
3198     aArgHash.erase(u"PasswordToModify"_ustr);
3199 
3200     std::optional<SfxAllItemSet> pItemSet(SfxGetpApp()->GetPool());
3201     pItemSet->Put(SfxStringItem(SID_FILE_NAME, sURL));
3202     if ( bSaveTo )
3203         pItemSet->Put(SfxBoolItem(SID_SAVETO, true));
3204 
3205     if (!aFilterName.isEmpty() && (!aPassword.isEmpty() || !aPasswordToModify.isEmpty()))
3206         sfx2::SetPassword(SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName(aFilterName),
3207                           &*pItemSet, aPassword, aPasswordToModify, false);
3208 
3209     TransformParameters(SID_SAVEASDOC, seqArguments, *pItemSet);
3210 
3211     const SfxBoolItem* pCopyStreamItem = pItemSet->GetItem<SfxBoolItem>(SID_COPY_STREAM_IF_POSSIBLE, false);
3212 
3213     if ( pCopyStreamItem && pCopyStreamItem->GetValue() && !bSaveTo )
3214     {
3215         throw frame::IllegalArgumentIOException(
3216                 u"CopyStreamIfPossible parameter is not acceptable for storeAsURL() call!"_ustr );
3217     }
3218 
3219     sal_uInt32 nModifyPasswordHash = 0;
3220     Sequence< beans::PropertyValue > aModifyPasswordInfo;
3221     const SfxUnoAnyItem* pModifyPasswordInfoItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_MODIFYPASSWORDINFO, false);
3222     if ( pModifyPasswordInfoItem )
3223     {
3224         // it contains either a simple hash or a set of PropertyValues
3225         // TODO/LATER: the sequence of PropertyValue should replace the hash completely in future
3226         sal_Int32 nMPHTmp = 0;
3227         pModifyPasswordInfoItem->GetValue() >>= nMPHTmp;
3228         nModifyPasswordHash = static_cast<sal_uInt32>(nMPHTmp);
3229         pModifyPasswordInfoItem->GetValue() >>= aModifyPasswordInfo;
3230     }
3231     pItemSet->ClearItem(SID_MODIFYPASSWORDINFO);
3232     sal_uInt32 nOldModifyPasswordHash = m_pData->m_pObjectShell->GetModifyPasswordHash();
3233     m_pData->m_pObjectShell->SetModifyPasswordHash( nModifyPasswordHash );
3234     Sequence< beans::PropertyValue > aOldModifyPasswordInfo = m_pData->m_pObjectShell->GetModifyPasswordInfo();
3235     m_pData->m_pObjectShell->SetModifyPasswordInfo( aModifyPasswordInfo );
3236 
3237     // since saving a document modifies its DocumentProperties, the current
3238     // DocumentProperties must be saved on "SaveTo", so it can be restored
3239     // after saving
3240     bool bCopyTo =  bSaveTo ||
3241         m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED;
3242     Reference<document::XDocumentProperties> xOldDocProps;
3243     if ( bCopyTo )
3244     {
3245         xOldDocProps = getDocumentProperties();
3246         const Reference<util::XCloneable> xCloneable(xOldDocProps,
3247             UNO_QUERY_THROW);
3248         const Reference<document::XDocumentProperties> xNewDocProps(
3249             xCloneable->createClone(), UNO_QUERY_THROW);
3250         m_pData->m_xDocumentProperties = xNewDocProps;
3251     }
3252 
3253     bool bRet = m_pData->m_pObjectShell->APISaveAs_Impl(sURL, *pItemSet, seqArguments);
3254 
3255     if ( bCopyTo )
3256     {
3257         // restore DocumentProperties if a copy was created
3258         m_pData->m_xDocumentProperties = std::move(xOldDocProps);
3259     }
3260 
3261     Reference < task::XInteractionHandler > xHandler;
3262     const SfxUnoAnyItem* pItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_INTERACTIONHANDLER, false);
3263     if ( pItem )
3264         pItem->GetValue() >>= xHandler;
3265 
3266     pItemSet.reset();
3267 
3268     ErrCodeMsg nErrCode = m_pData->m_pObjectShell->GetErrorCode();
3269     if ( !bRet && !nErrCode )
3270     {
3271         SAL_WARN("sfx.doc", "Storing has failed, no error is set!");
3272         nErrCode = ERRCODE_IO_CANTWRITE;
3273     }
3274     m_pData->m_pObjectShell->ResetError();
3275 
3276     if ( bRet )
3277     {
3278         if ( nErrCode )
3279         {
3280             // must be a warning - use Interactionhandler if possible or abandon
3281             if ( xHandler.is() )
3282             {
3283                 // TODO/LATER: a general way to set the error context should be available
3284                 SfxErrorContext aEc( ERRCTX_SFX_SAVEASDOC, m_pData->m_pObjectShell->GetTitle() );
3285 
3286                 task::ErrorCodeRequest2 aErrorCode(OUString(), uno::Reference<XInterface>(),
3287                     sal_Int32(sal_uInt32(nErrCode.GetCode())), nErrCode.GetArg1(), nErrCode.GetArg2(),
3288                     static_cast<sal_Int16>(nErrCode.GetDialogMask()));
3289                 SfxMedium::CallApproveHandler( xHandler, Any( aErrorCode ), false );
3290             }
3291         }
3292 
3293         if ( !bSaveTo )
3294         {
3295             m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();
3296             m_pData->m_pObjectShell->SetModifyPasswordEntered();
3297 
3298             SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveAsDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEASDOCDONE), m_pData->m_pObjectShell.get() ) );
3299         }
3300         else
3301         {
3302             m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
3303             m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
3304 
3305             SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveToDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVETODOCDONE), m_pData->m_pObjectShell.get() ) );
3306         }
3307     }
3308     else
3309     {
3310         m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
3311         m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
3312 
3313 
3314         SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDocFailed : SfxEventHintId::SaveAsDocFailed, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOCFAILED : GlobalEventId::SAVEASDOCFAILED),
3315                                                 m_pData->m_pObjectShell.get() ) );
3316 
3317         if (SfxViewShell* pNotifyView = comphelper::LibreOfficeKit::isActive() ? SfxViewShell::Current() : nullptr)
3318             pNotifyView->libreOfficeKitViewCallback(LOK_CALLBACK_EXPORT_FILE, "ERROR"_ostr);
3319 
3320         std::stringstream aErrCode;
3321         aErrCode << nErrCode;
3322         throw task::ErrorCodeIOException(
3323             "SfxBaseModel::impl_store <" + sURL + "> failed: " + OUString::fromUtf8(aErrCode.str()),
3324             Reference< XInterface >(), sal_uInt32(nErrCode.GetCode()));
3325     }
3326 }
3327 
3328 
3329 namespace {
3330 template< typename ListenerT, typename EventT >
3331 class NotifySingleListenerIgnoreRE
3332 {
3333 private:
3334     typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
3335     NotificationMethod  m_pMethod;
3336     const EventT&       m_rEvent;
3337 public:
NotifySingleListenerIgnoreRE(NotificationMethod method,const EventT & event)3338     NotifySingleListenerIgnoreRE( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
3339 
operator ()(const Reference<ListenerT> & listener) const3340     void operator()( const Reference<ListenerT>& listener ) const
3341     {
3342         try
3343         {
3344             (listener.get()->*m_pMethod)( m_rEvent );
3345         }
3346         catch( RuntimeException& )
3347         {
3348             // this exception is ignored to avoid problems with invalid listeners, the listener should be probably thrown away in future
3349             TOOLS_WARN_EXCEPTION("sfx.appl", "ignoring");
3350         }
3351     }
3352 };
3353 } // anonymous namespace
3354 
postEvent_Impl(const OUString & aName,const Reference<frame::XController2> & xController,const Any & supplement)3355 void SfxBaseModel::postEvent_Impl( const OUString& aName, const Reference< frame::XController2 >& xController, const Any& supplement )
3356 {
3357     if (aName.isEmpty())
3358     {
3359         SAL_WARN("sfx.doc", "postEvent_Impl: Empty event name!");
3360         return;
3361     }
3362 
3363     // also make sure this object doesn't self-destruct while notifying
3364     rtl::Reference<SfxBaseModel> xHoldAlive(this);
3365     // keep m_pData alive, if notified target would dispose the document
3366     std::shared_ptr<IMPL_SfxBaseModel_DataContainer> xKeepAlive(m_pData);
3367 
3368     // object already disposed?
3369     if ( impl_isDisposed() )
3370         return;
3371 
3372     if ( xKeepAlive->m_aDocumentEventListeners2.getLength() )
3373     {
3374         SAL_INFO("sfx.doc", "SfxDocumentEvent: " + aName);
3375 
3376         document::DocumentEvent aDocumentEvent( static_cast<frame::XModel*>(this), aName, xController, supplement );
3377 
3378         xKeepAlive->m_aDocumentEventListeners2.forEach(
3379             NotifySingleListenerIgnoreRE< document::XDocumentEventListener, document::DocumentEvent >(
3380                 &document::XDocumentEventListener::documentEventOccured,
3381                 aDocumentEvent ) );
3382     }
3383 
3384     if ( xKeepAlive->m_aDocumentEventListeners1.getLength() )
3385     {
3386         SAL_INFO("sfx.doc", "SfxEvent: " + aName);
3387 
3388         document::EventObject aEvent( static_cast<frame::XModel*>(this), aName );
3389 
3390         xKeepAlive->m_aDocumentEventListeners1.forEach(
3391             NotifySingleListenerIgnoreRE< document::XEventListener, document::EventObject >(
3392                 &document::XEventListener::notifyEvent,
3393                 aEvent ) );
3394     }
3395 }
3396 
getViewData()3397 Reference < container::XIndexAccess > SAL_CALL SfxBaseModel::getViewData()
3398 {
3399     SfxModelGuard aGuard( *this );
3400 
3401     if ( m_pData->m_pObjectShell.is() && !m_pData->m_contViewData.is() )
3402     {
3403         SfxViewFrame *pActFrame = SfxViewFrame::Current();
3404         if ( !pActFrame || pActFrame->GetObjectShell() != m_pData->m_pObjectShell.get() )
3405             pActFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
3406 
3407         if ( !pActFrame || !pActFrame->GetViewShell() )
3408             // currently no frame for this document at all or View is under construction
3409             return Reference < container::XIndexAccess >();
3410 
3411         m_pData->m_contViewData = new comphelper::IndexedPropertyValuesContainer();
3412 
3413         if ( !m_pData->m_contViewData.is() )
3414         {
3415             // error: no container class available!
3416             return Reference < container::XIndexAccess >();
3417         }
3418 
3419         Reference < container::XIndexContainer > xCont( m_pData->m_contViewData, UNO_QUERY );
3420         sal_Int32 nCount = 0;
3421         Sequence < beans::PropertyValue > aSeq;
3422         for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() ); pFrame;
3423                 pFrame = SfxViewFrame::GetNext( *pFrame, m_pData->m_pObjectShell.get() ) )
3424         {
3425             bool bIsActive = ( pFrame == pActFrame );
3426             pFrame->GetViewShell()->WriteUserDataSequence( aSeq );
3427             xCont->insertByIndex( bIsActive ? 0 : nCount, Any(aSeq) );
3428             nCount++;
3429         }
3430     }
3431 
3432     return m_pData->m_contViewData;
3433 }
3434 
setViewData(const Reference<container::XIndexAccess> & aData)3435 void SAL_CALL SfxBaseModel::setViewData( const Reference < container::XIndexAccess >& aData )
3436 {
3437     SfxModelGuard aGuard( *this );
3438 
3439     m_pData->m_contViewData = aData;
3440 }
3441 
3442 /** calls all XEventListeners */
notifyEvent(const document::EventObject & aEvent) const3443 void SfxBaseModel::notifyEvent( const document::EventObject& aEvent ) const
3444 {
3445     // object already disposed?
3446     if ( impl_isDisposed() )
3447         return;
3448 
3449     if( !m_pData->m_aDocumentEventListeners1.getLength() )
3450 
3451         return;
3452 
3453     comphelper::OInterfaceIteratorHelper3 aIt( m_pData->m_aDocumentEventListeners1 );
3454     while( aIt.hasMoreElements() )
3455     {
3456         try
3457         {
3458             aIt.next()->notifyEvent( aEvent );
3459         }
3460         catch( RuntimeException& )
3461         {
3462             aIt.remove();
3463         }
3464     }
3465     // for right now, we're only doing the event that this particular performance problem needed
3466     if (aEvent.EventName == "ShapeModified")
3467     {
3468         uno::Reference<drawing::XShape> xShape(aEvent.Source, uno::UNO_QUERY);
3469         if (xShape.is())
3470         {
3471             auto it = m_pData->maShapeListeners.find(xShape);
3472             if (it != m_pData->maShapeListeners.end())
3473                 for (auto const & rListenerUnoRef : it->second)
3474                     rListenerUnoRef->notifyShapeEvent(aEvent);
3475         }
3476     }
3477 }
3478 
3479 /** returns true if someone added a XEventListener to this XEventBroadcaster */
hasEventListeners() const3480 bool SfxBaseModel::hasEventListeners() const
3481 {
3482     return !impl_isDisposed()
3483         && ( m_pData->m_aDocumentEventListeners1.getLength() != 0
3484              || !m_pData->maShapeListeners.empty());
3485 }
3486 
addPrintJobListener(const Reference<view::XPrintJobListener> & xListener)3487 void SAL_CALL SfxBaseModel::addPrintJobListener( const Reference< view::XPrintJobListener >& xListener )
3488 {
3489     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3490 
3491     impl_getPrintHelper();
3492     if ( m_pData->m_xPrintable.is() )
3493         m_pData->m_xPrintable->addPrintJobListener( xListener );
3494 }
3495 
removePrintJobListener(const Reference<view::XPrintJobListener> & xListener)3496 void SAL_CALL SfxBaseModel::removePrintJobListener( const Reference< view::XPrintJobListener >& xListener )
3497 {
3498     SfxModelGuard aGuard( *this );
3499 
3500     impl_getPrintHelper();
3501     if ( m_pData->m_xPrintable.is() )
3502         m_pData->m_xPrintable->removePrintJobListener( xListener );
3503 }
3504 
getSomething(const Sequence<sal_Int8> & aIdentifier)3505 sal_Int64 SAL_CALL SfxBaseModel::getSomething( const Sequence< sal_Int8 >& aIdentifier )
3506 {
3507     SvGlobalName aName( aIdentifier );
3508     if (aName == SvGlobalName( SFX_GLOBAL_CLASSID ))
3509     {
3510         SolarMutexGuard aGuard;
3511         SfxObjectShell *const pObjectShell(GetObjectShell());
3512         if (pObjectShell)
3513         {
3514             return comphelper::getSomething_cast(pObjectShell);
3515         }
3516     }
3517 
3518     return 0;
3519 }
3520 
3521 
3522 //  XDocumentSubStorageSupplier
3523 
3524 
ListenForStorage_Impl(const Reference<embed::XStorage> & xStorage)3525 void SfxBaseModel::ListenForStorage_Impl( const Reference< embed::XStorage >& xStorage )
3526 {
3527     Reference< util::XModifiable > xModifiable( xStorage, UNO_QUERY );
3528     if ( xModifiable.is() )
3529     {
3530         if ( !m_pData->m_pStorageModifyListen.is() )
3531         {
3532             m_pData->m_pStorageModifyListen = new ::sfx2::DocumentStorageModifyListener( *m_pData, Application::GetSolarMutex() );
3533         }
3534 
3535         // no need to deregister the listening for old storage since it should be disposed automatically
3536         xModifiable->addModifyListener( m_pData->m_pStorageModifyListen );
3537     }
3538 }
3539 
getDocumentSubStorage(const OUString & aStorageName,sal_Int32 nMode)3540 Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode )
3541 {
3542     SfxModelGuard aGuard( *this );
3543 
3544     Reference< embed::XStorage > xResult;
3545     if ( m_pData->m_pObjectShell.is() )
3546     {
3547         Reference< embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
3548         if ( xStorage.is() )
3549         {
3550             try
3551             {
3552                 xResult = xStorage->openStorageElement( aStorageName, nMode );
3553             }
3554             catch ( Exception& )
3555             {
3556             }
3557         }
3558     }
3559 
3560     return xResult;
3561 }
3562 
getDocumentSubStoragesNames()3563 Sequence< OUString > SAL_CALL SfxBaseModel::getDocumentSubStoragesNames()
3564 {
3565     SfxModelGuard aGuard( *this );
3566 
3567     Sequence< OUString > aResult;
3568     bool bSuccess = false;
3569     if ( m_pData->m_pObjectShell.is() )
3570     {
3571         Reference < embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
3572         if ( xStorage.is() )
3573         {
3574             const Sequence< OUString > aTemp = xStorage->getElementNames();
3575             sal_Int32 nResultSize = 0;
3576             for ( const auto& rName : aTemp )
3577             {
3578                 if ( xStorage->isStorageElement( rName ) )
3579                 {
3580                     aResult.realloc( ++nResultSize );
3581                     aResult.getArray()[ nResultSize - 1 ] = rName;
3582                 }
3583             }
3584 
3585             bSuccess = true;
3586         }
3587     }
3588 
3589     if ( !bSuccess )
3590         throw io::IOException();
3591 
3592     return aResult;
3593 }
3594 
3595 
3596 //  XScriptProviderSupplier
3597 
3598 
getScriptProvider()3599 Reference< script::provider::XScriptProvider > SAL_CALL SfxBaseModel::getScriptProvider()
3600 {
3601     SfxModelGuard aGuard( *this );
3602 
3603     Reference< script::provider::XScriptProviderFactory > xScriptProviderFactory =
3604         script::provider::theMasterScriptProviderFactory::get( ::comphelper::getProcessComponentContext() );
3605 
3606     Reference< XScriptInvocationContext > xScriptContext( this );
3607 
3608     Reference< script::provider::XScriptProvider > xScriptProvider(
3609         xScriptProviderFactory->createScriptProvider( Any( xScriptContext ) ),
3610         UNO_SET_THROW );
3611 
3612     return xScriptProvider;
3613 }
3614 
3615 
3616 //  XUIConfigurationManagerSupplier
3617 
3618 
getRuntimeUID() const3619 OUString const & SfxBaseModel::getRuntimeUID() const
3620 {
3621     OSL_ENSURE( !m_pData->m_sRuntimeUID.isEmpty(),
3622                 "SfxBaseModel::getRuntimeUID - ID is empty!" );
3623     return m_pData->m_sRuntimeUID;
3624 }
3625 
hasValidSignatures() const3626 bool SfxBaseModel::hasValidSignatures() const
3627 {
3628     SolarMutexGuard aGuard;
3629     if ( m_pData->m_pObjectShell.is() )
3630         return ( m_pData->m_pObjectShell->ImplGetSignatureState() == SignatureState::OK );
3631     return false;
3632 }
3633 
getGrabBagItem(css::uno::Any & rVal) const3634 void SfxBaseModel::getGrabBagItem(css::uno::Any& rVal) const
3635 {
3636     if (m_pData->m_xGrabBagItem)
3637         m_pData->m_xGrabBagItem->QueryValue(rVal);
3638     else
3639         rVal <<= uno::Sequence<beans::PropertyValue>();
3640 }
3641 
setGrabBagItem(const css::uno::Any & rVal)3642 void SfxBaseModel::setGrabBagItem(const css::uno::Any& rVal)
3643 {
3644     if (!m_pData->m_xGrabBagItem)
3645         m_pData->m_xGrabBagItem = std::make_shared<SfxGrabBagItem>();
3646 
3647     m_pData->m_xGrabBagItem->PutValue(rVal, 0);
3648 }
3649 
GetCommandFromSequence(OUString & rCommand,sal_Int32 & nIndex,const Sequence<beans::PropertyValue> & rSeqPropValue)3650 static void GetCommandFromSequence( OUString& rCommand, sal_Int32& nIndex, const Sequence< beans::PropertyValue >& rSeqPropValue )
3651 {
3652     nIndex = -1;
3653 
3654     auto pPropValue = std::find_if(rSeqPropValue.begin(), rSeqPropValue.end(),
3655         [](const beans::PropertyValue& rPropValue) { return rPropValue.Name == "Command"; });
3656     if (pPropValue != rSeqPropValue.end())
3657     {
3658         pPropValue->Value >>= rCommand;
3659         nIndex = static_cast<sal_Int32>(std::distance(rSeqPropValue.begin(), pPropValue));
3660     }
3661 }
3662 
ConvertSlotsToCommands(SfxObjectShell const * pDoc,Reference<container::XIndexContainer> const & rToolbarDefinition)3663 static void ConvertSlotsToCommands( SfxObjectShell const * pDoc, Reference< container::XIndexContainer > const & rToolbarDefinition )
3664 {
3665     if ( !pDoc )
3666         return;
3667 
3668     SfxModule*    pModule( pDoc->GetFactory().GetModule() );
3669     Sequence< beans::PropertyValue > aSeqPropValue;
3670 
3671     for ( sal_Int32 i = 0; i < rToolbarDefinition->getCount(); i++ )
3672     {
3673         if ( rToolbarDefinition->getByIndex( i ) >>= aSeqPropValue )
3674         {
3675             OUString aCommand;
3676             sal_Int32 nIndex( -1 );
3677             GetCommandFromSequence( aCommand, nIndex, aSeqPropValue );
3678             if ( nIndex >= 0 && aCommand.startsWith( "slot:" ) )
3679             {
3680                 const sal_uInt16 nSlot = o3tl::toInt32(aCommand.subView( 5 ));
3681 
3682                 // We have to replace the old "slot-Command" with our new ".uno:-Command"
3683                 const SfxSlot* pSlot = pModule->GetSlotPool()->GetSlot( nSlot );
3684                 if ( pSlot )
3685                 {
3686                     aCommand = pSlot->GetCommand();
3687                     aSeqPropValue.getArray()[nIndex].Value <<= aCommand;
3688                     rToolbarDefinition->replaceByIndex( i, Any( aSeqPropValue ));
3689                 }
3690             }
3691         }
3692     }
3693 }
3694 
getUIConfigurationManager()3695 Reference< ui::XUIConfigurationManager > SAL_CALL SfxBaseModel::getUIConfigurationManager()
3696 {
3697     return Reference< ui::XUIConfigurationManager >( getUIConfigurationManager2(), UNO_QUERY_THROW );
3698 }
3699 
getUIConfigurationManager2()3700 Reference< ui::XUIConfigurationManager2 > SfxBaseModel::getUIConfigurationManager2()
3701 {
3702     SfxModelGuard aGuard( *this );
3703 
3704     if ( !m_pData->m_xUIConfigurationManager.is() )
3705     {
3706         Reference< ui::XUIConfigurationManager2 > xNewUIConfMan =
3707             ui::UIConfigurationManager::create( comphelper::getProcessComponentContext() );
3708 
3709         Reference< embed::XStorage > xConfigStorage;
3710 
3711         OUString aUIConfigFolderName( u"Configurations2"_ustr );
3712         // First try to open with READWRITE and then READ
3713         xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
3714         if ( xConfigStorage.is() )
3715         {
3716             static constexpr OUString aMediaTypeProp( u"MediaType"_ustr );
3717             OUString aMediaType;
3718             Reference< beans::XPropertySet > xPropSet( xConfigStorage, UNO_QUERY );
3719             Any a = xPropSet->getPropertyValue( aMediaTypeProp );
3720             if ( !( a >>= aMediaType ) ||  aMediaType.isEmpty())
3721             {
3722                 xPropSet->setPropertyValue( aMediaTypeProp, Any(u"application/vnd.sun.xml.ui.configuration"_ustr) );
3723             }
3724         }
3725         else
3726             xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
3727 
3728         // initialize ui configuration manager with document substorage
3729         xNewUIConfMan->setStorage( xConfigStorage );
3730 
3731         // embedded objects did not support local configuration data until OOo 3.0, so there's nothing to
3732         // migrate
3733         if ( m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
3734         {
3735             // Import old UI configuration from OOo 1.x
3736 
3737             // Try to open with READ
3738             Reference< embed::XStorage > xOOo1ConfigStorage = getDocumentSubStorage( u"Configurations"_ustr, embed::ElementModes::READ );
3739             if ( xOOo1ConfigStorage.is() )
3740             {
3741                 const Reference< XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
3742                 std::vector< Reference< container::XIndexContainer > > rToolbars;
3743 
3744                 bool bImported = framework::UIConfigurationImporterOOo1x::ImportCustomToolbars(
3745                                         xNewUIConfMan, rToolbars, xContext, xOOo1ConfigStorage );
3746                 if ( bImported )
3747                 {
3748                     SfxObjectShell* pObjShell = SfxBaseModel::GetObjectShell();
3749 
3750                     for ( size_t i = 0; i < rToolbars.size(); i++ )
3751                     {
3752                         const OUString sId(OUString::number( i + 1 ));
3753                         const OUString aCustomTbxName = "private:resource/toolbar/custom_OOo1x_" + sId;
3754 
3755                         const Reference< container::XIndexContainer >& xToolbar = rToolbars[i];
3756                         ConvertSlotsToCommands( pObjShell, xToolbar );
3757                         if ( !xNewUIConfMan->hasSettings( aCustomTbxName ))
3758                         {
3759                             // Set UIName for the toolbar with container property
3760                             Reference< beans::XPropertySet > xPropSet( xToolbar, UNO_QUERY );
3761                             if ( xPropSet.is() )
3762                             {
3763                                 try
3764                                 {
3765                                     xPropSet->setPropertyValue( u"UIName"_ustr, Any( "Toolbar " + sId ) );
3766                                 }
3767                                 catch ( beans::UnknownPropertyException& )
3768                                 {
3769                                 }
3770                             }
3771 
3772                             xNewUIConfMan->insertSettings( aCustomTbxName, xToolbar );
3773                             xNewUIConfMan->store();
3774                         }
3775                     }
3776                 }
3777             }
3778         }
3779 
3780         m_pData->m_xUIConfigurationManager = std::move(xNewUIConfMan);
3781     }
3782 
3783     return m_pData->m_xUIConfigurationManager;
3784 }
3785 
3786 
3787 //  XVisualObject
3788 
3789 
setVisualAreaSize(sal_Int64 nAspect,const awt::Size & aSize)3790 void SAL_CALL SfxBaseModel::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize )
3791 {
3792     SfxModelGuard aGuard( *this );
3793 
3794     if ( !m_pData->m_pObjectShell.is() )
3795         throw Exception(u"no object shell"_ustr, nullptr); // TODO: error handling
3796 
3797     SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get(), false );
3798     if ( pViewFrm && m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !pViewFrm->GetFrame().IsInPlace() )
3799     {
3800         VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( pViewFrm->GetFrame().GetFrameInterface()->getContainerWindow() );
3801         Size aWinSize = pWindow->GetSizePixel();
3802         awt::Size aCurrent = getVisualAreaSize( nAspect );
3803         Size aDiff( aSize.Width-aCurrent.Width, aSize.Height-aCurrent.Height );
3804         aDiff = pViewFrm->GetViewShell()->GetWindow()->LogicToPixel( aDiff );
3805         aWinSize.AdjustWidth(aDiff.Width() );
3806         aWinSize.AdjustHeight(aDiff.Height() );
3807         pWindow->SetSizePixel( aWinSize );
3808     }
3809     else
3810     {
3811         tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
3812         aTmpRect.SetSize( Size( aSize.Width, aSize.Height ) );
3813         m_pData->m_pObjectShell->SetVisArea( aTmpRect );
3814     }
3815 }
3816 
getVisualAreaSize(sal_Int64)3817 awt::Size SAL_CALL SfxBaseModel::getVisualAreaSize( sal_Int64 /*nAspect*/ )
3818 {
3819     SfxModelGuard aGuard( *this );
3820 
3821     if ( !m_pData->m_pObjectShell.is() )
3822         throw Exception(u"no object shell"_ustr, nullptr); // TODO: error handling
3823 
3824     tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
3825 
3826     return awt::Size( aTmpRect.GetWidth(), aTmpRect.GetHeight() );
3827 }
3828 
3829 
getMapUnit(sal_Int64)3830 sal_Int32 SAL_CALL SfxBaseModel::getMapUnit( sal_Int64 /*nAspect*/ )
3831 {
3832     SfxModelGuard aGuard( *this );
3833 
3834     if ( !m_pData->m_pObjectShell.is() )
3835         throw Exception(u"no object shell"_ustr, nullptr); // TODO: error handling
3836 
3837     return VCLUnoHelper::VCL2UnoEmbedMapUnit( m_pData->m_pObjectShell->GetMapUnit() );
3838 }
3839 
getPreferredVisualRepresentation(::sal_Int64)3840 embed::VisualRepresentation SAL_CALL SfxBaseModel::getPreferredVisualRepresentation( ::sal_Int64 /*nAspect*/ )
3841 {
3842     SfxModelGuard aGuard( *this );
3843 
3844     datatransfer::DataFlavor aDataFlavor(
3845             u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr,
3846             u"GDIMetaFile"_ustr,
3847             cppu::UnoType<Sequence< sal_Int8 >>::get() );
3848 
3849     embed::VisualRepresentation aVisualRepresentation;
3850     aVisualRepresentation.Data = getTransferData( aDataFlavor );
3851     aVisualRepresentation.Flavor = std::move(aDataFlavor);
3852 
3853     return aVisualRepresentation;
3854 }
3855 
3856 
3857 //  XStorageBasedDocument
3858 
3859 
loadFromStorage(const Reference<embed::XStorage> & xStorage,const Sequence<beans::PropertyValue> & aMediaDescriptor)3860 void SAL_CALL SfxBaseModel::loadFromStorage( const Reference< embed::XStorage >& xStorage,
3861                                              const Sequence< beans::PropertyValue >& aMediaDescriptor )
3862 {
3863     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3864     if ( IsInitialized() )
3865         throw frame::DoubleInitializationException( OUString(), *this );
3866 
3867     // after i36090 is fixed the pool from object shell can be used
3868     // SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );
3869     SfxAllItemSet aSet( SfxGetpApp()->GetPool() );
3870 
3871     // the BaseURL is part of the ItemSet
3872     SfxMedium* pMedium = new SfxMedium( xStorage, OUString() );
3873     TransformParameters( SID_OPENDOC, aMediaDescriptor, aSet );
3874     pMedium->GetItemSet().Put( aSet );
3875 
3876     // allow to use an interactionhandler (if there is one)
3877     pMedium->UseInteractionHandler( true );
3878 
3879     m_pData->m_pObjectShell->SetActivateEvent_Impl(m_pData->m_pObjectShell->IsBasedOnTemplate()
3880                                                        ? SfxEventHintId::CreateDoc
3881                                                        : SfxEventHintId::OpenDoc);
3882     m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
3883 
3884     // load document
3885     if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
3886     {
3887         ErrCodeMsg nError = m_pData->m_pObjectShell->GetErrorCode();
3888         nError = nError ? nError : ERRCODE_IO_CANTREAD;
3889         throw task::ErrorCodeIOException(
3890             "SfxBaseModel::loadFromStorage: " + nError.toString(),
3891             Reference< XInterface >(), sal_uInt32(nError.GetCode()));
3892     }
3893     loadCmisProperties( );
3894 }
3895 
storeToStorage(const Reference<embed::XStorage> & xStorage,const Sequence<beans::PropertyValue> & aMediaDescriptor)3896 void SAL_CALL SfxBaseModel::storeToStorage( const Reference< embed::XStorage >& xStorage,
3897                                 const Sequence< beans::PropertyValue >& aMediaDescriptor )
3898 {
3899     SfxModelGuard aGuard( *this );
3900 
3901     if ( !m_pData->m_pObjectShell.is() )
3902         throw io::IOException(); // TODO:
3903 
3904     auto xSet = std::make_shared<SfxAllItemSet>(m_pData->m_pObjectShell->GetPool());
3905     TransformParameters( SID_SAVEASDOC, aMediaDescriptor, *xSet );
3906 
3907     // TODO/LATER: maybe a special URL "private:storage" should be used
3908     const SfxStringItem* pItem = xSet->GetItem<SfxStringItem>(SID_FILTER_NAME, false);
3909     sal_Int32 nVersion = SOFFICE_FILEFORMAT_CURRENT;
3910     if( pItem )
3911     {
3912         std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( pItem->GetValue() );
3913         if ( pFilter && pFilter->UsesStorage() )
3914             nVersion = pFilter->GetVersion();
3915     }
3916 
3917     bool bSuccess = false;
3918     if ( xStorage == m_pData->m_pObjectShell->GetStorage() )
3919     {
3920         // storing to the own storage
3921         bSuccess = m_pData->m_pObjectShell->DoSave();
3922     }
3923     else
3924     {
3925         // TODO/LATER: if the provided storage has some data inside the storing might fail, probably the storage must be truncated
3926         // TODO/LATER: is it possible to have a template here?
3927         m_pData->m_pObjectShell->SetupStorage( xStorage, nVersion, false );
3928 
3929         // BaseURL is part of the ItemSet
3930         SfxMedium aMedium( xStorage, OUString(), xSet );
3931         aMedium.CanDisposeStorage_Impl( false );
3932         if ( aMedium.GetFilter() )
3933         {
3934             // storing without a valid filter will often crash
3935             bSuccess = m_pData->m_pObjectShell->DoSaveObjectAs( aMedium, true );
3936             m_pData->m_pObjectShell->DoSaveCompleted();
3937         }
3938     }
3939 
3940     ErrCodeMsg nError = m_pData->m_pObjectShell->GetErrorCode();
3941     m_pData->m_pObjectShell->ResetError();
3942 
3943     // the warnings are currently not transported
3944     if ( !bSuccess )
3945     {
3946         nError = nError ? nError : ERRCODE_IO_GENERAL;
3947         throw task::ErrorCodeIOException(
3948             "SfxBaseModel::storeToStorage: " + nError.toString(),
3949             Reference< XInterface >(), sal_uInt32(nError.GetCode()));
3950     }
3951 }
3952 
switchToStorage(const Reference<embed::XStorage> & xStorage)3953 void SAL_CALL SfxBaseModel::switchToStorage( const Reference< embed::XStorage >& xStorage )
3954 {
3955     SfxModelGuard aGuard( *this );
3956 
3957     if ( !m_pData->m_pObjectShell.is() )
3958         throw io::IOException(); // TODO:
3959 
3960     // the persistence should be switched only if the storage is different
3961     if ( xStorage != m_pData->m_pObjectShell->GetStorage() )
3962     {
3963         if ( !m_pData->m_pObjectShell->SwitchPersistence( xStorage ) )
3964         {
3965             ErrCodeMsg nError = m_pData->m_pObjectShell->GetErrorCode();
3966             nError = nError ? nError : ERRCODE_IO_GENERAL;
3967             throw task::ErrorCodeIOException(
3968                 "SfxBaseModel::switchToStorage: " + nError.toString(),
3969                 Reference< XInterface >(), sal_uInt32(nError.GetCode()));
3970         }
3971         else
3972         {
3973             // UICfgMgr has a reference to the old storage, update it
3974             getUIConfigurationManager2()->setStorage( xStorage );
3975         }
3976     }
3977     m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
3978 }
3979 
getDocumentStorage()3980 Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentStorage()
3981 {
3982     SfxModelGuard aGuard( *this );
3983 
3984     if ( !m_pData->m_pObjectShell.is() )
3985         throw io::IOException(); // TODO
3986 
3987     return m_pData->m_pObjectShell->GetStorage();
3988 }
3989 
addStorageChangeListener(const Reference<document::XStorageChangeListener> & xListener)3990 void SAL_CALL SfxBaseModel::addStorageChangeListener(
3991             const Reference< document::XStorageChangeListener >& xListener )
3992 {
3993     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3994 
3995     m_pData->m_aStorageChangeListeners.addInterface( xListener );
3996 }
3997 
removeStorageChangeListener(const Reference<document::XStorageChangeListener> & xListener)3998 void SAL_CALL SfxBaseModel::removeStorageChangeListener(
3999             const Reference< document::XStorageChangeListener >& xListener )
4000 {
4001     SfxModelGuard aGuard( *this );
4002 
4003     m_pData->m_aStorageChangeListeners.removeInterface( xListener );
4004 }
4005 
impl_getPrintHelper()4006 void SfxBaseModel::impl_getPrintHelper()
4007 {
4008     if ( m_pData->m_xPrintable.is() )
4009         return;
4010     m_pData->m_xPrintable = new SfxPrintHelper();
4011     m_pData->m_xPrintable->initialize( { Any(Reference < frame::XModel > (this)) } );
4012     m_pData->m_xPrintable->addPrintJobListener( new SfxPrintHelperListener_Impl( m_pData.get() ) );
4013 }
4014 
4015 
4016 // css.frame.XModule
setIdentifier(const OUString & Identifier)4017  void SAL_CALL SfxBaseModel::setIdentifier(const OUString& Identifier)
4018 {
4019     SfxModelGuard aGuard( *this );
4020     m_pData->m_sModuleIdentifier = Identifier;
4021 }
4022 
4023 
4024 // css.frame.XModule
getIdentifier()4025  OUString SAL_CALL SfxBaseModel::getIdentifier()
4026 {
4027     SfxModelGuard aGuard( *this );
4028     if (!m_pData->m_sModuleIdentifier.isEmpty())
4029         return m_pData->m_sModuleIdentifier;
4030     if (m_pData->m_pObjectShell.is())
4031         return m_pData->m_pObjectShell->GetFactory().GetDocumentServiceName();
4032     return OUString();
4033 }
4034 
4035 
impl_getTitleHelper()4036 Reference< frame::XTitle > SfxBaseModel::impl_getTitleHelper ()
4037 {
4038     SfxModelGuard aGuard( *this );
4039 
4040     if ( ! m_pData->m_xTitleHelper.is ())
4041     {
4042         const Reference< XComponentContext >&     xContext = ::comphelper::getProcessComponentContext();
4043         Reference< frame::XUntitledNumbers >    xDesktop( frame::Desktop::create(xContext), UNO_QUERY_THROW);
4044 
4045         m_pData->m_xTitleHelper = new ::framework::TitleHelper(xContext, Reference< frame::XModel >(this), xDesktop);
4046     }
4047 
4048     return m_pData->m_xTitleHelper;
4049 }
4050 
4051 
impl_getUntitledHelper()4052 Reference< frame::XUntitledNumbers > SfxBaseModel::impl_getUntitledHelper ()
4053 {
4054     SfxModelGuard aGuard( *this );
4055 
4056     if ( ! m_pData->m_xNumberedControllers.is ())
4057     {
4058         m_pData->m_xNumberedControllers = new ::comphelper::NumberedCollection();
4059         m_pData->m_xNumberedControllers->setOwner          (Reference< frame::XModel >(this));
4060         m_pData->m_xNumberedControllers->setUntitledPrefix (u" : "_ustr);
4061     }
4062 
4063     return m_pData->m_xNumberedControllers;
4064 }
4065 
4066 
4067 // css.frame.XTitle
getTitle()4068 OUString SAL_CALL SfxBaseModel::getTitle()
4069 {
4070     // SYNCHRONIZED ->
4071     SfxModelGuard aGuard( *this );
4072 
4073     OUString aResult = impl_getTitleHelper()->getTitle ();
4074     if ( !m_pData->m_bExternalTitle && m_pData->m_pObjectShell )
4075     {
4076         SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
4077         if ( pMedium )
4078         {
4079             if (!pMedium->GetName().equalsIgnoreAsciiCase("private:stream"))
4080             {
4081                 try {
4082                     ::ucbhelper::Content aContent( pMedium->GetName(),
4083                         utl::UCBContentHelper::getDefaultCommandEnvironment(),
4084                         comphelper::getProcessComponentContext() );
4085                     const Reference < beans::XPropertySetInfo > xProps
4086                          = aContent.getProperties();
4087                     if ( xProps.is() )
4088                     {
4089                         static constexpr OUString aServerTitle( u"TitleOnServer"_ustr );
4090                         if ( xProps->hasPropertyByName( aServerTitle ) )
4091                         {
4092                             Any aAny = aContent.getPropertyValue( aServerTitle );
4093                             aAny >>= aResult;
4094                         }
4095                     }
4096                 }
4097                 catch (const ucb::ContentCreationException &)
4098                 {
4099                 }
4100                 catch (const ucb::CommandAbortedException &)
4101                 {
4102                 }
4103             }
4104             if (pMedium->IsRepairPackage())
4105                 aResult += SfxResId(STR_REPAIREDDOCUMENT);
4106         }
4107 
4108         if ( m_pData->m_pObjectShell->IsReadOnlyUI() || (pMedium && pMedium->IsReadOnly()) )
4109             aResult += SfxResId(STR_READONLY);
4110         else if ( m_pData->m_pObjectShell->IsDocShared() )
4111             aResult += SfxResId(STR_SHARED);
4112 
4113         if ( m_pData->m_pObjectShell->GetDocumentSignatureState() == SignatureState::OK )
4114             aResult += SfxResId(RID_XMLSEC_DOCUMENTSIGNED);
4115     }
4116 
4117     return aResult;
4118 }
4119 
4120 
4121 // css.frame.XTitle
setTitle(const OUString & sTitle)4122 void SAL_CALL SfxBaseModel::setTitle( const OUString& sTitle )
4123 {
4124     // SYNCHRONIZED ->
4125     SfxModelGuard aGuard( *this );
4126 
4127     impl_getTitleHelper()->setTitle (sTitle);
4128     m_pData->m_bExternalTitle = true;
4129 }
4130 
4131 
4132 // css.frame.XTitleChangeBroadcaster
addTitleChangeListener(const Reference<frame::XTitleChangeListener> & xListener)4133 void SAL_CALL SfxBaseModel::addTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
4134 {
4135     // SYNCHRONIZED ->
4136     SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
4137 
4138     Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
4139     if (xBroadcaster.is ())
4140         xBroadcaster->addTitleChangeListener (xListener);
4141 }
4142 
4143 
4144 // css.frame.XTitleChangeBroadcaster
removeTitleChangeListener(const Reference<frame::XTitleChangeListener> & xListener)4145 void SAL_CALL SfxBaseModel::removeTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
4146 {
4147     // SYNCHRONIZED ->
4148     SfxModelGuard aGuard( *this );
4149 
4150     Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
4151     if (xBroadcaster.is ())
4152         xBroadcaster->removeTitleChangeListener (xListener);
4153 }
4154 
4155 
4156 // css.frame.XUntitledNumbers
leaseNumber(const Reference<XInterface> & xComponent)4157 ::sal_Int32 SAL_CALL SfxBaseModel::leaseNumber( const Reference< XInterface >& xComponent )
4158 {
4159     SfxModelGuard aGuard( *this );
4160 
4161     return impl_getUntitledHelper ()->leaseNumber (xComponent);
4162 }
4163 
4164 
4165 // css.frame.XUntitledNumbers
releaseNumber(::sal_Int32 nNumber)4166 void SAL_CALL SfxBaseModel::releaseNumber( ::sal_Int32 nNumber )
4167 {
4168     SfxModelGuard aGuard( *this );
4169     impl_getUntitledHelper ()->releaseNumber (nNumber);
4170 }
4171 
4172 
4173 // css.frame.XUntitledNumbers
releaseNumberForComponent(const Reference<XInterface> & xComponent)4174 void SAL_CALL SfxBaseModel::releaseNumberForComponent( const Reference< XInterface >& xComponent )
4175 {
4176     SfxModelGuard aGuard( *this );
4177     impl_getUntitledHelper ()->releaseNumberForComponent (xComponent);
4178 }
4179 
4180 
4181 // css.frame.XUntitledNumbers
getUntitledPrefix()4182 OUString SAL_CALL SfxBaseModel::getUntitledPrefix()
4183 {
4184     SfxModelGuard aGuard( *this );
4185     return impl_getUntitledHelper ()->getUntitledPrefix ();
4186 }
4187 
4188 
4189 // frame::XModel2
getControllers()4190 Reference< container::XEnumeration > SAL_CALL SfxBaseModel::getControllers()
4191 {
4192     SfxModelGuard aGuard( *this );
4193 
4194     sal_Int32 c = m_pData->m_seqControllers.size();
4195     Sequence< Any > lEnum(c);
4196     std::transform(m_pData->m_seqControllers.begin(), m_pData->m_seqControllers.end(),
4197                    lEnum.getArray(), [](const auto& x) { return css::uno::Any(x); });
4198 
4199     return new ::comphelper::OAnyEnumeration(lEnum);
4200 }
4201 
4202 
4203 // frame::XModel2
getAvailableViewControllerNames()4204 Sequence< OUString > SAL_CALL SfxBaseModel::getAvailableViewControllerNames()
4205 {
4206     SfxModelGuard aGuard( *this );
4207 
4208     const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
4209     const sal_Int16 nViewFactoryCount = rDocumentFactory.GetViewFactoryCount();
4210 
4211     Sequence< OUString > aViewNames( nViewFactoryCount );
4212     auto aViewNamesRange = asNonConstRange(aViewNames);
4213     for ( sal_Int16 nViewNo = 0; nViewNo < nViewFactoryCount; ++nViewNo )
4214         aViewNamesRange[nViewNo] = rDocumentFactory.GetViewFactory( nViewNo ).GetAPIViewName();
4215     return aViewNames;
4216 }
4217 
4218 
4219 // frame::XModel2
createDefaultViewController(const Reference<frame::XFrame> & i_rFrame)4220 Reference< frame::XController2 > SAL_CALL SfxBaseModel::createDefaultViewController( const Reference< frame::XFrame >& i_rFrame )
4221 {
4222     SfxModelGuard aGuard( *this );
4223 
4224     const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
4225     const OUString sDefaultViewName = rDocumentFactory.GetViewFactory().GetAPIViewName();
4226 
4227     aGuard.clear();
4228 
4229     return createViewController( sDefaultViewName, Sequence< PropertyValue >(), i_rFrame );
4230 }
4231 
4232 
4233 namespace sfx::intern {
4234 
4235     /** a class which, in its dtor, cleans up various objects (well, at the moment only the frame) collected during
4236         the creation of a document view, unless the creation was successful.
4237     */
4238     class ViewCreationGuard
4239     {
4240     public:
ViewCreationGuard()4241         ViewCreationGuard()
4242             :m_bSuccess( false )
4243         {
4244         }
4245 
~ViewCreationGuard()4246         ~ViewCreationGuard()
4247         {
4248             suppress_fun_call_w_exception(ImplDestroy());
4249         }
4250 
takeFrameOwnership(SfxFrame * i_pFrame)4251         void takeFrameOwnership( SfxFrame* i_pFrame )
4252         {
4253             OSL_PRECOND( !m_aWeakFrame, "ViewCreationGuard::takeFrameOwnership: already have a frame!" );
4254             OSL_PRECOND( i_pFrame != nullptr, "ViewCreationGuard::takeFrameOwnership: invalid frame!" );
4255             m_aWeakFrame = i_pFrame;
4256         }
4257 
releaseAll()4258         void    releaseAll()
4259         {
4260             m_bSuccess = true;
4261         }
4262 
4263     private:
4264         bool             m_bSuccess;
4265         SfxFrameWeakRef  m_aWeakFrame;
4266 
ImplDestroy()4267         void ImplDestroy()
4268         {
4269             if ( !m_bSuccess && m_aWeakFrame && !m_aWeakFrame->GetCurrentDocument() )
4270             {
4271                 m_aWeakFrame->SetFrameInterface_Impl( nullptr );
4272                 m_aWeakFrame->DoClose();
4273             }
4274         }
4275     };
4276 }
4277 
4278 
FindOrCreateViewFrame_Impl(const Reference<XFrame> & i_rFrame,::sfx::intern::ViewCreationGuard & i_rGuard) const4279 SfxViewFrame* SfxBaseModel::FindOrCreateViewFrame_Impl( const Reference< XFrame >& i_rFrame, ::sfx::intern::ViewCreationGuard& i_rGuard ) const
4280 {
4281     SfxViewFrame* pViewFrame = nullptr;
4282     for (   pViewFrame = SfxViewFrame::GetFirst( GetObjectShell(), false );
4283             pViewFrame;
4284             pViewFrame= SfxViewFrame::GetNext( *pViewFrame, GetObjectShell(), false )
4285         )
4286     {
4287         if ( pViewFrame->GetFrame().GetFrameInterface() == i_rFrame )
4288             break;
4289     }
4290     if ( !pViewFrame )
4291     {
4292     #if OSL_DEBUG_LEVEL > 0
4293         for (   SfxFrame* pCheckFrame = SfxFrame::GetFirst();
4294                 pCheckFrame;
4295                 pCheckFrame = SfxFrame::GetNext( *pCheckFrame )
4296              )
4297         {
4298             if ( pCheckFrame->GetFrameInterface() == i_rFrame )
4299             {
4300                 if  (   ( pCheckFrame->GetCurrentViewFrame() != nullptr )
4301                     ||  ( pCheckFrame->GetCurrentDocument() != nullptr )
4302                     )
4303                     // Note that it is perfectly legitimate that during loading into an XFrame which already contains
4304                     // a document, there exist two SfxFrame instances bound to this XFrame - the old one, which will be
4305                     // destroyed later, and the new one, which we're going to create
4306                     continue;
4307 
4308                 OSL_FAIL( "SfxBaseModel::FindOrCreateViewFrame_Impl: there already is an SfxFrame for the given XFrame, but no view in it!" );
4309                     // nowadays, we're the only instance allowed to create an SfxFrame for an XFrame, so this case here should not happen
4310                 break;
4311             }
4312         }
4313     #endif
4314 
4315         SfxFrame* pTargetFrame = SfxFrame::Create( i_rFrame );
4316         ENSURE_OR_THROW( pTargetFrame, "could not create an SfxFrame" );
4317         i_rGuard.takeFrameOwnership( pTargetFrame );
4318 
4319         // prepare it
4320         pTargetFrame->PrepareForDoc_Impl( *GetObjectShell() );
4321 
4322         // create view frame
4323         pViewFrame = new SfxViewFrame( *pTargetFrame, GetObjectShell() );
4324     }
4325     return pViewFrame;
4326 }
4327 
4328 
4329 // frame::XModel2
createViewController(const OUString & i_rViewName,const Sequence<PropertyValue> & i_rArguments,const Reference<XFrame> & i_rFrame)4330 Reference< frame::XController2 > SAL_CALL SfxBaseModel::createViewController(
4331         const OUString& i_rViewName, const Sequence< PropertyValue >& i_rArguments, const Reference< XFrame >& i_rFrame )
4332 {
4333     SfxModelGuard aGuard( *this );
4334 
4335     if ( !i_rFrame.is() )
4336         throw lang::IllegalArgumentException( OUString(), *this, 3 );
4337 
4338     // find the proper SFX view factory
4339     SfxViewFactory* pViewFactory = GetObjectShell()->GetFactory().GetViewFactoryByViewName( i_rViewName );
4340     if ( !pViewFactory )
4341         throw IllegalArgumentException( OUString(), *this, 1 );
4342 
4343     // determine previous shell (used in some special cases)
4344     Reference< XController > xPreviousController( i_rFrame->getController() );
4345     const Reference< XModel > xMe( this );
4346     if  (   ( xPreviousController.is() )
4347         &&  ( xMe != xPreviousController->getModel() )
4348         )
4349     {
4350         xPreviousController.clear();
4351     }
4352     SfxViewShell* pOldViewShell = SfxViewShell::Get( xPreviousController );
4353     OSL_ENSURE( !xPreviousController.is() || ( pOldViewShell != nullptr ),
4354         "SfxBaseModel::createViewController: invalid old controller!" );
4355 
4356     // a guard which will clean up in case of failure
4357     ::sfx::intern::ViewCreationGuard aViewCreationGuard;
4358 
4359     // determine the ViewFrame belonging to the given XFrame
4360     SfxViewFrame* pViewFrame = FindOrCreateViewFrame_Impl( i_rFrame, aViewCreationGuard );
4361     assert(pViewFrame && "SfxBaseModel::createViewController: no frame");
4362 
4363     // delegate to SFX' view factory
4364     pViewFrame->GetBindings().ENTERREGISTRATIONS();
4365     SfxViewShell* pViewShell = pViewFactory->CreateInstance(*pViewFrame, pOldViewShell);
4366     pViewFrame->GetBindings().LEAVEREGISTRATIONS();
4367     ENSURE_OR_THROW( pViewShell, "invalid view shell provided by factory" );
4368 
4369     // by setting the ViewShell it is prevented that disposing the Controller will destroy this ViewFrame also
4370     pViewFrame->GetDispatcher()->SetDisableFlags( SfxDisableFlags::NONE );
4371     pViewFrame->SetViewShell_Impl( pViewShell );
4372 
4373     // remember ViewID
4374     pViewFrame->SetCurViewId_Impl( pViewFactory->GetOrdinal() );
4375 
4376     // ensure a default controller, if the view shell did not provide an own implementation
4377     if ( !pViewShell->GetController().is() )
4378         pViewShell->SetController( new SfxBaseController( pViewShell ) );
4379 
4380     // pass the creation arguments to the controller
4381     SfxBaseController* pBaseController = pViewShell->GetBaseController_Impl();
4382     ENSURE_OR_THROW( pBaseController, "invalid controller implementation!" );
4383     pBaseController->SetCreationArguments_Impl( i_rArguments );
4384 
4385     // some initial view settings, coming from our most recent attachResource call
4386     ::comphelper::NamedValueCollection aDocumentLoadArgs( getArgs2( { u"ViewOnly"_ustr, u"PluginMode"_ustr } ) );
4387     if ( aDocumentLoadArgs.getOrDefault( u"ViewOnly"_ustr, false ) )
4388         pViewFrame->GetFrame().SetMenuBarOn_Impl( false );
4389 
4390     const sal_Int16 nPluginMode = aDocumentLoadArgs.getOrDefault( u"PluginMode"_ustr, sal_Int16( 0 ) );
4391     if ( nPluginMode == 1 )
4392     {
4393         pViewFrame->ForceOuterResize_Impl();
4394         pViewFrame->GetBindings().HidePopups();
4395 
4396         SfxFrame& rFrame = pViewFrame->GetFrame();
4397         // MBA: layoutmanager of inplace frame starts locked and invisible
4398         rFrame.GetWorkWindow_Impl()->MakeVisible_Impl( false );
4399         rFrame.GetWorkWindow_Impl()->Lock_Impl( true );
4400 
4401         rFrame.GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
4402         pViewFrame->GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
4403     }
4404 
4405     // tell the guard we were successful
4406     aViewCreationGuard.releaseAll();
4407 
4408     // outta here
4409     return pBaseController;
4410 }
4411 
4412 
4413 // RDF DocumentMetadataAccess
4414 
4415 // rdf::XRepositorySupplier:
4416 Reference< rdf::XRepository > SAL_CALL
getRDFRepository()4417 SfxBaseModel::getRDFRepository()
4418 {
4419     SfxModelGuard aGuard( *this );
4420 
4421     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4422     if (!xDMA.is()) {
4423         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4424     }
4425 
4426     return xDMA->getRDFRepository();
4427 }
4428 
4429 // rdf::XNode:
4430 OUString SAL_CALL
getStringValue()4431 SfxBaseModel::getStringValue()
4432 {
4433     SfxModelGuard aGuard( *this );
4434 
4435     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4436     if (!xDMA.is()) {
4437         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4438     }
4439 
4440     return xDMA->getStringValue();
4441 }
4442 
4443 // rdf::XURI:
4444 OUString SAL_CALL
getNamespace()4445 SfxBaseModel::getNamespace()
4446 {
4447     SfxModelGuard aGuard( *this );
4448 
4449     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4450     if (!xDMA.is()) {
4451         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4452     }
4453 
4454     return xDMA->getNamespace();
4455 }
4456 
4457 OUString SAL_CALL
getLocalName()4458 SfxBaseModel::getLocalName()
4459 {
4460     SfxModelGuard aGuard( *this );
4461 
4462     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4463     if (!xDMA.is()) {
4464         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4465     }
4466 
4467     return xDMA->getLocalName();
4468 }
4469 
4470 // rdf::XDocumentMetadataAccess:
4471 Reference< rdf::XMetadatable > SAL_CALL
getElementByMetadataReference(const beans::StringPair & i_rReference)4472 SfxBaseModel::getElementByMetadataReference(
4473     const beans::StringPair & i_rReference)
4474 {
4475     SfxModelGuard aGuard( *this );
4476 
4477     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4478     if (!xDMA.is()) {
4479         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4480     }
4481 
4482     return xDMA->getElementByMetadataReference(i_rReference);
4483 }
4484 
4485 Reference< rdf::XMetadatable > SAL_CALL
getElementByURI(const Reference<rdf::XURI> & i_xURI)4486 SfxBaseModel::getElementByURI(const Reference< rdf::XURI > & i_xURI)
4487 {
4488     SfxModelGuard aGuard( *this );
4489 
4490     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4491     if (!xDMA.is()) {
4492         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4493     }
4494 
4495     return xDMA->getElementByURI(i_xURI);
4496 }
4497 
4498 Sequence< Reference< rdf::XURI > > SAL_CALL
getMetadataGraphsWithType(const Reference<rdf::XURI> & i_xType)4499 SfxBaseModel::getMetadataGraphsWithType(
4500     const Reference<rdf::XURI> & i_xType)
4501 {
4502     SfxModelGuard aGuard( *this );
4503 
4504     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4505     if (!xDMA.is()) {
4506         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4507     }
4508 
4509     return xDMA->getMetadataGraphsWithType(i_xType);
4510 }
4511 
4512 Reference<rdf::XURI> SAL_CALL
addMetadataFile(const OUString & i_rFileName,const Sequence<Reference<rdf::XURI>> & i_rTypes)4513 SfxBaseModel::addMetadataFile(const OUString & i_rFileName,
4514     const Sequence < Reference< rdf::XURI > > & i_rTypes)
4515 {
4516     SfxModelGuard aGuard( *this );
4517 
4518     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4519     if (!xDMA.is()) {
4520         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4521     }
4522 
4523     return xDMA->addMetadataFile(i_rFileName, i_rTypes);
4524 }
4525 
4526 Reference<rdf::XURI> SAL_CALL
importMetadataFile(::sal_Int16 i_Format,const Reference<io::XInputStream> & i_xInStream,const OUString & i_rFileName,const Reference<rdf::XURI> & i_xBaseURI,const Sequence<Reference<rdf::XURI>> & i_rTypes)4527 SfxBaseModel::importMetadataFile(::sal_Int16 i_Format,
4528     const Reference< io::XInputStream > & i_xInStream,
4529     const OUString & i_rFileName,
4530     const Reference< rdf::XURI > & i_xBaseURI,
4531     const Sequence < Reference< rdf::XURI > > & i_rTypes)
4532 {
4533     SfxModelGuard aGuard( *this );
4534 
4535     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4536     if (!xDMA.is()) {
4537         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4538     }
4539 
4540     return xDMA->importMetadataFile(i_Format,
4541         i_xInStream, i_rFileName, i_xBaseURI, i_rTypes);
4542 }
4543 
4544 void SAL_CALL
removeMetadataFile(const Reference<rdf::XURI> & i_xGraphName)4545 SfxBaseModel::removeMetadataFile(
4546     const Reference< rdf::XURI > & i_xGraphName)
4547 {
4548     SfxModelGuard aGuard( *this );
4549 
4550     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4551     if (!xDMA.is()) {
4552         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4553     }
4554 
4555     return xDMA->removeMetadataFile(i_xGraphName);
4556 }
4557 
4558 void SAL_CALL
addContentOrStylesFile(const OUString & i_rFileName)4559 SfxBaseModel::addContentOrStylesFile(const OUString & i_rFileName)
4560 {
4561     SfxModelGuard aGuard( *this );
4562 
4563     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4564     if (!xDMA.is()) {
4565         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4566     }
4567 
4568     return xDMA->addContentOrStylesFile(i_rFileName);
4569 }
4570 
4571 void SAL_CALL
removeContentOrStylesFile(const OUString & i_rFileName)4572 SfxBaseModel::removeContentOrStylesFile(const OUString & i_rFileName)
4573 {
4574     SfxModelGuard aGuard( *this );
4575 
4576     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4577     if (!xDMA.is()) {
4578         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4579     }
4580 
4581     return xDMA->removeContentOrStylesFile(i_rFileName);
4582 }
4583 
4584 void SAL_CALL
loadMetadataFromStorage(Reference<embed::XStorage> const & i_xStorage,Reference<rdf::XURI> const & i_xBaseURI,Reference<task::XInteractionHandler> const & i_xHandler)4585 SfxBaseModel::loadMetadataFromStorage(
4586     Reference< embed::XStorage > const & i_xStorage,
4587     Reference<rdf::XURI> const & i_xBaseURI,
4588     Reference<task::XInteractionHandler> const & i_xHandler)
4589 {
4590     SfxModelGuard aGuard( *this );
4591 
4592     rtl::Reference<::sfx2::DocumentMetadataAccess> xDMA(
4593         m_pData->CreateDMAUninitialized());
4594     if (!xDMA.is()) {
4595         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4596     }
4597 
4598     try {
4599         xDMA->loadMetadataFromStorage(i_xStorage, i_xBaseURI, i_xHandler);
4600     } catch (lang::IllegalArgumentException &) {
4601         throw; // not initialized
4602     } catch (Exception &) {
4603         // UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
4604         m_pData->m_xDocumentMetadata = xDMA;
4605         throw;
4606     }
4607     m_pData->m_xDocumentMetadata = std::move(xDMA);
4608 }
4609 
4610 void SAL_CALL
storeMetadataToStorage(Reference<embed::XStorage> const & i_xStorage)4611 SfxBaseModel::storeMetadataToStorage(
4612     Reference< embed::XStorage > const & i_xStorage)
4613 {
4614     SfxModelGuard aGuard( *this );
4615 
4616     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4617     if (!xDMA.is()) {
4618         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4619     }
4620 
4621     return xDMA->storeMetadataToStorage(i_xStorage);
4622 }
4623 
4624 void SAL_CALL
loadMetadataFromMedium(const Sequence<beans::PropertyValue> & i_rMedium)4625 SfxBaseModel::loadMetadataFromMedium(
4626     const Sequence< beans::PropertyValue > & i_rMedium)
4627 {
4628     SfxModelGuard aGuard( *this );
4629 
4630     rtl::Reference<::sfx2::DocumentMetadataAccess> xDMA(
4631         m_pData->CreateDMAUninitialized());
4632     if (!xDMA.is()) {
4633         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4634     }
4635 
4636     try {
4637         xDMA->loadMetadataFromMedium(i_rMedium);
4638     } catch (lang::IllegalArgumentException &) {
4639         throw; // not initialized
4640     } catch (Exception &) {
4641         // UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
4642         m_pData->m_xDocumentMetadata = xDMA;
4643         throw;
4644     }
4645     m_pData->m_xDocumentMetadata = std::move(xDMA);
4646 }
4647 
4648 void SAL_CALL
storeMetadataToMedium(const Sequence<beans::PropertyValue> & i_rMedium)4649 SfxBaseModel::storeMetadataToMedium(
4650     const Sequence< beans::PropertyValue > & i_rMedium)
4651 {
4652     SfxModelGuard aGuard( *this );
4653 
4654     const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4655     if (!xDMA.is()) {
4656         throw RuntimeException( u"model has no document metadata"_ustr, *this );
4657     }
4658 
4659     return xDMA->storeMetadataToMedium(i_rMedium);
4660 }
4661 
4662 
4663 // = SfxModelSubComponent
4664 
4665 
~SfxModelSubComponent()4666 SfxModelSubComponent::~SfxModelSubComponent()
4667 {
4668 }
4669 
4670 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4671