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