Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / doc / sfxbasemodel.cxx
blobdcd5fd6a6aaadbf6385ab07efe534e23fda9298e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <config_features.h>
23 #include <sfx2/sfxbasemodel.hxx>
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/XStorage.hpp>
41 #include <com/sun/star/document/XStorageChangeListener.hpp>
42 #include <com/sun/star/document/IndexedPropertyValues.hpp>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/beans/XPropertySetInfo.hpp>
45 #include <com/sun/star/container/XIndexContainer.hpp>
46 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
47 #include <com/sun/star/script/provider/XScriptProvider.hpp>
48 #include <com/sun/star/ui/UIConfigurationManager.hpp>
49 #include <com/sun/star/embed/ElementModes.hpp>
50 #include <com/sun/star/embed/Aspects.hpp>
51 #include <com/sun/star/document/DocumentProperties.hpp>
52 #include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
53 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
54 #include <com/sun/star/ucb/ContentCreationException.hpp>
55 #include <com/sun/star/ucb/CommandAbortedException.hpp>
56 #include <com/sun/star/util/XCloneable.hpp>
57 #include <com/sun/star/util/InvalidStateException.hpp>
58 #include <com/sun/star/util/CloseVetoException.hpp>
59 #include <comphelper/enumhelper.hxx>
61 #include <cppuhelper/implbase.hxx>
62 #include <cppuhelper/interfacecontainer.hxx>
63 #include <cppuhelper/exc_hlp.hxx>
64 #include <comphelper/processfactory.hxx>
65 #include <comphelper/sequenceashashmap.hxx>
66 #include <comphelper/namedvaluecollection.hxx>
67 #include <svl/itemset.hxx>
68 #include <svl/stritem.hxx>
69 #include <svl/eitem.hxx>
70 #include <svl/grabbagitem.hxx>
71 #include <tools/urlobj.hxx>
72 #include <tools/debug.hxx>
73 #include <tools/diagnose_ex.h>
74 #include <tools/svborder.hxx>
75 #include <unotools/tempfile.hxx>
76 #include <osl/mutex.hxx>
77 #include <vcl/errcode.hxx>
78 #include <vcl/salctype.hxx>
79 #include <vcl/gdimtf.hxx>
80 #include <comphelper/fileformat.h>
81 #include <comphelper/storagehelper.hxx>
82 #include <toolkit/helper/vclunohelper.hxx>
83 #include <vcl/transfer.hxx>
84 #include <svtools/ehdl.hxx>
85 #include <svtools/sfxecode.hxx>
86 #include <sal/log.hxx>
87 #include <framework/configimporter.hxx>
88 #include <framework/titlehelper.hxx>
89 #include <comphelper/numberedcollection.hxx>
90 #include <unotools/ucbhelper.hxx>
91 #include <ucbhelper/content.hxx>
93 #include <sfx2/sfxbasecontroller.hxx>
94 #include <sfx2/viewfac.hxx>
95 #include <workwin.hxx>
96 #include <sfx2/signaturestate.hxx>
97 #include <sfx2/sfxuno.hxx>
98 #include <objshimp.hxx>
99 #include <sfx2/viewfrm.hxx>
100 #include <sfx2/viewsh.hxx>
101 #include <sfx2/docfile.hxx>
102 #include <sfx2/docfilt.hxx>
103 #include <sfx2/dispatch.hxx>
104 #include <sfx2/module.hxx>
105 #include <basic/basmgr.hxx>
106 #include <sfx2/event.hxx>
107 #include <eventsupplier.hxx>
108 #include <sfx2/sfxsids.hrc>
109 #include <sfx2/strings.hrc>
110 #include <sfx2/app.hxx>
111 #include <sfx2/docfac.hxx>
112 #include <sfx2/fcontnr.hxx>
113 #include <sfx2/docstoragemodifylistener.hxx>
114 #include <sfx2/brokenpackageint.hxx>
115 #include "graphhelp.hxx"
116 #include <docundomanager.hxx>
117 #include <openurlhint.hxx>
118 #include <sfx2/msgpool.hxx>
119 #include <sfx2/DocumentMetadataAccess.hxx>
120 #include "printhelper.hxx"
121 #include <sfx2/sfxresid.hxx>
122 #include <comphelper/profilezone.hxx>
123 #include <vcl/threadex.hxx>
124 #include <unotools/mediadescriptor.hxx>
126 // namespaces
129 using namespace ::com::sun::star;
130 using namespace ::com::sun::star::uno;
131 using ::com::sun::star::beans::PropertyValue;
132 using ::com::sun::star::document::CmisProperty;
133 using ::com::sun::star::frame::XFrame;
134 using ::com::sun::star::frame::XController;
135 using ::com::sun::star::frame::XController2;
136 using ::com::sun::star::lang::IllegalArgumentException;
137 using ::com::sun::star::io::IOException;
138 using ::com::sun::star::uno::Sequence;
139 using ::com::sun::star::document::XDocumentRecovery;
140 using ::com::sun::star::document::XUndoManager;
141 using ::com::sun::star::document::XUndoAction;
142 using ::com::sun::star::frame::XModel;
144 namespace {
146 /** This Listener is used to get notified when the XDocumentProperties of the
147 XModel change.
149 class SfxDocInfoListener_Impl : public ::cppu::WeakImplHelper<
150 util::XModifyListener >
153 public:
154 SfxObjectShell& m_rShell;
156 explicit SfxDocInfoListener_Impl( SfxObjectShell& i_rDoc )
157 : m_rShell(i_rDoc)
158 { };
160 virtual void SAL_CALL disposing( const lang::EventObject& ) override;
161 virtual void SAL_CALL modified( const lang::EventObject& ) override;
166 void SAL_CALL SfxDocInfoListener_Impl::modified( const lang::EventObject& )
168 SolarMutexGuard aSolarGuard;
170 // notify changes to the SfxObjectShell
171 m_rShell.FlushDocInfo();
174 void SAL_CALL SfxDocInfoListener_Impl::disposing( const lang::EventObject& )
179 // impl. declarations
182 struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument
184 // counter for SfxBaseModel instances created.
185 static sal_Int64 g_nInstanceCounter ;
186 SfxObjectShellRef m_pObjectShell ;
187 OUString m_sURL ;
188 OUString m_sRuntimeUID ;
189 OUString m_aPreusedFilterName ;
190 ::cppu::OMultiTypeInterfaceContainerHelper m_aInterfaceContainer ;
191 std::unordered_map<css::uno::Reference< css::drawing::XShape >,
192 std::vector<css::uno::Reference< css::document::XShapeEventListener >>> maShapeListeners;
193 Reference< XInterface > m_xParent ;
194 Reference< frame::XController > m_xCurrent ;
195 Reference< document::XDocumentProperties > m_xDocumentProperties ;
196 Reference< script::XStarBasicAccess > m_xStarBasicAccess ;
197 Reference< container::XNameReplace > m_xEvents ;
198 Sequence< beans::PropertyValue> m_seqArguments ;
199 std::vector< Reference< frame::XController > > m_seqControllers ;
200 Reference< container::XIndexAccess > m_contViewData ;
201 sal_uInt16 m_nControllerLockCount ;
202 bool m_bClosed ;
203 bool m_bClosing ;
204 bool m_bSaving ;
205 bool m_bSuicide ;
206 bool m_bExternalTitle ;
207 bool m_bModifiedSinceLastSave ;
208 Reference< view::XPrintable> m_xPrintable ;
209 Reference< ui::XUIConfigurationManager2 > m_xUIConfigurationManager;
210 ::rtl::Reference< ::sfx2::DocumentStorageModifyListener > m_pStorageModifyListen ;
211 OUString m_sModuleIdentifier ;
212 Reference< frame::XTitle > m_xTitleHelper ;
213 Reference< frame::XUntitledNumbers > m_xNumberedControllers ;
214 Reference< rdf::XDocumentMetadataAccess> m_xDocumentMetadata ;
215 ::rtl::Reference< ::sfx2::DocumentUndoManager > m_pDocumentUndoManager ;
216 Sequence< document::CmisProperty> m_cmisProperties ;
217 std::shared_ptr<SfxGrabBagItem> m_xGrabBagItem ;
219 IMPL_SfxBaseModel_DataContainer( ::osl::Mutex& rMutex, SfxObjectShell* pObjectShell )
220 : m_pObjectShell ( pObjectShell )
221 , m_aInterfaceContainer ( rMutex )
222 , m_nControllerLockCount ( 0 )
223 , m_bClosed ( false )
224 , m_bClosing ( false )
225 , m_bSaving ( false )
226 , m_bSuicide ( false )
227 , m_bExternalTitle ( false )
228 , m_bModifiedSinceLastSave( false )
229 , m_xTitleHelper ()
230 , m_xNumberedControllers ()
231 , m_xDocumentMetadata () // lazy
232 , m_pDocumentUndoManager ()
233 , m_cmisProperties ()
235 // increase global instance counter.
236 ++g_nInstanceCounter;
237 // set own Runtime UID
238 m_sRuntimeUID = OUString::number( g_nInstanceCounter );
241 virtual ~IMPL_SfxBaseModel_DataContainer()
245 // ::sfx2::IModifiableDocument
246 virtual void storageIsModified() override
248 if ( m_pObjectShell.is() && !m_pObjectShell->IsModified() )
249 m_pObjectShell->SetModified();
252 void impl_setDocumentProperties(
253 const Reference< document::XDocumentProperties >& );
255 Reference<rdf::XDocumentMetadataAccess> GetDMA()
257 if (!m_xDocumentMetadata.is())
259 OSL_ENSURE(m_pObjectShell.is(), "GetDMA: no object shell?");
260 if (!m_pObjectShell.is())
262 return nullptr;
265 const Reference<XComponentContext> xContext(
266 ::comphelper::getProcessComponentContext());
267 const Reference<frame::XModel> xModel(
268 m_pObjectShell->GetModel());
269 const Reference<lang::XMultiComponentFactory> xMsf(
270 xContext->getServiceManager());
271 const Reference<frame::
272 XTransientDocumentsDocumentContentFactory> xTDDCF(
273 xMsf->createInstanceWithContext(
274 "com.sun.star.frame.TransientDocumentsDocumentContentFactory",
275 xContext),
276 UNO_QUERY_THROW);
277 const Reference<ucb::XContent> xContent(
278 xTDDCF->createDocumentContent(xModel) );
279 OSL_ENSURE(xContent.is(), "GetDMA: cannot create DocumentContent");
280 if (!xContent.is())
282 return nullptr;
284 OUString uri = xContent->getIdentifier()->getContentIdentifier();
285 OSL_ENSURE(!uri.isEmpty(), "GetDMA: empty uri?");
286 if (!uri.isEmpty() && !uri.endsWith("/"))
288 uri += "/";
291 m_xDocumentMetadata = new ::sfx2::DocumentMetadataAccess(
292 xContext, *m_pObjectShell, uri);
294 return m_xDocumentMetadata;
297 Reference<rdf::XDocumentMetadataAccess> CreateDMAUninitialized()
299 return (m_pObjectShell.is())
300 ? new ::sfx2::DocumentMetadataAccess(
301 ::comphelper::getProcessComponentContext(), *m_pObjectShell)
302 : nullptr;
306 // static member initialization.
307 sal_Int64 IMPL_SfxBaseModel_DataContainer::g_nInstanceCounter = 0;
309 namespace {
311 // Listener that forwards notifications from the PrintHelper to the "real" listeners
312 class SfxPrintHelperListener_Impl : public ::cppu::WeakImplHelper< view::XPrintJobListener >
314 public:
315 IMPL_SfxBaseModel_DataContainer* m_pData;
316 explicit SfxPrintHelperListener_Impl( IMPL_SfxBaseModel_DataContainer* pData )
317 : m_pData( pData )
320 virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override ;
321 virtual void SAL_CALL printJobEvent( const view::PrintJobEvent& rEvent ) override;
326 void SAL_CALL SfxPrintHelperListener_Impl::disposing( const lang::EventObject& )
328 m_pData->m_xPrintable = nullptr;
331 void SAL_CALL SfxPrintHelperListener_Impl::printJobEvent( const view::PrintJobEvent& rEvent )
333 ::cppu::OInterfaceContainerHelper* pContainer = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<view::XPrintJobListener>::get());
334 if ( pContainer!=nullptr )
336 ::cppu::OInterfaceIteratorHelper pIterator(*pContainer);
337 while (pIterator.hasMoreElements())
338 static_cast<view::XPrintJobListener*>(pIterator.next())->printJobEvent( rEvent );
342 namespace {
344 // SfxOwnFramesLocker ====================================================================================
345 // allows to lock all the frames related to the provided SfxObjectShell
346 class SfxOwnFramesLocker
348 Sequence< Reference< frame::XFrame > > m_aLockedFrames;
350 static vcl::Window* GetVCLWindow( const Reference< frame::XFrame >& xFrame );
351 public:
352 explicit SfxOwnFramesLocker( SfxObjectShell const * ObjechShell );
353 ~SfxOwnFramesLocker();
358 SfxOwnFramesLocker::SfxOwnFramesLocker( SfxObjectShell const * pObjectShell )
360 if ( !pObjectShell )
361 return;
363 for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pObjectShell );
364 pFrame;
365 pFrame = SfxViewFrame::GetNext( *pFrame, pObjectShell )
368 SfxFrame& rSfxFrame = pFrame->GetFrame();
371 // get vcl window related to the frame and lock it if it is still not locked
372 const Reference< frame::XFrame >& xFrame = rSfxFrame.GetFrameInterface();
373 vcl::Window* pWindow = GetVCLWindow( xFrame );
374 if ( !pWindow )
375 throw RuntimeException();
377 if ( pWindow->IsEnabled() )
379 pWindow->Disable();
383 sal_Int32 nLen = m_aLockedFrames.getLength();
384 m_aLockedFrames.realloc( nLen + 1 );
385 m_aLockedFrames[nLen] = xFrame;
387 catch( Exception& )
389 pWindow->Enable();
390 throw;
394 catch( Exception& )
396 OSL_FAIL( "Not possible to lock the frame window!" );
401 SfxOwnFramesLocker::~SfxOwnFramesLocker()
403 for ( auto& rFrame : m_aLockedFrames )
407 if ( rFrame.is() )
409 // get vcl window related to the frame and unlock it
410 vcl::Window* pWindow = GetVCLWindow( rFrame );
411 if ( !pWindow )
412 throw RuntimeException();
414 pWindow->Enable();
416 rFrame.clear();
419 catch( Exception& )
421 OSL_FAIL( "Can't unlock the frame window!" );
426 vcl::Window* SfxOwnFramesLocker::GetVCLWindow( const Reference< frame::XFrame >& xFrame )
428 VclPtr<vcl::Window> pWindow;
430 if ( xFrame.is() )
432 Reference< awt::XWindow > xWindow = xFrame->getContainerWindow();
433 if ( xWindow.is() )
434 pWindow = VCLUnoHelper::GetWindow( xWindow );
437 return pWindow;
440 namespace {
442 // SfxSaveGuard ====================================================================================
443 class SfxSaveGuard
445 private:
446 Reference< frame::XModel > m_xModel;
447 IMPL_SfxBaseModel_DataContainer* m_pData;
448 std::unique_ptr<SfxOwnFramesLocker> m_pFramesLock;
450 SfxSaveGuard(SfxSaveGuard const &) = delete;
451 void operator =(const SfxSaveGuard&) = delete;
453 public:
454 SfxSaveGuard(const Reference< frame::XModel >& xModel ,
455 IMPL_SfxBaseModel_DataContainer* pData);
456 ~SfxSaveGuard();
461 SfxSaveGuard::SfxSaveGuard(const Reference< frame::XModel >& xModel ,
462 IMPL_SfxBaseModel_DataContainer* pData)
463 : m_xModel ( xModel )
464 , m_pData ( pData )
466 if ( m_pData->m_bClosed )
467 throw lang::DisposedException("Object already disposed.");
469 m_pData->m_bSaving = true;
470 m_pFramesLock.reset(new SfxOwnFramesLocker( m_pData->m_pObjectShell.get() ));
473 SfxSaveGuard::~SfxSaveGuard()
475 m_pFramesLock.reset();
477 m_pData->m_bSaving = false;
479 // m_bSuicide was set e.g. in case someone tried to close a document, while it was used for
480 // storing at the same time. Further m_bSuicide was set to sal_True only if close(sal_True) was called.
481 // So the ownership was delegated to the place where a veto exception was thrown.
482 // Now we have to call close() again and delegate the ownership to the next one, which
483 // can't accept that. Close(sal_False) can't work in this case. Because then the document will may be never closed...
485 if ( !m_pData->m_bSuicide )
486 return;
488 // Reset this state. In case the new close() request is not accepted by someone else...
489 // it's not a good idea to have two "owners" for close.-)
490 m_pData->m_bSuicide = false;
493 Reference< util::XCloseable > xClose(m_xModel, UNO_QUERY);
494 if (xClose.is())
495 xClose->close(true);
497 catch(const util::CloseVetoException&)
501 SfxBaseModel::SfxBaseModel( SfxObjectShell *pObjectShell )
502 : BaseMutex()
503 , m_pData( std::make_shared<IMPL_SfxBaseModel_DataContainer>( m_aMutex, pObjectShell ) )
504 , m_bSupportEmbeddedScripts( pObjectShell && pObjectShell->Get_Impl() && !pObjectShell->Get_Impl()->m_bNoBasicCapabilities )
505 , m_bSupportDocRecovery( pObjectShell && pObjectShell->Get_Impl() && pObjectShell->Get_Impl()->m_bDocRecoverySupport )
507 if ( pObjectShell != nullptr )
509 StartListening( *pObjectShell ) ;
513 // destructor
514 SfxBaseModel::~SfxBaseModel()
518 // XInterface
519 Any SAL_CALL SfxBaseModel::queryInterface( const uno::Type& rType )
521 if ( ( !m_bSupportEmbeddedScripts && rType.equals( cppu::UnoType<document::XEmbeddedScripts>::get() ) )
522 || ( !m_bSupportDocRecovery && rType.equals( cppu::UnoType<XDocumentRecovery>::get() ) )
524 return Any();
526 return SfxBaseModel_Base::queryInterface( rType );
530 // XTypeProvider
533 namespace
535 void lcl_stripType( Sequence< uno::Type >& io_rTypes, const uno::Type& i_rTypeToStrip )
537 Sequence< uno::Type > aStrippedTypes( io_rTypes.getLength() - 1 );
538 ::std::remove_copy_if(
539 io_rTypes.begin(),
540 io_rTypes.end(),
541 aStrippedTypes.getArray(),
542 [&i_rTypeToStrip](const uno::Type& aType) { return aType == i_rTypeToStrip; }
544 io_rTypes = aStrippedTypes;
548 Sequence< uno::Type > SAL_CALL SfxBaseModel::getTypes()
550 Sequence< uno::Type > aTypes( SfxBaseModel_Base::getTypes() );
552 if ( !m_bSupportEmbeddedScripts )
553 lcl_stripType( aTypes, cppu::UnoType<document::XEmbeddedScripts>::get() );
555 if ( !m_bSupportDocRecovery )
556 lcl_stripType( aTypes, cppu::UnoType<XDocumentRecovery>::get() );
558 return aTypes;
562 // XTypeProvider
565 Sequence< sal_Int8 > SAL_CALL SfxBaseModel::getImplementationId()
567 return css::uno::Sequence<sal_Int8>();
571 // XStarBasicAccess
573 #if HAVE_FEATURE_SCRIPTING
575 static Reference< script::XStarBasicAccess > implGetStarBasicAccess( SfxObjectShell const * pObjectShell )
577 Reference< script::XStarBasicAccess > xRet;
579 #if !HAVE_FEATURE_SCRIPTING
580 (void) pObjectShell;
581 #else
582 if( pObjectShell )
584 BasicManager* pMgr = pObjectShell->GetBasicManager();
585 xRet = getStarBasicAccess( pMgr );
587 #endif
588 return xRet;
591 #endif
593 Reference< container::XNameContainer > SAL_CALL SfxBaseModel::getLibraryContainer()
595 #if !HAVE_FEATURE_SCRIPTING
596 Reference< container::XNameContainer > dummy;
598 return dummy;
599 #else
600 SfxModelGuard aGuard( *this );
602 Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
603 if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
604 rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
606 Reference< container::XNameContainer > xRet;
607 if( rxAccess.is() )
608 xRet = rxAccess->getLibraryContainer();
609 return xRet;
610 #endif
613 /**___________________________________________________________________________________________________
614 @seealso XStarBasicAccess
616 void SAL_CALL SfxBaseModel::createLibrary( const OUString& LibName, const OUString& Password,
617 const OUString& ExternalSourceURL, const OUString& LinkTargetURL )
619 #if !HAVE_FEATURE_SCRIPTING
620 (void) LibName;
621 (void) Password;
622 (void) ExternalSourceURL;
623 (void) LinkTargetURL;
624 #else
625 SfxModelGuard aGuard( *this );
627 Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
628 if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
629 rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
631 if( rxAccess.is() )
632 rxAccess->createLibrary( LibName, Password, ExternalSourceURL, LinkTargetURL );
633 #endif
636 /**___________________________________________________________________________________________________
637 @seealso XStarBasicAccess
639 void SAL_CALL SfxBaseModel::addModule( const OUString& LibraryName, const OUString& ModuleName,
640 const OUString& Language, const OUString& Source )
642 #if !HAVE_FEATURE_SCRIPTING
643 (void) LibraryName;
644 (void) ModuleName;
645 (void) Language;
646 (void) Source;
647 #else
648 SfxModelGuard aGuard( *this );
650 Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
651 if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
652 rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
654 if( rxAccess.is() )
655 rxAccess->addModule( LibraryName, ModuleName, Language, Source );
656 #endif
659 /**___________________________________________________________________________________________________
660 @seealso XStarBasicAccess
662 void SAL_CALL SfxBaseModel::addDialog( const OUString& LibraryName, const OUString& DialogName,
663 const Sequence< sal_Int8 >& Data )
665 #if !HAVE_FEATURE_SCRIPTING
666 (void) LibraryName;
667 (void) DialogName;
668 (void) Data;
669 #else
670 SfxModelGuard aGuard( *this );
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() );
676 if( rxAccess.is() )
677 rxAccess->addDialog( LibraryName, DialogName, Data );
678 #endif
682 // XChild
685 Reference< XInterface > SAL_CALL SfxBaseModel::getParent()
687 SfxModelGuard aGuard( *this );
689 return m_pData->m_xParent;
693 // XChild
696 void SAL_CALL SfxBaseModel::setParent(const Reference< XInterface >& Parent)
698 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
699 m_pData->m_xParent = Parent;
703 // XChild
706 void SAL_CALL SfxBaseModel::dispose()
708 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
710 if ( !m_pData->m_bClosed )
712 // gracefully accept wrong dispose calls instead of close call
713 // and try to make it work (may be really disposed later!)
716 close( true );
718 catch ( util::CloseVetoException& )
722 return;
725 if ( m_pData->m_pStorageModifyListen.is() )
727 m_pData->m_pStorageModifyListen->dispose();
728 m_pData->m_pStorageModifyListen = nullptr;
731 if ( m_pData->m_pDocumentUndoManager.is() )
733 m_pData->m_pDocumentUndoManager->disposing();
734 m_pData->m_pDocumentUndoManager = nullptr;
737 lang::EventObject aEvent( static_cast<frame::XModel *>(this) );
738 m_pData->m_aInterfaceContainer.disposeAndClear( aEvent );
740 m_pData->m_xDocumentProperties.clear();
742 m_pData->m_xDocumentMetadata.clear();
744 if ( m_pData->m_pObjectShell.is() )
746 EndListening( *m_pData->m_pObjectShell );
749 m_pData->m_xCurrent.clear();
750 m_pData->m_seqControllers.clear();
752 // m_pData member must be set to zero before delete is called to
753 // force disposed exception whenever someone tries to access our
754 // instance while in the dtor.
755 m_pData.reset();
759 // XChild
762 void SAL_CALL SfxBaseModel::addEventListener( const Reference< lang::XEventListener >& aListener )
764 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
765 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), aListener );
769 // XChild
772 void SAL_CALL SfxBaseModel::removeEventListener( const Reference< lang::XEventListener >& aListener )
774 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
775 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), aListener );
778 void
779 IMPL_SfxBaseModel_DataContainer::impl_setDocumentProperties(
780 const Reference< document::XDocumentProperties >& rxNewDocProps)
782 m_xDocumentProperties.set(rxNewDocProps, UNO_SET_THROW);
783 if (m_pObjectShell.is())
785 Reference<util::XModifyBroadcaster> const xMB(
786 m_xDocumentProperties, UNO_QUERY_THROW);
787 xMB->addModifyListener(new SfxDocInfoListener_Impl(*m_pObjectShell));
791 // document::XDocumentPropertiesSupplier:
792 Reference< document::XDocumentProperties > SAL_CALL
793 SfxBaseModel::getDocumentProperties()
795 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
796 if ( !m_pData->m_xDocumentProperties.is() )
798 Reference< document::XDocumentProperties > xDocProps(
799 document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
800 m_pData->impl_setDocumentProperties(xDocProps);
803 return m_pData->m_xDocumentProperties;
807 // lang::XEventListener
810 void SAL_CALL SfxBaseModel::disposing( const lang::EventObject& aObject )
812 SolarMutexGuard aGuard;
813 if ( impl_isDisposed() )
814 return;
816 Reference< util::XModifyListener > xMod( aObject.Source, UNO_QUERY );
817 Reference< lang::XEventListener > xListener( aObject.Source, UNO_QUERY );
818 Reference< document::XEventListener > xDocListener( aObject.Source, UNO_QUERY );
820 if ( xMod.is() )
821 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<util::XModifyListener>::get(), xMod );
822 else if ( xListener.is() )
823 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
824 else if ( xDocListener.is() )
825 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<document::XEventListener>::get(), xListener );
829 // frame::XModel
832 sal_Bool SAL_CALL SfxBaseModel::attachResource( const OUString& rURL ,
833 const Sequence< beans::PropertyValue >& rArgs )
835 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
836 if ( rURL.isEmpty() && rArgs.getLength() == 1 && rArgs[0].Name == "SetEmbedded" )
838 // allows to set a windowless document to EMBEDDED state
839 // but _only_ before load() or initNew() methods
840 if ( m_pData->m_pObjectShell.is() && !m_pData->m_pObjectShell->GetMedium() )
842 bool bEmb(false);
843 if ( ( rArgs[0].Value >>= bEmb ) && bEmb )
844 m_pData->m_pObjectShell->SetCreateMode_Impl( SfxObjectCreateMode::EMBEDDED );
847 return true;
850 if ( m_pData->m_pObjectShell.is() )
852 m_pData->m_sURL = rURL;
854 SfxObjectShell* pObjectShell = m_pData->m_pObjectShell.get();
856 ::comphelper::NamedValueCollection aArgs( rArgs );
858 Sequence< sal_Int32 > aWinExtent;
859 if ( ( aArgs.get( "WinExtent" ) >>= aWinExtent )&& ( aWinExtent.getLength() == 4 ) )
861 tools::Rectangle aVisArea( aWinExtent[0], aWinExtent[1], aWinExtent[2], aWinExtent[3] );
862 aVisArea = OutputDevice::LogicToLogic(aVisArea, MapMode(MapUnit::Map100thMM), MapMode(pObjectShell->GetMapUnit()));
863 pObjectShell->SetVisArea( aVisArea );
866 bool bBreakMacroSign = false;
867 if ( aArgs.get( "BreakMacroSignature" ) >>= bBreakMacroSign )
869 pObjectShell->BreakMacroSign_Impl( bBreakMacroSign );
872 bool bMacroEventRead = false;
873 if ((aArgs.get("MacroEventRead") >>= bMacroEventRead) && bMacroEventRead)
875 pObjectShell->SetMacroCallsSeenWhileLoading();
878 aArgs.remove( "WinExtent" );
879 aArgs.remove( "BreakMacroSignature" );
880 aArgs.remove( "MacroEventRead" );
881 aArgs.remove( "Stream" );
882 aArgs.remove( "InputStream" );
883 aArgs.remove( "URL" );
884 aArgs.remove( "Frame" );
885 aArgs.remove( "Password" );
886 aArgs.remove( "EncryptionData" );
888 // TODO/LATER: all the parameters that are accepted by ItemSet of the DocShell must be removed here
890 m_pData->m_seqArguments = aArgs.getPropertyValues();
892 SfxMedium* pMedium = pObjectShell->GetMedium();
893 if ( pMedium )
895 SfxAllItemSet aSet( pObjectShell->GetPool() );
896 TransformParameters( SID_OPENDOC, rArgs, aSet );
898 // the arguments are not allowed to reach the medium
899 aSet.ClearItem( SID_FILE_NAME );
900 aSet.ClearItem( SID_FILLFRAME );
902 pMedium->GetItemSet()->Put( aSet );
903 const SfxStringItem* pItem = aSet.GetItem<SfxStringItem>(SID_FILTER_NAME, false);
904 if ( pItem )
905 pMedium->SetFilter(
906 pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( pItem->GetValue() ) );
908 const SfxStringItem* pTitleItem = aSet.GetItem<SfxStringItem>(SID_DOCINFO_TITLE, false);
909 if ( pTitleItem )
911 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pObjectShell );
912 if ( pFrame )
913 pFrame->UpdateTitle();
918 return true ;
922 // frame::XModel
925 OUString SAL_CALL SfxBaseModel::getURL()
927 SfxModelGuard aGuard( *this );
928 return m_pData->m_sURL ;
932 // frame::XModel
935 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs()
937 SfxModelGuard aGuard( *this );
939 if (!SfxApplication::Get()) // tdf#113755
941 SAL_WARN("sfx.appl", "Unexpected operations on model");
942 return m_pData->m_seqArguments;
945 if ( m_pData->m_pObjectShell.is() )
947 Sequence< beans::PropertyValue > seqArgsNew;
948 Sequence< beans::PropertyValue > seqArgsOld;
949 SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );
951 // we need to know which properties are supported by the transformer
952 // hopefully it is a temporary solution, I guess nonconvertable properties
953 // should not be supported so then there will be only ItemSet from medium
955 TransformItems( SID_OPENDOC, *(m_pData->m_pObjectShell->GetMedium()->GetItemSet()), seqArgsNew );
956 TransformParameters( SID_OPENDOC, m_pData->m_seqArguments, aSet );
957 TransformItems( SID_OPENDOC, aSet, seqArgsOld );
959 sal_Int32 nNewLength = seqArgsNew.getLength();
961 // "WinExtent" property should be updated always.
962 // We can store it now to overwrite an old value
963 // since it is not from ItemSet
964 tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
965 aTmpRect = OutputDevice::LogicToLogic(aTmpRect, MapMode(m_pData->m_pObjectShell->GetMapUnit()), MapMode(MapUnit::Map100thMM));
967 Sequence< sal_Int32 > aRectSeq(4);
968 aRectSeq[0] = aTmpRect.Left();
969 aRectSeq[1] = aTmpRect.Top();
970 aRectSeq[2] = aTmpRect.IsWidthEmpty() ? aTmpRect.Left() : aTmpRect.Right();
971 aRectSeq[3] = aTmpRect.IsHeightEmpty() ? aTmpRect.Top() : aTmpRect.Bottom();
973 seqArgsNew.realloc( ++nNewLength );
974 seqArgsNew[ nNewLength - 1 ].Name = "WinExtent";
975 seqArgsNew[ nNewLength - 1 ].Value <<= aRectSeq;
977 if ( !m_pData->m_aPreusedFilterName.isEmpty() )
979 seqArgsNew.realloc( ++nNewLength );
980 seqArgsNew[ nNewLength - 1 ].Name = "PreusedFilterName";
981 seqArgsNew[ nNewLength - 1 ].Value <<= m_pData->m_aPreusedFilterName;
984 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
985 if ( pFrame )
987 SvBorder aBorder = pFrame->GetBorderPixelImpl();
989 Sequence< sal_Int32 > aBorderSeq(4);
990 aBorderSeq[0] = aBorder.Left();
991 aBorderSeq[1] = aBorder.Top();
992 aBorderSeq[2] = aBorder.Right();
993 aBorderSeq[3] = aBorder.Bottom();
995 seqArgsNew.realloc( ++nNewLength );
996 seqArgsNew[ nNewLength - 1 ].Name = "DocumentBorder";
997 seqArgsNew[ nNewLength - 1 ].Value <<= aBorderSeq;
1000 // only the values that are not supported by the ItemSet must be cached here
1001 Sequence< beans::PropertyValue > aFinalCache;
1002 sal_Int32 nFinalLength = 0;
1004 for ( const auto& rOrg : std::as_const(m_pData->m_seqArguments) )
1006 auto bNew = std::none_of(seqArgsOld.begin(), seqArgsOld.end(),
1007 [&rOrg](const beans::PropertyValue& rOld){ return rOld.Name == rOrg.Name; });
1008 if ( bNew )
1010 // the entity with this name should be new for seqArgsNew
1011 // since it is not supported by transformer
1013 seqArgsNew.realloc( ++nNewLength );
1014 seqArgsNew[ nNewLength - 1 ] = rOrg;
1016 aFinalCache.realloc( ++nFinalLength );
1017 aFinalCache[ nFinalLength - 1 ] = rOrg;
1021 m_pData->m_seqArguments = aFinalCache;
1023 return seqArgsNew;
1026 return m_pData->m_seqArguments;
1029 void SAL_CALL SfxBaseModel::setArgs(const Sequence<beans::PropertyValue>& aArgs)
1031 SfxModelGuard aGuard( *this );
1033 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
1034 if (!pMedium)
1036 throw util::InvalidStateException(
1037 "Medium could not be retrieved, unable to execute setArgs");
1040 for (const auto& rArg : aArgs)
1042 OUString sValue;
1043 bool bValue;
1044 bool ok = false;
1045 if (rArg.Name == "SuggestedSaveAsName")
1047 if (rArg.Value >>= sValue)
1049 pMedium->GetItemSet()->Put(SfxStringItem(SID_SUGGESTEDSAVEASNAME, sValue));
1050 ok = true;
1053 else if (rArg.Name == "SuggestedSaveAsDir")
1055 if (rArg.Value >>= sValue)
1057 pMedium->GetItemSet()->Put(SfxStringItem(SID_SUGGESTEDSAVEASDIR, sValue));
1058 ok = true;
1061 else if (rArg.Name == "LockContentExtraction")
1063 if (rArg.Value >>= bValue)
1065 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_CONTENT_EXTRACTION, bValue));
1066 ok = true;
1069 else if (rArg.Name == "LockExport")
1071 if (rArg.Value >>= bValue)
1073 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_EXPORT, bValue));
1074 ok = true;
1077 else if (rArg.Name == "LockPrint")
1079 if (rArg.Value >>= bValue)
1081 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_PRINT, bValue));
1082 ok = true;
1085 else if (rArg.Name == "LockSave")
1087 if (rArg.Value >>= bValue)
1089 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_SAVE, bValue));
1090 ok = true;
1093 else if (rArg.Name == "LockEditDoc")
1095 if (rArg.Value >>= bValue)
1097 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_EDITDOC, bValue));
1098 ok = true;
1101 else if (rArg.Name == "Replaceable")
1103 if (rArg.Value >>= bValue)
1105 pMedium->GetItemSet()->Put(SfxBoolItem(SID_REPLACEABLE, bValue));
1106 ok = true;
1109 else if (rArg.Name == "EncryptionData")
1111 pMedium->GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, rArg.Value));
1112 ok = true;
1114 if (!ok)
1116 throw lang::IllegalArgumentException("Setting property not supported: " + rArg.Name,
1117 comphelper::getProcessComponentContext(), 0);
1122 // frame::XModel
1125 void SAL_CALL SfxBaseModel::connectController( const Reference< frame::XController >& xController )
1127 SfxModelGuard aGuard( *this );
1128 OSL_PRECOND( xController.is(), "SfxBaseModel::connectController: invalid controller!" );
1129 if ( !xController.is() )
1130 return;
1132 m_pData->m_seqControllers.push_back(xController);
1134 if ( m_pData->m_seqControllers.size() == 1 )
1136 SfxViewFrame* pViewFrame = SfxViewFrame::Get( xController, GetObjectShell() );
1137 ENSURE_OR_THROW( pViewFrame, "SFX document without SFX view!?" );
1138 pViewFrame->UpdateDocument_Impl();
1139 const OUString sDocumentURL = GetObjectShell()->GetMedium()->GetName();
1140 if ( !sDocumentURL.isEmpty() )
1141 SfxGetpApp()->Broadcast( SfxOpenUrlHint( sDocumentURL ) );
1146 // frame::XModel
1149 void SAL_CALL SfxBaseModel::disconnectController( const Reference< frame::XController >& xController )
1151 SfxModelGuard aGuard( *this );
1153 if ( m_pData->m_seqControllers.empty() )
1154 return;
1156 auto& vec = m_pData->m_seqControllers;
1157 vec.erase(std::remove(vec.begin(), vec.end(), xController), vec.end());
1159 if ( xController == m_pData->m_xCurrent )
1160 m_pData->m_xCurrent.clear();
1163 namespace
1165 class ControllerLockUndoAction : public ::cppu::WeakImplHelper< XUndoAction >
1167 public:
1168 ControllerLockUndoAction( const Reference< XModel >& i_model, const bool i_undoIsUnlock )
1169 :m_xModel( i_model )
1170 ,m_bUndoIsUnlock( i_undoIsUnlock )
1174 // XUndoAction
1175 virtual OUString SAL_CALL getTitle() override;
1176 virtual void SAL_CALL undo( ) override;
1177 virtual void SAL_CALL redo( ) override;
1179 private:
1180 const Reference< XModel > m_xModel;
1181 const bool m_bUndoIsUnlock;
1184 OUString SAL_CALL ControllerLockUndoAction::getTitle()
1186 // this action is intended to be used within an UndoContext only, so nobody will ever see this title ...
1187 return OUString();
1190 void SAL_CALL ControllerLockUndoAction::undo( )
1192 if ( m_bUndoIsUnlock )
1193 m_xModel->unlockControllers();
1194 else
1195 m_xModel->lockControllers();
1198 void SAL_CALL ControllerLockUndoAction::redo( )
1200 if ( m_bUndoIsUnlock )
1201 m_xModel->lockControllers();
1202 else
1203 m_xModel->unlockControllers();
1208 // frame::XModel
1211 void SAL_CALL SfxBaseModel::lockControllers()
1213 SfxModelGuard aGuard( *this );
1215 ++m_pData->m_nControllerLockCount ;
1217 if ( m_pData->m_pDocumentUndoManager.is()
1218 && m_pData->m_pDocumentUndoManager->isInContext()
1219 && !m_pData->m_pDocumentUndoManager->isLocked()
1222 m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( this, true ) );
1227 // frame::XModel
1230 void SAL_CALL SfxBaseModel::unlockControllers()
1232 SfxModelGuard aGuard( *this );
1234 --m_pData->m_nControllerLockCount ;
1236 if ( m_pData->m_pDocumentUndoManager.is()
1237 && m_pData->m_pDocumentUndoManager->isInContext()
1238 && !m_pData->m_pDocumentUndoManager->isLocked()
1241 m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( this, false ) );
1246 // frame::XModel
1249 sal_Bool SAL_CALL SfxBaseModel::hasControllersLocked()
1251 SfxModelGuard aGuard( *this );
1252 return ( m_pData->m_nControllerLockCount != 0 ) ;
1256 // frame::XModel
1259 Reference< frame::XController > SAL_CALL SfxBaseModel::getCurrentController()
1261 SfxModelGuard aGuard( *this );
1263 // get the last active controller of this model
1264 if ( m_pData->m_xCurrent.is() )
1265 return m_pData->m_xCurrent;
1267 // get the first controller of this model
1268 return !m_pData->m_seqControllers.empty() ? m_pData->m_seqControllers.front() : m_pData->m_xCurrent;
1272 // frame::XModel
1275 void SAL_CALL SfxBaseModel::setCurrentController( const Reference< frame::XController >& xCurrentController )
1277 SfxModelGuard aGuard( *this );
1279 m_pData->m_xCurrent = xCurrentController;
1283 // frame::XModel
1286 Reference< XInterface > SAL_CALL SfxBaseModel::getCurrentSelection()
1288 SfxModelGuard aGuard( *this );
1290 Reference< XInterface > xReturn;
1291 Reference< frame::XController > xController = getCurrentController() ;
1293 if ( xController.is() )
1295 Reference< view::XSelectionSupplier > xDocView( xController, UNO_QUERY );
1296 if ( xDocView.is() )
1298 Any aSel = xDocView->getSelection();
1299 aSel >>= xReturn ;
1303 return xReturn ;
1307 // XModifiable2
1310 sal_Bool SAL_CALL SfxBaseModel::disableSetModified()
1312 SfxModelGuard aGuard( *this );
1314 if ( !m_pData->m_pObjectShell.is() )
1315 throw RuntimeException();
1317 bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
1318 m_pData->m_pObjectShell->EnableSetModified( false );
1320 return bResult;
1323 sal_Bool SAL_CALL SfxBaseModel::enableSetModified()
1325 SfxModelGuard aGuard( *this );
1327 if ( !m_pData->m_pObjectShell.is() )
1328 throw RuntimeException();
1330 bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
1331 m_pData->m_pObjectShell->EnableSetModified();
1333 return bResult;
1336 sal_Bool SAL_CALL SfxBaseModel::isSetModifiedEnabled()
1338 SfxModelGuard aGuard( *this );
1340 if ( !m_pData->m_pObjectShell.is() )
1341 throw RuntimeException();
1343 return m_pData->m_pObjectShell->IsEnableSetModified();
1347 // XModifiable
1350 sal_Bool SAL_CALL SfxBaseModel::isModified()
1352 SfxModelGuard aGuard( *this );
1354 return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->IsModified();
1358 // XModifiable
1361 void SAL_CALL SfxBaseModel::setModified( sal_Bool bModified )
1363 SfxModelGuard aGuard( *this );
1365 if ( m_pData->m_pObjectShell.is() )
1366 m_pData->m_pObjectShell->SetModified(bModified);
1370 // XModifiable
1373 void SAL_CALL SfxBaseModel::addModifyListener(const Reference< util::XModifyListener >& xListener)
1375 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1377 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<util::XModifyListener>::get(),xListener );
1381 // XModifiable
1384 void SAL_CALL SfxBaseModel::removeModifyListener(const Reference< util::XModifyListener >& xListener)
1386 SfxModelGuard aGuard( *this );
1388 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<util::XModifyListener>::get(), xListener );
1392 // XCloseable
1395 void SAL_CALL SfxBaseModel::close( sal_Bool bDeliverOwnership )
1397 SolarMutexGuard aGuard;
1398 if ( impl_isDisposed() || m_pData->m_bClosed || m_pData->m_bClosing )
1399 return;
1401 Reference< XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
1402 lang::EventObject aSource ( static_cast< ::cppu::OWeakObject* >(this) );
1403 ::cppu::OInterfaceContainerHelper* pContainer = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<util::XCloseListener>::get());
1404 if (pContainer!=nullptr)
1406 ::cppu::OInterfaceIteratorHelper pIterator(*pContainer);
1407 while (pIterator.hasMoreElements())
1411 static_cast<util::XCloseListener*>(pIterator.next())->queryClosing( aSource, bDeliverOwnership );
1413 catch( RuntimeException& )
1415 pIterator.remove();
1420 if ( m_pData->m_bSaving )
1422 if (bDeliverOwnership)
1423 m_pData->m_bSuicide = true;
1424 throw util::CloseVetoException(
1425 "Can not close while saving.",
1426 static_cast< util::XCloseable* >(this));
1429 // no own objections against closing!
1430 m_pData->m_bClosing = true;
1431 pContainer = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<util::XCloseListener>::get());
1432 if (pContainer!=nullptr)
1434 ::cppu::OInterfaceIteratorHelper pCloseIterator(*pContainer);
1435 while (pCloseIterator.hasMoreElements())
1439 static_cast<util::XCloseListener*>(pCloseIterator.next())->notifyClosing( aSource );
1441 catch( RuntimeException& )
1443 pCloseIterator.remove();
1448 m_pData->m_bClosed = true;
1449 m_pData->m_bClosing = false;
1451 dispose();
1455 // XCloseBroadcaster
1458 void SAL_CALL SfxBaseModel::addCloseListener( const Reference< util::XCloseListener >& xListener )
1460 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1462 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
1466 // XCloseBroadcaster
1469 void SAL_CALL SfxBaseModel::removeCloseListener( const Reference< util::XCloseListener >& xListener )
1471 SfxModelGuard aGuard( *this );
1473 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
1477 // XPrintable
1480 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getPrinter()
1482 SfxModelGuard aGuard( *this );
1484 impl_getPrintHelper();
1485 return m_pData->m_xPrintable->getPrinter();
1488 void SAL_CALL SfxBaseModel::setPrinter(const Sequence< beans::PropertyValue >& rPrinter)
1490 SfxModelGuard aGuard( *this );
1492 impl_getPrintHelper();
1493 m_pData->m_xPrintable->setPrinter( rPrinter );
1496 void SAL_CALL SfxBaseModel::print(const Sequence< beans::PropertyValue >& rOptions)
1498 SfxModelGuard aGuard( *this );
1500 impl_getPrintHelper();
1502 // tdf#123728 Always print on main thread to avoid deadlocks
1503 vcl::solarthread::syncExecute([this, &rOptions]() { m_pData->m_xPrintable->print(rOptions); });
1506 // XStorable
1509 sal_Bool SAL_CALL SfxBaseModel::hasLocation()
1511 SfxModelGuard aGuard( *this );
1513 return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->HasName();
1517 // XStorable
1520 OUString SAL_CALL SfxBaseModel::getLocation()
1522 SfxModelGuard aGuard( *this );
1524 if ( m_pData->m_pObjectShell.is() )
1526 // TODO/LATER: is it correct that the shared document returns shared file location?
1527 if ( m_pData->m_pObjectShell->IsDocShared() )
1528 return m_pData->m_pObjectShell->GetSharedFileURL();
1529 else
1530 return m_pData->m_pObjectShell->GetMedium()->GetName();
1533 return m_pData->m_sURL;
1537 // XStorable
1540 sal_Bool SAL_CALL SfxBaseModel::isReadonly()
1542 SfxModelGuard aGuard( *this );
1544 return !m_pData->m_pObjectShell.is() || m_pData->m_pObjectShell->IsReadOnly();
1547 // XStorable2
1550 void SAL_CALL SfxBaseModel::storeSelf( const Sequence< beans::PropertyValue >& aSeqArgs )
1552 SfxModelGuard aGuard( *this );
1554 if ( !m_pData->m_pObjectShell.is() )
1555 return;
1557 SfxSaveGuard aSaveGuard(this, m_pData.get());
1559 bool bCheckIn = false;
1560 bool bOnMainThread = false;
1561 for ( const auto& rArg : aSeqArgs )
1563 // check that only acceptable parameters are provided here
1564 if ( rArg.Name != "VersionComment" && rArg.Name != "Author"
1565 && rArg.Name != "DontTerminateEdit"
1566 && rArg.Name != "InteractionHandler" && rArg.Name != "StatusIndicator"
1567 && rArg.Name != "VersionMajor"
1568 && rArg.Name != "FailOnWarning"
1569 && rArg.Name != "CheckIn"
1570 && rArg.Name != "NoFileSync"
1571 && rArg.Name != "OnMainThread" )
1573 const OUString aMessage( "Unexpected MediaDescriptor parameter: " + rArg.Name );
1574 throw lang::IllegalArgumentException( aMessage, Reference< XInterface >(), 1 );
1576 else if ( rArg.Name == "CheckIn" )
1578 rArg.Value >>= bCheckIn;
1580 else if (rArg.Name == "OnMainThread")
1582 rArg.Value >>= bOnMainThread;
1586 // Remove CheckIn property if needed
1587 sal_uInt16 nSlotId = SID_SAVEDOC;
1588 Sequence< beans::PropertyValue > aArgs = aSeqArgs;
1589 if ( bCheckIn )
1591 nSlotId = SID_CHECKIN;
1592 sal_Int32 nLength = aSeqArgs.getLength( );
1593 aArgs = Sequence< beans::PropertyValue >( nLength - 1 );
1594 std::copy_if(aSeqArgs.begin(), aSeqArgs.end(), aArgs.begin(),
1595 [](const beans::PropertyValue& rProp) { return rProp.Name != "CheckIn"; });
1598 std::unique_ptr<SfxAllItemSet> pParams(new SfxAllItemSet( SfxGetpApp()->GetPool() ));
1599 TransformParameters( nSlotId, aArgs, *pParams );
1601 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDoc, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOC), m_pData->m_pObjectShell.get() ) );
1603 bool bRet = false;
1605 // TODO/LATER: let the embedded case of saving be handled more careful
1606 if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1608 // If this is an embedded object that has no URL based location it should be stored to own storage.
1609 // An embedded object can have a location based on URL in case it is a link, then it should be
1610 // stored in normal way.
1611 if ( !hasLocation() || getLocation().startsWith("private:") )
1613 // actually in this very rare case only UI parameters have sense
1614 // TODO/LATER: should be done later, after integration of sb19
1615 bRet = m_pData->m_pObjectShell->DoSave()
1616 && m_pData->m_pObjectShell->DoSaveCompleted();
1618 else
1620 bRet = m_pData->m_pObjectShell->Save_Impl( pParams.get() );
1623 else
1625 // Tell the SfxMedium if we are in checkin instead of normal save
1626 m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId == SID_CHECKIN );
1627 if (bOnMainThread)
1628 bRet = vcl::solarthread::syncExecute(
1629 [this, &pParams] { return m_pData->m_pObjectShell->Save_Impl(pParams.get()); });
1630 else
1631 bRet = m_pData->m_pObjectShell->Save_Impl(pParams.get());
1632 m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId != SID_CHECKIN );
1635 pParams.reset();
1637 ErrCode nErrCode = m_pData->m_pObjectShell->GetError() ? m_pData->m_pObjectShell->GetError()
1638 : ERRCODE_IO_CANTWRITE;
1639 m_pData->m_pObjectShell->ResetError();
1641 if ( bRet )
1643 m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();
1645 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCDONE), m_pData->m_pObjectShell.get() ) );
1647 else
1649 // write the contents of the logger to the file
1650 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocFailed, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCFAILED), m_pData->m_pObjectShell.get() ) );
1652 throw task::ErrorCodeIOException(
1653 "SfxBaseModel::storeSelf: " + nErrCode.toHexString(),
1654 Reference< XInterface >(), sal_uInt32(nErrCode));
1659 // XStorable
1662 void SAL_CALL SfxBaseModel::store()
1664 comphelper::ProfileZone aZone("store");
1665 storeSelf( Sequence< beans::PropertyValue >() );
1669 // XStorable
1672 void SAL_CALL SfxBaseModel::storeAsURL( const OUString& rURL ,
1673 const Sequence< beans::PropertyValue >& rArgs )
1675 SfxModelGuard aGuard( *this );
1676 comphelper::ProfileZone aZone("storeAs");
1678 if ( !m_pData->m_pObjectShell.is() )
1679 return;
1681 SfxSaveGuard aSaveGuard(this, m_pData.get());
1683 impl_store( rURL, rArgs, false );
1685 Sequence< beans::PropertyValue > aSequence ;
1686 TransformItems( SID_OPENDOC, *m_pData->m_pObjectShell->GetMedium()->GetItemSet(), aSequence );
1687 attachResource( rURL, aSequence );
1689 loadCmisProperties( );
1691 #if OSL_DEBUG_LEVEL > 0
1692 const SfxStringItem* pPasswdItem = SfxItemSet::GetItem<SfxStringItem>(m_pData->m_pObjectShell->GetMedium()->GetItemSet(), SID_PASSWORD, false);
1693 OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
1694 #endif
1698 // XUndoManagerSupplier
1700 Reference< XUndoManager > SAL_CALL SfxBaseModel::getUndoManager( )
1702 SfxModelGuard aGuard( *this );
1703 if ( !m_pData->m_pDocumentUndoManager.is() )
1704 m_pData->m_pDocumentUndoManager.set( new ::sfx2::DocumentUndoManager( *this ) );
1705 return m_pData->m_pDocumentUndoManager.get();
1709 // XStorable
1712 void SAL_CALL SfxBaseModel::storeToURL( const OUString& rURL ,
1713 const Sequence< beans::PropertyValue >& rArgs )
1715 SfxModelGuard aGuard( *this );
1716 comphelper::ProfileZone aZone("storeToURL");
1718 if ( !m_pData->m_pObjectShell.is() )
1719 return;
1721 SfxSaveGuard aSaveGuard(this, m_pData.get());
1722 try {
1723 utl::MediaDescriptor aDescriptor(rArgs);
1724 bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault("OnMainThread", false);
1725 if (bOnMainThread)
1726 vcl::solarthread::syncExecute([this, rURL, rArgs]() { impl_store(rURL, rArgs, true); });
1727 else
1728 impl_store(rURL, rArgs, true);
1730 catch (const uno::Exception &e)
1732 // convert to the exception we announce in the throw
1733 // (eg. neon likes to throw InteractiveAugmentedIOException which
1734 // is not an io::IOException)
1735 throw io::IOException(e.Message, e.Context);
1739 sal_Bool SAL_CALL SfxBaseModel::wasModifiedSinceLastSave()
1741 SfxModelGuard aGuard( *this );
1742 return m_pData->m_bModifiedSinceLastSave;
1745 void SAL_CALL SfxBaseModel::storeToRecoveryFile( const OUString& i_TargetLocation, const Sequence< PropertyValue >& i_MediaDescriptor )
1747 SfxModelGuard aGuard( *this );
1749 // delegate
1750 SfxSaveGuard aSaveGuard( this, m_pData.get() );
1751 impl_store( i_TargetLocation, i_MediaDescriptor, true );
1753 // no need for subsequent calls to storeToRecoveryFile, unless we're modified, again
1754 m_pData->m_bModifiedSinceLastSave = false;
1757 void SAL_CALL SfxBaseModel::recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor )
1759 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1761 // delegate to our "load" method
1762 ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor );
1764 // our load implementation expects the SalvagedFile to be in the media descriptor
1765 OSL_ENSURE( !aMediaDescriptor.has( "SalvagedFile" ) || ( aMediaDescriptor.getOrDefault( "SalvagedFile", OUString() ) == i_SalvagedFile ),
1766 "SfxBaseModel::recoverFromFile: inconsistent information!" );
1767 aMediaDescriptor.put( "SalvagedFile", i_SalvagedFile );
1769 // similar for the to-be-loaded file
1770 OSL_ENSURE( !aMediaDescriptor.has( "URL" ) || ( aMediaDescriptor.getOrDefault( "URL", OUString() ) == i_SourceLocation ),
1771 "SfxBaseModel::recoverFromFile: inconsistent information!" );
1772 aMediaDescriptor.put( "URL", i_SourceLocation );
1774 load( aMediaDescriptor.getPropertyValues() );
1776 // Note: The XDocumentRecovery interface specification requires us to do an attachResource after loading.
1777 // However, we will not do this here, as we know that our load implementation (respectively some method
1778 // called from there) already did so.
1779 // In particular, the load process might already have modified some elements of the media
1780 // descriptor, for instance the MacroExecMode (in case the user was involved to decide about it), and we do
1781 // not want to overwrite it with the "old" elements passed to this method here.
1785 // XLoadable
1788 void SAL_CALL SfxBaseModel::initNew()
1790 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1791 if ( IsInitialized() )
1792 throw frame::DoubleInitializationException( OUString(), *this );
1794 // the object shell should exist always
1795 DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );
1796 if ( !m_pData->m_pObjectShell.is() )
1797 return;
1799 if( m_pData->m_pObjectShell->GetMedium() )
1800 throw frame::DoubleInitializationException();
1802 bool bRes = m_pData->m_pObjectShell->DoInitNew();
1803 ErrCode nErrCode = m_pData->m_pObjectShell->GetError() ?
1804 m_pData->m_pObjectShell->GetError() : ERRCODE_IO_CANTCREATE;
1805 m_pData->m_pObjectShell->ResetError();
1807 if ( !bRes )
1808 throw task::ErrorCodeIOException(
1809 "SfxBaseModel::initNew: " + nErrCode.toHexString(),
1810 Reference< XInterface >(), sal_uInt32(nErrCode));
1813 namespace {
1815 OUString getFilterProvider( SfxMedium const & rMedium )
1817 const std::shared_ptr<const SfxFilter>& pFilter = rMedium.GetFilter();
1818 if (!pFilter)
1819 return OUString();
1821 return pFilter->GetProviderName();
1824 void setUpdatePickList( SfxMedium* pMedium )
1826 if (!pMedium)
1827 return;
1829 bool bHidden = false;
1830 const SfxBoolItem* pHidItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_HIDDEN, false);
1831 if (pHidItem)
1832 bHidden = pHidItem->GetValue();
1834 pMedium->SetUpdatePickList(!bHidden);
1839 void SAL_CALL SfxBaseModel::load( const Sequence< beans::PropertyValue >& seqArguments )
1841 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1842 if ( IsInitialized() )
1843 throw frame::DoubleInitializationException( OUString(), *this );
1845 // the object shell should exist always
1846 DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );
1848 if (!m_pData->m_pObjectShell.is())
1849 return;
1851 if( m_pData->m_pObjectShell->GetMedium() )
1852 // if a Medium is present, the document is already initialized
1853 throw frame::DoubleInitializationException();
1855 SfxMedium* pMedium = new SfxMedium( seqArguments );
1857 ErrCode nError = ERRCODE_NONE;
1858 if (!getFilterProvider(*pMedium).isEmpty())
1860 if (!m_pData->m_pObjectShell->DoLoadExternal(pMedium))
1861 nError = ERRCODE_IO_GENERAL;
1863 pMedium = handleLoadError(nError, pMedium);
1864 setUpdatePickList(pMedium);
1865 return;
1868 OUString aFilterName;
1869 const SfxStringItem* pFilterNameItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_FILTER_NAME, false);
1870 if( pFilterNameItem )
1871 aFilterName = pFilterNameItem->GetValue();
1872 if( !m_pData->m_pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) )
1874 // filtername is not valid
1875 delete pMedium;
1876 throw frame::IllegalArgumentIOException();
1879 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_DOC_SALVAGE, false);
1880 bool bSalvage = pSalvageItem != nullptr;
1882 // load document
1883 if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
1884 nError=ERRCODE_IO_GENERAL;
1886 // QUESTION: if the following happens outside of DoLoad, something important is missing there!
1887 Reference< task::XInteractionHandler > xHandler = pMedium->GetInteractionHandler();
1888 if( m_pData->m_pObjectShell->GetErrorCode() )
1890 nError = m_pData->m_pObjectShell->GetErrorCode();
1891 if ( nError == ERRCODE_IO_BROKENPACKAGE && xHandler.is() )
1893 const OUString aDocName( pMedium->GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ) );
1894 const SfxBoolItem* pRepairItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_REPAIRPACKAGE, false);
1895 if ( !pRepairItem || !pRepairItem->GetValue() )
1897 RequestPackageReparation aRequest( aDocName );
1898 xHandler->handle( aRequest.GetRequest() );
1899 if( aRequest.isApproved() )
1901 // broken package: try second loading and allow repair
1902 pMedium->GetItemSet()->Put( SfxBoolItem( SID_REPAIRPACKAGE, true ) );
1903 pMedium->GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, true ) );
1904 pMedium->GetItemSet()->Put( SfxStringItem( SID_DOCINFO_TITLE, aDocName ) );
1906 // the error must be reset and the storage must be reopened in new mode
1907 pMedium->ResetError();
1908 pMedium->CloseStorage();
1909 m_pData->m_pObjectShell->PrepareSecondTryLoad_Impl();
1910 nError = ERRCODE_NONE;
1911 if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
1912 nError=ERRCODE_IO_GENERAL;
1913 if (m_pData->m_pObjectShell->GetErrorCode())
1914 nError = m_pData->m_pObjectShell->GetErrorCode();
1918 if ( nError == ERRCODE_IO_BROKENPACKAGE )
1920 // repair either not allowed or not successful
1921 NotifyBrokenPackage aRequest( aDocName );
1922 xHandler->handle( aRequest.GetRequest() );
1927 if( m_pData->m_pObjectShell->IsAbortingImport() )
1928 nError = ERRCODE_ABORT;
1930 if( bSalvage )
1932 // file recovery: restore original filter
1933 const SfxStringItem* pFilterItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_FILTER_NAME, false);
1934 SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
1935 std::shared_ptr<const SfxFilter> pSetFilter = rMatcher.GetFilter4FilterName( pFilterItem->GetValue() );
1936 pMedium->SetFilter( pSetFilter );
1937 m_pData->m_pObjectShell->SetModified();
1940 // TODO/LATER: maybe the mode should be retrieved from outside and the preused filter should not be set
1941 if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1943 const SfxStringItem* pFilterItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_FILTER_NAME, false);
1944 if ( pFilterItem )
1945 m_pData->m_aPreusedFilterName = pFilterItem->GetValue();
1948 if ( !nError )
1949 nError = pMedium->GetError();
1951 m_pData->m_pObjectShell->ResetError();
1953 pMedium = handleLoadError(nError, pMedium);
1954 loadCmisProperties();
1955 setUpdatePickList(pMedium);
1957 #if OSL_DEBUG_LEVEL > 0
1958 const SfxStringItem* pPasswdItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_PASSWORD, false);
1959 OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
1960 #endif
1964 // XTransferable
1967 Any SAL_CALL SfxBaseModel::getTransferData( const datatransfer::DataFlavor& aFlavor )
1969 SfxModelGuard aGuard( *this );
1971 Any aAny;
1973 if ( m_pData->m_pObjectShell.is() )
1975 if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
1977 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
1978 throw datatransfer::UnsupportedFlavorException();
1980 TransferableObjectDescriptor aDesc;
1982 aDesc.maClassName = m_pData->m_pObjectShell->GetClassName();
1983 aDesc.maTypeName = aFlavor.HumanPresentableName;
1985 // TODO/LATER: ViewAspect needs to be sal_Int64
1986 aDesc.mnViewAspect = sal::static_int_cast< sal_uInt16 >( embed::Aspects::MSOLE_CONTENT );
1988 Size aSize = m_pData->m_pObjectShell->GetVisArea().GetSize();
1990 MapUnit aMapUnit = m_pData->m_pObjectShell->GetMapUnit();
1991 aDesc.maSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
1992 aDesc.maDragStartPos = Point();
1993 aDesc.maDisplayName.clear();
1995 SvMemoryStream aMemStm( 1024, 1024 );
1996 WriteTransferableObjectDescriptor( aMemStm, aDesc );
1997 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
1999 else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
2001 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2002 throw datatransfer::UnsupportedFlavorException();
2006 utl::TempFile aTmp;
2007 aTmp.EnableKillingFile();
2008 storeToURL( aTmp.GetURL(), Sequence < beans::PropertyValue >() );
2009 std::unique_ptr<SvStream> pStream(aTmp.GetStream( StreamMode::READ ));
2010 const sal_uInt32 nLen = pStream->TellEnd();
2011 Sequence< sal_Int8 > aSeq( nLen );
2012 pStream->ReadBytes(aSeq.getArray(), nLen);
2013 if( aSeq.hasElements() )
2014 aAny <<= aSeq;
2016 catch ( Exception& )
2020 else if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2022 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2023 throw datatransfer::UnsupportedFlavorException();
2026 std::shared_ptr<GDIMetaFile> xMetaFile =
2027 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2029 if (xMetaFile)
2031 SvMemoryStream aMemStm( 65535, 65535 );
2032 aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2034 xMetaFile->Write( aMemStm );
2035 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
2036 aMemStm.TellEnd() );
2039 else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2041 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2042 throw datatransfer::UnsupportedFlavorException();
2044 std::shared_ptr<GDIMetaFile> xMetaFile =
2045 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2047 if (xMetaFile)
2049 SvMemoryStream aMemStm( 65535, 65535 );
2050 aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2052 xMetaFile->Write( aMemStm );
2053 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
2054 aMemStm.TellEnd() );
2057 else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
2059 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2061 std::shared_ptr<GDIMetaFile> xMetaFile =
2062 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2064 if (xMetaFile)
2066 std::unique_ptr<SvMemoryStream> xStream(
2067 GraphicHelper::getFormatStrFromGDI_Impl(
2068 xMetaFile.get(), ConvertDataFormat::EMF ) );
2069 if (xStream)
2071 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2072 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2073 xStream->TellEnd() );
2077 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2078 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2080 std::shared_ptr<GDIMetaFile> xMetaFile =
2081 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2083 if (xMetaFile)
2085 aAny <<= reinterpret_cast< sal_uInt64 >(
2086 GraphicHelper::getEnhMetaFileFromGDI_Impl( xMetaFile.get() ) );
2089 else
2090 throw datatransfer::UnsupportedFlavorException();
2092 else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
2094 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2096 std::shared_ptr<GDIMetaFile> xMetaFile =
2097 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2099 if (xMetaFile)
2101 std::unique_ptr<SvMemoryStream> xStream(
2102 GraphicHelper::getFormatStrFromGDI_Impl(
2103 xMetaFile.get(), ConvertDataFormat::WMF ) );
2105 if (xStream)
2107 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2108 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2109 xStream->TellEnd() );
2113 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2114 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2116 // means HGLOBAL handler to memory storage containing METAFILEPICT structure
2118 std::shared_ptr<GDIMetaFile> xMetaFile =
2119 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2121 if (xMetaFile)
2123 Size aMetaSize = xMetaFile->GetPrefSize();
2124 aAny <<= reinterpret_cast< sal_uInt64 >(
2125 GraphicHelper::getWinMetaFileFromGDI_Impl(
2126 xMetaFile.get(), aMetaSize ) );
2129 else
2130 throw datatransfer::UnsupportedFlavorException();
2132 else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
2134 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2135 throw datatransfer::UnsupportedFlavorException();
2137 std::shared_ptr<GDIMetaFile> xMetaFile =
2138 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2140 if (xMetaFile)
2142 std::unique_ptr<SvMemoryStream> xStream(
2143 GraphicHelper::getFormatStrFromGDI_Impl(
2144 xMetaFile.get(), ConvertDataFormat::BMP ) );
2146 if (xStream)
2148 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2149 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2150 xStream->TellEnd() );
2154 else if ( aFlavor.MimeType == "image/png" )
2156 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2157 throw datatransfer::UnsupportedFlavorException();
2159 std::shared_ptr<GDIMetaFile> xMetaFile =
2160 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2162 if (xMetaFile)
2164 std::unique_ptr<SvMemoryStream> xStream(
2165 GraphicHelper::getFormatStrFromGDI_Impl(
2166 xMetaFile.get(), ConvertDataFormat::PNG ) );
2168 if (xStream)
2170 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2171 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2172 xStream->TellEnd() );
2176 else
2177 throw datatransfer::UnsupportedFlavorException();
2180 return aAny;
2184 // XTransferable
2187 Sequence< datatransfer::DataFlavor > SAL_CALL SfxBaseModel::getTransferDataFlavors()
2189 SfxModelGuard aGuard( *this );
2191 const sal_Int32 nSuppFlavors = GraphicHelper::supportsMetaFileHandle_Impl() ? 10 : 8;
2192 Sequence< datatransfer::DataFlavor > aFlavorSeq( nSuppFlavors );
2194 aFlavorSeq[0].MimeType =
2195 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
2196 aFlavorSeq[0].HumanPresentableName = "GDIMetaFile";
2197 aFlavorSeq[0].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2199 aFlavorSeq[1].MimeType =
2200 "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"";
2201 aFlavorSeq[1].HumanPresentableName = "GDIMetaFile";
2202 aFlavorSeq[1].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2204 aFlavorSeq[2].MimeType =
2205 "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ;
2206 aFlavorSeq[2].HumanPresentableName = "Enhanced Windows MetaFile";
2207 aFlavorSeq[2].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2209 aFlavorSeq[3].MimeType =
2210 "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
2211 aFlavorSeq[3].HumanPresentableName = "Windows MetaFile";
2212 aFlavorSeq[3].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2214 aFlavorSeq[4].MimeType =
2215 "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
2216 aFlavorSeq[4].HumanPresentableName = "Star Object Descriptor (XML)";
2217 aFlavorSeq[4].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2219 aFlavorSeq[5].MimeType =
2220 "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
2221 aFlavorSeq[5].HumanPresentableName = "Star Embed Source (XML)";
2222 aFlavorSeq[5].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2224 aFlavorSeq[6].MimeType =
2225 "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"";
2226 aFlavorSeq[6].HumanPresentableName = "Bitmap";
2227 aFlavorSeq[6].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2229 aFlavorSeq[7].MimeType = "image/png";
2230 aFlavorSeq[7].HumanPresentableName = "PNG";
2231 aFlavorSeq[7].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2233 if ( nSuppFlavors == 10 )
2235 aFlavorSeq[8].MimeType =
2236 "application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
2237 aFlavorSeq[8].HumanPresentableName = "Enhanced Windows MetaFile";
2238 aFlavorSeq[8].DataType = cppu::UnoType<sal_uInt64>::get();
2240 aFlavorSeq[9].MimeType =
2241 "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
2242 aFlavorSeq[9].HumanPresentableName = "Windows MetaFile";
2243 aFlavorSeq[9].DataType = cppu::UnoType<sal_uInt64>::get();
2246 return aFlavorSeq;
2250 // XTransferable
2253 sal_Bool SAL_CALL SfxBaseModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
2255 SfxModelGuard aGuard( *this );
2257 if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2259 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2260 return true;
2262 else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2264 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2265 return true;
2267 else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
2269 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2270 return true;
2271 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2272 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2273 return true;
2275 else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
2277 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2278 return true;
2279 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2280 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2281 return true;
2283 else if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
2285 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2286 return true;
2288 else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
2290 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2291 return true;
2293 else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
2295 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2296 return true;
2298 else if ( aFlavor.MimeType == "image/png" )
2300 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2301 return true;
2304 return false;
2308 // XEventsSupplier
2311 Reference< container::XNameReplace > SAL_CALL SfxBaseModel::getEvents()
2313 SfxModelGuard aGuard( *this );
2315 if ( ! m_pData->m_xEvents.is() )
2317 m_pData->m_xEvents = new SfxEvents_Impl( m_pData->m_pObjectShell.get(), this );
2320 return m_pData->m_xEvents;
2324 // XEmbeddedScripts
2327 Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getBasicLibraries()
2329 SfxModelGuard aGuard( *this );
2331 Reference< script::XStorageBasedLibraryContainer > xBasicLibraries;
2332 if ( m_pData->m_pObjectShell.is() )
2333 xBasicLibraries.set(m_pData->m_pObjectShell->GetBasicContainer(), UNO_QUERY);
2334 return xBasicLibraries;
2337 Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getDialogLibraries()
2339 SfxModelGuard aGuard( *this );
2341 Reference< script::XStorageBasedLibraryContainer > xDialogLibraries;
2342 if ( m_pData->m_pObjectShell.is() )
2343 xDialogLibraries.set(m_pData->m_pObjectShell->GetDialogContainer(), UNO_QUERY);
2344 return xDialogLibraries;
2347 sal_Bool SAL_CALL SfxBaseModel::getAllowMacroExecution()
2349 SfxModelGuard aGuard( *this );
2351 if ( m_pData->m_pObjectShell.is() )
2352 return m_pData->m_pObjectShell->AdjustMacroMode();
2353 return false;
2357 // XScriptInvocationContext
2360 Reference< document::XEmbeddedScripts > SAL_CALL SfxBaseModel::getScriptContainer()
2362 SfxModelGuard aGuard( *this );
2364 Reference< document::XEmbeddedScripts > xDocumentScripts;
2368 Reference< frame::XModel > xDocument( this );
2369 xDocumentScripts.set( xDocument, UNO_QUERY );
2370 while ( !xDocumentScripts.is() && xDocument.is() )
2372 Reference< container::XChild > xDocAsChild( xDocument, UNO_QUERY );
2373 if ( !xDocAsChild.is() )
2375 xDocument = nullptr;
2376 break;
2379 xDocument.set( xDocAsChild->getParent(), UNO_QUERY );
2380 xDocumentScripts.set( xDocument, UNO_QUERY );
2383 catch( const Exception& )
2385 DBG_UNHANDLED_EXCEPTION("sfx.doc");
2386 xDocumentScripts = nullptr;
2389 return xDocumentScripts;
2393 // XEventBroadcaster
2396 void SAL_CALL SfxBaseModel::addEventListener( const Reference< document::XEventListener >& aListener )
2398 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2400 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<document::XEventListener>::get(), aListener );
2404 // XEventBroadcaster
2407 void SAL_CALL SfxBaseModel::removeEventListener( const Reference< document::XEventListener >& aListener )
2409 SfxModelGuard aGuard( *this );
2411 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<document::XEventListener>::get(), aListener );
2414 // XShapeEventBroadcaster
2416 void SAL_CALL SfxBaseModel::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
2418 assert(xShape.is() && "no shape?");
2419 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2421 m_pData->maShapeListeners[xShape].push_back(xListener);
2425 // XShapeEventBroadcaster
2428 void SAL_CALL SfxBaseModel::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
2430 SfxModelGuard aGuard( *this );
2432 auto it = m_pData->maShapeListeners.find(xShape);
2433 if (it != m_pData->maShapeListeners.end())
2435 auto rVec = it->second;
2436 auto it2 = std::find(rVec.begin(), rVec.end(), xListener);
2437 if (it2 != rVec.end())
2439 rVec.erase(it2);
2440 if (rVec.empty())
2441 m_pData->maShapeListeners.erase(it);
2446 // XDocumentEventBroadcaster
2449 void SAL_CALL SfxBaseModel::addDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
2451 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2452 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<document::XDocumentEventListener>::get(), aListener );
2456 void SAL_CALL SfxBaseModel::removeDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
2458 SfxModelGuard aGuard( *this );
2459 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<document::XDocumentEventListener>::get(), aListener );
2463 void SAL_CALL SfxBaseModel::notifyDocumentEvent( const OUString&, const Reference< frame::XController2 >&, const Any& )
2465 throw lang::NoSupportException("SfxBaseModel controls all the sent notifications itself!" );
2468 Sequence<document::CmisProperty> SAL_CALL SfxBaseModel::getCmisProperties()
2470 if (impl_isDisposed())
2471 return Sequence<document::CmisProperty>();
2472 return m_pData->m_cmisProperties;
2475 void SAL_CALL SfxBaseModel::setCmisProperties( const Sequence< document::CmisProperty >& _cmisproperties )
2477 m_pData->m_cmisProperties = _cmisproperties;
2480 void SAL_CALL SfxBaseModel::updateCmisProperties( const Sequence< document::CmisProperty >& aProperties )
2482 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2483 if ( !pMedium )
2484 return;
2488 ::ucbhelper::Content aContent( pMedium->GetName( ),
2489 Reference<ucb::XCommandEnvironment>(),
2490 comphelper::getProcessComponentContext() );
2492 aContent.executeCommand( "updateProperties", uno::makeAny( aProperties ) );
2493 loadCmisProperties( );
2495 catch (const Exception & e)
2497 css::uno::Any anyEx = cppu::getCaughtException();
2498 throw lang::WrappedTargetRuntimeException( e.Message,
2499 e.Context, anyEx );
2504 void SAL_CALL SfxBaseModel::checkOut( )
2506 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2507 if ( !pMedium )
2508 return;
2512 ::ucbhelper::Content aContent( pMedium->GetName(),
2513 Reference<ucb::XCommandEnvironment>(),
2514 comphelper::getProcessComponentContext() );
2516 Any aResult = aContent.executeCommand( "checkout", Any( ) );
2517 OUString sURL;
2518 aResult >>= sURL;
2520 m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
2521 m_pData->m_pObjectShell->GetMedium( )->GetMedium_Impl( );
2522 m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
2523 Sequence< beans::PropertyValue > aSequence ;
2524 TransformItems( SID_OPENDOC, *pMedium->GetItemSet(), aSequence );
2525 attachResource( sURL, aSequence );
2527 // Reload the CMIS properties
2528 loadCmisProperties( );
2530 catch ( const Exception & e )
2532 css::uno::Any anyEx = cppu::getCaughtException();
2533 throw lang::WrappedTargetRuntimeException( e.Message,
2534 e.Context, anyEx );
2538 void SAL_CALL SfxBaseModel::cancelCheckOut( )
2540 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2541 if ( !pMedium )
2542 return;
2546 ::ucbhelper::Content aContent( pMedium->GetName(),
2547 Reference<ucb::XCommandEnvironment>(),
2548 comphelper::getProcessComponentContext() );
2550 Any aResult = aContent.executeCommand( "cancelCheckout", Any( ) );
2551 OUString sURL;
2552 aResult >>= sURL;
2554 m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
2556 catch ( const Exception & e )
2558 css::uno::Any anyEx = cppu::getCaughtException();
2559 throw lang::WrappedTargetRuntimeException( e.Message,
2560 e.Context, anyEx );
2564 void SAL_CALL SfxBaseModel::checkIn( sal_Bool bIsMajor, const OUString& rMessage )
2566 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2567 if ( !pMedium )
2568 return;
2572 Sequence< beans::PropertyValue > aProps( 3 );
2573 aProps[0].Name = "VersionMajor";
2574 aProps[0].Value <<= bIsMajor;
2575 aProps[1].Name = "VersionComment";
2576 aProps[1].Value <<= rMessage;
2577 aProps[2].Name = "CheckIn";
2578 aProps[2].Value <<= true;
2580 const OUString sName( pMedium->GetName( ) );
2581 storeSelf( aProps );
2583 // Refresh pMedium as it has probably changed during the storeSelf call
2584 pMedium = m_pData->m_pObjectShell->GetMedium( );
2585 const OUString sNewName( pMedium->GetName( ) );
2587 // URL has changed, update the document
2588 if ( sName != sNewName )
2590 m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
2591 Sequence< beans::PropertyValue > aSequence ;
2592 TransformItems( SID_OPENDOC, *pMedium->GetItemSet(), aSequence );
2593 attachResource( sNewName, aSequence );
2595 // Reload the CMIS properties
2596 loadCmisProperties( );
2599 catch ( const Exception & e )
2601 css::uno::Any anyEx = cppu::getCaughtException();
2602 throw lang::WrappedTargetRuntimeException( e.Message,
2603 e.Context, anyEx );
2607 uno::Sequence< document::CmisVersion > SAL_CALL SfxBaseModel::getAllVersions( )
2609 uno::Sequence<document::CmisVersion> aVersions;
2610 if (impl_isDisposed())
2611 return aVersions;
2612 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2613 if ( pMedium )
2617 ::ucbhelper::Content aContent( pMedium->GetName(),
2618 Reference<ucb::XCommandEnvironment>(),
2619 comphelper::getProcessComponentContext() );
2621 Any aResult = aContent.executeCommand( "getAllVersions", Any( ) );
2622 aResult >>= aVersions;
2624 catch ( const Exception & e )
2626 css::uno::Any anyEx = cppu::getCaughtException();
2627 throw lang::WrappedTargetRuntimeException( e.Message,
2628 e.Context, anyEx );
2631 return aVersions;
2634 bool SfxBaseModel::getBoolPropertyValue( const OUString& rName )
2636 bool bValue = false;
2637 if ( m_pData->m_pObjectShell.is() )
2639 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2640 if ( pMedium )
2644 ::ucbhelper::Content aContent( pMedium->GetName( ),
2645 utl::UCBContentHelper::getDefaultCommandEnvironment(),
2646 comphelper::getProcessComponentContext() );
2647 Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
2648 if ( xProps->hasPropertyByName( rName ) )
2650 aContent.getPropertyValue( rName ) >>= bValue;
2653 catch ( const Exception & )
2655 // Simply ignore it: it's likely the document isn't versionable in that case
2656 bValue = false;
2660 return bValue;
2663 sal_Bool SAL_CALL SfxBaseModel::isVersionable( )
2665 return getBoolPropertyValue( "IsVersionable" );
2668 sal_Bool SAL_CALL SfxBaseModel::canCheckOut( )
2670 return getBoolPropertyValue( "CanCheckOut" );
2673 sal_Bool SAL_CALL SfxBaseModel::canCancelCheckOut( )
2675 return getBoolPropertyValue( "CanCancelCheckOut" );
2678 sal_Bool SAL_CALL SfxBaseModel::canCheckIn( )
2680 return getBoolPropertyValue( "CanCheckIn" );
2683 void SfxBaseModel::loadCmisProperties( )
2685 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2686 if ( !pMedium )
2687 return;
2691 ::ucbhelper::Content aContent( pMedium->GetName( ),
2692 utl::UCBContentHelper::getDefaultCommandEnvironment(),
2693 comphelper::getProcessComponentContext() );
2694 Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
2695 const OUString aCmisProps( "CmisProperties" );
2696 if ( xProps->hasPropertyByName( aCmisProps ) )
2698 Sequence< document::CmisProperty> aCmisProperties;
2699 aContent.getPropertyValue( aCmisProps ) >>= aCmisProperties;
2700 setCmisProperties( aCmisProperties );
2703 catch (const ucb::ContentCreationException &)
2706 catch (const ucb::CommandAbortedException &)
2711 SfxMedium* SfxBaseModel::handleLoadError( ErrCode nError, SfxMedium* pMedium )
2713 if (!nError)
2715 // No error condition.
2716 return pMedium;
2719 bool bSilent = false;
2720 const SfxBoolItem* pSilentItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_SILENT, false);
2721 if( pSilentItem )
2722 bSilent = pSilentItem->GetValue();
2724 bool bWarning = nError.IsWarning();
2725 if ( nError != ERRCODE_IO_BROKENPACKAGE && !bSilent )
2727 // broken package was handled already
2728 if ( SfxObjectShell::UseInteractionToHandleError(pMedium->GetInteractionHandler(), nError) && !bWarning)
2730 // abort loading (except for warnings)
2731 nError = ERRCODE_IO_ABORT;
2735 if ( m_pData->m_pObjectShell->GetMedium() != pMedium )
2737 // for whatever reason document now has another medium
2738 OSL_FAIL("Document has rejected the medium?!");
2739 delete pMedium;
2740 pMedium = nullptr;
2743 if ( !bWarning ) // #i30711# don't abort loading if it's only a warning
2745 nError = nError ? nError : ERRCODE_IO_CANTREAD;
2746 throw task::ErrorCodeIOException(
2747 "SfxBaseModel::handleLoadError: 0x" + nError.toHexString(),
2748 Reference< XInterface >(), sal_uInt32(nError));
2751 return pMedium;
2755 // SfxListener
2758 static void addTitle_Impl( Sequence < beans::PropertyValue >& rSeq, const OUString& rTitle )
2760 auto pProp = std::find_if(rSeq.begin(), rSeq.end(),
2761 [](const beans::PropertyValue& rProp) { return rProp.Name == "Title"; });
2762 if (pProp != rSeq.end())
2764 pProp->Value <<= rTitle;
2766 else
2768 sal_Int32 nCount = rSeq.getLength();
2769 rSeq.realloc( nCount+1 );
2770 rSeq[nCount].Name = "Title";
2771 rSeq[nCount].Value <<= rTitle;
2775 void SfxBaseModel::Notify( SfxBroadcaster& rBC ,
2776 const SfxHint& rHint )
2778 if ( !m_pData )
2779 return;
2781 if ( &rBC != m_pData->m_pObjectShell.get() )
2782 return;
2784 if ( rHint.GetId() == SfxHintId::DocChanged )
2785 changing();
2787 const SfxEventHint* pNamedHint = dynamic_cast<const SfxEventHint*>(&rHint);
2788 if ( pNamedHint )
2791 switch ( pNamedHint->GetEventId() )
2793 case SfxEventHintId::StorageChanged:
2795 if ( m_pData->m_xUIConfigurationManager.is()
2796 && m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
2798 Reference< embed::XStorage > xConfigStorage;
2799 const OUString aUIConfigFolderName( "Configurations2" );
2801 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
2802 if ( !xConfigStorage.is() )
2803 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
2805 if ( xConfigStorage.is() || !m_pData->m_pObjectShell->GetStorage()->hasByName( aUIConfigFolderName ) )
2807 // the storage is different, since otherwise it could not be opened, so it must be exchanged
2808 m_pData->m_xUIConfigurationManager->setStorage( xConfigStorage );
2810 else
2812 OSL_FAIL( "Unexpected scenario!" );
2816 ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
2818 break;
2820 case SfxEventHintId::LoadFinished:
2822 impl_getPrintHelper();
2823 ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
2824 m_pData->m_bModifiedSinceLastSave = false;
2826 break;
2828 case SfxEventHintId::SaveAsDocDone:
2830 m_pData->m_sURL = m_pData->m_pObjectShell->GetMedium()->GetName();
2832 SfxItemSet *pSet = m_pData->m_pObjectShell->GetMedium()->GetItemSet();
2833 Sequence< beans::PropertyValue > aArgs;
2834 TransformItems( SID_SAVEASDOC, *pSet, aArgs );
2835 addTitle_Impl( aArgs, m_pData->m_pObjectShell->GetTitle() );
2836 attachResource( m_pData->m_pObjectShell->GetMedium()->GetName(), aArgs );
2838 break;
2840 case SfxEventHintId::DocCreated:
2842 impl_getPrintHelper();
2843 m_pData->m_bModifiedSinceLastSave = false;
2845 break;
2847 case SfxEventHintId::ModifyChanged:
2849 m_pData->m_bModifiedSinceLastSave = isModified();
2851 break;
2852 default: break;
2855 const SfxViewEventHint* pViewHint = dynamic_cast<const SfxViewEventHint*>(&rHint);
2856 postEvent_Impl( pNamedHint->GetEventName(), pViewHint ? pViewHint->GetController() : Reference< frame::XController2 >() );
2859 if ( rHint.GetId() == SfxHintId::TitleChanged )
2861 addTitle_Impl( m_pData->m_seqArguments, m_pData->m_pObjectShell->GetTitle() );
2862 postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::TITLECHANGED ) );
2864 else if ( rHint.GetId() == SfxHintId::ModeChanged )
2866 postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::MODECHANGED ) );
2871 // public impl.
2874 void SfxBaseModel::NotifyModifyListeners_Impl() const
2876 ::cppu::OInterfaceContainerHelper* pIC = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<util::XModifyListener>::get());
2877 if ( pIC )
2879 lang::EventObject aEvent( static_cast<frame::XModel *>(const_cast<SfxBaseModel *>(this)) );
2880 pIC->notifyEach( &util::XModifyListener::modified, aEvent );
2883 // this notification here is done too generously, we cannot simply assume that we're really modified
2884 // now, but we need to check it ...
2885 m_pData->m_bModifiedSinceLastSave = const_cast< SfxBaseModel* >( this )->isModified();
2888 void SfxBaseModel::changing()
2890 SfxModelGuard aGuard( *this );
2892 // the notification should not be sent if the document can not be modified
2893 if ( !m_pData->m_pObjectShell.is() || !m_pData->m_pObjectShell->IsEnableSetModified() )
2894 return;
2896 NotifyModifyListeners_Impl();
2900 // public impl.
2903 SfxObjectShell* SfxBaseModel::GetObjectShell() const
2905 return m_pData ? m_pData->m_pObjectShell.get() : nullptr;
2909 // public impl.
2912 bool SfxBaseModel::IsInitialized() const
2914 if ( !m_pData || !m_pData->m_pObjectShell.is() )
2916 OSL_FAIL( "SfxBaseModel::IsInitialized: this should have been caught earlier!" );
2917 return false;
2920 return m_pData->m_pObjectShell->GetMedium() != nullptr;
2923 void SfxBaseModel::MethodEntryCheck( const bool i_mustBeInitialized ) const
2925 if ( impl_isDisposed() )
2926 throw lang::DisposedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
2927 if ( i_mustBeInitialized && !IsInitialized() )
2928 throw lang::NotInitializedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
2931 bool SfxBaseModel::impl_isDisposed() const
2933 return ( m_pData == nullptr ) ;
2937 // private impl.
2940 OUString SfxBaseModel::GetMediumFilterName_Impl() const
2942 std::shared_ptr<const SfxFilter> pFilter;
2943 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2944 if ( pMedium )
2945 pFilter = pMedium->GetFilter();
2947 if ( pFilter )
2948 return pFilter->GetName();
2950 return OUString();
2953 void SfxBaseModel::impl_store( const OUString& sURL ,
2954 const Sequence< beans::PropertyValue >& seqArguments ,
2955 bool bSaveTo )
2957 if( sURL.isEmpty() )
2958 throw frame::IllegalArgumentIOException();
2960 bool bSaved = false;
2961 if ( !bSaveTo && m_pData->m_pObjectShell.is() && !sURL.isEmpty()
2962 && !sURL.startsWith( "private:stream" )
2963 && ::utl::UCBContentHelper::EqualURLs( getLocation(), sURL ) )
2965 // this is the same file URL as the current document location, try to use storeOwn if possible
2967 ::comphelper::SequenceAsHashMap aArgHash( seqArguments );
2968 const OUString aFilterString( "FilterName" );
2969 const OUString aFilterName( aArgHash.getUnpackedValueOrDefault( aFilterString, OUString() ) );
2970 if ( !aFilterName.isEmpty() )
2972 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2973 if ( pMedium )
2975 const std::shared_ptr<const SfxFilter>& pFilter = pMedium->GetFilter();
2976 if ( pFilter && aFilterName == pFilter->GetFilterName() )
2978 // #i119366# - If the former file saving with password, do not trying in StoreSelf anyway...
2979 bool bFormerPassword = false;
2981 uno::Sequence< beans::NamedValue > aOldEncryptionData;
2982 if (GetEncryptionData_Impl( pMedium->GetItemSet(), aOldEncryptionData ))
2984 bFormerPassword = true;
2987 if ( !bFormerPassword )
2989 aArgHash.erase( aFilterString );
2990 aArgHash.erase( "URL" );
2994 storeSelf( aArgHash.getAsConstPropertyValueList() );
2995 bSaved = true;
2997 catch( const lang::IllegalArgumentException& )
2999 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
3000 // some additional arguments do not allow to use saving, SaveAs should be done
3001 // but only for normal documents, the shared documents would be overwritten in this case
3002 // that would mean an information loss
3003 // TODO/LATER: need a new interaction for this case
3004 if ( m_pData->m_pObjectShell->IsDocShared() )
3006 uno::Sequence< beans::NamedValue > aNewEncryptionData = aArgHash.getUnpackedValueOrDefault("EncryptionData", uno::Sequence< beans::NamedValue >() );
3007 if ( !aNewEncryptionData.hasElements() )
3009 aNewEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( aArgHash.getUnpackedValueOrDefault("Password", OUString()) );
3012 uno::Sequence< beans::NamedValue > aOldEncryptionData;
3013 (void)GetEncryptionData_Impl( pMedium->GetItemSet(), aOldEncryptionData );
3015 if ( !aOldEncryptionData.hasElements() && !aNewEncryptionData.hasElements() )
3016 throw;
3017 else
3019 // if the password is changed a special error should be used in case of shared document
3020 throw task::ErrorCodeIOException("Can not change password for shared document.", uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_SFX_SHARED_NOPASSWORDCHANGE) );
3023 #endif
3031 if ( bSaved || !m_pData->m_pObjectShell.is() )
3032 return;
3034 SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDoc : SfxEventHintId::SaveAsDoc, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOC : GlobalEventId::SAVEASDOC ),
3035 m_pData->m_pObjectShell.get() ) );
3037 std::unique_ptr<SfxAllItemSet> pItemSet(new SfxAllItemSet(SfxGetpApp()->GetPool()));
3038 pItemSet->Put(SfxStringItem(SID_FILE_NAME, sURL));
3039 if ( bSaveTo )
3040 pItemSet->Put(SfxBoolItem(SID_SAVETO, true));
3042 TransformParameters(SID_SAVEASDOC, seqArguments, *pItemSet);
3044 const SfxBoolItem* pCopyStreamItem = pItemSet->GetItem<SfxBoolItem>(SID_COPY_STREAM_IF_POSSIBLE, false);
3046 if ( pCopyStreamItem && pCopyStreamItem->GetValue() && !bSaveTo )
3048 throw frame::IllegalArgumentIOException(
3049 "CopyStreamIfPossible parameter is not acceptable for storeAsURL() call!" );
3052 sal_uInt32 nModifyPasswordHash = 0;
3053 Sequence< beans::PropertyValue > aModifyPasswordInfo;
3054 const SfxUnoAnyItem* pModifyPasswordInfoItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_MODIFYPASSWORDINFO, false);
3055 if ( pModifyPasswordInfoItem )
3057 // it contains either a simple hash or a set of PropertyValues
3058 // TODO/LATER: the sequence of PropertyValue should replace the hash completely in future
3059 sal_Int32 nMPHTmp = 0;
3060 pModifyPasswordInfoItem->GetValue() >>= nMPHTmp;
3061 nModifyPasswordHash = static_cast<sal_uInt32>(nMPHTmp);
3062 pModifyPasswordInfoItem->GetValue() >>= aModifyPasswordInfo;
3064 pItemSet->ClearItem(SID_MODIFYPASSWORDINFO);
3065 sal_uInt32 nOldModifyPasswordHash = m_pData->m_pObjectShell->GetModifyPasswordHash();
3066 m_pData->m_pObjectShell->SetModifyPasswordHash( nModifyPasswordHash );
3067 Sequence< beans::PropertyValue > aOldModifyPasswordInfo = m_pData->m_pObjectShell->GetModifyPasswordInfo();
3068 m_pData->m_pObjectShell->SetModifyPasswordInfo( aModifyPasswordInfo );
3070 // since saving a document modifies its DocumentProperties, the current
3071 // DocumentProperties must be saved on "SaveTo", so it can be restored
3072 // after saving
3073 bool bCopyTo = bSaveTo ||
3074 m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED;
3075 Reference<document::XDocumentProperties> xOldDocProps;
3076 if ( bCopyTo )
3078 xOldDocProps = getDocumentProperties();
3079 const Reference<util::XCloneable> xCloneable(xOldDocProps,
3080 UNO_QUERY_THROW);
3081 const Reference<document::XDocumentProperties> xNewDocProps(
3082 xCloneable->createClone(), UNO_QUERY_THROW);
3083 m_pData->m_xDocumentProperties = xNewDocProps;
3086 bool bRet = m_pData->m_pObjectShell->APISaveAs_Impl(sURL, *pItemSet, seqArguments);
3088 if ( bCopyTo )
3090 // restore DocumentProperties if a copy was created
3091 m_pData->m_xDocumentProperties = xOldDocProps;
3094 Reference < task::XInteractionHandler > xHandler;
3095 const SfxUnoAnyItem* pItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_INTERACTIONHANDLER, false);
3096 if ( pItem )
3097 pItem->GetValue() >>= xHandler;
3099 pItemSet.reset();
3101 ErrCode nErrCode = m_pData->m_pObjectShell->GetErrorCode();
3102 if ( !bRet && !nErrCode )
3104 SAL_WARN("sfx.doc", "Storing has failed, no error is set!");
3105 nErrCode = ERRCODE_IO_CANTWRITE;
3107 m_pData->m_pObjectShell->ResetError();
3109 if ( bRet )
3111 if ( nErrCode )
3113 // must be a warning - use Interactionhandler if possible or abandon
3114 if ( xHandler.is() )
3116 // TODO/LATER: a general way to set the error context should be available
3117 SfxErrorContext aEc( ERRCTX_SFX_SAVEASDOC, m_pData->m_pObjectShell->GetTitle() );
3119 task::ErrorCodeRequest aErrorCode;
3120 aErrorCode.ErrCode = sal_uInt32(nErrCode);
3121 SfxMedium::CallApproveHandler( xHandler, makeAny( aErrorCode ), false );
3125 if ( !bSaveTo )
3127 m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();
3128 m_pData->m_pObjectShell->SetModifyPasswordEntered();
3130 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveAsDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEASDOCDONE), m_pData->m_pObjectShell.get() ) );
3132 else
3134 m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
3135 m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
3137 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveToDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVETODOCDONE), m_pData->m_pObjectShell.get() ) );
3140 else
3142 m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
3143 m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
3146 SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDocFailed : SfxEventHintId::SaveAsDocFailed, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOCFAILED : GlobalEventId::SAVEASDOCFAILED),
3147 m_pData->m_pObjectShell.get() ) );
3149 std::stringstream aErrCode;
3150 aErrCode << nErrCode;
3151 throw task::ErrorCodeIOException(
3152 "SfxBaseModel::impl_store <" + sURL + "> failed: " + OUString::fromUtf8(aErrCode.str().c_str()),
3153 Reference< XInterface >(), sal_uInt32(nErrCode));
3158 namespace {
3159 template< typename ListenerT, typename EventT >
3160 class NotifySingleListenerIgnoreRE
3162 private:
3163 typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
3164 NotificationMethod m_pMethod;
3165 const EventT& m_rEvent;
3166 public:
3167 NotifySingleListenerIgnoreRE( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
3169 void operator()( const Reference<ListenerT>& listener ) const
3173 (listener.get()->*m_pMethod)( m_rEvent );
3175 catch( RuntimeException& )
3177 // this exception is ignored to avoid problems with invalid listeners, the listener should be probably thrown away in future
3181 } // anonymous namespace
3183 void SfxBaseModel::postEvent_Impl( const OUString& aName, const Reference< frame::XController2 >& xController )
3185 // object already disposed?
3186 if ( impl_isDisposed() )
3187 return;
3189 // keep m_pData alive, if notified target would dispose the document
3190 std::shared_ptr<IMPL_SfxBaseModel_DataContainer> xKeepAlive(m_pData);
3192 // also make sure this object doesn't self-destruct while notifying
3193 rtl::Reference<SfxBaseModel> xHoldAlive(this);
3195 DBG_ASSERT( !aName.isEmpty(), "Empty event name!" );
3196 if (aName.isEmpty())
3197 return;
3199 ::cppu::OInterfaceContainerHelper* pIC =
3200 m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XDocumentEventListener>::get());
3201 if ( pIC )
3203 SAL_INFO("sfx.doc", "SfxDocumentEvent: " + aName);
3205 document::DocumentEvent aDocumentEvent( static_cast<frame::XModel*>(this), aName, xController, Any() );
3207 pIC->forEach< document::XDocumentEventListener, NotifySingleListenerIgnoreRE< document::XDocumentEventListener, document::DocumentEvent > >(
3208 NotifySingleListenerIgnoreRE< document::XDocumentEventListener, document::DocumentEvent >(
3209 &document::XDocumentEventListener::documentEventOccured,
3210 aDocumentEvent ) );
3213 pIC = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XEventListener>::get());
3214 if ( pIC )
3216 SAL_INFO("sfx.doc", "SfxEvent: " + aName);
3218 document::EventObject aEvent( static_cast<frame::XModel*>(this), aName );
3220 pIC->forEach< document::XEventListener, NotifySingleListenerIgnoreRE< document::XEventListener, document::EventObject > >(
3221 NotifySingleListenerIgnoreRE< document::XEventListener, document::EventObject >(
3222 &document::XEventListener::notifyEvent,
3223 aEvent ) );
3228 Reference < container::XIndexAccess > SAL_CALL SfxBaseModel::getViewData()
3230 SfxModelGuard aGuard( *this );
3232 if ( m_pData->m_pObjectShell.is() && !m_pData->m_contViewData.is() )
3234 SfxViewFrame *pActFrame = SfxViewFrame::Current();
3235 if ( !pActFrame || pActFrame->GetObjectShell() != m_pData->m_pObjectShell.get() )
3236 pActFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
3238 if ( !pActFrame || !pActFrame->GetViewShell() )
3239 // currently no frame for this document at all or View is under construction
3240 return Reference < container::XIndexAccess >();
3242 m_pData->m_contViewData = document::IndexedPropertyValues::create( ::comphelper::getProcessComponentContext() );
3244 if ( !m_pData->m_contViewData.is() )
3246 // error: no container class available!
3247 return Reference < container::XIndexAccess >();
3250 Reference < container::XIndexContainer > xCont( m_pData->m_contViewData, UNO_QUERY );
3251 sal_Int32 nCount = 0;
3252 Sequence < beans::PropertyValue > aSeq;
3253 for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() ); pFrame;
3254 pFrame = SfxViewFrame::GetNext( *pFrame, m_pData->m_pObjectShell.get() ) )
3256 bool bIsActive = ( pFrame == pActFrame );
3257 pFrame->GetViewShell()->WriteUserDataSequence( aSeq );
3258 xCont->insertByIndex( bIsActive ? 0 : nCount, Any(aSeq) );
3259 nCount++;
3263 return m_pData->m_contViewData;
3266 void SAL_CALL SfxBaseModel::setViewData( const Reference < container::XIndexAccess >& aData )
3268 SfxModelGuard aGuard( *this );
3270 m_pData->m_contViewData = aData;
3273 /** calls all XEventListeners */
3274 void SfxBaseModel::notifyEvent( const document::EventObject& aEvent ) const
3276 // object already disposed?
3277 if ( impl_isDisposed() )
3278 return;
3280 ::cppu::OInterfaceContainerHelper* pIC = m_pData->m_aInterfaceContainer.getContainer(
3281 cppu::UnoType<document::XEventListener>::get());
3282 if( !pIC )
3284 return;
3286 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
3287 while( aIt.hasMoreElements() )
3291 static_cast<document::XEventListener *>(aIt.next())->notifyEvent( aEvent );
3293 catch( RuntimeException& )
3295 aIt.remove();
3298 // for right now, we're only doing the event that this particular performance problem needed
3299 if (aEvent.EventName == "ShapeModified")
3301 uno::Reference<drawing::XShape> xShape(aEvent.Source, uno::UNO_QUERY);
3302 if (xShape.is())
3304 auto it = m_pData->maShapeListeners.find(xShape);
3305 if (it != m_pData->maShapeListeners.end())
3306 for (auto const & rListenerUnoRef : it->second)
3307 rListenerUnoRef->notifyShapeEvent(aEvent);
3312 /** returns true if someone added a XEventListener to this XEventBroadcaster */
3313 bool SfxBaseModel::hasEventListeners() const
3315 return !impl_isDisposed()
3316 && ( (nullptr != m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XEventListener>::get()) )
3317 || !m_pData->maShapeListeners.empty());
3320 void SAL_CALL SfxBaseModel::addPrintJobListener( const Reference< view::XPrintJobListener >& xListener )
3322 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3324 impl_getPrintHelper();
3325 Reference < view::XPrintJobBroadcaster > xPJB( m_pData->m_xPrintable, UNO_QUERY );
3326 if ( xPJB.is() )
3327 xPJB->addPrintJobListener( xListener );
3330 void SAL_CALL SfxBaseModel::removePrintJobListener( const Reference< view::XPrintJobListener >& xListener )
3332 SfxModelGuard aGuard( *this );
3334 impl_getPrintHelper();
3335 Reference < view::XPrintJobBroadcaster > xPJB( m_pData->m_xPrintable, UNO_QUERY );
3336 if ( xPJB.is() )
3337 xPJB->removePrintJobListener( xListener );
3340 sal_Int64 SAL_CALL SfxBaseModel::getSomething( const Sequence< sal_Int8 >& aIdentifier )
3342 SvGlobalName aName( aIdentifier );
3343 if (aName == SvGlobalName( SFX_GLOBAL_CLASSID ))
3345 SolarMutexGuard aGuard;
3346 SfxObjectShell *const pObjectShell(GetObjectShell());
3347 if (pObjectShell)
3349 return reinterpret_cast<sal_Int64>(pObjectShell);
3353 return 0;
3357 // XDocumentSubStorageSupplier
3360 void SfxBaseModel::ListenForStorage_Impl( const Reference< embed::XStorage >& xStorage )
3362 Reference< util::XModifiable > xModifiable( xStorage, UNO_QUERY );
3363 if ( xModifiable.is() )
3365 if ( !m_pData->m_pStorageModifyListen.is() )
3367 m_pData->m_pStorageModifyListen = new ::sfx2::DocumentStorageModifyListener( *m_pData, Application::GetSolarMutex() );
3370 // no need to deregister the listening for old storage since it should be disposed automatically
3371 xModifiable->addModifyListener( m_pData->m_pStorageModifyListen.get() );
3375 Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode )
3377 SfxModelGuard aGuard( *this );
3379 Reference< embed::XStorage > xResult;
3380 if ( m_pData->m_pObjectShell.is() )
3382 Reference< embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
3383 if ( xStorage.is() )
3387 xResult = xStorage->openStorageElement( aStorageName, nMode );
3389 catch ( Exception& )
3395 return xResult;
3398 Sequence< OUString > SAL_CALL SfxBaseModel::getDocumentSubStoragesNames()
3400 SfxModelGuard aGuard( *this );
3402 Sequence< OUString > aResult;
3403 bool bSuccess = false;
3404 if ( m_pData->m_pObjectShell.is() )
3406 Reference < embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
3407 if ( xStorage.is() )
3409 const Sequence< OUString > aTemp = xStorage->getElementNames();
3410 sal_Int32 nResultSize = 0;
3411 for ( const auto& rName : aTemp )
3413 if ( xStorage->isStorageElement( rName ) )
3415 aResult.realloc( ++nResultSize );
3416 aResult[ nResultSize - 1 ] = rName;
3420 bSuccess = true;
3424 if ( !bSuccess )
3425 throw io::IOException();
3427 return aResult;
3431 // XScriptProviderSupplier
3434 Reference< script::provider::XScriptProvider > SAL_CALL SfxBaseModel::getScriptProvider()
3436 SfxModelGuard aGuard( *this );
3438 Reference< script::provider::XScriptProviderFactory > xScriptProviderFactory =
3439 script::provider::theMasterScriptProviderFactory::get( ::comphelper::getProcessComponentContext() );
3441 Reference< XScriptInvocationContext > xScriptContext( this );
3443 Reference< script::provider::XScriptProvider > xScriptProvider(
3444 xScriptProviderFactory->createScriptProvider( makeAny( xScriptContext ) ),
3445 UNO_SET_THROW );
3447 return xScriptProvider;
3451 // XUIConfigurationManagerSupplier
3454 OUString const & SfxBaseModel::getRuntimeUID() const
3456 OSL_ENSURE( !m_pData->m_sRuntimeUID.isEmpty(),
3457 "SfxBaseModel::getRuntimeUID - ID is empty!" );
3458 return m_pData->m_sRuntimeUID;
3461 bool SfxBaseModel::hasValidSignatures() const
3463 SolarMutexGuard aGuard;
3464 if ( m_pData->m_pObjectShell.is() )
3465 return ( m_pData->m_pObjectShell->ImplGetSignatureState() == SignatureState::OK );
3466 return false;
3469 void SfxBaseModel::getGrabBagItem(css::uno::Any& rVal) const
3471 if (m_pData->m_xGrabBagItem)
3472 m_pData->m_xGrabBagItem->QueryValue(rVal);
3473 else
3474 rVal <<= uno::Sequence<beans::PropertyValue>();
3477 void SfxBaseModel::setGrabBagItem(const css::uno::Any& rVal)
3479 if (!m_pData->m_xGrabBagItem)
3480 m_pData->m_xGrabBagItem = std::make_shared<SfxGrabBagItem>();
3482 m_pData->m_xGrabBagItem->PutValue(rVal, 0);
3485 static void GetCommandFromSequence( OUString& rCommand, sal_Int32& nIndex, const Sequence< beans::PropertyValue >& rSeqPropValue )
3487 nIndex = -1;
3489 auto pPropValue = std::find_if(rSeqPropValue.begin(), rSeqPropValue.end(),
3490 [](const beans::PropertyValue& rPropValue) { return rPropValue.Name == "Command"; });
3491 if (pPropValue != rSeqPropValue.end())
3493 pPropValue->Value >>= rCommand;
3494 nIndex = static_cast<sal_Int32>(std::distance(rSeqPropValue.begin(), pPropValue));
3498 static void ConvertSlotsToCommands( SfxObjectShell const * pDoc, Reference< container::XIndexContainer > const & rToolbarDefinition )
3500 if ( !pDoc )
3501 return;
3503 SfxModule* pModule( pDoc->GetFactory().GetModule() );
3504 Sequence< beans::PropertyValue > aSeqPropValue;
3506 for ( sal_Int32 i = 0; i < rToolbarDefinition->getCount(); i++ )
3508 if ( rToolbarDefinition->getByIndex( i ) >>= aSeqPropValue )
3510 OUString aCommand;
3511 sal_Int32 nIndex( -1 );
3512 GetCommandFromSequence( aCommand, nIndex, aSeqPropValue );
3513 if ( nIndex >= 0 && aCommand.startsWith( "slot:" ) )
3515 const sal_uInt16 nSlot = aCommand.copy( 5 ).toInt32();
3517 // We have to replace the old "slot-Command" with our new ".uno:-Command"
3518 const SfxSlot* pSlot = pModule->GetSlotPool()->GetSlot( nSlot );
3519 if ( pSlot )
3521 OUStringBuffer aStrBuf( ".uno:" );
3522 aStrBuf.appendAscii( pSlot->GetUnoName() );
3524 aCommand = aStrBuf.makeStringAndClear();
3525 aSeqPropValue[nIndex].Value <<= aCommand;
3526 rToolbarDefinition->replaceByIndex( i, Any( aSeqPropValue ));
3533 Reference< ui::XUIConfigurationManager > SAL_CALL SfxBaseModel::getUIConfigurationManager()
3535 return Reference< ui::XUIConfigurationManager >( getUIConfigurationManager2(), UNO_QUERY_THROW );
3538 Reference< ui::XUIConfigurationManager2 > SfxBaseModel::getUIConfigurationManager2()
3540 SfxModelGuard aGuard( *this );
3542 if ( !m_pData->m_xUIConfigurationManager.is() )
3544 Reference< ui::XUIConfigurationManager2 > xNewUIConfMan =
3545 ui::UIConfigurationManager::create( comphelper::getProcessComponentContext() );
3547 Reference< embed::XStorage > xConfigStorage;
3549 OUString aUIConfigFolderName( "Configurations2" );
3550 // First try to open with READWRITE and then READ
3551 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
3552 if ( xConfigStorage.is() )
3554 const OUString aMediaTypeProp( "MediaType" );
3555 OUString aMediaType;
3556 Reference< beans::XPropertySet > xPropSet( xConfigStorage, UNO_QUERY );
3557 Any a = xPropSet->getPropertyValue( aMediaTypeProp );
3558 if ( !( a >>= aMediaType ) || aMediaType.isEmpty())
3560 xPropSet->setPropertyValue( aMediaTypeProp, Any(OUString("application/vnd.sun.xml.ui.configuration")) );
3563 else
3564 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
3566 // initialize ui configuration manager with document substorage
3567 xNewUIConfMan->setStorage( xConfigStorage );
3569 // embedded objects did not support local configuration data until OOo 3.0, so there's nothing to
3570 // migrate
3571 if ( m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
3573 // Import old UI configuration from OOo 1.x
3575 // Try to open with READ
3576 Reference< embed::XStorage > xOOo1ConfigStorage = getDocumentSubStorage( "Configurations", embed::ElementModes::READ );
3577 if ( xOOo1ConfigStorage.is() )
3579 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
3580 std::vector< Reference< container::XIndexContainer > > rToolbars;
3582 bool bImported = framework::UIConfigurationImporterOOo1x::ImportCustomToolbars(
3583 xNewUIConfMan, rToolbars, xContext, xOOo1ConfigStorage );
3584 if ( bImported )
3586 SfxObjectShell* pObjShell = SfxBaseModel::GetObjectShell();
3588 for ( size_t i = 0; i < rToolbars.size(); i++ )
3590 const OUString sId(OUString::number( i + 1 ));
3591 const OUString aCustomTbxName = "private:resource/toolbar/custom_OOo1x_" + sId;
3593 Reference< container::XIndexContainer > xToolbar = rToolbars[i];
3594 ConvertSlotsToCommands( pObjShell, xToolbar );
3595 if ( !xNewUIConfMan->hasSettings( aCustomTbxName ))
3597 // Set UIName for the toolbar with container property
3598 Reference< beans::XPropertySet > xPropSet( xToolbar, UNO_QUERY );
3599 if ( xPropSet.is() )
3603 xPropSet->setPropertyValue( "UIName", Any( "Toolbar " + sId ) );
3605 catch ( beans::UnknownPropertyException& )
3610 xNewUIConfMan->insertSettings( aCustomTbxName, xToolbar );
3611 xNewUIConfMan->store();
3618 m_pData->m_xUIConfigurationManager = xNewUIConfMan;
3621 return m_pData->m_xUIConfigurationManager;
3625 // XVisualObject
3628 void SAL_CALL SfxBaseModel::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize )
3630 SfxModelGuard aGuard( *this );
3632 if ( !m_pData->m_pObjectShell.is() )
3633 throw Exception("no object shell", nullptr); // TODO: error handling
3635 SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get(), false );
3636 if ( pViewFrm && m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !pViewFrm->GetFrame().IsInPlace() )
3638 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( pViewFrm->GetFrame().GetFrameInterface()->getContainerWindow() );
3639 Size aWinSize = pWindow->GetSizePixel();
3640 awt::Size aCurrent = getVisualAreaSize( nAspect );
3641 Size aDiff( aSize.Width-aCurrent.Width, aSize.Height-aCurrent.Height );
3642 aDiff = pViewFrm->GetViewShell()->GetWindow()->LogicToPixel( aDiff );
3643 aWinSize.AdjustWidth(aDiff.Width() );
3644 aWinSize.AdjustHeight(aDiff.Height() );
3645 pWindow->SetSizePixel( aWinSize );
3647 else
3649 tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
3650 aTmpRect.SetSize( Size( aSize.Width, aSize.Height ) );
3651 m_pData->m_pObjectShell->SetVisArea( aTmpRect );
3655 awt::Size SAL_CALL SfxBaseModel::getVisualAreaSize( sal_Int64 /*nAspect*/ )
3657 SfxModelGuard aGuard( *this );
3659 if ( !m_pData->m_pObjectShell.is() )
3660 throw Exception("no object shell", nullptr); // TODO: error handling
3662 tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
3664 return awt::Size( aTmpRect.GetWidth(), aTmpRect.GetHeight() );
3668 sal_Int32 SAL_CALL SfxBaseModel::getMapUnit( sal_Int64 /*nAspect*/ )
3670 SfxModelGuard aGuard( *this );
3672 if ( !m_pData->m_pObjectShell.is() )
3673 throw Exception("no object shell", nullptr); // TODO: error handling
3675 return VCLUnoHelper::VCL2UnoEmbedMapUnit( m_pData->m_pObjectShell->GetMapUnit() );
3678 embed::VisualRepresentation SAL_CALL SfxBaseModel::getPreferredVisualRepresentation( ::sal_Int64 /*nAspect*/ )
3680 SfxModelGuard aGuard( *this );
3682 datatransfer::DataFlavor aDataFlavor(
3683 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"",
3684 "GDIMetaFile",
3685 cppu::UnoType<Sequence< sal_Int8 >>::get() );
3687 embed::VisualRepresentation aVisualRepresentation;
3688 aVisualRepresentation.Data = getTransferData( aDataFlavor );
3689 aVisualRepresentation.Flavor = aDataFlavor;
3691 return aVisualRepresentation;
3695 // XStorageBasedDocument
3698 void SAL_CALL SfxBaseModel::loadFromStorage( const Reference< embed::XStorage >& xStorage,
3699 const Sequence< beans::PropertyValue >& aMediaDescriptor )
3701 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3702 if ( IsInitialized() )
3703 throw frame::DoubleInitializationException( OUString(), *this );
3705 // after i36090 is fixed the pool from object shell can be used
3706 // SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );
3707 SfxAllItemSet aSet( SfxGetpApp()->GetPool() );
3709 // the BaseURL is part of the ItemSet
3710 SfxMedium* pMedium = new SfxMedium( xStorage, OUString() );
3711 TransformParameters( SID_OPENDOC, aMediaDescriptor, aSet );
3712 pMedium->GetItemSet()->Put( aSet );
3714 // allow to use an interactionhandler (if there is one)
3715 pMedium->UseInteractionHandler( true );
3717 const SfxBoolItem* pTemplateItem = aSet.GetItem<SfxBoolItem>(SID_TEMPLATE, false);
3718 bool bTemplate = pTemplateItem && pTemplateItem->GetValue();
3719 m_pData->m_pObjectShell->SetActivateEvent_Impl( bTemplate ? SfxEventHintId::CreateDoc : SfxEventHintId::OpenDoc );
3720 m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
3722 // load document
3723 if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
3725 ErrCode nError = m_pData->m_pObjectShell->GetErrorCode();
3726 nError = nError ? nError : ERRCODE_IO_CANTREAD;
3727 throw task::ErrorCodeIOException(
3728 "SfxBaseModel::loadFromStorage: " + nError.toHexString(),
3729 Reference< XInterface >(), sal_uInt32(nError));
3731 loadCmisProperties( );
3734 void SAL_CALL SfxBaseModel::storeToStorage( const Reference< embed::XStorage >& xStorage,
3735 const Sequence< beans::PropertyValue >& aMediaDescriptor )
3737 SfxModelGuard aGuard( *this );
3739 if ( !m_pData->m_pObjectShell.is() )
3740 throw io::IOException(); // TODO:
3742 auto xSet = std::make_shared<SfxAllItemSet>(m_pData->m_pObjectShell->GetPool());
3743 TransformParameters( SID_SAVEASDOC, aMediaDescriptor, *xSet );
3745 // TODO/LATER: maybe a special URL "private:storage" should be used
3746 const SfxStringItem* pItem = xSet->GetItem<SfxStringItem>(SID_FILTER_NAME, false);
3747 sal_Int32 nVersion = SOFFICE_FILEFORMAT_CURRENT;
3748 if( pItem )
3750 std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( pItem->GetValue() );
3751 if ( pFilter && pFilter->UsesStorage() )
3752 nVersion = pFilter->GetVersion();
3755 bool bSuccess = false;
3756 if ( xStorage == m_pData->m_pObjectShell->GetStorage() )
3758 // storing to the own storage
3759 bSuccess = m_pData->m_pObjectShell->DoSave();
3761 else
3763 // TODO/LATER: if the provided storage has some data inside the storing might fail, probably the storage must be truncated
3764 // TODO/LATER: is it possible to have a template here?
3765 m_pData->m_pObjectShell->SetupStorage( xStorage, nVersion, false );
3767 // BaseURL is part of the ItemSet
3768 SfxMedium aMedium( xStorage, OUString(), xSet );
3769 aMedium.CanDisposeStorage_Impl( false );
3770 if ( aMedium.GetFilter() )
3772 // storing without a valid filter will often crash
3773 bSuccess = m_pData->m_pObjectShell->DoSaveObjectAs( aMedium, true );
3774 m_pData->m_pObjectShell->DoSaveCompleted();
3778 ErrCode nError = m_pData->m_pObjectShell->GetErrorCode();
3779 m_pData->m_pObjectShell->ResetError();
3781 // the warnings are currently not transported
3782 if ( !bSuccess )
3784 nError = nError ? nError : ERRCODE_IO_GENERAL;
3785 throw task::ErrorCodeIOException(
3786 "SfxBaseModel::storeToStorage: " + nError.toHexString(),
3787 Reference< XInterface >(), sal_uInt32(nError));
3791 void SAL_CALL SfxBaseModel::switchToStorage( const Reference< embed::XStorage >& xStorage )
3793 SfxModelGuard aGuard( *this );
3795 if ( !m_pData->m_pObjectShell.is() )
3796 throw io::IOException(); // TODO:
3798 // the persistence should be switched only if the storage is different
3799 if ( xStorage != m_pData->m_pObjectShell->GetStorage() )
3801 if ( !m_pData->m_pObjectShell->SwitchPersistance( xStorage ) )
3803 ErrCode nError = m_pData->m_pObjectShell->GetErrorCode();
3804 nError = nError ? nError : ERRCODE_IO_GENERAL;
3805 throw task::ErrorCodeIOException(
3806 "SfxBaseModel::switchToStorage: " + nError.toHexString(),
3807 Reference< XInterface >(), sal_uInt32(nError));
3809 else
3811 // UICfgMgr has a reference to the old storage, update it
3812 getUIConfigurationManager2()->setStorage( xStorage );
3815 m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
3818 Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentStorage()
3820 SfxModelGuard aGuard( *this );
3822 if ( !m_pData->m_pObjectShell.is() )
3823 throw io::IOException(); // TODO
3825 return m_pData->m_pObjectShell->GetStorage();
3828 void SAL_CALL SfxBaseModel::addStorageChangeListener(
3829 const Reference< document::XStorageChangeListener >& xListener )
3831 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3833 m_pData->m_aInterfaceContainer.addInterface(
3834 cppu::UnoType<document::XStorageChangeListener>::get(), xListener );
3837 void SAL_CALL SfxBaseModel::removeStorageChangeListener(
3838 const Reference< document::XStorageChangeListener >& xListener )
3840 SfxModelGuard aGuard( *this );
3842 m_pData->m_aInterfaceContainer.removeInterface(
3843 cppu::UnoType<document::XStorageChangeListener>::get(), xListener );
3846 void SfxBaseModel::impl_getPrintHelper()
3848 if ( m_pData->m_xPrintable.is() )
3849 return;
3850 m_pData->m_xPrintable = new SfxPrintHelper();
3851 Reference < lang::XInitialization > xInit( m_pData->m_xPrintable, UNO_QUERY );
3852 Sequence < Any > aValues(1);
3853 aValues[0] <<= Reference < frame::XModel > (static_cast< frame::XModel* >(this), UNO_QUERY );
3854 xInit->initialize( aValues );
3855 Reference < view::XPrintJobBroadcaster > xBrd( m_pData->m_xPrintable, UNO_QUERY );
3856 xBrd->addPrintJobListener( new SfxPrintHelperListener_Impl( m_pData.get() ) );
3860 // css.frame.XModule
3861 void SAL_CALL SfxBaseModel::setIdentifier(const OUString& Identifier)
3863 SfxModelGuard aGuard( *this );
3864 m_pData->m_sModuleIdentifier = Identifier;
3868 // css.frame.XModule
3869 OUString SAL_CALL SfxBaseModel::getIdentifier()
3871 SfxModelGuard aGuard( *this );
3872 if (!m_pData->m_sModuleIdentifier.isEmpty())
3873 return m_pData->m_sModuleIdentifier;
3874 if (m_pData->m_pObjectShell.is())
3875 return m_pData->m_pObjectShell->GetFactory().GetDocumentServiceName();
3876 return OUString();
3880 Reference< frame::XTitle > SfxBaseModel::impl_getTitleHelper ()
3882 SfxModelGuard aGuard( *this );
3884 if ( ! m_pData->m_xTitleHelper.is ())
3886 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
3887 Reference< frame::XUntitledNumbers > xDesktop( frame::Desktop::create(xContext), UNO_QUERY_THROW);
3888 Reference< frame::XModel > xThis (static_cast< frame::XModel* >(this), UNO_QUERY_THROW);
3890 ::framework::TitleHelper* pHelper = new ::framework::TitleHelper(xContext);
3891 m_pData->m_xTitleHelper.set(static_cast< ::cppu::OWeakObject* >(pHelper), UNO_QUERY_THROW);
3892 pHelper->setOwner (xThis );
3893 pHelper->connectWithUntitledNumbers (xDesktop);
3896 return m_pData->m_xTitleHelper;
3900 Reference< frame::XUntitledNumbers > SfxBaseModel::impl_getUntitledHelper ()
3902 SfxModelGuard aGuard( *this );
3904 if ( ! m_pData->m_xNumberedControllers.is ())
3906 Reference< frame::XModel > xThis (static_cast< frame::XModel* >(this), UNO_QUERY_THROW);
3907 ::comphelper::NumberedCollection* pHelper = new ::comphelper::NumberedCollection();
3909 m_pData->m_xNumberedControllers.set(static_cast< ::cppu::OWeakObject* >(pHelper), UNO_QUERY_THROW);
3911 pHelper->setOwner (xThis);
3912 pHelper->setUntitledPrefix (" : ");
3915 return m_pData->m_xNumberedControllers;
3919 // css.frame.XTitle
3920 OUString SAL_CALL SfxBaseModel::getTitle()
3922 // SYNCHRONIZED ->
3923 SfxModelGuard aGuard( *this );
3925 OUString aResult = impl_getTitleHelper()->getTitle ();
3926 if ( !m_pData->m_bExternalTitle && m_pData->m_pObjectShell )
3928 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
3929 if ( pMedium )
3931 try {
3932 ::ucbhelper::Content aContent( pMedium->GetName(),
3933 utl::UCBContentHelper::getDefaultCommandEnvironment(),
3934 comphelper::getProcessComponentContext() );
3935 const Reference < beans::XPropertySetInfo > xProps
3936 = aContent.getProperties();
3937 if ( xProps.is() )
3939 const OUString aServerTitle( "TitleOnServer" );
3940 if ( xProps->hasPropertyByName( aServerTitle ) )
3942 Any aAny = aContent.getPropertyValue( aServerTitle );
3943 aAny >>= aResult;
3947 catch (const ucb::ContentCreationException &)
3950 catch (const ucb::CommandAbortedException &)
3953 const SfxBoolItem* pRepairedDocItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_REPAIRPACKAGE, false);
3954 if ( pRepairedDocItem && pRepairedDocItem->GetValue() )
3955 aResult += SfxResId(STR_REPAIREDDOCUMENT);
3958 if ( m_pData->m_pObjectShell->IsReadOnlyUI() || (pMedium && pMedium->IsReadOnly()) )
3959 aResult += SfxResId(STR_READONLY);
3960 else if ( m_pData->m_pObjectShell->IsDocShared() )
3961 aResult += SfxResId(STR_SHARED);
3963 if ( m_pData->m_pObjectShell->GetDocumentSignatureState() == SignatureState::OK )
3964 aResult += SfxResId(RID_XMLSEC_DOCUMENTSIGNED);
3967 return aResult;
3971 // css.frame.XTitle
3972 void SAL_CALL SfxBaseModel::setTitle( const OUString& sTitle )
3974 // SYNCHRONIZED ->
3975 SfxModelGuard aGuard( *this );
3977 impl_getTitleHelper()->setTitle (sTitle);
3978 m_pData->m_bExternalTitle = true;
3982 // css.frame.XTitleChangeBroadcaster
3983 void SAL_CALL SfxBaseModel::addTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
3985 // SYNCHRONIZED ->
3986 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3988 Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
3989 if (xBroadcaster.is ())
3990 xBroadcaster->addTitleChangeListener (xListener);
3994 // css.frame.XTitleChangeBroadcaster
3995 void SAL_CALL SfxBaseModel::removeTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
3997 // SYNCHRONIZED ->
3998 SfxModelGuard aGuard( *this );
4000 Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
4001 if (xBroadcaster.is ())
4002 xBroadcaster->removeTitleChangeListener (xListener);
4006 // css.frame.XUntitledNumbers
4007 ::sal_Int32 SAL_CALL SfxBaseModel::leaseNumber( const Reference< XInterface >& xComponent )
4009 SfxModelGuard aGuard( *this );
4011 return impl_getUntitledHelper ()->leaseNumber (xComponent);
4015 // css.frame.XUntitledNumbers
4016 void SAL_CALL SfxBaseModel::releaseNumber( ::sal_Int32 nNumber )
4018 SfxModelGuard aGuard( *this );
4019 impl_getUntitledHelper ()->releaseNumber (nNumber);
4023 // css.frame.XUntitledNumbers
4024 void SAL_CALL SfxBaseModel::releaseNumberForComponent( const Reference< XInterface >& xComponent )
4026 SfxModelGuard aGuard( *this );
4027 impl_getUntitledHelper ()->releaseNumberForComponent (xComponent);
4031 // css.frame.XUntitledNumbers
4032 OUString SAL_CALL SfxBaseModel::getUntitledPrefix()
4034 SfxModelGuard aGuard( *this );
4035 return impl_getUntitledHelper ()->getUntitledPrefix ();
4039 // frame::XModel2
4040 Reference< container::XEnumeration > SAL_CALL SfxBaseModel::getControllers()
4042 SfxModelGuard aGuard( *this );
4044 sal_Int32 c = m_pData->m_seqControllers.size();
4045 sal_Int32 i = 0;
4046 Sequence< Any > lEnum(c);
4047 for (i=0; i<c; ++i)
4048 lEnum[i] <<= m_pData->m_seqControllers[i];
4050 ::comphelper::OAnyEnumeration* pEnum = new ::comphelper::OAnyEnumeration(lEnum);
4051 Reference< container::XEnumeration > xEnum(static_cast< container::XEnumeration* >(pEnum), UNO_QUERY_THROW);
4052 return xEnum;
4056 // frame::XModel2
4057 Sequence< OUString > SAL_CALL SfxBaseModel::getAvailableViewControllerNames()
4059 SfxModelGuard aGuard( *this );
4061 const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
4062 const sal_Int16 nViewFactoryCount = rDocumentFactory.GetViewFactoryCount();
4064 Sequence< OUString > aViewNames( nViewFactoryCount );
4065 for ( sal_Int16 nViewNo = 0; nViewNo < nViewFactoryCount; ++nViewNo )
4066 aViewNames[nViewNo] = rDocumentFactory.GetViewFactory( nViewNo ).GetAPIViewName();
4067 return aViewNames;
4071 // frame::XModel2
4072 Reference< frame::XController2 > SAL_CALL SfxBaseModel::createDefaultViewController( const Reference< frame::XFrame >& i_rFrame )
4074 SfxModelGuard aGuard( *this );
4076 const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
4077 const OUString sDefaultViewName = rDocumentFactory.GetViewFactory().GetAPIViewName();
4079 aGuard.clear();
4081 return createViewController( sDefaultViewName, Sequence< PropertyValue >(), i_rFrame );
4085 namespace sfx::intern {
4087 /** a class which, in its dtor, cleans up various objects (well, at the moment only the frame) collected during
4088 the creation of a document view, unless the creation was successful.
4090 class ViewCreationGuard
4092 public:
4093 ViewCreationGuard()
4094 :m_bSuccess( false )
4098 ~ViewCreationGuard()
4100 if ( !m_bSuccess && m_aWeakFrame && !m_aWeakFrame->GetCurrentDocument() )
4102 m_aWeakFrame->SetFrameInterface_Impl( nullptr );
4103 m_aWeakFrame->DoClose();
4107 void takeFrameOwnership( SfxFrame* i_pFrame )
4109 OSL_PRECOND( !m_aWeakFrame, "ViewCreationGuard::takeFrameOwnership: already have a frame!" );
4110 OSL_PRECOND( i_pFrame != nullptr, "ViewCreationGuard::takeFrameOwnership: invalid frame!" );
4111 m_aWeakFrame = i_pFrame;
4114 void releaseAll()
4116 m_bSuccess = true;
4119 private:
4120 bool m_bSuccess;
4121 SfxFrameWeakRef m_aWeakFrame;
4126 SfxViewFrame* SfxBaseModel::FindOrCreateViewFrame_Impl( const Reference< XFrame >& i_rFrame, ::sfx::intern::ViewCreationGuard& i_rGuard ) const
4128 SfxViewFrame* pViewFrame = nullptr;
4129 for ( pViewFrame = SfxViewFrame::GetFirst( GetObjectShell(), false );
4130 pViewFrame;
4131 pViewFrame= SfxViewFrame::GetNext( *pViewFrame, GetObjectShell(), false )
4134 if ( pViewFrame->GetFrame().GetFrameInterface() == i_rFrame )
4135 break;
4137 if ( !pViewFrame )
4139 #if OSL_DEBUG_LEVEL > 0
4140 for ( SfxFrame* pCheckFrame = SfxFrame::GetFirst();
4141 pCheckFrame;
4142 pCheckFrame = SfxFrame::GetNext( *pCheckFrame )
4145 if ( pCheckFrame->GetFrameInterface() == i_rFrame )
4147 if ( ( pCheckFrame->GetCurrentViewFrame() != nullptr )
4148 || ( pCheckFrame->GetCurrentDocument() != nullptr )
4150 // Note that it is perfectly legitimate that during loading into an XFrame which already contains
4151 // a document, there exist two SfxFrame instances bound to this XFrame - the old one, which will be
4152 // destroyed later, and the new one, which we're going to create
4153 continue;
4155 OSL_FAIL( "SfxBaseModel::FindOrCreateViewFrame_Impl: there already is an SfxFrame for the given XFrame, but no view in it!" );
4156 // nowadays, we're the only instance allowed to create an SfxFrame for an XFrame, so this case here should not happen
4157 break;
4160 #endif
4162 SfxFrame* pTargetFrame = SfxFrame::Create( i_rFrame );
4163 ENSURE_OR_THROW( pTargetFrame, "could not create an SfxFrame" );
4164 i_rGuard.takeFrameOwnership( pTargetFrame );
4166 // prepare it
4167 pTargetFrame->PrepareForDoc_Impl( *GetObjectShell() );
4169 // create view frame
4170 pViewFrame = new SfxViewFrame( *pTargetFrame, GetObjectShell() );
4172 return pViewFrame;
4176 // frame::XModel2
4177 Reference< frame::XController2 > SAL_CALL SfxBaseModel::createViewController(
4178 const OUString& i_rViewName, const Sequence< PropertyValue >& i_rArguments, const Reference< XFrame >& i_rFrame )
4180 SfxModelGuard aGuard( *this );
4182 if ( !i_rFrame.is() )
4183 throw lang::IllegalArgumentException( OUString(), *this, 3 );
4185 // find the proper SFX view factory
4186 SfxViewFactory* pViewFactory = GetObjectShell()->GetFactory().GetViewFactoryByViewName( i_rViewName );
4187 if ( !pViewFactory )
4188 throw IllegalArgumentException( OUString(), *this, 1 );
4190 // determine previous shell (used in some special cases)
4191 Reference< XController > xPreviousController( i_rFrame->getController() );
4192 const Reference< XModel > xMe( this );
4193 if ( ( xPreviousController.is() )
4194 && ( xMe != xPreviousController->getModel() )
4197 xPreviousController.clear();
4199 SfxViewShell* pOldViewShell = SfxViewShell::Get( xPreviousController );
4200 OSL_ENSURE( !xPreviousController.is() || ( pOldViewShell != nullptr ),
4201 "SfxBaseModel::createViewController: invalid old controller!" );
4203 // a guard which will clean up in case of failure
4204 ::sfx::intern::ViewCreationGuard aViewCreationGuard;
4206 // determine the ViewFrame belonging to the given XFrame
4207 SfxViewFrame* pViewFrame = FindOrCreateViewFrame_Impl( i_rFrame, aViewCreationGuard );
4208 SAL_WARN_IF( !pViewFrame , "sfx.doc", "SfxBaseModel::createViewController: no frame?" );
4210 // delegate to SFX' view factory
4211 pViewFrame->GetBindings().ENTERREGISTRATIONS();
4212 SfxViewShell* pViewShell = pViewFactory->CreateInstance( pViewFrame, pOldViewShell );
4213 pViewFrame->GetBindings().LEAVEREGISTRATIONS();
4214 ENSURE_OR_THROW( pViewShell, "invalid view shell provided by factory" );
4216 // by setting the ViewShell it is prevented that disposing the Controller will destroy this ViewFrame also
4217 pViewFrame->GetDispatcher()->SetDisableFlags( SfxDisableFlags::NONE );
4218 pViewFrame->SetViewShell_Impl( pViewShell );
4220 // remember ViewID
4221 pViewFrame->SetCurViewId_Impl( pViewFactory->GetOrdinal() );
4223 // ensure a default controller, if the view shell did not provide an own implementation
4224 if ( !pViewShell->GetController().is() )
4225 pViewShell->SetController( new SfxBaseController( pViewShell ) );
4227 // pass the creation arguments to the controller
4228 SfxBaseController* pBaseController = pViewShell->GetBaseController_Impl();
4229 ENSURE_OR_THROW( pBaseController, "invalid controller implementation!" );
4230 pBaseController->SetCreationArguments_Impl( i_rArguments );
4232 // some initial view settings, coming from our most recent attachResource call
4233 ::comphelper::NamedValueCollection aDocumentLoadArgs( getArgs() );
4234 if ( aDocumentLoadArgs.getOrDefault( "ViewOnly", false ) )
4235 pViewFrame->GetFrame().SetMenuBarOn_Impl( false );
4237 const sal_Int16 nPluginMode = aDocumentLoadArgs.getOrDefault( "PluginMode", sal_Int16( 0 ) );
4238 if ( nPluginMode == 1 )
4240 pViewFrame->ForceOuterResize_Impl();
4241 pViewFrame->GetBindings().HidePopups();
4243 SfxFrame& rFrame = pViewFrame->GetFrame();
4244 // MBA: layoutmanager of inplace frame starts locked and invisible
4245 rFrame.GetWorkWindow_Impl()->MakeVisible_Impl( false );
4246 rFrame.GetWorkWindow_Impl()->Lock_Impl( true );
4248 rFrame.GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
4249 pViewFrame->GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
4252 // tell the guard we were successful
4253 aViewCreationGuard.releaseAll();
4255 // outta here
4256 return pBaseController;
4260 // RDF DocumentMetadataAccess
4262 // rdf::XRepositorySupplier:
4263 Reference< rdf::XRepository > SAL_CALL
4264 SfxBaseModel::getRDFRepository()
4266 SfxModelGuard aGuard( *this );
4268 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4269 if (!xDMA.is()) {
4270 throw RuntimeException( "model has no document metadata", *this );
4273 return xDMA->getRDFRepository();
4276 // rdf::XNode:
4277 OUString SAL_CALL
4278 SfxBaseModel::getStringValue()
4280 SfxModelGuard aGuard( *this );
4282 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4283 if (!xDMA.is()) {
4284 throw RuntimeException( "model has no document metadata", *this );
4287 return xDMA->getStringValue();
4290 // rdf::XURI:
4291 OUString SAL_CALL
4292 SfxBaseModel::getNamespace()
4294 SfxModelGuard aGuard( *this );
4296 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4297 if (!xDMA.is()) {
4298 throw RuntimeException( "model has no document metadata", *this );
4301 return xDMA->getNamespace();
4304 OUString SAL_CALL
4305 SfxBaseModel::getLocalName()
4307 SfxModelGuard aGuard( *this );
4309 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4310 if (!xDMA.is()) {
4311 throw RuntimeException( "model has no document metadata", *this );
4314 return xDMA->getLocalName();
4317 // rdf::XDocumentMetadataAccess:
4318 Reference< rdf::XMetadatable > SAL_CALL
4319 SfxBaseModel::getElementByMetadataReference(
4320 const beans::StringPair & i_rReference)
4322 SfxModelGuard aGuard( *this );
4324 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4325 if (!xDMA.is()) {
4326 throw RuntimeException( "model has no document metadata", *this );
4329 return xDMA->getElementByMetadataReference(i_rReference);
4332 Reference< rdf::XMetadatable > SAL_CALL
4333 SfxBaseModel::getElementByURI(const Reference< rdf::XURI > & i_xURI)
4335 SfxModelGuard aGuard( *this );
4337 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4338 if (!xDMA.is()) {
4339 throw RuntimeException( "model has no document metadata", *this );
4342 return xDMA->getElementByURI(i_xURI);
4345 Sequence< Reference< rdf::XURI > > SAL_CALL
4346 SfxBaseModel::getMetadataGraphsWithType(
4347 const Reference<rdf::XURI> & i_xType)
4349 SfxModelGuard aGuard( *this );
4351 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4352 if (!xDMA.is()) {
4353 throw RuntimeException( "model has no document metadata", *this );
4356 return xDMA->getMetadataGraphsWithType(i_xType);
4359 Reference<rdf::XURI> SAL_CALL
4360 SfxBaseModel::addMetadataFile(const OUString & i_rFileName,
4361 const Sequence < Reference< rdf::XURI > > & i_rTypes)
4363 SfxModelGuard aGuard( *this );
4365 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4366 if (!xDMA.is()) {
4367 throw RuntimeException( "model has no document metadata", *this );
4370 return xDMA->addMetadataFile(i_rFileName, i_rTypes);
4373 Reference<rdf::XURI> SAL_CALL
4374 SfxBaseModel::importMetadataFile(::sal_Int16 i_Format,
4375 const Reference< io::XInputStream > & i_xInStream,
4376 const OUString & i_rFileName,
4377 const Reference< rdf::XURI > & i_xBaseURI,
4378 const Sequence < Reference< rdf::XURI > > & i_rTypes)
4380 SfxModelGuard aGuard( *this );
4382 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4383 if (!xDMA.is()) {
4384 throw RuntimeException( "model has no document metadata", *this );
4387 return xDMA->importMetadataFile(i_Format,
4388 i_xInStream, i_rFileName, i_xBaseURI, i_rTypes);
4391 void SAL_CALL
4392 SfxBaseModel::removeMetadataFile(
4393 const Reference< rdf::XURI > & i_xGraphName)
4395 SfxModelGuard aGuard( *this );
4397 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4398 if (!xDMA.is()) {
4399 throw RuntimeException( "model has no document metadata", *this );
4402 return xDMA->removeMetadataFile(i_xGraphName);
4405 void SAL_CALL
4406 SfxBaseModel::addContentOrStylesFile(const OUString & i_rFileName)
4408 SfxModelGuard aGuard( *this );
4410 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4411 if (!xDMA.is()) {
4412 throw RuntimeException( "model has no document metadata", *this );
4415 return xDMA->addContentOrStylesFile(i_rFileName);
4418 void SAL_CALL
4419 SfxBaseModel::removeContentOrStylesFile(const OUString & i_rFileName)
4421 SfxModelGuard aGuard( *this );
4423 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4424 if (!xDMA.is()) {
4425 throw RuntimeException( "model has no document metadata", *this );
4428 return xDMA->removeContentOrStylesFile(i_rFileName);
4431 void SAL_CALL
4432 SfxBaseModel::loadMetadataFromStorage(
4433 Reference< embed::XStorage > const & i_xStorage,
4434 Reference<rdf::XURI> const & i_xBaseURI,
4435 Reference<task::XInteractionHandler> const & i_xHandler)
4437 SfxModelGuard aGuard( *this );
4439 const Reference<rdf::XDocumentMetadataAccess> xDMA(
4440 m_pData->CreateDMAUninitialized());
4441 if (!xDMA.is()) {
4442 throw RuntimeException( "model has no document metadata", *this );
4445 try {
4446 xDMA->loadMetadataFromStorage(i_xStorage, i_xBaseURI, i_xHandler);
4447 } catch (lang::IllegalArgumentException &) {
4448 throw; // not initialized
4449 } catch (Exception &) {
4450 // UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
4451 m_pData->m_xDocumentMetadata = xDMA;
4452 throw;
4454 m_pData->m_xDocumentMetadata = xDMA;
4458 void SAL_CALL
4459 SfxBaseModel::storeMetadataToStorage(
4460 Reference< embed::XStorage > const & i_xStorage)
4462 SfxModelGuard aGuard( *this );
4464 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4465 if (!xDMA.is()) {
4466 throw RuntimeException( "model has no document metadata", *this );
4469 return xDMA->storeMetadataToStorage(i_xStorage);
4472 void SAL_CALL
4473 SfxBaseModel::loadMetadataFromMedium(
4474 const Sequence< beans::PropertyValue > & i_rMedium)
4476 SfxModelGuard aGuard( *this );
4478 const Reference<rdf::XDocumentMetadataAccess> xDMA(
4479 m_pData->CreateDMAUninitialized());
4480 if (!xDMA.is()) {
4481 throw RuntimeException( "model has no document metadata", *this );
4484 try {
4485 xDMA->loadMetadataFromMedium(i_rMedium);
4486 } catch (lang::IllegalArgumentException &) {
4487 throw; // not initialized
4488 } catch (Exception &) {
4489 // UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
4490 m_pData->m_xDocumentMetadata = xDMA;
4491 throw;
4493 m_pData->m_xDocumentMetadata = xDMA;
4496 void SAL_CALL
4497 SfxBaseModel::storeMetadataToMedium(
4498 const Sequence< beans::PropertyValue > & i_rMedium)
4500 SfxModelGuard aGuard( *this );
4502 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4503 if (!xDMA.is()) {
4504 throw RuntimeException( "model has no document metadata", *this );
4507 return xDMA->storeMetadataToMedium(i_rMedium);
4511 // = SfxModelSubComponent
4514 SfxModelSubComponent::~SfxModelSubComponent()
4518 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */