LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / doc / sfxbasemodel.cxx
blob44cd4216bece2c5c3d37d9ade55672f1364bd110
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 <sal/config.h>
22 #include <algorithm>
23 #include <memory>
24 #include <config_features.h>
26 #include <sfx2/sfxbasemodel.hxx>
28 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
29 #include <com/sun/star/task/XInteractionHandler.hpp>
30 #include <com/sun/star/task/ErrorCodeIOException.hpp>
31 #include <com/sun/star/task/ErrorCodeRequest.hpp>
32 #include <com/sun/star/view/XSelectionSupplier.hpp>
33 #include <com/sun/star/view/XPrintJobListener.hpp>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/lang/IllegalArgumentException.hpp>
36 #include <com/sun/star/lang/NoSupportException.hpp>
37 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
38 #include <com/sun/star/lang/NotInitializedException.hpp>
39 #include <com/sun/star/frame/Desktop.hpp>
40 #include <com/sun/star/frame/IllegalArgumentIOException.hpp>
41 #include <com/sun/star/frame/XUntitledNumbers.hpp>
42 #include <com/sun/star/frame/DoubleInitializationException.hpp>
43 #include <com/sun/star/embed/XStorage.hpp>
44 #include <com/sun/star/document/XStorageChangeListener.hpp>
45 #include <com/sun/star/document/IndexedPropertyValues.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/beans/XPropertySetInfo.hpp>
48 #include <com/sun/star/container/XIndexContainer.hpp>
49 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
50 #include <com/sun/star/script/provider/XScriptProvider.hpp>
51 #include <com/sun/star/ui/UIConfigurationManager.hpp>
52 #include <com/sun/star/embed/ElementModes.hpp>
53 #include <com/sun/star/embed/Aspects.hpp>
54 #include <com/sun/star/document/DocumentProperties.hpp>
55 #include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
56 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
57 #include <com/sun/star/ucb/ContentCreationException.hpp>
58 #include <com/sun/star/ucb/CommandAbortedException.hpp>
59 #include <com/sun/star/util/XCloneable.hpp>
60 #include <com/sun/star/util/InvalidStateException.hpp>
61 #include <com/sun/star/util/CloseVetoException.hpp>
62 #include <comphelper/enumhelper.hxx>
64 #include <cppuhelper/implbase.hxx>
65 #include <comphelper/multicontainer2.hxx>
66 #include <cppuhelper/exc_hlp.hxx>
67 #include <comphelper/processfactory.hxx>
68 #include <comphelper/propertyvalue.hxx>
69 #include <comphelper/sequenceashashmap.hxx>
70 #include <comphelper/namedvaluecollection.hxx>
71 #include <o3tl/safeint.hxx>
72 #include <svl/itemset.hxx>
73 #include <svl/stritem.hxx>
74 #include <svl/eitem.hxx>
75 #include <svl/grabbagitem.hxx>
76 #include <tools/urlobj.hxx>
77 #include <tools/debug.hxx>
78 #include <tools/diagnose_ex.h>
79 #include <tools/svborder.hxx>
80 #include <unotools/tempfile.hxx>
81 #include <osl/mutex.hxx>
82 #include <vcl/errcode.hxx>
83 #include <vcl/filter/SvmWriter.hxx>
84 #include <vcl/salctype.hxx>
85 #include <vcl/gdimtf.hxx>
86 #include <comphelper/fileformat.h>
87 #include <comphelper/servicehelper.hxx>
88 #include <comphelper/storagehelper.hxx>
89 #include <toolkit/helper/vclunohelper.hxx>
90 #include <vcl/transfer.hxx>
91 #include <svtools/ehdl.hxx>
92 #include <svtools/sfxecode.hxx>
93 #include <sal/log.hxx>
94 #include <framework/configimporter.hxx>
95 #include <framework/titlehelper.hxx>
96 #include <comphelper/numberedcollection.hxx>
97 #include <unotools/ucbhelper.hxx>
98 #include <ucbhelper/content.hxx>
100 #include <sfx2/sfxbasecontroller.hxx>
101 #include <sfx2/viewfac.hxx>
102 #include <workwin.hxx>
103 #include <sfx2/signaturestate.hxx>
104 #include <sfx2/sfxuno.hxx>
105 #include <objshimp.hxx>
106 #include <sfx2/viewfrm.hxx>
107 #include <sfx2/viewsh.hxx>
108 #include <sfx2/docfile.hxx>
109 #include <sfx2/docfilt.hxx>
110 #include <sfx2/dispatch.hxx>
111 #include <sfx2/module.hxx>
112 #include <basic/basmgr.hxx>
113 #include <sfx2/event.hxx>
114 #include <eventsupplier.hxx>
115 #include <sfx2/sfxsids.hrc>
116 #include <sfx2/strings.hrc>
117 #include <sfx2/app.hxx>
118 #include <sfx2/docfac.hxx>
119 #include <sfx2/fcontnr.hxx>
120 #include <sfx2/docstoragemodifylistener.hxx>
121 #include <sfx2/brokenpackageint.hxx>
122 #include "graphhelp.hxx"
123 #include <docundomanager.hxx>
124 #include <openurlhint.hxx>
125 #include <sfx2/msgpool.hxx>
126 #include <sfx2/DocumentMetadataAccess.hxx>
127 #include "printhelper.hxx"
128 #include <sfx2/sfxresid.hxx>
129 #include <comphelper/profilezone.hxx>
130 #include <vcl/threadex.hxx>
131 #include <unotools/mediadescriptor.hxx>
133 // namespaces
136 using namespace ::com::sun::star;
137 using namespace ::com::sun::star::uno;
138 using ::com::sun::star::beans::PropertyValue;
139 using ::com::sun::star::document::CmisProperty;
140 using ::com::sun::star::frame::XFrame;
141 using ::com::sun::star::frame::XController;
142 using ::com::sun::star::frame::XController2;
143 using ::com::sun::star::lang::IllegalArgumentException;
144 using ::com::sun::star::io::IOException;
145 using ::com::sun::star::uno::Sequence;
146 using ::com::sun::star::document::XDocumentRecovery;
147 using ::com::sun::star::document::XUndoManager;
148 using ::com::sun::star::document::XUndoAction;
149 using ::com::sun::star::frame::XModel;
151 namespace {
153 /** This Listener is used to get notified when the XDocumentProperties of the
154 XModel change.
156 class SfxDocInfoListener_Impl : public ::cppu::WeakImplHelper<
157 util::XModifyListener >
160 public:
161 SfxObjectShell& m_rShell;
163 explicit SfxDocInfoListener_Impl( SfxObjectShell& i_rDoc )
164 : m_rShell(i_rDoc)
165 { };
167 virtual void SAL_CALL disposing( const lang::EventObject& ) override;
168 virtual void SAL_CALL modified( const lang::EventObject& ) override;
173 void SAL_CALL SfxDocInfoListener_Impl::modified( const lang::EventObject& )
175 SolarMutexGuard aSolarGuard;
177 // notify changes to the SfxObjectShell
178 m_rShell.FlushDocInfo();
181 void SAL_CALL SfxDocInfoListener_Impl::disposing( const lang::EventObject& )
186 // impl. declarations
189 struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument
191 // counter for SfxBaseModel instances created.
192 static sal_Int64 g_nInstanceCounter ;
193 SfxObjectShellRef m_pObjectShell ;
194 OUString m_sURL ;
195 OUString m_sRuntimeUID ;
196 OUString m_aPreusedFilterName ;
197 comphelper::OMultiTypeInterfaceContainerHelper2 m_aInterfaceContainer ;
198 std::unordered_map<css::uno::Reference< css::drawing::XShape >,
199 std::vector<css::uno::Reference< css::document::XShapeEventListener >>> maShapeListeners;
200 Reference< XInterface > m_xParent ;
201 Reference< frame::XController > m_xCurrent ;
202 Reference< document::XDocumentProperties > m_xDocumentProperties ;
203 Reference< script::XStarBasicAccess > m_xStarBasicAccess ;
204 Reference< container::XNameReplace > m_xEvents ;
205 Sequence< beans::PropertyValue> m_seqArguments ;
206 std::vector< Reference< frame::XController > > m_seqControllers ;
207 Reference< container::XIndexAccess > m_contViewData ;
208 sal_uInt16 m_nControllerLockCount ;
209 bool m_bClosed ;
210 bool m_bClosing ;
211 bool m_bSaving ;
212 bool m_bSuicide ;
213 bool m_bExternalTitle ;
214 bool m_bModifiedSinceLastSave ;
215 Reference< view::XPrintable> m_xPrintable ;
216 Reference< ui::XUIConfigurationManager2 > m_xUIConfigurationManager;
217 ::rtl::Reference< ::sfx2::DocumentStorageModifyListener > m_pStorageModifyListen ;
218 OUString m_sModuleIdentifier ;
219 Reference< frame::XTitle > m_xTitleHelper ;
220 Reference< frame::XUntitledNumbers > m_xNumberedControllers ;
221 Reference< rdf::XDocumentMetadataAccess> m_xDocumentMetadata ;
222 ::rtl::Reference< ::sfx2::DocumentUndoManager > m_pDocumentUndoManager ;
223 Sequence< document::CmisProperty> m_cmisProperties ;
224 std::shared_ptr<SfxGrabBagItem> m_xGrabBagItem ;
226 IMPL_SfxBaseModel_DataContainer( ::osl::Mutex& rMutex, SfxObjectShell* pObjectShell )
227 : m_pObjectShell ( pObjectShell )
228 , m_aInterfaceContainer ( rMutex )
229 , m_nControllerLockCount ( 0 )
230 , m_bClosed ( false )
231 , m_bClosing ( false )
232 , m_bSaving ( false )
233 , m_bSuicide ( false )
234 , m_bExternalTitle ( false )
235 , m_bModifiedSinceLastSave( false )
237 // increase global instance counter.
238 ++g_nInstanceCounter;
239 // set own Runtime UID
240 m_sRuntimeUID = OUString::number( g_nInstanceCounter );
243 virtual ~IMPL_SfxBaseModel_DataContainer()
247 // ::sfx2::IModifiableDocument
248 virtual void storageIsModified() override
250 if ( m_pObjectShell.is() && !m_pObjectShell->IsModified() )
251 m_pObjectShell->SetModified();
254 void impl_setDocumentProperties(
255 const Reference< document::XDocumentProperties >& );
257 Reference<rdf::XDocumentMetadataAccess> GetDMA()
259 if (!m_xDocumentMetadata.is())
261 OSL_ENSURE(m_pObjectShell.is(), "GetDMA: no object shell?");
262 if (!m_pObjectShell.is())
264 return nullptr;
267 const Reference<XComponentContext> xContext(
268 ::comphelper::getProcessComponentContext());
269 const Reference<frame::XModel> xModel(
270 m_pObjectShell->GetModel());
271 const Reference<lang::XMultiComponentFactory> xMsf(
272 xContext->getServiceManager());
273 const Reference<frame::
274 XTransientDocumentsDocumentContentFactory> xTDDCF(
275 xMsf->createInstanceWithContext(
276 "com.sun.star.frame.TransientDocumentsDocumentContentFactory",
277 xContext),
278 UNO_QUERY_THROW);
279 const Reference<ucb::XContent> xContent(
280 xTDDCF->createDocumentContent(xModel) );
281 OSL_ENSURE(xContent.is(), "GetDMA: cannot create DocumentContent");
282 if (!xContent.is())
284 return nullptr;
286 OUString uri = xContent->getIdentifier()->getContentIdentifier();
287 OSL_ENSURE(!uri.isEmpty(), "GetDMA: empty uri?");
288 if (!uri.isEmpty() && !uri.endsWith("/"))
290 uri += "/";
293 m_xDocumentMetadata = new ::sfx2::DocumentMetadataAccess(
294 xContext, *m_pObjectShell, uri);
296 return m_xDocumentMetadata;
299 Reference<rdf::XDocumentMetadataAccess> CreateDMAUninitialized()
301 return (m_pObjectShell.is())
302 ? new ::sfx2::DocumentMetadataAccess(
303 ::comphelper::getProcessComponentContext(), *m_pObjectShell)
304 : nullptr;
308 // static member initialization.
309 sal_Int64 IMPL_SfxBaseModel_DataContainer::g_nInstanceCounter = 0;
311 namespace {
313 // Listener that forwards notifications from the PrintHelper to the "real" listeners
314 class SfxPrintHelperListener_Impl : public ::cppu::WeakImplHelper< view::XPrintJobListener >
316 public:
317 IMPL_SfxBaseModel_DataContainer* m_pData;
318 explicit SfxPrintHelperListener_Impl( IMPL_SfxBaseModel_DataContainer* pData )
319 : m_pData( pData )
322 virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override ;
323 virtual void SAL_CALL printJobEvent( const view::PrintJobEvent& rEvent ) override;
328 void SAL_CALL SfxPrintHelperListener_Impl::disposing( const lang::EventObject& )
330 m_pData->m_xPrintable = nullptr;
333 void SAL_CALL SfxPrintHelperListener_Impl::printJobEvent( const view::PrintJobEvent& rEvent )
335 ::comphelper::OInterfaceContainerHelper2* pContainer = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<view::XPrintJobListener>::get());
336 if ( pContainer!=nullptr )
338 ::comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
339 while (pIterator.hasMoreElements())
340 static_cast<view::XPrintJobListener*>(pIterator.next())->printJobEvent( rEvent );
344 namespace {
346 // SfxOwnFramesLocker ====================================================================================
347 // allows to lock all the frames related to the provided SfxObjectShell
348 class SfxOwnFramesLocker
350 Sequence< Reference< frame::XFrame > > m_aLockedFrames;
352 static vcl::Window* GetVCLWindow( const Reference< frame::XFrame >& xFrame );
353 public:
354 explicit SfxOwnFramesLocker( SfxObjectShell const * ObjechShell );
355 ~SfxOwnFramesLocker();
360 SfxOwnFramesLocker::SfxOwnFramesLocker( SfxObjectShell const * pObjectShell )
362 if ( !pObjectShell )
363 return;
365 for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pObjectShell );
366 pFrame;
367 pFrame = SfxViewFrame::GetNext( *pFrame, pObjectShell )
370 SfxFrame& rSfxFrame = pFrame->GetFrame();
373 // get vcl window related to the frame and lock it if it is still not locked
374 const Reference< frame::XFrame >& xFrame = rSfxFrame.GetFrameInterface();
375 vcl::Window* pWindow = GetVCLWindow( xFrame );
376 if ( !pWindow )
377 throw RuntimeException();
379 if ( pWindow->IsEnabled() )
381 pWindow->Disable();
385 sal_Int32 nLen = m_aLockedFrames.getLength();
386 m_aLockedFrames.realloc( nLen + 1 );
387 m_aLockedFrames.getArray()[nLen] = xFrame;
389 catch( Exception& )
391 pWindow->Enable();
392 throw;
396 catch( Exception& )
398 OSL_FAIL( "Not possible to lock the frame window!" );
403 SfxOwnFramesLocker::~SfxOwnFramesLocker()
405 for ( auto& rFrame : asNonConstRange(m_aLockedFrames) )
409 if ( rFrame.is() )
411 // get vcl window related to the frame and unlock it
412 vcl::Window* pWindow = GetVCLWindow( rFrame );
413 if ( !pWindow )
414 throw RuntimeException();
416 pWindow->Enable();
418 rFrame.clear();
421 catch( Exception& )
423 OSL_FAIL( "Can't unlock the frame window!" );
428 vcl::Window* SfxOwnFramesLocker::GetVCLWindow( const Reference< frame::XFrame >& xFrame )
430 VclPtr<vcl::Window> pWindow;
432 if ( xFrame.is() )
434 Reference< awt::XWindow > xWindow = xFrame->getContainerWindow();
435 if ( xWindow.is() )
436 pWindow = VCLUnoHelper::GetWindow( xWindow );
439 return pWindow;
442 namespace {
444 // SfxSaveGuard ====================================================================================
445 class SfxSaveGuard
447 private:
448 Reference< frame::XModel > m_xModel;
449 IMPL_SfxBaseModel_DataContainer* m_pData;
450 std::unique_ptr<SfxOwnFramesLocker> m_pFramesLock;
452 SfxSaveGuard(SfxSaveGuard const &) = delete;
453 void operator =(const SfxSaveGuard&) = delete;
455 public:
456 SfxSaveGuard(const Reference< frame::XModel >& xModel ,
457 IMPL_SfxBaseModel_DataContainer* pData);
458 ~SfxSaveGuard();
463 SfxSaveGuard::SfxSaveGuard(const Reference< frame::XModel >& xModel ,
464 IMPL_SfxBaseModel_DataContainer* pData)
465 : m_xModel ( xModel )
466 , m_pData ( pData )
468 if ( m_pData->m_bClosed )
469 throw lang::DisposedException("Object already disposed.");
471 m_pData->m_bSaving = true;
472 m_pFramesLock.reset(new SfxOwnFramesLocker( m_pData->m_pObjectShell.get() ));
475 SfxSaveGuard::~SfxSaveGuard()
477 m_pFramesLock.reset();
479 m_pData->m_bSaving = false;
481 // m_bSuicide was set e.g. in case someone tried to close a document, while it was used for
482 // storing at the same time. Further m_bSuicide was set to sal_True only if close(sal_True) was called.
483 // So the ownership was delegated to the place where a veto exception was thrown.
484 // Now we have to call close() again and delegate the ownership to the next one, which
485 // can't accept that. Close(sal_False) can't work in this case. Because then the document will may be never closed...
487 if ( !m_pData->m_bSuicide )
488 return;
490 // Reset this state. In case the new close() request is not accepted by someone else...
491 // it's not a good idea to have two "owners" for close.-)
492 m_pData->m_bSuicide = false;
495 Reference< util::XCloseable > xClose(m_xModel, UNO_QUERY);
496 if (xClose.is())
497 xClose->close(true);
499 catch(const util::CloseVetoException&)
503 SfxBaseModel::SfxBaseModel( SfxObjectShell *pObjectShell )
504 : BaseMutex()
505 , m_pData( std::make_shared<IMPL_SfxBaseModel_DataContainer>( m_aMutex, pObjectShell ) )
506 , m_bSupportEmbeddedScripts( pObjectShell && pObjectShell->Get_Impl() && !pObjectShell->Get_Impl()->m_bNoBasicCapabilities )
507 , m_bSupportDocRecovery( pObjectShell && pObjectShell->Get_Impl() && pObjectShell->Get_Impl()->m_bDocRecoverySupport )
509 if ( pObjectShell != nullptr )
511 StartListening( *pObjectShell ) ;
515 // destructor
516 SfxBaseModel::~SfxBaseModel()
520 // XInterface
521 Any SAL_CALL SfxBaseModel::queryInterface( const uno::Type& rType )
523 if ( ( !m_bSupportEmbeddedScripts && rType.equals( cppu::UnoType<document::XEmbeddedScripts>::get() ) )
524 || ( !m_bSupportDocRecovery && rType.equals( cppu::UnoType<XDocumentRecovery>::get() ) )
526 return Any();
528 return SfxBaseModel_Base::queryInterface( rType );
532 // XTypeProvider
535 namespace
537 void lcl_stripType( Sequence< uno::Type >& io_rTypes, const uno::Type& i_rTypeToStrip )
539 Sequence< uno::Type > aStrippedTypes( io_rTypes.getLength() - 1 );
540 ::std::remove_copy_if(
541 std::cbegin(io_rTypes),
542 std::cend(io_rTypes),
543 aStrippedTypes.getArray(),
544 [&i_rTypeToStrip](const uno::Type& aType) { return aType == i_rTypeToStrip; }
546 io_rTypes = aStrippedTypes;
550 Sequence< uno::Type > SAL_CALL SfxBaseModel::getTypes()
552 Sequence< uno::Type > aTypes( SfxBaseModel_Base::getTypes() );
554 if ( !m_bSupportEmbeddedScripts )
555 lcl_stripType( aTypes, cppu::UnoType<document::XEmbeddedScripts>::get() );
557 if ( !m_bSupportDocRecovery )
558 lcl_stripType( aTypes, cppu::UnoType<XDocumentRecovery>::get() );
560 return aTypes;
564 // XTypeProvider
567 Sequence< sal_Int8 > SAL_CALL SfxBaseModel::getImplementationId()
569 return css::uno::Sequence<sal_Int8>();
573 // XStarBasicAccess
575 #if HAVE_FEATURE_SCRIPTING
577 static Reference< script::XStarBasicAccess > implGetStarBasicAccess( SfxObjectShell const * pObjectShell )
579 Reference< script::XStarBasicAccess > xRet;
581 #if !HAVE_FEATURE_SCRIPTING
582 (void) pObjectShell;
583 #else
584 if( pObjectShell )
586 BasicManager* pMgr = pObjectShell->GetBasicManager();
587 xRet = getStarBasicAccess( pMgr );
589 #endif
590 return xRet;
593 #endif
595 Reference< container::XNameContainer > SAL_CALL SfxBaseModel::getLibraryContainer()
597 #if !HAVE_FEATURE_SCRIPTING
598 Reference< container::XNameContainer > dummy;
600 return dummy;
601 #else
602 SfxModelGuard aGuard( *this );
604 Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
605 if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
606 rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
608 Reference< container::XNameContainer > xRet;
609 if( rxAccess.is() )
610 xRet = rxAccess->getLibraryContainer();
611 return xRet;
612 #endif
615 /**___________________________________________________________________________________________________
616 @seealso XStarBasicAccess
618 void SAL_CALL SfxBaseModel::createLibrary( const OUString& LibName, const OUString& Password,
619 const OUString& ExternalSourceURL, const OUString& LinkTargetURL )
621 #if !HAVE_FEATURE_SCRIPTING
622 (void) LibName;
623 (void) Password;
624 (void) ExternalSourceURL;
625 (void) LinkTargetURL;
626 #else
627 SfxModelGuard aGuard( *this );
629 Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
630 if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
631 rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
633 if( rxAccess.is() )
634 rxAccess->createLibrary( LibName, Password, ExternalSourceURL, LinkTargetURL );
635 #endif
638 /**___________________________________________________________________________________________________
639 @seealso XStarBasicAccess
641 void SAL_CALL SfxBaseModel::addModule( const OUString& LibraryName, const OUString& ModuleName,
642 const OUString& Language, const OUString& Source )
644 #if !HAVE_FEATURE_SCRIPTING
645 (void) LibraryName;
646 (void) ModuleName;
647 (void) Language;
648 (void) Source;
649 #else
650 SfxModelGuard aGuard( *this );
652 Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
653 if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
654 rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
656 if( rxAccess.is() )
657 rxAccess->addModule( LibraryName, ModuleName, Language, Source );
658 #endif
661 /**___________________________________________________________________________________________________
662 @seealso XStarBasicAccess
664 void SAL_CALL SfxBaseModel::addDialog( const OUString& LibraryName, const OUString& DialogName,
665 const Sequence< sal_Int8 >& Data )
667 #if !HAVE_FEATURE_SCRIPTING
668 (void) LibraryName;
669 (void) DialogName;
670 (void) Data;
671 #else
672 SfxModelGuard aGuard( *this );
674 Reference< script::XStarBasicAccess >& rxAccess = m_pData->m_xStarBasicAccess;
675 if( !rxAccess.is() && m_pData->m_pObjectShell.is() )
676 rxAccess = implGetStarBasicAccess( m_pData->m_pObjectShell.get() );
678 if( rxAccess.is() )
679 rxAccess->addDialog( LibraryName, DialogName, Data );
680 #endif
684 // XChild
687 Reference< XInterface > SAL_CALL SfxBaseModel::getParent()
689 SfxModelGuard aGuard( *this );
691 return m_pData->m_xParent;
695 // XChild
698 void SAL_CALL SfxBaseModel::setParent(const Reference< XInterface >& Parent)
700 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
701 m_pData->m_xParent = Parent;
705 // XChild
708 void SAL_CALL SfxBaseModel::dispose()
710 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
712 if ( !m_pData->m_bClosed )
714 // gracefully accept wrong dispose calls instead of close call
715 // and try to make it work (may be really disposed later!)
718 close( true );
720 catch ( util::CloseVetoException& )
724 return;
727 if ( m_pData->m_pStorageModifyListen.is() )
729 m_pData->m_pStorageModifyListen->dispose();
730 m_pData->m_pStorageModifyListen = nullptr;
733 if ( m_pData->m_pDocumentUndoManager.is() )
735 m_pData->m_pDocumentUndoManager->disposing();
736 m_pData->m_pDocumentUndoManager = nullptr;
739 lang::EventObject aEvent( static_cast<frame::XModel *>(this) );
740 m_pData->m_aInterfaceContainer.disposeAndClear( aEvent );
742 m_pData->m_xDocumentProperties.clear();
744 m_pData->m_xDocumentMetadata.clear();
746 if ( m_pData->m_pObjectShell.is() )
748 EndListening( *m_pData->m_pObjectShell );
751 m_pData->m_xCurrent.clear();
752 m_pData->m_seqControllers.clear();
754 // m_pData member must be set to zero before delete is called to
755 // force disposed exception whenever someone tries to access our
756 // instance while in the dtor.
757 m_pData.reset();
761 // XChild
764 void SAL_CALL SfxBaseModel::addEventListener( const Reference< lang::XEventListener >& aListener )
766 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
767 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), aListener );
771 // XChild
774 void SAL_CALL SfxBaseModel::removeEventListener( const Reference< lang::XEventListener >& aListener )
776 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
777 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), aListener );
780 void
781 IMPL_SfxBaseModel_DataContainer::impl_setDocumentProperties(
782 const Reference< document::XDocumentProperties >& rxNewDocProps)
784 m_xDocumentProperties.set(rxNewDocProps, UNO_SET_THROW);
785 if (m_pObjectShell.is())
787 Reference<util::XModifyBroadcaster> const xMB(
788 m_xDocumentProperties, UNO_QUERY_THROW);
789 xMB->addModifyListener(new SfxDocInfoListener_Impl(*m_pObjectShell));
793 // document::XDocumentPropertiesSupplier:
794 Reference< document::XDocumentProperties > SAL_CALL
795 SfxBaseModel::getDocumentProperties()
797 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
798 if ( !m_pData->m_xDocumentProperties.is() )
800 Reference< document::XDocumentProperties > xDocProps(
801 document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
802 m_pData->impl_setDocumentProperties(xDocProps);
805 return m_pData->m_xDocumentProperties;
809 // lang::XEventListener
812 void SAL_CALL SfxBaseModel::disposing( const lang::EventObject& aObject )
814 SolarMutexGuard aGuard;
815 if ( impl_isDisposed() )
816 return;
818 Reference< util::XModifyListener > xMod( aObject.Source, UNO_QUERY );
819 Reference< lang::XEventListener > xListener( aObject.Source, UNO_QUERY );
820 Reference< document::XEventListener > xDocListener( aObject.Source, UNO_QUERY );
822 if ( xMod.is() )
823 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<util::XModifyListener>::get(), xMod );
824 else if ( xListener.is() )
825 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
826 else if ( xDocListener.is() )
827 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<document::XEventListener>::get(), xListener );
831 // frame::XModel
834 sal_Bool SAL_CALL SfxBaseModel::attachResource( const OUString& rURL ,
835 const Sequence< beans::PropertyValue >& rArgs )
837 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
838 if ( rURL.isEmpty() && rArgs.getLength() == 1 && rArgs[0].Name == "SetEmbedded" )
840 // allows to set a windowless document to EMBEDDED state
841 // but _only_ before load() or initNew() methods
842 if ( m_pData->m_pObjectShell.is() && !m_pData->m_pObjectShell->GetMedium() )
844 bool bEmb(false);
845 if ( ( rArgs[0].Value >>= bEmb ) && bEmb )
846 m_pData->m_pObjectShell->SetCreateMode_Impl( SfxObjectCreateMode::EMBEDDED );
849 return true;
852 if ( m_pData->m_pObjectShell.is() )
854 m_pData->m_sURL = rURL;
856 SfxObjectShell* pObjectShell = m_pData->m_pObjectShell.get();
858 ::comphelper::NamedValueCollection aArgs( rArgs );
860 Sequence< sal_Int32 > aWinExtent;
861 if ( ( aArgs.get( "WinExtent" ) >>= aWinExtent )&& ( aWinExtent.getLength() == 4 ) )
863 tools::Rectangle aVisArea( aWinExtent[0], aWinExtent[1], aWinExtent[2], aWinExtent[3] );
864 aVisArea = OutputDevice::LogicToLogic(aVisArea, MapMode(MapUnit::Map100thMM), MapMode(pObjectShell->GetMapUnit()));
865 pObjectShell->SetVisArea( aVisArea );
868 bool bBreakMacroSign = false;
869 if ( aArgs.get( "BreakMacroSignature" ) >>= bBreakMacroSign )
871 pObjectShell->BreakMacroSign_Impl( bBreakMacroSign );
874 bool bMacroEventRead = false;
875 if ((aArgs.get("MacroEventRead") >>= bMacroEventRead) && bMacroEventRead)
877 pObjectShell->SetMacroCallsSeenWhileLoading();
880 aArgs.remove( "WinExtent" );
881 aArgs.remove( "BreakMacroSignature" );
882 aArgs.remove( "MacroEventRead" );
883 aArgs.remove( "Stream" );
884 aArgs.remove( "InputStream" );
885 aArgs.remove( "URL" );
886 aArgs.remove( "Frame" );
887 aArgs.remove( "Password" );
888 aArgs.remove( "EncryptionData" );
890 // TODO/LATER: all the parameters that are accepted by ItemSet of the DocShell must be removed here
892 m_pData->m_seqArguments = aArgs.getPropertyValues();
894 SfxMedium* pMedium = pObjectShell->GetMedium();
895 if ( pMedium )
897 SfxAllItemSet aSet( pObjectShell->GetPool() );
898 TransformParameters( SID_OPENDOC, rArgs, aSet );
900 // the arguments are not allowed to reach the medium
901 aSet.ClearItem( SID_FILE_NAME );
902 aSet.ClearItem( SID_FILLFRAME );
904 pMedium->GetItemSet()->Put( aSet );
905 const SfxStringItem* pItem = aSet.GetItem<SfxStringItem>(SID_FILTER_NAME, false);
906 if ( pItem )
907 pMedium->SetFilter(
908 pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( pItem->GetValue() ) );
910 const SfxStringItem* pTitleItem = aSet.GetItem<SfxStringItem>(SID_DOCINFO_TITLE, false);
911 if ( pTitleItem )
913 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pObjectShell );
914 if ( pFrame )
915 pFrame->UpdateTitle();
920 return true ;
924 // frame::XModel
927 OUString SAL_CALL SfxBaseModel::getURL()
929 SfxModelGuard aGuard( *this );
930 return m_pData->m_sURL ;
934 // frame::XModel
936 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs()
938 return getArgs2({});
941 // frame::XModel3
943 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getArgs2(const Sequence<OUString> & requestedArgsSeq )
945 SfxModelGuard aGuard( *this );
947 if (!SfxApplication::Get()) // tdf#113755
949 SAL_WARN("sfx.appl", "Unexpected operations on model");
950 return m_pData->m_seqArguments;
953 std::set<std::u16string_view> requestedArgs;
954 for (OUString const & s : requestedArgsSeq)
955 requestedArgs.insert(s);
957 if ( m_pData->m_pObjectShell.is() )
959 Sequence< beans::PropertyValue > seqArgsNew;
960 Sequence< beans::PropertyValue > seqArgsOld;
961 SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );
963 // we need to know which properties are supported by the transformer
964 // hopefully it is a temporary solution, I guess nonconvertable properties
965 // should not be supported so then there will be only ItemSet from medium
967 TransformItems( SID_OPENDOC, *(m_pData->m_pObjectShell->GetMedium()->GetItemSet()), seqArgsNew );
968 TransformParameters( SID_OPENDOC, m_pData->m_seqArguments, aSet );
969 TransformItems( SID_OPENDOC, aSet, seqArgsOld );
971 sal_Int32 nNewLength = seqArgsNew.getLength();
973 if (requestedArgs.empty() || requestedArgs.count(u"WinExtent"))
975 // "WinExtent" property should be updated always.
976 // We can store it now to overwrite an old value
977 // since it is not from ItemSet
978 tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
979 aTmpRect = OutputDevice::LogicToLogic(aTmpRect, MapMode(m_pData->m_pObjectShell->GetMapUnit()), MapMode(MapUnit::Map100thMM));
981 Sequence< sal_Int32 > aRectSeq
983 o3tl::narrowing<int>(aTmpRect.Left()),
984 o3tl::narrowing<int>(aTmpRect.Top()),
985 o3tl::narrowing<int>(aTmpRect.IsWidthEmpty() ? aTmpRect.Left() : aTmpRect.Right()),
986 o3tl::narrowing<int>(aTmpRect.IsHeightEmpty() ? aTmpRect.Top() : aTmpRect.Bottom())
989 seqArgsNew.realloc( ++nNewLength );
990 auto pseqArgsNew = seqArgsNew.getArray();
991 pseqArgsNew[ nNewLength - 1 ].Name = "WinExtent";
992 pseqArgsNew[ nNewLength - 1 ].Value <<= aRectSeq;
995 if (requestedArgs.empty() || requestedArgs.count(u"PreusedFilterName"))
997 if ( !m_pData->m_aPreusedFilterName.isEmpty() )
999 seqArgsNew.realloc( ++nNewLength );
1000 auto pseqArgsNew = seqArgsNew.getArray();
1001 pseqArgsNew[ nNewLength - 1 ].Name = "PreusedFilterName";
1002 pseqArgsNew[ nNewLength - 1 ].Value <<= m_pData->m_aPreusedFilterName;
1006 if (requestedArgs.empty() || requestedArgs.count(u"DocumentBorder"))
1008 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
1009 if ( pFrame )
1011 SvBorder aBorder = pFrame->GetBorderPixelImpl();
1013 Sequence< sal_Int32 > aBorderSeq
1015 o3tl::narrowing<int>(aBorder.Left()),
1016 o3tl::narrowing<int>(aBorder.Top()),
1017 o3tl::narrowing<int>(aBorder.Right()),
1018 o3tl::narrowing<int>(aBorder.Bottom())
1021 seqArgsNew.realloc( ++nNewLength );
1022 auto pseqArgsNew = seqArgsNew.getArray();
1023 pseqArgsNew[ nNewLength - 1 ].Name = "DocumentBorder";
1024 pseqArgsNew[ nNewLength - 1 ].Value <<= aBorderSeq;
1028 if (requestedArgs.empty())
1030 // only the values that are not supported by the ItemSet must be cached here
1031 Sequence< beans::PropertyValue > aFinalCache;
1032 sal_Int32 nFinalLength = 0;
1034 for ( const auto& rOrg : std::as_const(m_pData->m_seqArguments) )
1036 auto bNew = std::none_of(std::cbegin(seqArgsOld), std::cend(seqArgsOld),
1037 [&rOrg](const beans::PropertyValue& rOld){ return rOld.Name == rOrg.Name; });
1038 if ( bNew )
1040 // the entity with this name should be new for seqArgsNew
1041 // since it is not supported by transformer
1043 seqArgsNew.realloc( ++nNewLength );
1044 seqArgsNew.getArray()[ nNewLength - 1 ] = rOrg;
1046 aFinalCache.realloc( ++nFinalLength );
1047 aFinalCache.getArray()[ nFinalLength - 1 ] = rOrg;
1051 m_pData->m_seqArguments = aFinalCache;
1054 return seqArgsNew;
1057 return m_pData->m_seqArguments;
1060 void SAL_CALL SfxBaseModel::setArgs(const Sequence<beans::PropertyValue>& aArgs)
1062 SfxModelGuard aGuard( *this );
1064 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
1065 if (!pMedium)
1067 throw util::InvalidStateException(
1068 "Medium could not be retrieved, unable to execute setArgs");
1071 for (const auto& rArg : aArgs)
1073 OUString sValue;
1074 bool bValue;
1075 bool ok = false;
1076 if (rArg.Name == "SuggestedSaveAsName")
1078 if (rArg.Value >>= sValue)
1080 pMedium->GetItemSet()->Put(SfxStringItem(SID_SUGGESTEDSAVEASNAME, sValue));
1081 ok = true;
1084 else if (rArg.Name == "SuggestedSaveAsDir")
1086 if (rArg.Value >>= sValue)
1088 pMedium->GetItemSet()->Put(SfxStringItem(SID_SUGGESTEDSAVEASDIR, sValue));
1089 ok = true;
1092 else if (rArg.Name == "LockContentExtraction")
1094 if (rArg.Value >>= bValue)
1096 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_CONTENT_EXTRACTION, bValue));
1097 ok = true;
1100 else if (rArg.Name == "LockExport")
1102 if (rArg.Value >>= bValue)
1104 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_EXPORT, bValue));
1105 ok = true;
1108 else if (rArg.Name == "LockPrint")
1110 if (rArg.Value >>= bValue)
1112 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_PRINT, bValue));
1113 ok = true;
1116 else if (rArg.Name == "LockSave")
1118 if (rArg.Value >>= bValue)
1120 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_SAVE, bValue));
1121 ok = true;
1124 else if (rArg.Name == "LockEditDoc")
1126 if (rArg.Value >>= bValue)
1128 pMedium->GetItemSet()->Put(SfxBoolItem(SID_LOCK_EDITDOC, bValue));
1129 ok = true;
1132 else if (rArg.Name == "Replaceable")
1134 if (rArg.Value >>= bValue)
1136 pMedium->GetItemSet()->Put(SfxBoolItem(SID_REPLACEABLE, bValue));
1137 ok = true;
1140 else if (rArg.Name == "EncryptionData")
1142 pMedium->GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, rArg.Value));
1143 ok = true;
1145 if (!ok)
1147 throw lang::IllegalArgumentException("Setting property not supported: " + rArg.Name,
1148 comphelper::getProcessComponentContext(), 0);
1153 // frame::XModel
1156 void SAL_CALL SfxBaseModel::connectController( const Reference< frame::XController >& xController )
1158 SfxModelGuard aGuard( *this );
1159 OSL_PRECOND( xController.is(), "SfxBaseModel::connectController: invalid controller!" );
1160 if ( !xController.is() )
1161 return;
1163 m_pData->m_seqControllers.push_back(xController);
1165 if ( m_pData->m_seqControllers.size() == 1 )
1167 SfxViewFrame* pViewFrame = SfxViewFrame::Get( xController, GetObjectShell() );
1168 ENSURE_OR_THROW( pViewFrame, "SFX document without SFX view!?" );
1169 pViewFrame->UpdateDocument_Impl();
1170 const OUString sDocumentURL = GetObjectShell()->GetMedium()->GetName();
1171 if ( !sDocumentURL.isEmpty() )
1172 SfxGetpApp()->Broadcast( SfxOpenUrlHint( sDocumentURL ) );
1177 // frame::XModel
1180 void SAL_CALL SfxBaseModel::disconnectController( const Reference< frame::XController >& xController )
1182 SfxModelGuard aGuard( *this );
1184 if ( m_pData->m_seqControllers.empty() )
1185 return;
1187 auto& vec = m_pData->m_seqControllers;
1188 vec.erase(std::remove(vec.begin(), vec.end(), xController), vec.end());
1190 if ( xController == m_pData->m_xCurrent )
1191 m_pData->m_xCurrent.clear();
1194 namespace
1196 class ControllerLockUndoAction : public ::cppu::WeakImplHelper< XUndoAction >
1198 public:
1199 ControllerLockUndoAction( const Reference< XModel >& i_model, const bool i_undoIsUnlock )
1200 :m_xModel( i_model )
1201 ,m_bUndoIsUnlock( i_undoIsUnlock )
1205 // XUndoAction
1206 virtual OUString SAL_CALL getTitle() override;
1207 virtual void SAL_CALL undo( ) override;
1208 virtual void SAL_CALL redo( ) override;
1210 private:
1211 const Reference< XModel > m_xModel;
1212 const bool m_bUndoIsUnlock;
1215 OUString SAL_CALL ControllerLockUndoAction::getTitle()
1217 // this action is intended to be used within an UndoContext only, so nobody will ever see this title ...
1218 return OUString();
1221 void SAL_CALL ControllerLockUndoAction::undo( )
1223 if ( m_bUndoIsUnlock )
1224 m_xModel->unlockControllers();
1225 else
1226 m_xModel->lockControllers();
1229 void SAL_CALL ControllerLockUndoAction::redo( )
1231 if ( m_bUndoIsUnlock )
1232 m_xModel->lockControllers();
1233 else
1234 m_xModel->unlockControllers();
1239 // frame::XModel
1242 void SAL_CALL SfxBaseModel::lockControllers()
1244 SfxModelGuard aGuard( *this );
1246 ++m_pData->m_nControllerLockCount ;
1248 if ( m_pData->m_pDocumentUndoManager.is()
1249 && m_pData->m_pDocumentUndoManager->isInContext()
1250 && !m_pData->m_pDocumentUndoManager->isLocked()
1253 m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( this, true ) );
1258 // frame::XModel
1261 void SAL_CALL SfxBaseModel::unlockControllers()
1263 SfxModelGuard aGuard( *this );
1265 --m_pData->m_nControllerLockCount ;
1267 if ( m_pData->m_pDocumentUndoManager.is()
1268 && m_pData->m_pDocumentUndoManager->isInContext()
1269 && !m_pData->m_pDocumentUndoManager->isLocked()
1272 m_pData->m_pDocumentUndoManager->addUndoAction( new ControllerLockUndoAction( this, false ) );
1277 // frame::XModel
1280 sal_Bool SAL_CALL SfxBaseModel::hasControllersLocked()
1282 SfxModelGuard aGuard( *this );
1283 return ( m_pData->m_nControllerLockCount != 0 ) ;
1287 // frame::XModel
1290 Reference< frame::XController > SAL_CALL SfxBaseModel::getCurrentController()
1292 SfxModelGuard aGuard( *this );
1294 // get the last active controller of this model
1295 if ( m_pData->m_xCurrent.is() )
1296 return m_pData->m_xCurrent;
1298 // get the first controller of this model
1299 return !m_pData->m_seqControllers.empty() ? m_pData->m_seqControllers.front() : m_pData->m_xCurrent;
1303 // frame::XModel
1306 void SAL_CALL SfxBaseModel::setCurrentController( const Reference< frame::XController >& xCurrentController )
1308 SfxModelGuard aGuard( *this );
1310 m_pData->m_xCurrent = xCurrentController;
1314 // frame::XModel
1317 Reference< XInterface > SAL_CALL SfxBaseModel::getCurrentSelection()
1319 SfxModelGuard aGuard( *this );
1321 Reference< XInterface > xReturn;
1322 Reference< frame::XController > xController = getCurrentController() ;
1324 if ( xController.is() )
1326 Reference< view::XSelectionSupplier > xDocView( xController, UNO_QUERY );
1327 if ( xDocView.is() )
1329 Any aSel = xDocView->getSelection();
1330 aSel >>= xReturn ;
1334 return xReturn ;
1338 // XModifiable2
1341 sal_Bool SAL_CALL SfxBaseModel::disableSetModified()
1343 SfxModelGuard aGuard( *this );
1345 if ( !m_pData->m_pObjectShell.is() )
1346 throw RuntimeException();
1348 bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
1349 m_pData->m_pObjectShell->EnableSetModified( false );
1351 return bResult;
1354 sal_Bool SAL_CALL SfxBaseModel::enableSetModified()
1356 SfxModelGuard aGuard( *this );
1358 if ( !m_pData->m_pObjectShell.is() )
1359 throw RuntimeException();
1361 bool bResult = m_pData->m_pObjectShell->IsEnableSetModified();
1362 m_pData->m_pObjectShell->EnableSetModified();
1364 return bResult;
1367 sal_Bool SAL_CALL SfxBaseModel::isSetModifiedEnabled()
1369 SfxModelGuard aGuard( *this );
1371 if ( !m_pData->m_pObjectShell.is() )
1372 throw RuntimeException();
1374 return m_pData->m_pObjectShell->IsEnableSetModified();
1378 // XModifiable
1381 sal_Bool SAL_CALL SfxBaseModel::isModified()
1383 SfxModelGuard aGuard( *this );
1385 return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->IsModified();
1389 // XModifiable
1392 void SAL_CALL SfxBaseModel::setModified( sal_Bool bModified )
1394 SfxModelGuard aGuard( *this );
1396 if ( m_pData->m_pObjectShell.is() )
1397 m_pData->m_pObjectShell->SetModified(bModified);
1401 // XModifiable
1404 void SAL_CALL SfxBaseModel::addModifyListener(const Reference< util::XModifyListener >& xListener)
1406 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1408 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<util::XModifyListener>::get(),xListener );
1412 // XModifiable
1415 void SAL_CALL SfxBaseModel::removeModifyListener(const Reference< util::XModifyListener >& xListener)
1417 SfxModelGuard aGuard( *this );
1419 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<util::XModifyListener>::get(), xListener );
1423 // XCloseable
1426 void SAL_CALL SfxBaseModel::close( sal_Bool bDeliverOwnership )
1428 SolarMutexGuard aGuard;
1429 if ( impl_isDisposed() || m_pData->m_bClosed || m_pData->m_bClosing )
1430 return;
1432 Reference< XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
1433 lang::EventObject aSource ( static_cast< ::cppu::OWeakObject* >(this) );
1434 comphelper::OInterfaceContainerHelper2* pContainer = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<util::XCloseListener>::get());
1435 if (pContainer!=nullptr)
1437 comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
1438 while (pIterator.hasMoreElements())
1442 static_cast<util::XCloseListener*>(pIterator.next())->queryClosing( aSource, bDeliverOwnership );
1444 catch( RuntimeException& )
1446 pIterator.remove();
1451 if ( m_pData->m_bSaving )
1453 if (bDeliverOwnership)
1454 m_pData->m_bSuicide = true;
1455 throw util::CloseVetoException(
1456 "Can not close while saving.",
1457 static_cast< util::XCloseable* >(this));
1460 // no own objections against closing!
1461 m_pData->m_bClosing = true;
1462 pContainer = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<util::XCloseListener>::get());
1463 if (pContainer!=nullptr)
1465 comphelper::OInterfaceIteratorHelper2 pCloseIterator(*pContainer);
1466 while (pCloseIterator.hasMoreElements())
1470 static_cast<util::XCloseListener*>(pCloseIterator.next())->notifyClosing( aSource );
1472 catch( RuntimeException& )
1474 pCloseIterator.remove();
1479 m_pData->m_bClosed = true;
1480 m_pData->m_bClosing = false;
1482 dispose();
1486 // XCloseBroadcaster
1489 void SAL_CALL SfxBaseModel::addCloseListener( const Reference< util::XCloseListener >& xListener )
1491 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1493 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
1497 // XCloseBroadcaster
1500 void SAL_CALL SfxBaseModel::removeCloseListener( const Reference< util::XCloseListener >& xListener )
1502 SfxModelGuard aGuard( *this );
1504 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
1508 // XPrintable
1511 Sequence< beans::PropertyValue > SAL_CALL SfxBaseModel::getPrinter()
1513 SfxModelGuard aGuard( *this );
1515 impl_getPrintHelper();
1516 return m_pData->m_xPrintable->getPrinter();
1519 void SAL_CALL SfxBaseModel::setPrinter(const Sequence< beans::PropertyValue >& rPrinter)
1521 SfxModelGuard aGuard( *this );
1523 impl_getPrintHelper();
1524 m_pData->m_xPrintable->setPrinter( rPrinter );
1527 void SAL_CALL SfxBaseModel::print(const Sequence< beans::PropertyValue >& rOptions)
1529 SfxModelGuard aGuard( *this );
1531 impl_getPrintHelper();
1533 // tdf#123728 Always print on main thread to avoid deadlocks
1534 vcl::solarthread::syncExecute([this, &rOptions]() { m_pData->m_xPrintable->print(rOptions); });
1537 // XStorable
1540 sal_Bool SAL_CALL SfxBaseModel::hasLocation()
1542 SfxModelGuard aGuard( *this );
1544 return m_pData->m_pObjectShell.is() && m_pData->m_pObjectShell->HasName();
1548 // XStorable
1551 OUString SAL_CALL SfxBaseModel::getLocation()
1553 SfxModelGuard aGuard( *this );
1555 if ( m_pData->m_pObjectShell.is() )
1557 // TODO/LATER: is it correct that the shared document returns shared file location?
1558 if ( m_pData->m_pObjectShell->IsDocShared() )
1559 return m_pData->m_pObjectShell->GetSharedFileURL();
1560 else
1561 return m_pData->m_pObjectShell->GetMedium()->GetName();
1564 return m_pData->m_sURL;
1568 // XStorable
1571 sal_Bool SAL_CALL SfxBaseModel::isReadonly()
1573 SfxModelGuard aGuard( *this );
1575 return !m_pData->m_pObjectShell.is() || m_pData->m_pObjectShell->IsReadOnly();
1578 // XStorable2
1581 void SAL_CALL SfxBaseModel::storeSelf( const Sequence< beans::PropertyValue >& aSeqArgs )
1583 SfxModelGuard aGuard( *this );
1585 if ( !m_pData->m_pObjectShell.is() )
1586 return;
1588 SfxSaveGuard aSaveGuard(this, m_pData.get());
1590 bool bCheckIn = false;
1591 bool bOnMainThread = false;
1592 for ( const auto& rArg : aSeqArgs )
1594 // check that only acceptable parameters are provided here
1595 if ( rArg.Name != "VersionComment" && rArg.Name != "Author"
1596 && rArg.Name != "DontTerminateEdit"
1597 && rArg.Name != "InteractionHandler" && rArg.Name != "StatusIndicator"
1598 && rArg.Name != "VersionMajor"
1599 && rArg.Name != "FailOnWarning"
1600 && rArg.Name != "CheckIn"
1601 && rArg.Name != "NoFileSync"
1602 && rArg.Name != "OnMainThread" )
1604 const OUString aMessage( "Unexpected MediaDescriptor parameter: " + rArg.Name );
1605 throw lang::IllegalArgumentException( aMessage, Reference< XInterface >(), 1 );
1607 else if ( rArg.Name == "CheckIn" )
1609 rArg.Value >>= bCheckIn;
1611 else if (rArg.Name == "OnMainThread")
1613 rArg.Value >>= bOnMainThread;
1617 // Remove CheckIn property if needed
1618 sal_uInt16 nSlotId = SID_SAVEDOC;
1619 Sequence< beans::PropertyValue > aArgs = aSeqArgs;
1620 if ( bCheckIn )
1622 nSlotId = SID_CHECKIN;
1623 sal_Int32 nLength = aSeqArgs.getLength( );
1624 aArgs = Sequence< beans::PropertyValue >( nLength - 1 );
1625 std::copy_if(aSeqArgs.begin(), aSeqArgs.end(), aArgs.getArray(),
1626 [](const beans::PropertyValue& rProp) { return rProp.Name != "CheckIn"; });
1629 std::optional<SfxAllItemSet> pParams(SfxGetpApp()->GetPool() );
1630 TransformParameters( nSlotId, aArgs, *pParams );
1632 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDoc, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOC), m_pData->m_pObjectShell.get() ) );
1634 bool bRet = false;
1636 // TODO/LATER: let the embedded case of saving be handled more careful
1637 if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1639 // If this is an embedded object that has no URL based location it should be stored to own storage.
1640 // An embedded object can have a location based on URL in case it is a link, then it should be
1641 // stored in normal way.
1642 if ( !hasLocation() || getLocation().startsWith("private:") )
1644 // actually in this very rare case only UI parameters have sense
1645 // TODO/LATER: should be done later, after integration of sb19
1646 bRet = m_pData->m_pObjectShell->DoSave()
1647 && m_pData->m_pObjectShell->DoSaveCompleted();
1649 else
1651 bRet = m_pData->m_pObjectShell->Save_Impl( &*pParams );
1654 else
1656 // Tell the SfxMedium if we are in checkin instead of normal save
1657 m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId == SID_CHECKIN );
1658 if (bOnMainThread)
1659 bRet = vcl::solarthread::syncExecute(
1660 [this, &pParams] { return m_pData->m_pObjectShell->Save_Impl(&*pParams); });
1661 else
1662 bRet = m_pData->m_pObjectShell->Save_Impl(&*pParams);
1663 m_pData->m_pObjectShell->GetMedium( )->SetInCheckIn( nSlotId != SID_CHECKIN );
1666 pParams.reset();
1668 ErrCode nErrCode = m_pData->m_pObjectShell->GetError() ? m_pData->m_pObjectShell->GetError()
1669 : ERRCODE_IO_CANTWRITE;
1670 m_pData->m_pObjectShell->ResetError();
1672 if ( bRet )
1674 m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();
1676 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCDONE), m_pData->m_pObjectShell.get() ) );
1678 else
1680 // write the contents of the logger to the file
1681 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveDocFailed, GlobalEventConfig::GetEventName(GlobalEventId::SAVEDOCFAILED), m_pData->m_pObjectShell.get() ) );
1683 throw task::ErrorCodeIOException(
1684 "SfxBaseModel::storeSelf: " + nErrCode.toHexString(),
1685 Reference< XInterface >(), sal_uInt32(nErrCode));
1690 // XStorable
1693 void SAL_CALL SfxBaseModel::store()
1695 comphelper::ProfileZone aZone("store");
1696 storeSelf( Sequence< beans::PropertyValue >() );
1700 // XStorable
1703 void SAL_CALL SfxBaseModel::storeAsURL( const OUString& rURL ,
1704 const Sequence< beans::PropertyValue >& rArgs )
1706 SfxModelGuard aGuard( *this );
1707 comphelper::ProfileZone aZone("storeAs");
1709 if ( !m_pData->m_pObjectShell.is() )
1710 return;
1712 SfxSaveGuard aSaveGuard(this, m_pData.get());
1714 utl::MediaDescriptor aDescriptor(rArgs);
1715 bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault("OnMainThread", false);
1716 if (bOnMainThread)
1718 vcl::solarthread::syncExecute([this, rURL, rArgs]() { impl_store(rURL, rArgs, false); });
1720 else
1722 impl_store(rURL, rArgs, false);
1725 Sequence< beans::PropertyValue > aSequence ;
1726 TransformItems( SID_OPENDOC, *m_pData->m_pObjectShell->GetMedium()->GetItemSet(), aSequence );
1727 attachResource( rURL, aSequence );
1729 loadCmisProperties( );
1731 #if OSL_DEBUG_LEVEL > 0
1732 const SfxStringItem* pPasswdItem = SfxItemSet::GetItem<SfxStringItem>(m_pData->m_pObjectShell->GetMedium()->GetItemSet(), SID_PASSWORD, false);
1733 OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
1734 #endif
1738 // XUndoManagerSupplier
1740 Reference< XUndoManager > SAL_CALL SfxBaseModel::getUndoManager( )
1742 SfxModelGuard aGuard( *this );
1743 if ( !m_pData->m_pDocumentUndoManager.is() )
1744 m_pData->m_pDocumentUndoManager.set( new ::sfx2::DocumentUndoManager( *this ) );
1745 return m_pData->m_pDocumentUndoManager;
1749 // XStorable
1752 void SAL_CALL SfxBaseModel::storeToURL( const OUString& rURL ,
1753 const Sequence< beans::PropertyValue >& rArgs )
1755 SfxModelGuard aGuard( *this );
1756 comphelper::ProfileZone aZone("storeToURL");
1758 if ( !m_pData->m_pObjectShell.is() )
1759 return;
1761 SfxSaveGuard aSaveGuard(this, m_pData.get());
1762 try {
1763 utl::MediaDescriptor aDescriptor(rArgs);
1764 bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault("OnMainThread", false);
1765 if (bOnMainThread)
1766 vcl::solarthread::syncExecute([this, rURL, rArgs]() { impl_store(rURL, rArgs, true); });
1767 else
1768 impl_store(rURL, rArgs, true);
1770 catch (const uno::Exception &e)
1772 // convert to the exception we announce in the throw
1773 // (eg. neon likes to throw InteractiveAugmentedIOException which
1774 // is not an io::IOException)
1775 throw io::IOException(e.Message, e.Context);
1779 sal_Bool SAL_CALL SfxBaseModel::wasModifiedSinceLastSave()
1781 SfxModelGuard aGuard( *this );
1782 return m_pData->m_bModifiedSinceLastSave;
1785 void SAL_CALL SfxBaseModel::storeToRecoveryFile( const OUString& i_TargetLocation, const Sequence< PropertyValue >& i_MediaDescriptor )
1787 SfxModelGuard aGuard( *this );
1789 // delegate
1790 SfxSaveGuard aSaveGuard( this, m_pData.get() );
1791 impl_store( i_TargetLocation, i_MediaDescriptor, true );
1793 // no need for subsequent calls to storeToRecoveryFile, unless we're modified, again
1794 m_pData->m_bModifiedSinceLastSave = false;
1797 void SAL_CALL SfxBaseModel::recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor )
1799 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1801 // delegate to our "load" method
1802 ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor );
1804 // our load implementation expects the SalvagedFile to be in the media descriptor
1805 OSL_ENSURE( !aMediaDescriptor.has( "SalvagedFile" ) || ( aMediaDescriptor.getOrDefault( "SalvagedFile", OUString() ) == i_SalvagedFile ),
1806 "SfxBaseModel::recoverFromFile: inconsistent information!" );
1807 aMediaDescriptor.put( "SalvagedFile", i_SalvagedFile );
1809 // similar for the to-be-loaded file
1810 OSL_ENSURE( !aMediaDescriptor.has( "URL" ) || ( aMediaDescriptor.getOrDefault( "URL", OUString() ) == i_SourceLocation ),
1811 "SfxBaseModel::recoverFromFile: inconsistent information!" );
1812 aMediaDescriptor.put( "URL", i_SourceLocation );
1814 load( aMediaDescriptor.getPropertyValues() );
1816 // Note: The XDocumentRecovery interface specification requires us to do an attachResource after loading.
1817 // However, we will not do this here, as we know that our load implementation (respectively some method
1818 // called from there) already did so.
1819 // In particular, the load process might already have modified some elements of the media
1820 // descriptor, for instance the MacroExecMode (in case the user was involved to decide about it), and we do
1821 // not want to overwrite it with the "old" elements passed to this method here.
1825 // XLoadable
1828 void SAL_CALL SfxBaseModel::initNew()
1830 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1831 if ( IsInitialized() )
1832 throw frame::DoubleInitializationException( OUString(), *this );
1834 // the object shell should exist always
1835 DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );
1836 if ( !m_pData->m_pObjectShell.is() )
1837 return;
1839 if( m_pData->m_pObjectShell->GetMedium() )
1840 throw frame::DoubleInitializationException();
1842 bool bRes = m_pData->m_pObjectShell->DoInitNew();
1843 ErrCode nErrCode = m_pData->m_pObjectShell->GetError() ?
1844 m_pData->m_pObjectShell->GetError() : ERRCODE_IO_CANTCREATE;
1845 m_pData->m_pObjectShell->ResetError();
1847 if ( !bRes )
1848 throw task::ErrorCodeIOException(
1849 "SfxBaseModel::initNew: " + nErrCode.toHexString(),
1850 Reference< XInterface >(), sal_uInt32(nErrCode));
1853 namespace {
1855 OUString getFilterProvider( SfxMedium const & rMedium )
1857 const std::shared_ptr<const SfxFilter>& pFilter = rMedium.GetFilter();
1858 if (!pFilter)
1859 return OUString();
1861 return pFilter->GetProviderName();
1864 void setUpdatePickList( SfxMedium* pMedium )
1866 if (!pMedium)
1867 return;
1869 bool bHidden = false;
1870 const SfxBoolItem* pHidItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_HIDDEN, false);
1871 if (pHidItem)
1872 bHidden = pHidItem->GetValue();
1874 pMedium->SetUpdatePickList(!bHidden);
1879 void SAL_CALL SfxBaseModel::load( const Sequence< beans::PropertyValue >& seqArguments )
1881 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
1882 if ( IsInitialized() )
1883 throw frame::DoubleInitializationException( OUString(), *this );
1885 // the object shell should exist always
1886 DBG_ASSERT( m_pData->m_pObjectShell.is(), "Model is useless without an ObjectShell" );
1888 if (!m_pData->m_pObjectShell.is())
1889 return;
1891 if( m_pData->m_pObjectShell->GetMedium() )
1892 // if a Medium is present, the document is already initialized
1893 throw frame::DoubleInitializationException();
1895 SfxMedium* pMedium = new SfxMedium( seqArguments );
1897 ErrCode nError = ERRCODE_NONE;
1898 if (!getFilterProvider(*pMedium).isEmpty())
1900 if (!m_pData->m_pObjectShell->DoLoadExternal(pMedium))
1901 nError = ERRCODE_IO_GENERAL;
1903 pMedium = handleLoadError(nError, pMedium);
1904 setUpdatePickList(pMedium);
1905 return;
1908 OUString aFilterName;
1909 const SfxStringItem* pFilterNameItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_FILTER_NAME, false);
1910 if( pFilterNameItem )
1911 aFilterName = pFilterNameItem->GetValue();
1912 if( !m_pData->m_pObjectShell->GetFactory().GetFilterContainer()->GetFilter4FilterName( aFilterName ) )
1914 // filtername is not valid
1915 delete pMedium;
1916 throw frame::IllegalArgumentIOException();
1919 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_DOC_SALVAGE, false);
1920 bool bSalvage = pSalvageItem != nullptr;
1922 // load document
1923 if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
1924 nError=ERRCODE_IO_GENERAL;
1926 // QUESTION: if the following happens outside of DoLoad, something important is missing there!
1927 Reference< task::XInteractionHandler > xHandler = pMedium->GetInteractionHandler();
1928 if( m_pData->m_pObjectShell->GetErrorCode() )
1930 nError = m_pData->m_pObjectShell->GetErrorCode();
1931 if ( nError == ERRCODE_IO_BROKENPACKAGE && xHandler.is() )
1933 const OUString aDocName( pMedium->GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ) );
1934 const SfxBoolItem* pRepairItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_REPAIRPACKAGE, false);
1935 if ( !pRepairItem || !pRepairItem->GetValue() )
1937 RequestPackageReparation aRequest( aDocName );
1938 xHandler->handle( aRequest.GetRequest() );
1939 if( aRequest.isApproved() )
1941 // broken package: try second loading and allow repair
1942 pMedium->GetItemSet()->Put( SfxBoolItem( SID_REPAIRPACKAGE, true ) );
1943 pMedium->GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, true ) );
1944 pMedium->GetItemSet()->Put( SfxStringItem( SID_DOCINFO_TITLE, aDocName ) );
1946 // the error must be reset and the storage must be reopened in new mode
1947 pMedium->ResetError();
1948 pMedium->CloseStorage();
1949 m_pData->m_pObjectShell->PrepareSecondTryLoad_Impl();
1950 nError = ERRCODE_NONE;
1951 if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
1952 nError=ERRCODE_IO_GENERAL;
1953 if (m_pData->m_pObjectShell->GetErrorCode())
1954 nError = m_pData->m_pObjectShell->GetErrorCode();
1958 if ( nError == ERRCODE_IO_BROKENPACKAGE )
1960 // repair either not allowed or not successful
1961 NotifyBrokenPackage aRequest( aDocName );
1962 xHandler->handle( aRequest.GetRequest() );
1967 if( m_pData->m_pObjectShell->IsAbortingImport() )
1968 nError = ERRCODE_ABORT;
1970 if( bSalvage )
1972 // file recovery: restore original filter
1973 const SfxStringItem* pFilterItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_FILTER_NAME, false);
1974 SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
1975 std::shared_ptr<const SfxFilter> pSetFilter = rMatcher.GetFilter4FilterName( pFilterItem->GetValue() );
1976 pMedium->SetFilter( pSetFilter );
1977 m_pData->m_pObjectShell->SetModified();
1980 // TODO/LATER: maybe the mode should be retrieved from outside and the preused filter should not be set
1981 if ( m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1983 const SfxStringItem* pFilterItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_FILTER_NAME, false);
1984 if ( pFilterItem )
1985 m_pData->m_aPreusedFilterName = pFilterItem->GetValue();
1988 if ( !nError )
1989 nError = pMedium->GetError();
1991 m_pData->m_pObjectShell->ResetError();
1993 pMedium = handleLoadError(nError, pMedium);
1994 loadCmisProperties();
1995 setUpdatePickList(pMedium);
1997 #if OSL_DEBUG_LEVEL > 0
1998 const SfxStringItem* pPasswdItem = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_PASSWORD, false);
1999 OSL_ENSURE( !pPasswdItem, "There should be no Password property in the document MediaDescriptor!" );
2000 #endif
2004 // XTransferable
2007 Any SAL_CALL SfxBaseModel::getTransferData( const datatransfer::DataFlavor& aFlavor )
2009 SfxModelGuard aGuard( *this );
2011 Any aAny;
2013 if ( m_pData->m_pObjectShell.is() )
2015 if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
2017 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2018 throw datatransfer::UnsupportedFlavorException();
2020 TransferableObjectDescriptor aDesc;
2022 aDesc.maClassName = m_pData->m_pObjectShell->GetClassName();
2023 aDesc.maTypeName = aFlavor.HumanPresentableName;
2025 // TODO/LATER: ViewAspect needs to be sal_Int64
2026 aDesc.mnViewAspect = sal::static_int_cast< sal_uInt16 >( embed::Aspects::MSOLE_CONTENT );
2028 Size aSize = m_pData->m_pObjectShell->GetVisArea().GetSize();
2030 MapUnit aMapUnit = m_pData->m_pObjectShell->GetMapUnit();
2031 aDesc.maSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
2032 aDesc.maDragStartPos = Point();
2033 aDesc.maDisplayName.clear();
2035 SvMemoryStream aMemStm( 1024, 1024 );
2036 WriteTransferableObjectDescriptor( aMemStm, aDesc );
2037 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
2039 else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
2041 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2042 throw datatransfer::UnsupportedFlavorException();
2046 utl::TempFile aTmp;
2047 aTmp.EnableKillingFile();
2048 storeToURL( aTmp.GetURL(), Sequence < beans::PropertyValue >() );
2049 std::unique_ptr<SvStream> pStream(aTmp.GetStream( StreamMode::READ ));
2050 const sal_uInt32 nLen = pStream->TellEnd();
2051 Sequence< sal_Int8 > aSeq( nLen );
2052 pStream->ReadBytes(aSeq.getArray(), nLen);
2053 if( aSeq.hasElements() )
2054 aAny <<= aSeq;
2056 catch ( Exception& )
2060 else if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2062 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2063 throw datatransfer::UnsupportedFlavorException();
2066 std::shared_ptr<GDIMetaFile> xMetaFile =
2067 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2069 if (xMetaFile)
2071 SvMemoryStream aMemStm( 65535, 65535 );
2072 aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2074 SvmWriter aWriter( aMemStm );
2075 aWriter.Write( *xMetaFile );
2076 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
2077 aMemStm.TellEnd() );
2080 else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2082 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2083 throw datatransfer::UnsupportedFlavorException();
2085 std::shared_ptr<GDIMetaFile> xMetaFile =
2086 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2088 if (xMetaFile)
2090 SvMemoryStream aMemStm( 65535, 65535 );
2091 aMemStm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2093 SvmWriter aWriter( aMemStm );
2094 aWriter.Write( *xMetaFile );
2095 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ),
2096 aMemStm.TellEnd() );
2099 else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
2101 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2103 std::shared_ptr<GDIMetaFile> xMetaFile =
2104 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2106 if (xMetaFile)
2108 std::unique_ptr<SvMemoryStream> xStream(
2109 GraphicHelper::getFormatStrFromGDI_Impl(
2110 xMetaFile.get(), ConvertDataFormat::EMF ) );
2111 if (xStream)
2113 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2114 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2115 xStream->TellEnd() );
2119 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2120 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2122 std::shared_ptr<GDIMetaFile> xMetaFile =
2123 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2125 if (xMetaFile)
2127 aAny <<= reinterpret_cast< sal_uInt64 >(
2128 GraphicHelper::getEnhMetaFileFromGDI_Impl( xMetaFile.get() ) );
2131 else
2132 throw datatransfer::UnsupportedFlavorException();
2134 else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
2136 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2138 std::shared_ptr<GDIMetaFile> xMetaFile =
2139 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2141 if (xMetaFile)
2143 std::unique_ptr<SvMemoryStream> xStream(
2144 GraphicHelper::getFormatStrFromGDI_Impl(
2145 xMetaFile.get(), ConvertDataFormat::WMF ) );
2147 if (xStream)
2149 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2150 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2151 xStream->TellEnd() );
2155 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2156 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2158 // means HGLOBAL handler to memory storage containing METAFILEPICT structure
2160 std::shared_ptr<GDIMetaFile> xMetaFile =
2161 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2163 if (xMetaFile)
2165 Size aMetaSize = xMetaFile->GetPrefSize();
2166 aAny <<= reinterpret_cast< sal_uInt64 >(
2167 GraphicHelper::getWinMetaFileFromGDI_Impl(
2168 xMetaFile.get(), aMetaSize ) );
2171 else
2172 throw datatransfer::UnsupportedFlavorException();
2174 else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
2176 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2177 throw datatransfer::UnsupportedFlavorException();
2179 std::shared_ptr<GDIMetaFile> xMetaFile =
2180 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2182 if (xMetaFile)
2184 std::unique_ptr<SvMemoryStream> xStream(
2185 GraphicHelper::getFormatStrFromGDI_Impl(
2186 xMetaFile.get(), ConvertDataFormat::BMP ) );
2188 if (xStream)
2190 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2191 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2192 xStream->TellEnd() );
2196 else if ( aFlavor.MimeType == "image/png" )
2198 if ( aFlavor.DataType != cppu::UnoType<Sequence< sal_Int8 >>::get() )
2199 throw datatransfer::UnsupportedFlavorException();
2201 std::shared_ptr<GDIMetaFile> xMetaFile =
2202 m_pData->m_pObjectShell->GetPreviewMetaFile( true );
2204 if (xMetaFile)
2206 std::unique_ptr<SvMemoryStream> xStream(
2207 GraphicHelper::getFormatStrFromGDI_Impl(
2208 xMetaFile.get(), ConvertDataFormat::PNG ) );
2210 if (xStream)
2212 xStream->SetVersion( SOFFICE_FILEFORMAT_CURRENT );
2213 aAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( xStream->GetData() ),
2214 xStream->TellEnd() );
2218 else
2219 throw datatransfer::UnsupportedFlavorException();
2222 return aAny;
2226 // XTransferable
2229 Sequence< datatransfer::DataFlavor > SAL_CALL SfxBaseModel::getTransferDataFlavors()
2231 SfxModelGuard aGuard( *this );
2233 const sal_Int32 nSuppFlavors = GraphicHelper::supportsMetaFileHandle_Impl() ? 10 : 8;
2234 Sequence< datatransfer::DataFlavor > aFlavorSeq( nSuppFlavors );
2235 auto pFlavorSeq = aFlavorSeq.getArray();
2237 pFlavorSeq[0].MimeType =
2238 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
2239 pFlavorSeq[0].HumanPresentableName = "GDIMetaFile";
2240 pFlavorSeq[0].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2242 pFlavorSeq[1].MimeType =
2243 "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"";
2244 pFlavorSeq[1].HumanPresentableName = "GDIMetaFile";
2245 pFlavorSeq[1].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2247 pFlavorSeq[2].MimeType =
2248 "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" ;
2249 pFlavorSeq[2].HumanPresentableName = "Enhanced Windows MetaFile";
2250 pFlavorSeq[2].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2252 pFlavorSeq[3].MimeType =
2253 "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
2254 pFlavorSeq[3].HumanPresentableName = "Windows MetaFile";
2255 pFlavorSeq[3].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2257 pFlavorSeq[4].MimeType =
2258 "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
2259 pFlavorSeq[4].HumanPresentableName = "Star Object Descriptor (XML)";
2260 pFlavorSeq[4].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2262 pFlavorSeq[5].MimeType =
2263 "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
2264 pFlavorSeq[5].HumanPresentableName = "Star Embed Source (XML)";
2265 pFlavorSeq[5].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2267 pFlavorSeq[6].MimeType =
2268 "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"";
2269 pFlavorSeq[6].HumanPresentableName = "Bitmap";
2270 pFlavorSeq[6].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2272 pFlavorSeq[7].MimeType = "image/png";
2273 pFlavorSeq[7].HumanPresentableName = "PNG";
2274 pFlavorSeq[7].DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
2276 if ( nSuppFlavors == 10 )
2278 pFlavorSeq[8].MimeType =
2279 "application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
2280 pFlavorSeq[8].HumanPresentableName = "Enhanced Windows MetaFile";
2281 pFlavorSeq[8].DataType = cppu::UnoType<sal_uInt64>::get();
2283 pFlavorSeq[9].MimeType =
2284 "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
2285 pFlavorSeq[9].HumanPresentableName = "Windows MetaFile";
2286 pFlavorSeq[9].DataType = cppu::UnoType<sal_uInt64>::get();
2289 return aFlavorSeq;
2293 // XTransferable
2296 sal_Bool SAL_CALL SfxBaseModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
2298 SfxModelGuard aGuard( *this );
2300 if ( aFlavor.MimeType == "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2302 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2303 return true;
2305 else if ( aFlavor.MimeType == "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" )
2307 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2308 return true;
2310 else if ( aFlavor.MimeType == "application/x-openoffice-emf;windows_formatname=\"Image EMF\"" )
2312 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2313 return true;
2314 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2315 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2316 return true;
2318 else if ( aFlavor.MimeType == "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"" )
2320 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2321 return true;
2322 else if ( GraphicHelper::supportsMetaFileHandle_Impl()
2323 && aFlavor.DataType == cppu::UnoType<sal_uInt64>::get())
2324 return true;
2326 else if ( aFlavor.MimeType == "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"" )
2328 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2329 return true;
2331 else if ( aFlavor.MimeType == "application/x-openoffice-embed-source;windows_formatname=\"Star EMBS\"" )
2333 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2334 return true;
2336 else if ( aFlavor.MimeType == "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" )
2338 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2339 return true;
2341 else if ( aFlavor.MimeType == "image/png" )
2343 if ( aFlavor.DataType == cppu::UnoType<Sequence< sal_Int8 >>::get() )
2344 return true;
2347 return false;
2351 // XEventsSupplier
2354 Reference< container::XNameReplace > SAL_CALL SfxBaseModel::getEvents()
2356 SfxModelGuard aGuard( *this );
2358 if ( ! m_pData->m_xEvents.is() )
2360 m_pData->m_xEvents = new SfxEvents_Impl( m_pData->m_pObjectShell.get(), this );
2363 return m_pData->m_xEvents;
2367 // XEmbeddedScripts
2370 Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getBasicLibraries()
2372 SfxModelGuard aGuard( *this );
2374 Reference< script::XStorageBasedLibraryContainer > xBasicLibraries;
2375 if ( m_pData->m_pObjectShell.is() )
2376 xBasicLibraries.set(m_pData->m_pObjectShell->GetBasicContainer(), UNO_QUERY);
2377 return xBasicLibraries;
2380 Reference< script::XStorageBasedLibraryContainer > SAL_CALL SfxBaseModel::getDialogLibraries()
2382 SfxModelGuard aGuard( *this );
2384 Reference< script::XStorageBasedLibraryContainer > xDialogLibraries;
2385 if ( m_pData->m_pObjectShell.is() )
2386 xDialogLibraries.set(m_pData->m_pObjectShell->GetDialogContainer(), UNO_QUERY);
2387 return xDialogLibraries;
2390 sal_Bool SAL_CALL SfxBaseModel::getAllowMacroExecution()
2392 SfxModelGuard aGuard( *this );
2394 if ( m_pData->m_pObjectShell.is() )
2395 return m_pData->m_pObjectShell->AdjustMacroMode();
2396 return false;
2400 // XScriptInvocationContext
2403 Reference< document::XEmbeddedScripts > SAL_CALL SfxBaseModel::getScriptContainer()
2405 SfxModelGuard aGuard( *this );
2407 Reference< document::XEmbeddedScripts > xDocumentScripts;
2411 Reference< frame::XModel > xDocument( this );
2412 xDocumentScripts.set( xDocument, UNO_QUERY );
2413 while ( !xDocumentScripts.is() && xDocument.is() )
2415 Reference< container::XChild > xDocAsChild( xDocument, UNO_QUERY );
2416 if ( !xDocAsChild.is() )
2418 xDocument = nullptr;
2419 break;
2422 xDocument.set( xDocAsChild->getParent(), UNO_QUERY );
2423 xDocumentScripts.set( xDocument, UNO_QUERY );
2426 catch( const Exception& )
2428 DBG_UNHANDLED_EXCEPTION("sfx.doc");
2429 xDocumentScripts = nullptr;
2432 return xDocumentScripts;
2436 // XEventBroadcaster
2439 void SAL_CALL SfxBaseModel::addEventListener( const Reference< document::XEventListener >& aListener )
2441 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2443 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<document::XEventListener>::get(), aListener );
2447 // XEventBroadcaster
2450 void SAL_CALL SfxBaseModel::removeEventListener( const Reference< document::XEventListener >& aListener )
2452 SfxModelGuard aGuard( *this );
2454 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<document::XEventListener>::get(), aListener );
2457 // XShapeEventBroadcaster
2459 void SAL_CALL SfxBaseModel::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
2461 assert(xShape.is() && "no shape?");
2462 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2464 m_pData->maShapeListeners[xShape].push_back(xListener);
2468 // XShapeEventBroadcaster
2471 void SAL_CALL SfxBaseModel::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
2473 SfxModelGuard aGuard( *this );
2475 auto it = m_pData->maShapeListeners.find(xShape);
2476 if (it != m_pData->maShapeListeners.end())
2478 auto rVec = it->second;
2479 auto it2 = std::find(rVec.begin(), rVec.end(), xListener);
2480 if (it2 != rVec.end())
2482 rVec.erase(it2);
2483 if (rVec.empty())
2484 m_pData->maShapeListeners.erase(it);
2489 // XDocumentEventBroadcaster
2492 void SAL_CALL SfxBaseModel::addDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
2494 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
2495 m_pData->m_aInterfaceContainer.addInterface( cppu::UnoType<document::XDocumentEventListener>::get(), aListener );
2499 void SAL_CALL SfxBaseModel::removeDocumentEventListener( const Reference< document::XDocumentEventListener >& aListener )
2501 SfxModelGuard aGuard( *this );
2502 m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<document::XDocumentEventListener>::get(), aListener );
2506 void SAL_CALL SfxBaseModel::notifyDocumentEvent( const OUString&, const Reference< frame::XController2 >&, const Any& )
2508 throw lang::NoSupportException("SfxBaseModel controls all the sent notifications itself!" );
2511 Sequence<document::CmisProperty> SAL_CALL SfxBaseModel::getCmisProperties()
2513 if (impl_isDisposed())
2514 return Sequence<document::CmisProperty>();
2515 return m_pData->m_cmisProperties;
2518 void SAL_CALL SfxBaseModel::setCmisProperties( const Sequence< document::CmisProperty >& _cmisproperties )
2520 m_pData->m_cmisProperties = _cmisproperties;
2523 void SAL_CALL SfxBaseModel::updateCmisProperties( const Sequence< document::CmisProperty >& aProperties )
2525 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2526 if ( !pMedium )
2527 return;
2531 ::ucbhelper::Content aContent( pMedium->GetName( ),
2532 Reference<ucb::XCommandEnvironment>(),
2533 comphelper::getProcessComponentContext() );
2535 aContent.executeCommand( "updateProperties", uno::makeAny( aProperties ) );
2536 loadCmisProperties( );
2538 catch (const Exception & e)
2540 css::uno::Any anyEx = cppu::getCaughtException();
2541 throw lang::WrappedTargetRuntimeException( e.Message,
2542 e.Context, anyEx );
2547 void SAL_CALL SfxBaseModel::checkOut( )
2549 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2550 if ( !pMedium )
2551 return;
2555 ::ucbhelper::Content aContent( pMedium->GetName(),
2556 Reference<ucb::XCommandEnvironment>(),
2557 comphelper::getProcessComponentContext() );
2559 Any aResult = aContent.executeCommand( "checkout", Any( ) );
2560 OUString sURL;
2561 aResult >>= sURL;
2563 m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
2564 m_pData->m_pObjectShell->GetMedium( )->GetMedium_Impl( );
2565 m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
2566 Sequence< beans::PropertyValue > aSequence ;
2567 TransformItems( SID_OPENDOC, *pMedium->GetItemSet(), aSequence );
2568 attachResource( sURL, aSequence );
2570 // Reload the CMIS properties
2571 loadCmisProperties( );
2573 catch ( const Exception & e )
2575 css::uno::Any anyEx = cppu::getCaughtException();
2576 throw lang::WrappedTargetRuntimeException( e.Message,
2577 e.Context, anyEx );
2581 void SAL_CALL SfxBaseModel::cancelCheckOut( )
2583 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2584 if ( !pMedium )
2585 return;
2589 ::ucbhelper::Content aContent( pMedium->GetName(),
2590 Reference<ucb::XCommandEnvironment>(),
2591 comphelper::getProcessComponentContext() );
2593 Any aResult = aContent.executeCommand( "cancelCheckout", Any( ) );
2594 OUString sURL;
2595 aResult >>= sURL;
2597 m_pData->m_pObjectShell->GetMedium( )->SetName( sURL );
2599 catch ( const Exception & e )
2601 css::uno::Any anyEx = cppu::getCaughtException();
2602 throw lang::WrappedTargetRuntimeException( e.Message,
2603 e.Context, anyEx );
2607 void SAL_CALL SfxBaseModel::checkIn( sal_Bool bIsMajor, const OUString& rMessage )
2609 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2610 if ( !pMedium )
2611 return;
2615 Sequence< beans::PropertyValue > aProps{
2616 comphelper::makePropertyValue("VersionMajor", bIsMajor),
2617 comphelper::makePropertyValue("VersionComment", rMessage),
2618 comphelper::makePropertyValue("CheckIn", true)
2621 const OUString sName( pMedium->GetName( ) );
2622 storeSelf( aProps );
2624 // Refresh pMedium as it has probably changed during the storeSelf call
2625 pMedium = m_pData->m_pObjectShell->GetMedium( );
2626 const OUString sNewName( pMedium->GetName( ) );
2628 // URL has changed, update the document
2629 if ( sName != sNewName )
2631 m_pData->m_xDocumentProperties->setTitle( getTitle( ) );
2632 Sequence< beans::PropertyValue > aSequence ;
2633 TransformItems( SID_OPENDOC, *pMedium->GetItemSet(), aSequence );
2634 attachResource( sNewName, aSequence );
2636 // Reload the CMIS properties
2637 loadCmisProperties( );
2640 catch ( const Exception & e )
2642 css::uno::Any anyEx = cppu::getCaughtException();
2643 throw lang::WrappedTargetRuntimeException( e.Message,
2644 e.Context, anyEx );
2648 uno::Sequence< document::CmisVersion > SAL_CALL SfxBaseModel::getAllVersions( )
2650 uno::Sequence<document::CmisVersion> aVersions;
2651 if (impl_isDisposed())
2652 return aVersions;
2653 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2654 if ( pMedium )
2658 ::ucbhelper::Content aContent( pMedium->GetName(),
2659 Reference<ucb::XCommandEnvironment>(),
2660 comphelper::getProcessComponentContext() );
2662 Any aResult = aContent.executeCommand( "getAllVersions", Any( ) );
2663 aResult >>= aVersions;
2665 catch ( const Exception & e )
2667 css::uno::Any anyEx = cppu::getCaughtException();
2668 throw lang::WrappedTargetRuntimeException( e.Message,
2669 e.Context, anyEx );
2672 return aVersions;
2675 bool SfxBaseModel::getBoolPropertyValue( const OUString& rName )
2677 bool bValue = false;
2678 if ( m_pData->m_pObjectShell.is() )
2680 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2681 if ( pMedium )
2685 ::ucbhelper::Content aContent( pMedium->GetName( ),
2686 utl::UCBContentHelper::getDefaultCommandEnvironment(),
2687 comphelper::getProcessComponentContext() );
2688 Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
2689 if ( xProps->hasPropertyByName( rName ) )
2691 aContent.getPropertyValue( rName ) >>= bValue;
2694 catch ( const Exception & )
2696 // Simply ignore it: it's likely the document isn't versionable in that case
2697 bValue = false;
2701 return bValue;
2704 sal_Bool SAL_CALL SfxBaseModel::isVersionable( )
2706 return getBoolPropertyValue( "IsVersionable" );
2709 sal_Bool SAL_CALL SfxBaseModel::canCheckOut( )
2711 return getBoolPropertyValue( "CanCheckOut" );
2714 sal_Bool SAL_CALL SfxBaseModel::canCancelCheckOut( )
2716 return getBoolPropertyValue( "CanCancelCheckOut" );
2719 sal_Bool SAL_CALL SfxBaseModel::canCheckIn( )
2721 return getBoolPropertyValue( "CanCheckIn" );
2724 void SfxBaseModel::loadCmisProperties( )
2726 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2727 if ( !pMedium )
2728 return;
2732 ::ucbhelper::Content aContent( pMedium->GetName( ),
2733 utl::UCBContentHelper::getDefaultCommandEnvironment(),
2734 comphelper::getProcessComponentContext() );
2735 Reference < beans::XPropertySetInfo > xProps = aContent.getProperties();
2736 static const OUStringLiteral aCmisProps( u"CmisProperties" );
2737 if ( xProps->hasPropertyByName( aCmisProps ) )
2739 Sequence< document::CmisProperty> aCmisProperties;
2740 aContent.getPropertyValue( aCmisProps ) >>= aCmisProperties;
2741 setCmisProperties( aCmisProperties );
2744 catch (const ucb::ContentCreationException &)
2747 catch (const ucb::CommandAbortedException &)
2752 SfxMedium* SfxBaseModel::handleLoadError( ErrCode nError, SfxMedium* pMedium )
2754 if (!nError)
2756 // No error condition.
2757 return pMedium;
2760 bool bSilent = false;
2761 const SfxBoolItem* pSilentItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_SILENT, false);
2762 if( pSilentItem )
2763 bSilent = pSilentItem->GetValue();
2765 bool bWarning = nError.IsWarning();
2766 if ( nError != ERRCODE_IO_BROKENPACKAGE && !bSilent )
2768 // broken package was handled already
2769 if ( SfxObjectShell::UseInteractionToHandleError(pMedium->GetInteractionHandler(), nError) && !bWarning)
2771 // abort loading (except for warnings)
2772 nError = ERRCODE_IO_ABORT;
2776 if ( m_pData->m_pObjectShell->GetMedium() != pMedium )
2778 // for whatever reason document now has another medium
2779 OSL_FAIL("Document has rejected the medium?!");
2780 delete pMedium;
2781 pMedium = nullptr;
2784 if ( !bWarning ) // #i30711# don't abort loading if it's only a warning
2786 nError = nError ? nError : ERRCODE_IO_CANTREAD;
2787 throw task::ErrorCodeIOException(
2788 "SfxBaseModel::handleLoadError: 0x" + nError.toHexString(),
2789 Reference< XInterface >(), sal_uInt32(nError));
2792 return pMedium;
2796 // SfxListener
2799 static void addTitle_Impl( Sequence < beans::PropertyValue >& rSeq, const OUString& rTitle )
2801 auto [begin, end] = asNonConstRange(rSeq);
2802 auto pProp = std::find_if(begin, end,
2803 [](const beans::PropertyValue& rProp) { return rProp.Name == "Title"; });
2804 if (pProp != end)
2806 pProp->Value <<= rTitle;
2808 else
2810 sal_Int32 nCount = rSeq.getLength();
2811 rSeq.realloc( nCount+1 );
2812 auto& el = rSeq.getArray()[nCount];
2813 el.Name = "Title";
2814 el.Value <<= rTitle;
2818 void SfxBaseModel::Notify( SfxBroadcaster& rBC ,
2819 const SfxHint& rHint )
2821 if ( !m_pData )
2822 return;
2824 if ( &rBC != m_pData->m_pObjectShell.get() )
2825 return;
2827 if ( rHint.GetId() == SfxHintId::DocChanged )
2828 changing();
2830 const SfxEventHint* pNamedHint = dynamic_cast<const SfxEventHint*>(&rHint);
2831 if ( pNamedHint )
2834 switch ( pNamedHint->GetEventId() )
2836 case SfxEventHintId::StorageChanged:
2838 if ( m_pData->m_xUIConfigurationManager.is()
2839 && m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
2841 Reference< embed::XStorage > xConfigStorage;
2842 static const OUStringLiteral aUIConfigFolderName( u"Configurations2" );
2844 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
2845 if ( !xConfigStorage.is() )
2846 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
2848 if ( xConfigStorage.is() || !m_pData->m_pObjectShell->GetStorage()->hasByName( aUIConfigFolderName ) )
2850 // the storage is different, since otherwise it could not be opened, so it must be exchanged
2851 m_pData->m_xUIConfigurationManager->setStorage( xConfigStorage );
2853 else
2855 OSL_FAIL( "Unexpected scenario!" );
2859 ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
2861 break;
2863 case SfxEventHintId::LoadFinished:
2865 impl_getPrintHelper();
2866 ListenForStorage_Impl( m_pData->m_pObjectShell->GetStorage() );
2867 m_pData->m_bModifiedSinceLastSave = false;
2869 break;
2871 case SfxEventHintId::SaveAsDocDone:
2873 m_pData->m_sURL = m_pData->m_pObjectShell->GetMedium()->GetName();
2875 SfxItemSet *pSet = m_pData->m_pObjectShell->GetMedium()->GetItemSet();
2876 Sequence< beans::PropertyValue > aArgs;
2877 TransformItems( SID_SAVEASDOC, *pSet, aArgs );
2878 addTitle_Impl( aArgs, m_pData->m_pObjectShell->GetTitle() );
2879 attachResource( m_pData->m_pObjectShell->GetMedium()->GetName(), aArgs );
2881 break;
2883 case SfxEventHintId::DocCreated:
2885 impl_getPrintHelper();
2886 m_pData->m_bModifiedSinceLastSave = false;
2888 break;
2890 case SfxEventHintId::ModifyChanged:
2892 m_pData->m_bModifiedSinceLastSave = isModified();
2894 break;
2895 default: break;
2898 const SfxViewEventHint* pViewHint = dynamic_cast<const SfxViewEventHint*>(&rHint);
2899 if (pViewHint)
2901 const SfxPrintingHint* pPrintingHint = dynamic_cast<const SfxPrintingHint*>(&rHint);
2902 postEvent_Impl( pNamedHint->GetEventName(), pViewHint->GetController(), pPrintingHint? Any(pPrintingHint->GetWhich()) : Any() );
2904 else
2905 postEvent_Impl( pNamedHint->GetEventName(), Reference< frame::XController2 >() );
2908 if ( rHint.GetId() == SfxHintId::TitleChanged )
2910 addTitle_Impl( m_pData->m_seqArguments, m_pData->m_pObjectShell->GetTitle() );
2911 postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::TITLECHANGED ) );
2913 else if ( rHint.GetId() == SfxHintId::ModeChanged )
2915 postEvent_Impl( GlobalEventConfig::GetEventName( GlobalEventId::MODECHANGED ) );
2920 // public impl.
2923 void SfxBaseModel::NotifyModifyListeners_Impl() const
2925 comphelper::OInterfaceContainerHelper2* pIC = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<util::XModifyListener>::get());
2926 if ( pIC )
2928 lang::EventObject aEvent( static_cast<frame::XModel *>(const_cast<SfxBaseModel *>(this)) );
2929 pIC->notifyEach( &util::XModifyListener::modified, aEvent );
2932 // this notification here is done too generously, we cannot simply assume that we're really modified
2933 // now, but we need to check it ...
2934 m_pData->m_bModifiedSinceLastSave = const_cast< SfxBaseModel* >( this )->isModified();
2937 void SfxBaseModel::changing()
2939 SfxModelGuard aGuard( *this );
2941 // the notification should not be sent if the document can not be modified
2942 if ( !m_pData->m_pObjectShell.is() || !m_pData->m_pObjectShell->IsEnableSetModified() )
2943 return;
2945 NotifyModifyListeners_Impl();
2949 // public impl.
2952 SfxObjectShell* SfxBaseModel::GetObjectShell() const
2954 return m_pData ? m_pData->m_pObjectShell.get() : nullptr;
2958 // public impl.
2961 bool SfxBaseModel::IsInitialized() const
2963 if ( !m_pData || !m_pData->m_pObjectShell.is() )
2965 OSL_FAIL( "SfxBaseModel::IsInitialized: this should have been caught earlier!" );
2966 return false;
2969 return m_pData->m_pObjectShell->GetMedium() != nullptr;
2972 void SfxBaseModel::MethodEntryCheck( const bool i_mustBeInitialized ) const
2974 if ( impl_isDisposed() )
2975 throw lang::DisposedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
2976 if ( i_mustBeInitialized && !IsInitialized() )
2977 throw lang::NotInitializedException( OUString(), *const_cast< SfxBaseModel* >( this ) );
2980 bool SfxBaseModel::impl_isDisposed() const
2982 return ( m_pData == nullptr ) ;
2986 // private impl.
2989 OUString SfxBaseModel::GetMediumFilterName_Impl() const
2991 std::shared_ptr<const SfxFilter> pFilter;
2992 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
2993 if ( pMedium )
2994 pFilter = pMedium->GetFilter();
2996 if ( pFilter )
2997 return pFilter->GetName();
2999 return OUString();
3002 void SfxBaseModel::impl_store( const OUString& sURL ,
3003 const Sequence< beans::PropertyValue >& seqArguments ,
3004 bool bSaveTo )
3006 if( sURL.isEmpty() )
3007 throw frame::IllegalArgumentIOException();
3009 bool bSaved = false;
3010 if ( !bSaveTo && m_pData->m_pObjectShell.is() && !sURL.isEmpty()
3011 && !sURL.startsWith( "private:stream" )
3012 && ::utl::UCBContentHelper::EqualURLs( getLocation(), sURL ) )
3014 // this is the same file URL as the current document location, try to use storeOwn if possible
3016 ::comphelper::SequenceAsHashMap aArgHash( seqArguments );
3017 static const OUStringLiteral aFilterString( u"FilterName" );
3018 const OUString aFilterName( aArgHash.getUnpackedValueOrDefault( aFilterString, OUString() ) );
3019 if ( !aFilterName.isEmpty() )
3021 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
3022 if ( pMedium )
3024 const std::shared_ptr<const SfxFilter>& pFilter = pMedium->GetFilter();
3025 if ( pFilter && aFilterName == pFilter->GetFilterName() )
3027 // #i119366# - If the former file saving with password, do not trying in StoreSelf anyway...
3028 bool bFormerPassword = false;
3030 uno::Sequence< beans::NamedValue > aOldEncryptionData;
3031 if (GetEncryptionData_Impl( pMedium->GetItemSet(), aOldEncryptionData ))
3033 bFormerPassword = true;
3036 if ( !bFormerPassword )
3038 aArgHash.erase( aFilterString );
3039 aArgHash.erase( "URL" );
3043 storeSelf( aArgHash.getAsConstPropertyValueList() );
3044 bSaved = true;
3046 catch( const lang::IllegalArgumentException& )
3048 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
3049 // some additional arguments do not allow to use saving, SaveAs should be done
3050 // but only for normal documents, the shared documents would be overwritten in this case
3051 // that would mean an information loss
3052 // TODO/LATER: need a new interaction for this case
3053 if ( m_pData->m_pObjectShell->IsDocShared() )
3055 uno::Sequence< beans::NamedValue > aNewEncryptionData = aArgHash.getUnpackedValueOrDefault("EncryptionData", uno::Sequence< beans::NamedValue >() );
3056 if ( !aNewEncryptionData.hasElements() )
3058 aNewEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( aArgHash.getUnpackedValueOrDefault("Password", OUString()) );
3061 uno::Sequence< beans::NamedValue > aOldEncryptionData;
3062 (void)GetEncryptionData_Impl( pMedium->GetItemSet(), aOldEncryptionData );
3064 if ( !aOldEncryptionData.hasElements() && !aNewEncryptionData.hasElements() )
3065 throw;
3066 else
3068 // if the password is changed a special error should be used in case of shared document
3069 throw task::ErrorCodeIOException("Can not change password for shared document.", uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_SFX_SHARED_NOPASSWORDCHANGE) );
3072 #endif
3080 if ( bSaved || !m_pData->m_pObjectShell.is() )
3081 return;
3083 SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDoc : SfxEventHintId::SaveAsDoc, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOC : GlobalEventId::SAVEASDOC ),
3084 m_pData->m_pObjectShell.get() ) );
3086 std::optional<SfxAllItemSet> pItemSet(SfxGetpApp()->GetPool());
3087 pItemSet->Put(SfxStringItem(SID_FILE_NAME, sURL));
3088 if ( bSaveTo )
3089 pItemSet->Put(SfxBoolItem(SID_SAVETO, true));
3091 TransformParameters(SID_SAVEASDOC, seqArguments, *pItemSet);
3093 const SfxBoolItem* pCopyStreamItem = pItemSet->GetItem<SfxBoolItem>(SID_COPY_STREAM_IF_POSSIBLE, false);
3095 if ( pCopyStreamItem && pCopyStreamItem->GetValue() && !bSaveTo )
3097 throw frame::IllegalArgumentIOException(
3098 "CopyStreamIfPossible parameter is not acceptable for storeAsURL() call!" );
3101 sal_uInt32 nModifyPasswordHash = 0;
3102 Sequence< beans::PropertyValue > aModifyPasswordInfo;
3103 const SfxUnoAnyItem* pModifyPasswordInfoItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_MODIFYPASSWORDINFO, false);
3104 if ( pModifyPasswordInfoItem )
3106 // it contains either a simple hash or a set of PropertyValues
3107 // TODO/LATER: the sequence of PropertyValue should replace the hash completely in future
3108 sal_Int32 nMPHTmp = 0;
3109 pModifyPasswordInfoItem->GetValue() >>= nMPHTmp;
3110 nModifyPasswordHash = static_cast<sal_uInt32>(nMPHTmp);
3111 pModifyPasswordInfoItem->GetValue() >>= aModifyPasswordInfo;
3113 pItemSet->ClearItem(SID_MODIFYPASSWORDINFO);
3114 sal_uInt32 nOldModifyPasswordHash = m_pData->m_pObjectShell->GetModifyPasswordHash();
3115 m_pData->m_pObjectShell->SetModifyPasswordHash( nModifyPasswordHash );
3116 Sequence< beans::PropertyValue > aOldModifyPasswordInfo = m_pData->m_pObjectShell->GetModifyPasswordInfo();
3117 m_pData->m_pObjectShell->SetModifyPasswordInfo( aModifyPasswordInfo );
3119 // since saving a document modifies its DocumentProperties, the current
3120 // DocumentProperties must be saved on "SaveTo", so it can be restored
3121 // after saving
3122 bool bCopyTo = bSaveTo ||
3123 m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED;
3124 Reference<document::XDocumentProperties> xOldDocProps;
3125 if ( bCopyTo )
3127 xOldDocProps = getDocumentProperties();
3128 const Reference<util::XCloneable> xCloneable(xOldDocProps,
3129 UNO_QUERY_THROW);
3130 const Reference<document::XDocumentProperties> xNewDocProps(
3131 xCloneable->createClone(), UNO_QUERY_THROW);
3132 m_pData->m_xDocumentProperties = xNewDocProps;
3135 bool bRet = m_pData->m_pObjectShell->APISaveAs_Impl(sURL, *pItemSet, seqArguments);
3137 if ( bCopyTo )
3139 // restore DocumentProperties if a copy was created
3140 m_pData->m_xDocumentProperties = xOldDocProps;
3143 Reference < task::XInteractionHandler > xHandler;
3144 const SfxUnoAnyItem* pItem = pItemSet->GetItem<SfxUnoAnyItem>(SID_INTERACTIONHANDLER, false);
3145 if ( pItem )
3146 pItem->GetValue() >>= xHandler;
3148 pItemSet.reset();
3150 ErrCode nErrCode = m_pData->m_pObjectShell->GetErrorCode();
3151 if ( !bRet && !nErrCode )
3153 SAL_WARN("sfx.doc", "Storing has failed, no error is set!");
3154 nErrCode = ERRCODE_IO_CANTWRITE;
3156 m_pData->m_pObjectShell->ResetError();
3158 if ( bRet )
3160 if ( nErrCode )
3162 // must be a warning - use Interactionhandler if possible or abandon
3163 if ( xHandler.is() )
3165 // TODO/LATER: a general way to set the error context should be available
3166 SfxErrorContext aEc( ERRCTX_SFX_SAVEASDOC, m_pData->m_pObjectShell->GetTitle() );
3168 task::ErrorCodeRequest aErrorCode;
3169 aErrorCode.ErrCode = sal_uInt32(nErrCode);
3170 SfxMedium::CallApproveHandler( xHandler, makeAny( aErrorCode ), false );
3174 if ( !bSaveTo )
3176 m_pData->m_aPreusedFilterName = GetMediumFilterName_Impl();
3177 m_pData->m_pObjectShell->SetModifyPasswordEntered();
3179 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveAsDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVEASDOCDONE), m_pData->m_pObjectShell.get() ) );
3181 else
3183 m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
3184 m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
3186 SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::SaveToDocDone, GlobalEventConfig::GetEventName(GlobalEventId::SAVETODOCDONE), m_pData->m_pObjectShell.get() ) );
3189 else
3191 m_pData->m_pObjectShell->SetModifyPasswordHash( nOldModifyPasswordHash );
3192 m_pData->m_pObjectShell->SetModifyPasswordInfo( aOldModifyPasswordInfo );
3195 SfxGetpApp()->NotifyEvent( SfxEventHint( bSaveTo ? SfxEventHintId::SaveToDocFailed : SfxEventHintId::SaveAsDocFailed, GlobalEventConfig::GetEventName( bSaveTo ? GlobalEventId::SAVETODOCFAILED : GlobalEventId::SAVEASDOCFAILED),
3196 m_pData->m_pObjectShell.get() ) );
3198 std::stringstream aErrCode;
3199 aErrCode << nErrCode;
3200 throw task::ErrorCodeIOException(
3201 "SfxBaseModel::impl_store <" + sURL + "> failed: " + OUString::fromUtf8(aErrCode.str().c_str()),
3202 Reference< XInterface >(), sal_uInt32(nErrCode));
3207 namespace {
3208 template< typename ListenerT, typename EventT >
3209 class NotifySingleListenerIgnoreRE
3211 private:
3212 typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
3213 NotificationMethod m_pMethod;
3214 const EventT& m_rEvent;
3215 public:
3216 NotifySingleListenerIgnoreRE( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
3218 void operator()( const Reference<ListenerT>& listener ) const
3222 (listener.get()->*m_pMethod)( m_rEvent );
3224 catch( RuntimeException& )
3226 // this exception is ignored to avoid problems with invalid listeners, the listener should be probably thrown away in future
3230 } // anonymous namespace
3232 void SfxBaseModel::postEvent_Impl( const OUString& aName, const Reference< frame::XController2 >& xController, const Any& supplement )
3234 // object already disposed?
3235 if ( impl_isDisposed() )
3236 return;
3238 // keep m_pData alive, if notified target would dispose the document
3239 std::shared_ptr<IMPL_SfxBaseModel_DataContainer> xKeepAlive(m_pData);
3241 // also make sure this object doesn't self-destruct while notifying
3242 rtl::Reference<SfxBaseModel> xHoldAlive(this);
3244 DBG_ASSERT( !aName.isEmpty(), "Empty event name!" );
3245 if (aName.isEmpty())
3246 return;
3248 comphelper::OInterfaceContainerHelper2* pIC =
3249 m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XDocumentEventListener>::get());
3250 if ( pIC )
3252 SAL_INFO("sfx.doc", "SfxDocumentEvent: " + aName);
3254 document::DocumentEvent aDocumentEvent( static_cast<frame::XModel*>(this), aName, xController, supplement );
3256 pIC->forEach< document::XDocumentEventListener, NotifySingleListenerIgnoreRE< document::XDocumentEventListener, document::DocumentEvent > >(
3257 NotifySingleListenerIgnoreRE< document::XDocumentEventListener, document::DocumentEvent >(
3258 &document::XDocumentEventListener::documentEventOccured,
3259 aDocumentEvent ) );
3262 pIC = m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XEventListener>::get());
3263 if ( pIC )
3265 SAL_INFO("sfx.doc", "SfxEvent: " + aName);
3267 document::EventObject aEvent( static_cast<frame::XModel*>(this), aName );
3269 pIC->forEach< document::XEventListener, NotifySingleListenerIgnoreRE< document::XEventListener, document::EventObject > >(
3270 NotifySingleListenerIgnoreRE< document::XEventListener, document::EventObject >(
3271 &document::XEventListener::notifyEvent,
3272 aEvent ) );
3277 Reference < container::XIndexAccess > SAL_CALL SfxBaseModel::getViewData()
3279 SfxModelGuard aGuard( *this );
3281 if ( m_pData->m_pObjectShell.is() && !m_pData->m_contViewData.is() )
3283 SfxViewFrame *pActFrame = SfxViewFrame::Current();
3284 if ( !pActFrame || pActFrame->GetObjectShell() != m_pData->m_pObjectShell.get() )
3285 pActFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() );
3287 if ( !pActFrame || !pActFrame->GetViewShell() )
3288 // currently no frame for this document at all or View is under construction
3289 return Reference < container::XIndexAccess >();
3291 m_pData->m_contViewData = document::IndexedPropertyValues::create( ::comphelper::getProcessComponentContext() );
3293 if ( !m_pData->m_contViewData.is() )
3295 // error: no container class available!
3296 return Reference < container::XIndexAccess >();
3299 Reference < container::XIndexContainer > xCont( m_pData->m_contViewData, UNO_QUERY );
3300 sal_Int32 nCount = 0;
3301 Sequence < beans::PropertyValue > aSeq;
3302 for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get() ); pFrame;
3303 pFrame = SfxViewFrame::GetNext( *pFrame, m_pData->m_pObjectShell.get() ) )
3305 bool bIsActive = ( pFrame == pActFrame );
3306 pFrame->GetViewShell()->WriteUserDataSequence( aSeq );
3307 xCont->insertByIndex( bIsActive ? 0 : nCount, Any(aSeq) );
3308 nCount++;
3312 return m_pData->m_contViewData;
3315 void SAL_CALL SfxBaseModel::setViewData( const Reference < container::XIndexAccess >& aData )
3317 SfxModelGuard aGuard( *this );
3319 m_pData->m_contViewData = aData;
3322 /** calls all XEventListeners */
3323 void SfxBaseModel::notifyEvent( const document::EventObject& aEvent ) const
3325 // object already disposed?
3326 if ( impl_isDisposed() )
3327 return;
3329 comphelper::OInterfaceContainerHelper2* pIC = m_pData->m_aInterfaceContainer.getContainer(
3330 cppu::UnoType<document::XEventListener>::get());
3331 if( !pIC )
3333 return;
3335 comphelper::OInterfaceIteratorHelper2 aIt( *pIC );
3336 while( aIt.hasMoreElements() )
3340 static_cast<document::XEventListener *>(aIt.next())->notifyEvent( aEvent );
3342 catch( RuntimeException& )
3344 aIt.remove();
3347 // for right now, we're only doing the event that this particular performance problem needed
3348 if (aEvent.EventName == "ShapeModified")
3350 uno::Reference<drawing::XShape> xShape(aEvent.Source, uno::UNO_QUERY);
3351 if (xShape.is())
3353 auto it = m_pData->maShapeListeners.find(xShape);
3354 if (it != m_pData->maShapeListeners.end())
3355 for (auto const & rListenerUnoRef : it->second)
3356 rListenerUnoRef->notifyShapeEvent(aEvent);
3361 /** returns true if someone added a XEventListener to this XEventBroadcaster */
3362 bool SfxBaseModel::hasEventListeners() const
3364 return !impl_isDisposed()
3365 && ( (nullptr != m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XEventListener>::get()) )
3366 || !m_pData->maShapeListeners.empty());
3369 void SAL_CALL SfxBaseModel::addPrintJobListener( const Reference< view::XPrintJobListener >& xListener )
3371 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3373 impl_getPrintHelper();
3374 Reference < view::XPrintJobBroadcaster > xPJB( m_pData->m_xPrintable, UNO_QUERY );
3375 if ( xPJB.is() )
3376 xPJB->addPrintJobListener( xListener );
3379 void SAL_CALL SfxBaseModel::removePrintJobListener( const Reference< view::XPrintJobListener >& xListener )
3381 SfxModelGuard aGuard( *this );
3383 impl_getPrintHelper();
3384 Reference < view::XPrintJobBroadcaster > xPJB( m_pData->m_xPrintable, UNO_QUERY );
3385 if ( xPJB.is() )
3386 xPJB->removePrintJobListener( xListener );
3389 sal_Int64 SAL_CALL SfxBaseModel::getSomething( const Sequence< sal_Int8 >& aIdentifier )
3391 SvGlobalName aName( aIdentifier );
3392 if (aName == SvGlobalName( SFX_GLOBAL_CLASSID ))
3394 SolarMutexGuard aGuard;
3395 SfxObjectShell *const pObjectShell(GetObjectShell());
3396 if (pObjectShell)
3398 return comphelper::getSomething_cast(pObjectShell);
3402 return 0;
3406 // XDocumentSubStorageSupplier
3409 void SfxBaseModel::ListenForStorage_Impl( const Reference< embed::XStorage >& xStorage )
3411 Reference< util::XModifiable > xModifiable( xStorage, UNO_QUERY );
3412 if ( xModifiable.is() )
3414 if ( !m_pData->m_pStorageModifyListen.is() )
3416 m_pData->m_pStorageModifyListen = new ::sfx2::DocumentStorageModifyListener( *m_pData, Application::GetSolarMutex() );
3419 // no need to deregister the listening for old storage since it should be disposed automatically
3420 xModifiable->addModifyListener( m_pData->m_pStorageModifyListen );
3424 Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode )
3426 SfxModelGuard aGuard( *this );
3428 Reference< embed::XStorage > xResult;
3429 if ( m_pData->m_pObjectShell.is() )
3431 Reference< embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
3432 if ( xStorage.is() )
3436 xResult = xStorage->openStorageElement( aStorageName, nMode );
3438 catch ( Exception& )
3444 return xResult;
3447 Sequence< OUString > SAL_CALL SfxBaseModel::getDocumentSubStoragesNames()
3449 SfxModelGuard aGuard( *this );
3451 Sequence< OUString > aResult;
3452 bool bSuccess = false;
3453 if ( m_pData->m_pObjectShell.is() )
3455 Reference < embed::XStorage > xStorage = m_pData->m_pObjectShell->GetStorage();
3456 if ( xStorage.is() )
3458 const Sequence< OUString > aTemp = xStorage->getElementNames();
3459 sal_Int32 nResultSize = 0;
3460 for ( const auto& rName : aTemp )
3462 if ( xStorage->isStorageElement( rName ) )
3464 aResult.realloc( ++nResultSize );
3465 aResult.getArray()[ nResultSize - 1 ] = rName;
3469 bSuccess = true;
3473 if ( !bSuccess )
3474 throw io::IOException();
3476 return aResult;
3480 // XScriptProviderSupplier
3483 Reference< script::provider::XScriptProvider > SAL_CALL SfxBaseModel::getScriptProvider()
3485 SfxModelGuard aGuard( *this );
3487 Reference< script::provider::XScriptProviderFactory > xScriptProviderFactory =
3488 script::provider::theMasterScriptProviderFactory::get( ::comphelper::getProcessComponentContext() );
3490 Reference< XScriptInvocationContext > xScriptContext( this );
3492 Reference< script::provider::XScriptProvider > xScriptProvider(
3493 xScriptProviderFactory->createScriptProvider( makeAny( xScriptContext ) ),
3494 UNO_SET_THROW );
3496 return xScriptProvider;
3500 // XUIConfigurationManagerSupplier
3503 OUString const & SfxBaseModel::getRuntimeUID() const
3505 OSL_ENSURE( !m_pData->m_sRuntimeUID.isEmpty(),
3506 "SfxBaseModel::getRuntimeUID - ID is empty!" );
3507 return m_pData->m_sRuntimeUID;
3510 bool SfxBaseModel::hasValidSignatures() const
3512 SolarMutexGuard aGuard;
3513 if ( m_pData->m_pObjectShell.is() )
3514 return ( m_pData->m_pObjectShell->ImplGetSignatureState() == SignatureState::OK );
3515 return false;
3518 void SfxBaseModel::getGrabBagItem(css::uno::Any& rVal) const
3520 if (m_pData->m_xGrabBagItem)
3521 m_pData->m_xGrabBagItem->QueryValue(rVal);
3522 else
3523 rVal <<= uno::Sequence<beans::PropertyValue>();
3526 void SfxBaseModel::setGrabBagItem(const css::uno::Any& rVal)
3528 if (!m_pData->m_xGrabBagItem)
3529 m_pData->m_xGrabBagItem = std::make_shared<SfxGrabBagItem>();
3531 m_pData->m_xGrabBagItem->PutValue(rVal, 0);
3534 static void GetCommandFromSequence( OUString& rCommand, sal_Int32& nIndex, const Sequence< beans::PropertyValue >& rSeqPropValue )
3536 nIndex = -1;
3538 auto pPropValue = std::find_if(rSeqPropValue.begin(), rSeqPropValue.end(),
3539 [](const beans::PropertyValue& rPropValue) { return rPropValue.Name == "Command"; });
3540 if (pPropValue != rSeqPropValue.end())
3542 pPropValue->Value >>= rCommand;
3543 nIndex = static_cast<sal_Int32>(std::distance(rSeqPropValue.begin(), pPropValue));
3547 static void ConvertSlotsToCommands( SfxObjectShell const * pDoc, Reference< container::XIndexContainer > const & rToolbarDefinition )
3549 if ( !pDoc )
3550 return;
3552 SfxModule* pModule( pDoc->GetFactory().GetModule() );
3553 Sequence< beans::PropertyValue > aSeqPropValue;
3555 for ( sal_Int32 i = 0; i < rToolbarDefinition->getCount(); i++ )
3557 if ( rToolbarDefinition->getByIndex( i ) >>= aSeqPropValue )
3559 OUString aCommand;
3560 sal_Int32 nIndex( -1 );
3561 GetCommandFromSequence( aCommand, nIndex, aSeqPropValue );
3562 if ( nIndex >= 0 && aCommand.startsWith( "slot:" ) )
3564 const sal_uInt16 nSlot = aCommand.copy( 5 ).toInt32();
3566 // We have to replace the old "slot-Command" with our new ".uno:-Command"
3567 const SfxSlot* pSlot = pModule->GetSlotPool()->GetSlot( nSlot );
3568 if ( pSlot )
3570 OUStringBuffer aStrBuf( ".uno:" );
3571 aStrBuf.appendAscii( pSlot->GetUnoName() );
3573 aCommand = aStrBuf.makeStringAndClear();
3574 aSeqPropValue.getArray()[nIndex].Value <<= aCommand;
3575 rToolbarDefinition->replaceByIndex( i, Any( aSeqPropValue ));
3582 Reference< ui::XUIConfigurationManager > SAL_CALL SfxBaseModel::getUIConfigurationManager()
3584 return Reference< ui::XUIConfigurationManager >( getUIConfigurationManager2(), UNO_QUERY_THROW );
3587 Reference< ui::XUIConfigurationManager2 > SfxBaseModel::getUIConfigurationManager2()
3589 SfxModelGuard aGuard( *this );
3591 if ( !m_pData->m_xUIConfigurationManager.is() )
3593 Reference< ui::XUIConfigurationManager2 > xNewUIConfMan =
3594 ui::UIConfigurationManager::create( comphelper::getProcessComponentContext() );
3596 Reference< embed::XStorage > xConfigStorage;
3598 OUString aUIConfigFolderName( "Configurations2" );
3599 // First try to open with READWRITE and then READ
3600 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READWRITE );
3601 if ( xConfigStorage.is() )
3603 static const OUStringLiteral aMediaTypeProp( u"MediaType" );
3604 OUString aMediaType;
3605 Reference< beans::XPropertySet > xPropSet( xConfigStorage, UNO_QUERY );
3606 Any a = xPropSet->getPropertyValue( aMediaTypeProp );
3607 if ( !( a >>= aMediaType ) || aMediaType.isEmpty())
3609 xPropSet->setPropertyValue( aMediaTypeProp, Any(OUString("application/vnd.sun.xml.ui.configuration")) );
3612 else
3613 xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, embed::ElementModes::READ );
3615 // initialize ui configuration manager with document substorage
3616 xNewUIConfMan->setStorage( xConfigStorage );
3618 // embedded objects did not support local configuration data until OOo 3.0, so there's nothing to
3619 // migrate
3620 if ( m_pData->m_pObjectShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
3622 // Import old UI configuration from OOo 1.x
3624 // Try to open with READ
3625 Reference< embed::XStorage > xOOo1ConfigStorage = getDocumentSubStorage( "Configurations", embed::ElementModes::READ );
3626 if ( xOOo1ConfigStorage.is() )
3628 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
3629 std::vector< Reference< container::XIndexContainer > > rToolbars;
3631 bool bImported = framework::UIConfigurationImporterOOo1x::ImportCustomToolbars(
3632 xNewUIConfMan, rToolbars, xContext, xOOo1ConfigStorage );
3633 if ( bImported )
3635 SfxObjectShell* pObjShell = SfxBaseModel::GetObjectShell();
3637 for ( size_t i = 0; i < rToolbars.size(); i++ )
3639 const OUString sId(OUString::number( i + 1 ));
3640 const OUString aCustomTbxName = "private:resource/toolbar/custom_OOo1x_" + sId;
3642 Reference< container::XIndexContainer > xToolbar = rToolbars[i];
3643 ConvertSlotsToCommands( pObjShell, xToolbar );
3644 if ( !xNewUIConfMan->hasSettings( aCustomTbxName ))
3646 // Set UIName for the toolbar with container property
3647 Reference< beans::XPropertySet > xPropSet( xToolbar, UNO_QUERY );
3648 if ( xPropSet.is() )
3652 xPropSet->setPropertyValue( "UIName", Any( "Toolbar " + sId ) );
3654 catch ( beans::UnknownPropertyException& )
3659 xNewUIConfMan->insertSettings( aCustomTbxName, xToolbar );
3660 xNewUIConfMan->store();
3667 m_pData->m_xUIConfigurationManager = xNewUIConfMan;
3670 return m_pData->m_xUIConfigurationManager;
3674 // XVisualObject
3677 void SAL_CALL SfxBaseModel::setVisualAreaSize( sal_Int64 nAspect, const awt::Size& aSize )
3679 SfxModelGuard aGuard( *this );
3681 if ( !m_pData->m_pObjectShell.is() )
3682 throw Exception("no object shell", nullptr); // TODO: error handling
3684 SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst( m_pData->m_pObjectShell.get(), false );
3685 if ( pViewFrm && m_pData->m_pObjectShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !pViewFrm->GetFrame().IsInPlace() )
3687 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( pViewFrm->GetFrame().GetFrameInterface()->getContainerWindow() );
3688 Size aWinSize = pWindow->GetSizePixel();
3689 awt::Size aCurrent = getVisualAreaSize( nAspect );
3690 Size aDiff( aSize.Width-aCurrent.Width, aSize.Height-aCurrent.Height );
3691 aDiff = pViewFrm->GetViewShell()->GetWindow()->LogicToPixel( aDiff );
3692 aWinSize.AdjustWidth(aDiff.Width() );
3693 aWinSize.AdjustHeight(aDiff.Height() );
3694 pWindow->SetSizePixel( aWinSize );
3696 else
3698 tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
3699 aTmpRect.SetSize( Size( aSize.Width, aSize.Height ) );
3700 m_pData->m_pObjectShell->SetVisArea( aTmpRect );
3704 awt::Size SAL_CALL SfxBaseModel::getVisualAreaSize( sal_Int64 /*nAspect*/ )
3706 SfxModelGuard aGuard( *this );
3708 if ( !m_pData->m_pObjectShell.is() )
3709 throw Exception("no object shell", nullptr); // TODO: error handling
3711 tools::Rectangle aTmpRect = m_pData->m_pObjectShell->GetVisArea( ASPECT_CONTENT );
3713 return awt::Size( aTmpRect.GetWidth(), aTmpRect.GetHeight() );
3717 sal_Int32 SAL_CALL SfxBaseModel::getMapUnit( sal_Int64 /*nAspect*/ )
3719 SfxModelGuard aGuard( *this );
3721 if ( !m_pData->m_pObjectShell.is() )
3722 throw Exception("no object shell", nullptr); // TODO: error handling
3724 return VCLUnoHelper::VCL2UnoEmbedMapUnit( m_pData->m_pObjectShell->GetMapUnit() );
3727 embed::VisualRepresentation SAL_CALL SfxBaseModel::getPreferredVisualRepresentation( ::sal_Int64 /*nAspect*/ )
3729 SfxModelGuard aGuard( *this );
3731 datatransfer::DataFlavor aDataFlavor(
3732 "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"",
3733 "GDIMetaFile",
3734 cppu::UnoType<Sequence< sal_Int8 >>::get() );
3736 embed::VisualRepresentation aVisualRepresentation;
3737 aVisualRepresentation.Data = getTransferData( aDataFlavor );
3738 aVisualRepresentation.Flavor = aDataFlavor;
3740 return aVisualRepresentation;
3744 // XStorageBasedDocument
3747 void SAL_CALL SfxBaseModel::loadFromStorage( const Reference< embed::XStorage >& xStorage,
3748 const Sequence< beans::PropertyValue >& aMediaDescriptor )
3750 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3751 if ( IsInitialized() )
3752 throw frame::DoubleInitializationException( OUString(), *this );
3754 // after i36090 is fixed the pool from object shell can be used
3755 // SfxAllItemSet aSet( m_pData->m_pObjectShell->GetPool() );
3756 SfxAllItemSet aSet( SfxGetpApp()->GetPool() );
3758 // the BaseURL is part of the ItemSet
3759 SfxMedium* pMedium = new SfxMedium( xStorage, OUString() );
3760 TransformParameters( SID_OPENDOC, aMediaDescriptor, aSet );
3761 pMedium->GetItemSet()->Put( aSet );
3763 // allow to use an interactionhandler (if there is one)
3764 pMedium->UseInteractionHandler( true );
3766 const SfxBoolItem* pTemplateItem = aSet.GetItem<SfxBoolItem>(SID_TEMPLATE, false);
3767 bool bTemplate = pTemplateItem && pTemplateItem->GetValue();
3768 m_pData->m_pObjectShell->SetActivateEvent_Impl( bTemplate ? SfxEventHintId::CreateDoc : SfxEventHintId::OpenDoc );
3769 m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
3771 // load document
3772 if ( !m_pData->m_pObjectShell->DoLoad(pMedium) )
3774 ErrCode nError = m_pData->m_pObjectShell->GetErrorCode();
3775 nError = nError ? nError : ERRCODE_IO_CANTREAD;
3776 throw task::ErrorCodeIOException(
3777 "SfxBaseModel::loadFromStorage: " + nError.toHexString(),
3778 Reference< XInterface >(), sal_uInt32(nError));
3780 loadCmisProperties( );
3783 void SAL_CALL SfxBaseModel::storeToStorage( const Reference< embed::XStorage >& xStorage,
3784 const Sequence< beans::PropertyValue >& aMediaDescriptor )
3786 SfxModelGuard aGuard( *this );
3788 if ( !m_pData->m_pObjectShell.is() )
3789 throw io::IOException(); // TODO:
3791 auto xSet = std::make_shared<SfxAllItemSet>(m_pData->m_pObjectShell->GetPool());
3792 TransformParameters( SID_SAVEASDOC, aMediaDescriptor, *xSet );
3794 // TODO/LATER: maybe a special URL "private:storage" should be used
3795 const SfxStringItem* pItem = xSet->GetItem<SfxStringItem>(SID_FILTER_NAME, false);
3796 sal_Int32 nVersion = SOFFICE_FILEFORMAT_CURRENT;
3797 if( pItem )
3799 std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( pItem->GetValue() );
3800 if ( pFilter && pFilter->UsesStorage() )
3801 nVersion = pFilter->GetVersion();
3804 bool bSuccess = false;
3805 if ( xStorage == m_pData->m_pObjectShell->GetStorage() )
3807 // storing to the own storage
3808 bSuccess = m_pData->m_pObjectShell->DoSave();
3810 else
3812 // TODO/LATER: if the provided storage has some data inside the storing might fail, probably the storage must be truncated
3813 // TODO/LATER: is it possible to have a template here?
3814 m_pData->m_pObjectShell->SetupStorage( xStorage, nVersion, false );
3816 // BaseURL is part of the ItemSet
3817 SfxMedium aMedium( xStorage, OUString(), xSet );
3818 aMedium.CanDisposeStorage_Impl( false );
3819 if ( aMedium.GetFilter() )
3821 // storing without a valid filter will often crash
3822 bSuccess = m_pData->m_pObjectShell->DoSaveObjectAs( aMedium, true );
3823 m_pData->m_pObjectShell->DoSaveCompleted();
3827 ErrCode nError = m_pData->m_pObjectShell->GetErrorCode();
3828 m_pData->m_pObjectShell->ResetError();
3830 // the warnings are currently not transported
3831 if ( !bSuccess )
3833 nError = nError ? nError : ERRCODE_IO_GENERAL;
3834 throw task::ErrorCodeIOException(
3835 "SfxBaseModel::storeToStorage: " + nError.toHexString(),
3836 Reference< XInterface >(), sal_uInt32(nError));
3840 void SAL_CALL SfxBaseModel::switchToStorage( const Reference< embed::XStorage >& xStorage )
3842 SfxModelGuard aGuard( *this );
3844 if ( !m_pData->m_pObjectShell.is() )
3845 throw io::IOException(); // TODO:
3847 // the persistence should be switched only if the storage is different
3848 if ( xStorage != m_pData->m_pObjectShell->GetStorage() )
3850 if ( !m_pData->m_pObjectShell->SwitchPersistence( xStorage ) )
3852 ErrCode nError = m_pData->m_pObjectShell->GetErrorCode();
3853 nError = nError ? nError : ERRCODE_IO_GENERAL;
3854 throw task::ErrorCodeIOException(
3855 "SfxBaseModel::switchToStorage: " + nError.toHexString(),
3856 Reference< XInterface >(), sal_uInt32(nError));
3858 else
3860 // UICfgMgr has a reference to the old storage, update it
3861 getUIConfigurationManager2()->setStorage( xStorage );
3864 m_pData->m_pObjectShell->Get_Impl()->bOwnsStorage = false;
3867 Reference< embed::XStorage > SAL_CALL SfxBaseModel::getDocumentStorage()
3869 SfxModelGuard aGuard( *this );
3871 if ( !m_pData->m_pObjectShell.is() )
3872 throw io::IOException(); // TODO
3874 return m_pData->m_pObjectShell->GetStorage();
3877 void SAL_CALL SfxBaseModel::addStorageChangeListener(
3878 const Reference< document::XStorageChangeListener >& xListener )
3880 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
3882 m_pData->m_aInterfaceContainer.addInterface(
3883 cppu::UnoType<document::XStorageChangeListener>::get(), xListener );
3886 void SAL_CALL SfxBaseModel::removeStorageChangeListener(
3887 const Reference< document::XStorageChangeListener >& xListener )
3889 SfxModelGuard aGuard( *this );
3891 m_pData->m_aInterfaceContainer.removeInterface(
3892 cppu::UnoType<document::XStorageChangeListener>::get(), xListener );
3895 void SfxBaseModel::impl_getPrintHelper()
3897 if ( m_pData->m_xPrintable.is() )
3898 return;
3899 m_pData->m_xPrintable = new SfxPrintHelper();
3900 Reference < lang::XInitialization > xInit( m_pData->m_xPrintable, UNO_QUERY );
3901 xInit->initialize( { Any(Reference < frame::XModel > (this)) } );
3902 Reference < view::XPrintJobBroadcaster > xBrd( m_pData->m_xPrintable, UNO_QUERY );
3903 xBrd->addPrintJobListener( new SfxPrintHelperListener_Impl( m_pData.get() ) );
3907 // css.frame.XModule
3908 void SAL_CALL SfxBaseModel::setIdentifier(const OUString& Identifier)
3910 SfxModelGuard aGuard( *this );
3911 m_pData->m_sModuleIdentifier = Identifier;
3915 // css.frame.XModule
3916 OUString SAL_CALL SfxBaseModel::getIdentifier()
3918 SfxModelGuard aGuard( *this );
3919 if (!m_pData->m_sModuleIdentifier.isEmpty())
3920 return m_pData->m_sModuleIdentifier;
3921 if (m_pData->m_pObjectShell.is())
3922 return m_pData->m_pObjectShell->GetFactory().GetDocumentServiceName();
3923 return OUString();
3927 Reference< frame::XTitle > SfxBaseModel::impl_getTitleHelper ()
3929 SfxModelGuard aGuard( *this );
3931 if ( ! m_pData->m_xTitleHelper.is ())
3933 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
3934 Reference< frame::XUntitledNumbers > xDesktop( frame::Desktop::create(xContext), UNO_QUERY_THROW);
3936 m_pData->m_xTitleHelper = new ::framework::TitleHelper(xContext, Reference< frame::XModel >(this), xDesktop);
3939 return m_pData->m_xTitleHelper;
3943 Reference< frame::XUntitledNumbers > SfxBaseModel::impl_getUntitledHelper ()
3945 SfxModelGuard aGuard( *this );
3947 if ( ! m_pData->m_xNumberedControllers.is ())
3949 rtl::Reference<::comphelper::NumberedCollection> pHelper = new ::comphelper::NumberedCollection();
3950 m_pData->m_xNumberedControllers = pHelper;
3951 pHelper->setOwner (Reference< frame::XModel >(this));
3952 pHelper->setUntitledPrefix (" : ");
3955 return m_pData->m_xNumberedControllers;
3959 // css.frame.XTitle
3960 OUString SAL_CALL SfxBaseModel::getTitle()
3962 // SYNCHRONIZED ->
3963 SfxModelGuard aGuard( *this );
3965 OUString aResult = impl_getTitleHelper()->getTitle ();
3966 if ( !m_pData->m_bExternalTitle && m_pData->m_pObjectShell )
3968 SfxMedium* pMedium = m_pData->m_pObjectShell->GetMedium();
3969 if ( pMedium )
3971 try {
3972 ::ucbhelper::Content aContent( pMedium->GetName(),
3973 utl::UCBContentHelper::getDefaultCommandEnvironment(),
3974 comphelper::getProcessComponentContext() );
3975 const Reference < beans::XPropertySetInfo > xProps
3976 = aContent.getProperties();
3977 if ( xProps.is() )
3979 static const OUStringLiteral aServerTitle( u"TitleOnServer" );
3980 if ( xProps->hasPropertyByName( aServerTitle ) )
3982 Any aAny = aContent.getPropertyValue( aServerTitle );
3983 aAny >>= aResult;
3987 catch (const ucb::ContentCreationException &)
3990 catch (const ucb::CommandAbortedException &)
3993 const SfxBoolItem* pRepairedDocItem = SfxItemSet::GetItem<SfxBoolItem>(pMedium->GetItemSet(), SID_REPAIRPACKAGE, false);
3994 if ( pRepairedDocItem && pRepairedDocItem->GetValue() )
3995 aResult += SfxResId(STR_REPAIREDDOCUMENT);
3998 if ( m_pData->m_pObjectShell->IsReadOnlyUI() || (pMedium && pMedium->IsReadOnly()) )
3999 aResult += SfxResId(STR_READONLY);
4000 else if ( m_pData->m_pObjectShell->IsDocShared() )
4001 aResult += SfxResId(STR_SHARED);
4003 if ( m_pData->m_pObjectShell->GetDocumentSignatureState() == SignatureState::OK )
4004 aResult += SfxResId(RID_XMLSEC_DOCUMENTSIGNED);
4007 return aResult;
4011 // css.frame.XTitle
4012 void SAL_CALL SfxBaseModel::setTitle( const OUString& sTitle )
4014 // SYNCHRONIZED ->
4015 SfxModelGuard aGuard( *this );
4017 impl_getTitleHelper()->setTitle (sTitle);
4018 m_pData->m_bExternalTitle = true;
4022 // css.frame.XTitleChangeBroadcaster
4023 void SAL_CALL SfxBaseModel::addTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
4025 // SYNCHRONIZED ->
4026 SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );
4028 Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
4029 if (xBroadcaster.is ())
4030 xBroadcaster->addTitleChangeListener (xListener);
4034 // css.frame.XTitleChangeBroadcaster
4035 void SAL_CALL SfxBaseModel::removeTitleChangeListener( const Reference< frame::XTitleChangeListener >& xListener )
4037 // SYNCHRONIZED ->
4038 SfxModelGuard aGuard( *this );
4040 Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), UNO_QUERY);
4041 if (xBroadcaster.is ())
4042 xBroadcaster->removeTitleChangeListener (xListener);
4046 // css.frame.XUntitledNumbers
4047 ::sal_Int32 SAL_CALL SfxBaseModel::leaseNumber( const Reference< XInterface >& xComponent )
4049 SfxModelGuard aGuard( *this );
4051 return impl_getUntitledHelper ()->leaseNumber (xComponent);
4055 // css.frame.XUntitledNumbers
4056 void SAL_CALL SfxBaseModel::releaseNumber( ::sal_Int32 nNumber )
4058 SfxModelGuard aGuard( *this );
4059 impl_getUntitledHelper ()->releaseNumber (nNumber);
4063 // css.frame.XUntitledNumbers
4064 void SAL_CALL SfxBaseModel::releaseNumberForComponent( const Reference< XInterface >& xComponent )
4066 SfxModelGuard aGuard( *this );
4067 impl_getUntitledHelper ()->releaseNumberForComponent (xComponent);
4071 // css.frame.XUntitledNumbers
4072 OUString SAL_CALL SfxBaseModel::getUntitledPrefix()
4074 SfxModelGuard aGuard( *this );
4075 return impl_getUntitledHelper ()->getUntitledPrefix ();
4079 // frame::XModel2
4080 Reference< container::XEnumeration > SAL_CALL SfxBaseModel::getControllers()
4082 SfxModelGuard aGuard( *this );
4084 sal_Int32 c = m_pData->m_seqControllers.size();
4085 Sequence< Any > lEnum(c);
4086 std::transform(m_pData->m_seqControllers.begin(), m_pData->m_seqControllers.end(),
4087 lEnum.getArray(), [](const auto& x) { return css::uno::makeAny(x); });
4089 return new ::comphelper::OAnyEnumeration(lEnum);
4093 // frame::XModel2
4094 Sequence< OUString > SAL_CALL SfxBaseModel::getAvailableViewControllerNames()
4096 SfxModelGuard aGuard( *this );
4098 const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
4099 const sal_Int16 nViewFactoryCount = rDocumentFactory.GetViewFactoryCount();
4101 Sequence< OUString > aViewNames( nViewFactoryCount );
4102 auto aViewNamesRange = asNonConstRange(aViewNames);
4103 for ( sal_Int16 nViewNo = 0; nViewNo < nViewFactoryCount; ++nViewNo )
4104 aViewNamesRange[nViewNo] = rDocumentFactory.GetViewFactory( nViewNo ).GetAPIViewName();
4105 return aViewNames;
4109 // frame::XModel2
4110 Reference< frame::XController2 > SAL_CALL SfxBaseModel::createDefaultViewController( const Reference< frame::XFrame >& i_rFrame )
4112 SfxModelGuard aGuard( *this );
4114 const SfxObjectFactory& rDocumentFactory = GetObjectShell()->GetFactory();
4115 const OUString sDefaultViewName = rDocumentFactory.GetViewFactory().GetAPIViewName();
4117 aGuard.clear();
4119 return createViewController( sDefaultViewName, Sequence< PropertyValue >(), i_rFrame );
4123 namespace sfx::intern {
4125 /** a class which, in its dtor, cleans up various objects (well, at the moment only the frame) collected during
4126 the creation of a document view, unless the creation was successful.
4128 class ViewCreationGuard
4130 public:
4131 ViewCreationGuard()
4132 :m_bSuccess( false )
4136 ~ViewCreationGuard()
4138 if ( !m_bSuccess && m_aWeakFrame && !m_aWeakFrame->GetCurrentDocument() )
4140 m_aWeakFrame->SetFrameInterface_Impl( nullptr );
4141 m_aWeakFrame->DoClose();
4145 void takeFrameOwnership( SfxFrame* i_pFrame )
4147 OSL_PRECOND( !m_aWeakFrame, "ViewCreationGuard::takeFrameOwnership: already have a frame!" );
4148 OSL_PRECOND( i_pFrame != nullptr, "ViewCreationGuard::takeFrameOwnership: invalid frame!" );
4149 m_aWeakFrame = i_pFrame;
4152 void releaseAll()
4154 m_bSuccess = true;
4157 private:
4158 bool m_bSuccess;
4159 SfxFrameWeakRef m_aWeakFrame;
4164 SfxViewFrame* SfxBaseModel::FindOrCreateViewFrame_Impl( const Reference< XFrame >& i_rFrame, ::sfx::intern::ViewCreationGuard& i_rGuard ) const
4166 SfxViewFrame* pViewFrame = nullptr;
4167 for ( pViewFrame = SfxViewFrame::GetFirst( GetObjectShell(), false );
4168 pViewFrame;
4169 pViewFrame= SfxViewFrame::GetNext( *pViewFrame, GetObjectShell(), false )
4172 if ( pViewFrame->GetFrame().GetFrameInterface() == i_rFrame )
4173 break;
4175 if ( !pViewFrame )
4177 #if OSL_DEBUG_LEVEL > 0
4178 for ( SfxFrame* pCheckFrame = SfxFrame::GetFirst();
4179 pCheckFrame;
4180 pCheckFrame = SfxFrame::GetNext( *pCheckFrame )
4183 if ( pCheckFrame->GetFrameInterface() == i_rFrame )
4185 if ( ( pCheckFrame->GetCurrentViewFrame() != nullptr )
4186 || ( pCheckFrame->GetCurrentDocument() != nullptr )
4188 // Note that it is perfectly legitimate that during loading into an XFrame which already contains
4189 // a document, there exist two SfxFrame instances bound to this XFrame - the old one, which will be
4190 // destroyed later, and the new one, which we're going to create
4191 continue;
4193 OSL_FAIL( "SfxBaseModel::FindOrCreateViewFrame_Impl: there already is an SfxFrame for the given XFrame, but no view in it!" );
4194 // nowadays, we're the only instance allowed to create an SfxFrame for an XFrame, so this case here should not happen
4195 break;
4198 #endif
4200 SfxFrame* pTargetFrame = SfxFrame::Create( i_rFrame );
4201 ENSURE_OR_THROW( pTargetFrame, "could not create an SfxFrame" );
4202 i_rGuard.takeFrameOwnership( pTargetFrame );
4204 // prepare it
4205 pTargetFrame->PrepareForDoc_Impl( *GetObjectShell() );
4207 // create view frame
4208 pViewFrame = new SfxViewFrame( *pTargetFrame, GetObjectShell() );
4210 return pViewFrame;
4214 // frame::XModel2
4215 Reference< frame::XController2 > SAL_CALL SfxBaseModel::createViewController(
4216 const OUString& i_rViewName, const Sequence< PropertyValue >& i_rArguments, const Reference< XFrame >& i_rFrame )
4218 SfxModelGuard aGuard( *this );
4220 if ( !i_rFrame.is() )
4221 throw lang::IllegalArgumentException( OUString(), *this, 3 );
4223 // find the proper SFX view factory
4224 SfxViewFactory* pViewFactory = GetObjectShell()->GetFactory().GetViewFactoryByViewName( i_rViewName );
4225 if ( !pViewFactory )
4226 throw IllegalArgumentException( OUString(), *this, 1 );
4228 // determine previous shell (used in some special cases)
4229 Reference< XController > xPreviousController( i_rFrame->getController() );
4230 const Reference< XModel > xMe( this );
4231 if ( ( xPreviousController.is() )
4232 && ( xMe != xPreviousController->getModel() )
4235 xPreviousController.clear();
4237 SfxViewShell* pOldViewShell = SfxViewShell::Get( xPreviousController );
4238 OSL_ENSURE( !xPreviousController.is() || ( pOldViewShell != nullptr ),
4239 "SfxBaseModel::createViewController: invalid old controller!" );
4241 // a guard which will clean up in case of failure
4242 ::sfx::intern::ViewCreationGuard aViewCreationGuard;
4244 // determine the ViewFrame belonging to the given XFrame
4245 SfxViewFrame* pViewFrame = FindOrCreateViewFrame_Impl( i_rFrame, aViewCreationGuard );
4246 SAL_WARN_IF( !pViewFrame , "sfx.doc", "SfxBaseModel::createViewController: no frame?" );
4248 // delegate to SFX' view factory
4249 pViewFrame->GetBindings().ENTERREGISTRATIONS();
4250 SfxViewShell* pViewShell = pViewFactory->CreateInstance( pViewFrame, pOldViewShell );
4251 pViewFrame->GetBindings().LEAVEREGISTRATIONS();
4252 ENSURE_OR_THROW( pViewShell, "invalid view shell provided by factory" );
4254 // by setting the ViewShell it is prevented that disposing the Controller will destroy this ViewFrame also
4255 pViewFrame->GetDispatcher()->SetDisableFlags( SfxDisableFlags::NONE );
4256 pViewFrame->SetViewShell_Impl( pViewShell );
4258 // remember ViewID
4259 pViewFrame->SetCurViewId_Impl( pViewFactory->GetOrdinal() );
4261 // ensure a default controller, if the view shell did not provide an own implementation
4262 if ( !pViewShell->GetController().is() )
4263 pViewShell->SetController( new SfxBaseController( pViewShell ) );
4265 // pass the creation arguments to the controller
4266 SfxBaseController* pBaseController = pViewShell->GetBaseController_Impl();
4267 ENSURE_OR_THROW( pBaseController, "invalid controller implementation!" );
4268 pBaseController->SetCreationArguments_Impl( i_rArguments );
4270 // some initial view settings, coming from our most recent attachResource call
4271 ::comphelper::NamedValueCollection aDocumentLoadArgs( getArgs2( { "ViewOnly", "PluginMode" } ) );
4272 if ( aDocumentLoadArgs.getOrDefault( "ViewOnly", false ) )
4273 pViewFrame->GetFrame().SetMenuBarOn_Impl( false );
4275 const sal_Int16 nPluginMode = aDocumentLoadArgs.getOrDefault( "PluginMode", sal_Int16( 0 ) );
4276 if ( nPluginMode == 1 )
4278 pViewFrame->ForceOuterResize_Impl();
4279 pViewFrame->GetBindings().HidePopups();
4281 SfxFrame& rFrame = pViewFrame->GetFrame();
4282 // MBA: layoutmanager of inplace frame starts locked and invisible
4283 rFrame.GetWorkWindow_Impl()->MakeVisible_Impl( false );
4284 rFrame.GetWorkWindow_Impl()->Lock_Impl( true );
4286 rFrame.GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
4287 pViewFrame->GetWindow().SetBorderStyle( WindowBorderStyle::NOBORDER );
4290 // tell the guard we were successful
4291 aViewCreationGuard.releaseAll();
4293 // outta here
4294 return pBaseController;
4298 // RDF DocumentMetadataAccess
4300 // rdf::XRepositorySupplier:
4301 Reference< rdf::XRepository > SAL_CALL
4302 SfxBaseModel::getRDFRepository()
4304 SfxModelGuard aGuard( *this );
4306 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4307 if (!xDMA.is()) {
4308 throw RuntimeException( "model has no document metadata", *this );
4311 return xDMA->getRDFRepository();
4314 // rdf::XNode:
4315 OUString SAL_CALL
4316 SfxBaseModel::getStringValue()
4318 SfxModelGuard aGuard( *this );
4320 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4321 if (!xDMA.is()) {
4322 throw RuntimeException( "model has no document metadata", *this );
4325 return xDMA->getStringValue();
4328 // rdf::XURI:
4329 OUString SAL_CALL
4330 SfxBaseModel::getNamespace()
4332 SfxModelGuard aGuard( *this );
4334 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4335 if (!xDMA.is()) {
4336 throw RuntimeException( "model has no document metadata", *this );
4339 return xDMA->getNamespace();
4342 OUString SAL_CALL
4343 SfxBaseModel::getLocalName()
4345 SfxModelGuard aGuard( *this );
4347 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4348 if (!xDMA.is()) {
4349 throw RuntimeException( "model has no document metadata", *this );
4352 return xDMA->getLocalName();
4355 // rdf::XDocumentMetadataAccess:
4356 Reference< rdf::XMetadatable > SAL_CALL
4357 SfxBaseModel::getElementByMetadataReference(
4358 const beans::StringPair & i_rReference)
4360 SfxModelGuard aGuard( *this );
4362 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4363 if (!xDMA.is()) {
4364 throw RuntimeException( "model has no document metadata", *this );
4367 return xDMA->getElementByMetadataReference(i_rReference);
4370 Reference< rdf::XMetadatable > SAL_CALL
4371 SfxBaseModel::getElementByURI(const Reference< rdf::XURI > & i_xURI)
4373 SfxModelGuard aGuard( *this );
4375 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4376 if (!xDMA.is()) {
4377 throw RuntimeException( "model has no document metadata", *this );
4380 return xDMA->getElementByURI(i_xURI);
4383 Sequence< Reference< rdf::XURI > > SAL_CALL
4384 SfxBaseModel::getMetadataGraphsWithType(
4385 const Reference<rdf::XURI> & i_xType)
4387 SfxModelGuard aGuard( *this );
4389 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4390 if (!xDMA.is()) {
4391 throw RuntimeException( "model has no document metadata", *this );
4394 return xDMA->getMetadataGraphsWithType(i_xType);
4397 Reference<rdf::XURI> SAL_CALL
4398 SfxBaseModel::addMetadataFile(const OUString & i_rFileName,
4399 const Sequence < Reference< rdf::XURI > > & i_rTypes)
4401 SfxModelGuard aGuard( *this );
4403 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4404 if (!xDMA.is()) {
4405 throw RuntimeException( "model has no document metadata", *this );
4408 return xDMA->addMetadataFile(i_rFileName, i_rTypes);
4411 Reference<rdf::XURI> SAL_CALL
4412 SfxBaseModel::importMetadataFile(::sal_Int16 i_Format,
4413 const Reference< io::XInputStream > & i_xInStream,
4414 const OUString & i_rFileName,
4415 const Reference< rdf::XURI > & i_xBaseURI,
4416 const Sequence < Reference< rdf::XURI > > & i_rTypes)
4418 SfxModelGuard aGuard( *this );
4420 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4421 if (!xDMA.is()) {
4422 throw RuntimeException( "model has no document metadata", *this );
4425 return xDMA->importMetadataFile(i_Format,
4426 i_xInStream, i_rFileName, i_xBaseURI, i_rTypes);
4429 void SAL_CALL
4430 SfxBaseModel::removeMetadataFile(
4431 const Reference< rdf::XURI > & i_xGraphName)
4433 SfxModelGuard aGuard( *this );
4435 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4436 if (!xDMA.is()) {
4437 throw RuntimeException( "model has no document metadata", *this );
4440 return xDMA->removeMetadataFile(i_xGraphName);
4443 void SAL_CALL
4444 SfxBaseModel::addContentOrStylesFile(const OUString & i_rFileName)
4446 SfxModelGuard aGuard( *this );
4448 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4449 if (!xDMA.is()) {
4450 throw RuntimeException( "model has no document metadata", *this );
4453 return xDMA->addContentOrStylesFile(i_rFileName);
4456 void SAL_CALL
4457 SfxBaseModel::removeContentOrStylesFile(const OUString & i_rFileName)
4459 SfxModelGuard aGuard( *this );
4461 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4462 if (!xDMA.is()) {
4463 throw RuntimeException( "model has no document metadata", *this );
4466 return xDMA->removeContentOrStylesFile(i_rFileName);
4469 void SAL_CALL
4470 SfxBaseModel::loadMetadataFromStorage(
4471 Reference< embed::XStorage > const & i_xStorage,
4472 Reference<rdf::XURI> const & i_xBaseURI,
4473 Reference<task::XInteractionHandler> const & i_xHandler)
4475 SfxModelGuard aGuard( *this );
4477 const Reference<rdf::XDocumentMetadataAccess> xDMA(
4478 m_pData->CreateDMAUninitialized());
4479 if (!xDMA.is()) {
4480 throw RuntimeException( "model has no document metadata", *this );
4483 try {
4484 xDMA->loadMetadataFromStorage(i_xStorage, i_xBaseURI, i_xHandler);
4485 } catch (lang::IllegalArgumentException &) {
4486 throw; // not initialized
4487 } catch (Exception &) {
4488 // UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
4489 m_pData->m_xDocumentMetadata = xDMA;
4490 throw;
4492 m_pData->m_xDocumentMetadata = xDMA;
4496 void SAL_CALL
4497 SfxBaseModel::storeMetadataToStorage(
4498 Reference< embed::XStorage > const & i_xStorage)
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->storeMetadataToStorage(i_xStorage);
4510 void SAL_CALL
4511 SfxBaseModel::loadMetadataFromMedium(
4512 const Sequence< beans::PropertyValue > & i_rMedium)
4514 SfxModelGuard aGuard( *this );
4516 const Reference<rdf::XDocumentMetadataAccess> xDMA(
4517 m_pData->CreateDMAUninitialized());
4518 if (!xDMA.is()) {
4519 throw RuntimeException( "model has no document metadata", *this );
4522 try {
4523 xDMA->loadMetadataFromMedium(i_rMedium);
4524 } catch (lang::IllegalArgumentException &) {
4525 throw; // not initialized
4526 } catch (Exception &) {
4527 // UGLY: if it's a RuntimeException, we can't be sure DMA is initialized
4528 m_pData->m_xDocumentMetadata = xDMA;
4529 throw;
4531 m_pData->m_xDocumentMetadata = xDMA;
4534 void SAL_CALL
4535 SfxBaseModel::storeMetadataToMedium(
4536 const Sequence< beans::PropertyValue > & i_rMedium)
4538 SfxModelGuard aGuard( *this );
4540 const Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA());
4541 if (!xDMA.is()) {
4542 throw RuntimeException( "model has no document metadata", *this );
4545 return xDMA->storeMetadataToMedium(i_rMedium);
4549 // = SfxModelSubComponent
4552 SfxModelSubComponent::~SfxModelSubComponent()
4556 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */