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