xref: /core/sfx2/source/view/viewfrm.cxx (revision 9ad252b2)
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 <config_feature_desktop.h>
21 #include <osl/file.hxx>
22 #include <sfx2/docfilt.hxx>
23 #include <sfx2/infobar.hxx>
24 #include <sfx2/sfxsids.hrc>
25 #include <sfx2/viewfrm.hxx>
26 #include <sfx2/classificationhelper.hxx>
27 #include <sfx2/notebookbar/SfxNotebookBar.hxx>
28 #include <com/sun/star/document/MacroExecMode.hpp>
29 #include <com/sun/star/frame/Desktop.hpp>
30 #include <com/sun/star/frame/DispatchRecorder.hpp>
31 #include <com/sun/star/frame/DispatchRecorderSupplier.hpp>
32 #include <com/sun/star/frame/XLoadable.hpp>
33 #include <com/sun/star/frame/XLayoutManager.hpp>
34 #include <com/sun/star/frame/XComponentLoader.hpp>
35 #include <officecfg/Office/Common.hxx>
36 #include <officecfg/Setup.hxx>
37 #include <toolkit/helper/vclunohelper.hxx>
38 #include <vcl/button.hxx>
39 #include <vcl/wrkwin.hxx>
40 #include <unotools/moduleoptions.hxx>
41 #include <svl/intitem.hxx>
42 #include <svl/visitem.hxx>
43 #include <svl/stritem.hxx>
44 #include <svl/eitem.hxx>
45 #include <svl/whiter.hxx>
46 #include <svl/undo.hxx>
47 #include <vcl/stdtext.hxx>
48 #include <vcl/weld.hxx>
49 #include <svtools/miscopt.hxx>
50 #include <tools/diagnose_ex.h>
51 #include <com/sun/star/container/XIndexAccess.hpp>
52 #include <com/sun/star/frame/XFramesSupplier.hpp>
53 #include <com/sun/star/frame/FrameSearchFlag.hpp>
54 #include <com/sun/star/frame/XFrame.hpp>
55 #include <com/sun/star/awt/XWindow.hpp>
56 #include <com/sun/star/frame/XController.hpp>
57 #include <com/sun/star/util/URLTransformer.hpp>
58 #include <com/sun/star/util/XURLTransformer.hpp>
59 #include <com/sun/star/util/XCloseable.hpp>
60 #include <com/sun/star/frame/XDispatchRecorderSupplier.hpp>
61 #include <com/sun/star/document/UpdateDocMode.hpp>
62 #include <com/sun/star/beans/XPropertySet.hpp>
63 #include <com/sun/star/uri/UriReferenceFactory.hpp>
64 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
65 #include <com/sun/star/document/XViewDataSupplier.hpp>
66 #include <com/sun/star/container/XIndexContainer.hpp>
67 #include <com/sun/star/task/InteractionHandler.hpp>
68 #include <rtl/ustrbuf.hxx>
69 #include <sal/log.hxx>
70 
71 #include <unotools/ucbhelper.hxx>
72 #include <comphelper/lok.hxx>
73 #include <comphelper/processfactory.hxx>
74 #include <comphelper/namedvaluecollection.hxx>
75 #include <comphelper/docpasswordrequest.hxx>
76 #include <comphelper/docpasswordhelper.hxx>
77 
78 #include <com/sun/star/uno/Reference.h>
79 
80 #include <basic/basmgr.hxx>
81 #include <basic/sbmod.hxx>
82 #include <basic/sbmeth.hxx>
83 #include <svtools/strings.hrc>
84 #include <svtools/svtresid.hxx>
85 #include <framework/framelistanalyzer.hxx>
86 #include <shellimpl.hxx>
87 
88 #include <optional>
89 
90 #include <unotools/configmgr.hxx>
91 
92 using namespace ::com::sun::star;
93 using namespace ::com::sun::star::uno;
94 using namespace ::com::sun::star::ucb;
95 using namespace ::com::sun::star::frame;
96 using namespace ::com::sun::star::lang;
97 using ::com::sun::star::awt::XWindow;
98 using ::com::sun::star::beans::PropertyValue;
99 using ::com::sun::star::document::XViewDataSupplier;
100 using ::com::sun::star::container::XIndexContainer;
101 
102 // Due to ViewFrame::Current
103 #include <appdata.hxx>
104 #include <sfx2/app.hxx>
105 #include <sfx2/objface.hxx>
106 #include <openflag.hxx>
107 #include <objshimp.hxx>
108 #include <sfx2/viewsh.hxx>
109 #include <sfx2/objsh.hxx>
110 #include <sfx2/bindings.hxx>
111 #include <sfx2/dispatch.hxx>
112 #include <sfx2/request.hxx>
113 #include <sfx2/docfac.hxx>
114 #include <sfx2/ipclient.hxx>
115 #include <sfx2/sfxresid.hxx>
116 #include <sfx2/viewfac.hxx>
117 #include <sfx2/event.hxx>
118 #include <sfx2/fcontnr.hxx>
119 #include <sfx2/docfile.hxx>
120 #include <sfx2/module.hxx>
121 #include <sfx2/sfxuno.hxx>
122 #include <sfx2/progress.hxx>
123 #include <sfx2/sidebar/Sidebar.hxx>
124 #include <workwin.hxx>
125 #include <sfx2/minfitem.hxx>
126 #include <sfx2/strings.hrc>
127 #include "impviewframe.hxx"
128 #include <vcl/svapp.hxx>
129 
130 #define ShellClass_SfxViewFrame
131 #include <sfxslots.hxx>
132 
133 SFX_IMPL_SUPERCLASS_INTERFACE(SfxViewFrame,SfxShell)
134 
135 void SfxViewFrame::InitInterface_Impl()
136 {
137     GetStaticInterface()->RegisterChildWindow(SID_BROWSER);
138     GetStaticInterface()->RegisterChildWindow(SID_RECORDING_FLOATWINDOW);
139 #if HAVE_FEATURE_DESKTOP
140     GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_FULLSCREEN, SfxVisibilityFlags::FullScreen, ToolbarId::FullScreenToolbox);
141     GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_APPLICATION, SfxVisibilityFlags::Standard, ToolbarId::EnvToolbox);
142 #endif
143 }
144 
145 namespace {
146 /// Asks the user if editing a read-only document is really wanted.
147 class SfxEditDocumentDialog : public weld::MessageDialogController
148 {
149 private:
150     std::unique_ptr<weld::Button> m_xEditDocument;
151     std::unique_ptr<weld::Button> m_xCancel;
152 
153 public:
154     SfxEditDocumentDialog(weld::Widget* pParent);
155 };
156 
157 SfxEditDocumentDialog::SfxEditDocumentDialog(weld::Widget* pParent)
158     : MessageDialogController(pParent, "sfx/ui/editdocumentdialog.ui",
159             "EditDocumentDialog")
160     , m_xEditDocument(m_xBuilder->weld_button("edit"))
161     , m_xCancel(m_xBuilder->weld_button("cancel"))
162 {
163 }
164 
165 class SfxQueryOpenAsTemplate
166 {
167 private:
168     std::unique_ptr<weld::MessageDialog> m_xQueryBox;
169 public:
170     SfxQueryOpenAsTemplate(weld::Window* pParent, bool bAllowIgnoreLock, LockFileEntry& rLockData)
171         : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Question,
172                                                        VclButtonsType::NONE,
173                                                        QueryString(bAllowIgnoreLock, rLockData)))
174     {
175         m_xQueryBox->add_button(SfxResId(STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN), RET_YES);
176         if (bAllowIgnoreLock)
177             m_xQueryBox->add_button(SfxResId(STR_QUERY_OPENASTEMPLATE_OPEN_BTN), RET_IGNORE);
178         m_xQueryBox->add_button(GetStandardText( StandardButtonType::Cancel ), RET_CANCEL);
179         m_xQueryBox->set_default_response(RET_YES);
180     }
181     short run() { return m_xQueryBox->run(); }
182 
183 private:
184     static OUString QueryString(bool bAllowIgnoreLock, LockFileEntry& rLockData)
185     {
186         OUString sLockUserData;
187         if (!rLockData[LockFileComponent::OOOUSERNAME].isEmpty())
188             sLockUserData = rLockData[LockFileComponent::OOOUSERNAME];
189         else
190             sLockUserData = rLockData[LockFileComponent::SYSUSERNAME];
191 
192         if (!sLockUserData.isEmpty() && !rLockData[LockFileComponent::EDITTIME].isEmpty())
193             sLockUserData += " ( " + rLockData[LockFileComponent::EDITTIME] + " )";
194 
195         if (!sLockUserData.isEmpty())
196             sLockUserData = "\n\n" + sLockUserData + "\n";
197 
198         const bool bUseLockStr = bAllowIgnoreLock || !sLockUserData.isEmpty();
199 
200         OUString sMsg(
201             SfxResId(bUseLockStr ? STR_QUERY_OPENASTEMPLATE_LOCKED : STR_QUERY_OPENASTEMPLATE));
202 
203         if (bAllowIgnoreLock)
204             sMsg += "\n\n" + SfxResId(STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE);
205 
206         return sMsg.replaceFirst("%LOCKINFO", sLockUserData);
207     }
208 };
209 
210 /// Is this read-only object shell opened via .uno:SignPDF?
211 bool IsSignPDF(const SfxObjectShellRef& xObjSh)
212 {
213     if (!xObjSh.is())
214         return false;
215 
216     SfxMedium* pMedium = xObjSh->GetMedium();
217     if (pMedium && !pMedium->IsOriginallyReadOnly())
218     {
219         const std::shared_ptr<const SfxFilter>& pFilter = pMedium->GetFilter();
220         if (pFilter && pFilter->GetName() == "draw_pdf_import")
221             return true;
222     }
223 
224     return false;
225 }
226 
227 bool AskPasswordToModify_Impl( const uno::Reference< task::XInteractionHandler >& xHandler, const OUString& aPath, const std::shared_ptr<const SfxFilter>& pFilter, sal_uInt32 nPasswordHash, const uno::Sequence< beans::PropertyValue >& aInfo )
228 {
229     // TODO/LATER: In future the info should replace the direct hash completely
230     bool bResult = ( !nPasswordHash && !aInfo.hasElements() );
231 
232     SAL_WARN_IF( !(pFilter && ( pFilter->GetFilterFlags() & SfxFilterFlags::PASSWORDTOMODIFY )), "sfx.view",
233                        "PasswordToModify feature is active for a filter that does not support it!");
234 
235     if ( pFilter && xHandler.is() )
236     {
237         bool bCancel = false;
238         bool bFirstTime = true;
239 
240         while ( !bResult && !bCancel )
241         {
242             bool bMSType = !pFilter->IsOwnFormat();
243 
244             ::rtl::Reference< ::comphelper::DocPasswordRequest > pPasswordRequest(
245                  new ::comphelper::DocPasswordRequest(
246                  bMSType ? ::comphelper::DocPasswordRequestType::MS : ::comphelper::DocPasswordRequestType::Standard,
247                  bFirstTime ? css::task::PasswordRequestMode_PASSWORD_ENTER : css::task::PasswordRequestMode_PASSWORD_REENTER,
248                  aPath,
249                  true ) );
250 
251             uno::Reference< css::task::XInteractionRequest > rRequest( pPasswordRequest.get() );
252             xHandler->handle( rRequest );
253 
254             if ( pPasswordRequest->isPassword() )
255             {
256                 if ( aInfo.hasElements() )
257                 {
258                     bResult = ::comphelper::DocPasswordHelper::IsModifyPasswordCorrect( pPasswordRequest->getPasswordToModify(), aInfo );
259                 }
260                 else
261                 {
262                     // the binary format
263                     bResult = ( SfxMedium::CreatePasswordToModifyHash( pPasswordRequest->getPasswordToModify(), pFilter->GetServiceName()=="com.sun.star.text.TextDocument" ) == nPasswordHash );
264                 }
265             }
266             else
267                 bCancel = true;
268 
269             bFirstTime = false;
270         }
271     }
272 
273     return bResult;
274 }
275 }
276 
277 void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
278 {
279     SfxObjectShell* pSh = GetObjectShell();
280     switch ( rReq.GetSlot() )
281     {
282         case SID_EDITDOC:
283         case SID_READONLYDOC:
284         {
285             // Due to Double occupancy in toolboxes (with or without Ctrl),
286             // it is also possible that the slot is enabled, but Ctrl-click
287             // despite this is not!
288             if( !pSh || !pSh->HasName() || !(pSh->Get_Impl()->nLoadedFlags & SfxLoadedFlags::MAINDOCUMENT ))
289                 break;
290 
291             SfxViewShell* pViewSh = GetViewShell();
292             if (pViewSh && pViewSh->isEditDocLocked())
293                 break;
294 
295             // Only change read-only UI and remove info bar when we succeed
296             struct ReadOnlyUIGuard
297             {
298                 SfxViewFrame* m_pFrame;
299                 SfxObjectShell* m_pSh;
300                 SfxMedium* m_pMed = nullptr;
301                 bool m_bSetRO;
302                 ReadOnlyUIGuard(SfxViewFrame* pFrame, SfxObjectShell* p_Sh)
303                     : m_pFrame(pFrame), m_pSh(p_Sh), m_bSetRO(p_Sh->IsReadOnlyUI())
304                 {}
305                 ~ReadOnlyUIGuard() COVERITY_NOEXCEPT_FALSE
306                 {
307                     if (m_bSetRO != m_pSh->IsReadOnlyUI())
308                     {
309                         m_pSh->SetReadOnlyUI(m_bSetRO);
310                         if (!m_bSetRO)
311                             m_pFrame->RemoveInfoBar("readonly");
312                         if (m_pMed)
313                         {
314                             // tdf#116066: DoSaveCompleted should be called after SetReadOnlyUI
315                             m_pSh->DoSaveCompleted(m_pMed);
316                             m_pSh->Broadcast(SfxHint(SfxHintId::ModeChanged));
317                         }
318                     }
319                 }
320             } aReadOnlyUIGuard(this, pSh);
321 
322             SfxMedium* pMed = pSh->GetMedium();
323 
324             const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(pSh->GetMedium()->GetItemSet(), SID_VIEWONLY, false);
325             if ( pItem && pItem->GetValue() )
326             {
327                 SfxApplication* pApp = SfxGetpApp();
328                 SfxAllItemSet aSet( pApp->GetPool() );
329                 aSet.Put( SfxStringItem( SID_FILE_NAME, pMed->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE) ) );
330                 aSet.Put( SfxBoolItem( SID_TEMPLATE, true ) );
331                 aSet.Put( SfxStringItem( SID_TARGETNAME, "_blank" ) );
332                 const SfxStringItem* pReferer = SfxItemSet::GetItem<SfxStringItem>(pMed->GetItemSet(), SID_REFERER, false);
333                 if ( pReferer )
334                     aSet.Put( *pReferer );
335                 const SfxInt16Item* pVersionItem = SfxItemSet::GetItem<SfxInt16Item>(pSh->GetMedium()->GetItemSet(), SID_VERSION, false);
336                 if ( pVersionItem )
337                     aSet.Put( *pVersionItem );
338 
339                 if( pMed->GetFilter() )
340                 {
341                     aSet.Put( SfxStringItem( SID_FILTER_NAME, pMed->GetFilter()->GetFilterName() ) );
342                     const SfxStringItem* pOptions = SfxItemSet::GetItem<SfxStringItem>(pMed->GetItemSet(), SID_FILE_FILTEROPTIONS, false);
343                     if ( pOptions )
344                         aSet.Put( *pOptions );
345                 }
346 
347                 GetDispatcher()->Execute( SID_OPENDOC, SfxCallMode::ASYNCHRON, aSet );
348                 return;
349             }
350 
351             StreamMode nOpenMode;
352             bool bNeedsReload = false;
353             if ( !pSh->IsReadOnly() )
354             {
355                 // Save and reload Readonly
356                 if( pSh->IsModified() )
357                 {
358                     if ( pSh->PrepareClose() )
359                     {
360                         // the storing could let the medium be changed
361                         pMed = pSh->GetMedium();
362                         bNeedsReload = true;
363                     }
364                     else
365                     {
366                         rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), false ) );
367                         return;
368                     }
369                 }
370                 nOpenMode = SFX_STREAM_READONLY;
371                 aReadOnlyUIGuard.m_bSetRO = true;
372             }
373             else
374             {
375                 if ( pSh->IsReadOnlyMedium()
376                   && ( pSh->GetModifyPasswordHash() || pSh->GetModifyPasswordInfo().hasElements() )
377                   && !pSh->IsModifyPasswordEntered() )
378                 {
379                     const OUString aDocumentName = INetURLObject( pMed->GetOrigURL() ).GetMainURL( INetURLObject::DecodeMechanism::WithCharset );
380                     if( !AskPasswordToModify_Impl( pMed->GetInteractionHandler(), aDocumentName, pMed->GetFilter(), pSh->GetModifyPasswordHash(), pSh->GetModifyPasswordInfo() ) )
381                     {
382                         // this is a read-only document, if it has "Password to modify"
383                         // the user should enter password before he can edit the document
384                         rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), false ) );
385                         return;
386                     }
387 
388                     pSh->SetModifyPasswordEntered();
389                 }
390 
391                 nOpenMode = pSh->IsOriginallyReadOnlyMedium() ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
392                 aReadOnlyUIGuard.m_bSetRO = false;
393 
394                 // if only the view was in the readonly mode then there is no need to do the reload
395                 if ( !pSh->IsReadOnlyMedium() )
396                 {
397                     // SetReadOnlyUI causes recomputation of window title, using
398                     // open mode among other things, so call SetOpenMode before
399                     // SetReadOnlyUI:
400                     pMed->SetOpenMode( nOpenMode );
401                     return;
402                 }
403             }
404 
405             if ( rReq.IsAPI() )
406             {
407                 // Control through API if r/w or r/o
408                 const SfxBoolItem* pEditItem = rReq.GetArg<SfxBoolItem>(SID_EDITDOC);
409                 if ( pEditItem )
410                     nOpenMode = pEditItem->GetValue() ? SFX_STREAM_READWRITE : SFX_STREAM_READONLY;
411             }
412 
413             // doing
414 
415             OUString sTemp;
416             osl::FileBase::getFileURLFromSystemPath( pMed->GetPhysicalName(), sTemp );
417             INetURLObject aPhysObj( sTemp );
418             const SfxInt16Item* pVersionItem = SfxItemSet::GetItem<SfxInt16Item>(pSh->GetMedium()->GetItemSet(), SID_VERSION, false);
419 
420             INetURLObject aMedObj( pMed->GetName() );
421 
422             // -> tdf#82744
423             // the logic below is following:
424             // if the document seems not to need to be reloaded
425             //     and the physical name is different to the logical one,
426             // then on file system it can be checked that the copy is still newer than the original and no document reload is required.
427             // Did some semplification to enhance readability of the 'if' expression
428             //
429             // when the 'http/https' protocol is active, the bool bPhysObjIsYounger relies upon the getlastmodified Property of a WebDAV resource.
430             // Said property should be implemented, but sometimes it's not.
431             // implemented. On this case the reload activated here will not work properly.
432             // TODO: change the check age method for WebDAV to etag (entity-tag) property value, need some rethinking, since the
433             // etag tells that the cache representation (e.g. in LO) is different from the one on the server,
434             // but tells nothing about the age
435             // Details at this link: http://tools.ietf.org/html/rfc4918#section-15, section 15.7
436             bool bPhysObjIsYounger = ::utl::UCBContentHelper::IsYounger( aMedObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
437                                                                          aPhysObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
438             bool bIsWebDAV = aMedObj.isAnyKnownWebDAVScheme();
439 
440             if ( ( !bNeedsReload && ( ( aMedObj.GetProtocol() == INetProtocol::File &&
441                                         aMedObj.getFSysPath( FSysStyle::Detect ) != aPhysObj.getFSysPath( FSysStyle::Detect ) &&
442                                         !bPhysObjIsYounger )
443                                       || ( bIsWebDAV && !bPhysObjIsYounger )
444                                       || ( pMed->IsRemote() && !bIsWebDAV ) ) )
445                  || pVersionItem )
446             // <- tdf#82744
447             {
448                 bNeedsReload = true;
449 
450                 bool bOK = false;
451                 bool bRetryIgnoringLock = false;
452                 bool bOpenTemplate = false;
453                 std::optional<bool> aOrigROVal;
454                 if (!pVersionItem)
455                 {
456                     auto pRO = pMed->GetItemSet()->GetItem<SfxBoolItem>(SID_DOC_READONLY, false);
457                     if (pRO)
458                         aOrigROVal = pRO->GetValue();
459                 }
460                 do {
461                     LockFileEntry aLockData;
462                     if ( !pVersionItem )
463                     {
464                         if (bRetryIgnoringLock)
465                             pMed->ResetError();
466 
467                         bool bHasStorage = pMed->HasStorage_Impl();
468                         // switching edit mode could be possible without reload
469                         if ( bHasStorage && pMed->GetStorage() == pSh->GetStorage() )
470                         {
471                             // TODO/LATER: faster creation of copy
472                             if ( !pSh->ConnectTmpStorage_Impl( pMed->GetStorage(), pMed ) )
473                                 return;
474                         }
475 
476                         pMed->CloseAndRelease();
477                         pMed->SetOpenMode( nOpenMode );
478                         // We need to clear the SID_DOC_READONLY item from the set, to allow
479                         // MediaDescriptor::impl_openStreamWithURL (called indirectly by
480                         // SfxMedium::CompleteReOpen) to properly fill input stream of the
481                         // descriptor, even when the file can't be open in read-write mode.
482                         // Only then can following call to SfxMedium::LockOrigFileOnDemand
483                         // return proper information about who has locked the file, to show
484                         // in the SfxQueryOpenAsTemplate box below; otherwise it exits right
485                         // after call to SfxMedium::GetMedium_Impl. This mimics what happens
486                         // when the file is opened initially, when filter detection code also
487                         // calls MediaDescriptor::impl_openStreamWithURL without the item set.
488                         pMed->GetItemSet()->ClearItem(SID_DOC_READONLY);
489                         pMed->CompleteReOpen();
490                         pMed->GetItemSet()->Put(
491                             SfxBoolItem(SID_DOC_READONLY, !(nOpenMode & StreamMode::WRITE)));
492                         if ( nOpenMode & StreamMode::WRITE )
493                         {
494                             auto eResult = pMed->LockOrigFileOnDemand(
495                                 true, true, bRetryIgnoringLock, &aLockData);
496                             bRetryIgnoringLock
497                                 = eResult == SfxMedium::LockFileResult::FailedLockFile;
498                         }
499 
500                         // LockOrigFileOnDemand might set the readonly flag itself, it should be set back
501                         pMed->GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, !( nOpenMode & StreamMode::WRITE ) ) );
502 
503                         if ( !pMed->GetErrorCode() )
504                             bOK = true;
505                     }
506 
507                     if( !bOK )
508                     {
509                         if (nOpenMode == SFX_STREAM_READWRITE && !rReq.IsAPI())
510                         {
511                             // css::sdbcx::User offering to open it as a template
512                             SfxQueryOpenAsTemplate aBox(GetWindow().GetFrameWeld(),
513                                                         bRetryIgnoringLock, aLockData);
514 
515                             short nUserAnswer = aBox.run();
516                             bOpenTemplate = RET_YES == nUserAnswer;
517                             // Always reset this here to avoid infinite loop
518                             bRetryIgnoringLock = RET_IGNORE == nUserAnswer;
519                         }
520                         else
521                             bRetryIgnoringLock = false;
522                     }
523                 }
524                 while ( !bOK && bRetryIgnoringLock );
525 
526                 if( !bOK )
527                 {
528                     ErrCode nErr = pMed->GetErrorCode();
529                     if ( pVersionItem )
530                         nErr = ERRCODE_IO_ACCESSDENIED;
531                     else
532                     {
533                         pMed->ResetError();
534                         pMed->SetOpenMode( SFX_STREAM_READONLY );
535                         if (aOrigROVal)
536                             pMed->GetItemSet()->Put(SfxBoolItem(SID_DOC_READONLY, *aOrigROVal));
537                         else
538                             pMed->GetItemSet()->ClearItem(SID_DOC_READONLY);
539                         pMed->ReOpen();
540                         pSh->DoSaveCompleted( pMed );
541                     }
542 
543                     // Readonly document can not be switched to edit mode?
544                     rReq.Done();
545 
546                     if ( nOpenMode == SFX_STREAM_READWRITE && !rReq.IsAPI() )
547                     {
548                         if ( bOpenTemplate )
549                         {
550                             SfxApplication* pApp = SfxGetpApp();
551                             SfxAllItemSet aSet( pApp->GetPool() );
552                             aSet.Put( SfxStringItem( SID_FILE_NAME, pMed->GetName() ) );
553                             const SfxStringItem* pReferer = SfxItemSet::GetItem<SfxStringItem>(pMed->GetItemSet(), SID_REFERER, false);
554                             if ( pReferer )
555                                 aSet.Put( *pReferer );
556                             aSet.Put( SfxBoolItem( SID_TEMPLATE, true ) );
557                             if ( pVersionItem )
558                                 aSet.Put( *pVersionItem );
559 
560                             if( pMed->GetFilter() )
561                             {
562                                 aSet.Put( SfxStringItem( SID_FILTER_NAME, pMed->GetFilter()->GetFilterName() ) );
563                                 const SfxStringItem* pOptions = SfxItemSet::GetItem<SfxStringItem>(pMed->GetItemSet(), SID_FILE_FILTEROPTIONS, false);
564                                 if ( pOptions )
565                                     aSet.Put( *pOptions );
566                             }
567 
568                             GetDispatcher()->Execute( SID_OPENDOC, SfxCallMode::ASYNCHRON, aSet );
569                             return;
570                         }
571 
572                         nErr = ERRCODE_NONE;
573                     }
574 
575                     // Keep the read-only UI
576                     aReadOnlyUIGuard.m_bSetRO = true;
577 
578                     ErrorHandler::HandleError( nErr );
579                     rReq.SetReturnValue(
580                         SfxBoolItem( rReq.GetSlot(), false ) );
581                     return;
582                 }
583                 else
584                 {
585                     aReadOnlyUIGuard.m_pMed = pMed;
586                     rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), true ) );
587                     rReq.Done( true );
588                     return;
589                 }
590             }
591 
592             rReq.AppendItem( SfxBoolItem( SID_FORCERELOAD, bNeedsReload) );
593             rReq.AppendItem( SfxBoolItem( SID_SILENT, true ));
594 
595             [[fallthrough]]; //TODO ???
596         }
597 
598         case SID_RELOAD:
599         {
600             // Due to Double occupancy in toolboxes (with or without Ctrl),
601             // it is also possible that the slot is enabled, but Ctrl-click
602             // despite this is not!
603             if ( !pSh || !pSh->CanReload_Impl() )
604                 break;
605             SfxApplication* pApp = SfxGetpApp();
606             const SfxBoolItem* pForceReloadItem = rReq.GetArg<SfxBoolItem>(SID_FORCERELOAD);
607             if(  pForceReloadItem && !pForceReloadItem->GetValue() &&
608                 !pSh->GetMedium()->IsExpired() )
609                 return;
610             if( m_pImpl->bReloading || pSh->IsInModalMode() )
611                 return;
612 
613             // AutoLoad is prohibited if possible
614             const SfxBoolItem* pAutoLoadItem = rReq.GetArg<SfxBoolItem>(SID_AUTOLOAD);
615             if ( pAutoLoadItem && pAutoLoadItem->GetValue() &&
616                  GetFrame().IsAutoLoadLocked_Impl() )
617                 return;
618 
619             SfxObjectShellLock xOldObj( pSh );
620             m_pImpl->bReloading = true;
621             const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
622             // Open as editable?
623             bool bForEdit = !pSh->IsReadOnly();
624 
625             // If possible ask the User
626             bool bDo = GetViewShell()->PrepareClose();
627             const SfxBoolItem* pSilentItem = rReq.GetArg<SfxBoolItem>(SID_SILENT);
628             if ( bDo && GetFrame().DocIsModified_Impl() &&
629                  !rReq.IsAPI() && ( !pSilentItem || !pSilentItem->GetValue() ) )
630             {
631                 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetWindow().GetFrameWeld(),
632                                                                          VclMessageType::Question, VclButtonsType::YesNo,
633                                                                          SfxResId(STR_QUERY_LASTVERSION)));
634                 bDo = RET_YES == xBox->run();
635             }
636 
637             if ( bDo )
638             {
639                 SfxMedium *pMedium = xOldObj->GetMedium();
640 
641                 bool bHandsOff =
642                     ( pMedium->GetURLObject().GetProtocol() == INetProtocol::File && !xOldObj->IsDocShared() );
643 
644                 // Empty existing SfxMDIFrames for this Document
645                 // in native format or R/O, open it now for editing?
646                 SfxObjectShellLock xNewObj;
647 
648                 // collect the views of the document
649                 // TODO: when UNO ViewFactories are available for SFX-based documents, the below code should
650                 // be UNOized, too
651                 typedef ::std::pair< Reference< XFrame >, SfxInterfaceId >  ViewDescriptor;
652                 ::std::vector< ViewDescriptor > aViewFrames;
653                 SfxViewFrame *pView = GetFirst( xOldObj );
654                 while ( pView )
655                 {
656                     Reference< XFrame > xFrame( pView->GetFrame().GetFrameInterface() );
657                     SAL_WARN_IF( !xFrame.is(), "sfx.view", "SfxViewFrame::ExecReload_Impl: no XFrame?!");
658                     aViewFrames.emplace_back( xFrame, pView->GetCurViewId() );
659 
660                     pView = GetNext( *pView, xOldObj );
661                 }
662 
663                 xOldObj->Get_Impl()->pReloadTimer.reset();
664 
665                 std::unique_ptr<SfxItemSet> pNewSet;
666                 std::shared_ptr<const SfxFilter> pFilter = pMedium->GetFilter();
667                 if( pURLItem )
668                 {
669                     pNewSet.reset(new SfxAllItemSet( pApp->GetPool() ));
670                     pNewSet->Put( *pURLItem );
671 
672                     // Filter Detection
673                     OUString referer;
674                     const SfxStringItem* refererItem = rReq.GetArg<SfxStringItem>(SID_REFERER);
675                     if (refererItem != nullptr) {
676                         referer = refererItem->GetValue();
677                     }
678                     SfxMedium aMedium( pURLItem->GetValue(), referer, SFX_STREAM_READWRITE );
679                     SfxFilterMatcher().GuessFilter( aMedium, pFilter );
680                     if ( pFilter )
681                         pNewSet->Put( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) );
682                     pNewSet->Put( *aMedium.GetItemSet() );
683                 }
684                 else
685                 {
686                     pNewSet.reset(new SfxAllItemSet( *pMedium->GetItemSet() ));
687                     pNewSet->ClearItem( SID_VIEW_ID );
688                     pNewSet->ClearItem( SID_STREAM );
689                     pNewSet->ClearItem( SID_INPUTSTREAM );
690                     pNewSet->Put( SfxStringItem( SID_FILTER_NAME, pMedium->GetFilter()->GetName() ) );
691 
692                     // let the current security settings be checked again
693                     pNewSet->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::USE_CONFIG ) );
694 
695                     if ( pSh->IsOriginallyReadOnlyMedium()
696                          || pSh->IsOriginallyLoadedReadOnlyMedium() )
697                         // edit mode is switched or reload of readonly document
698                         pNewSet->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
699                     else
700                         // Reload of file opened for writing
701                         pNewSet->ClearItem( SID_DOC_READONLY );
702                 }
703 
704                 // If a salvaged file is present, do not enclose the OrigURL
705                 // again, since the Template is invalid after reload.
706                 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pNewSet.get(), SID_DOC_SALVAGE, false);
707                 if( pSalvageItem )
708                 {
709                     pNewSet->ClearItem( SID_DOC_SALVAGE );
710                 }
711 
712 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
713                 // TODO/LATER: Temporary solution, the SfxMedium must know the original URL as aLogicName
714                 //             SfxMedium::Transfer_Impl() will be forbidden then.
715                 if ( xOldObj->IsDocShared() )
716                     pNewSet->Put( SfxStringItem( SID_FILE_NAME, xOldObj->GetSharedFileURL() ) );
717 #endif
718                 if ( pURLItem )
719                     pNewSet->Put( SfxStringItem( SID_REFERER, pMedium->GetName() ) );
720                 else
721                     pNewSet->Put( SfxStringItem( SID_REFERER, OUString() ) );
722 
723                 xOldObj->CancelTransfers();
724 
725 
726                 if ( pSilentItem && pSilentItem->GetValue() )
727                     pNewSet->Put( SfxBoolItem( SID_SILENT, true ) );
728 
729                 const SfxUnoAnyItem* pInteractionItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pNewSet.get(), SID_INTERACTIONHANDLER, false);
730                 const SfxUInt16Item* pMacroExecItem = SfxItemSet::GetItem<SfxUInt16Item>(pNewSet.get(), SID_MACROEXECMODE, false);
731                 const SfxUInt16Item* pDocTemplateItem = SfxItemSet::GetItem<SfxUInt16Item>(pNewSet.get(), SID_UPDATEDOCMODE, false);
732 
733                 if (!pInteractionItem)
734                 {
735                     Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
736                     if (xHdl.is())
737                         pNewSet->Put( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHdl)) );
738                 }
739 
740                 if (!pMacroExecItem)
741                     pNewSet->Put( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) );
742                 if (!pDocTemplateItem)
743                     pNewSet->Put( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) );
744 
745                 xOldObj->SetModified( false );
746                 // Do not cache the old Document! Is invalid when loading
747                 // another document.
748 
749                 const SfxStringItem* pSavedOptions = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_FILE_FILTEROPTIONS, false);
750                 const SfxStringItem* pSavedReferer = SfxItemSet::GetItem<SfxStringItem>(pMedium->GetItemSet(), SID_REFERER, false);
751 
752                 bool bHasStorage = pMedium->HasStorage_Impl();
753                 if( bHandsOff )
754                 {
755                     if ( bHasStorage && pMedium->GetStorage() == xOldObj->GetStorage() )
756                     {
757                         // TODO/LATER: faster creation of copy
758                         if ( !xOldObj->ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
759                             return;
760                     }
761 
762                     pMedium->CloseAndRelease();
763                 }
764 
765                 xNewObj = SfxObjectShell::CreateObject( pFilter->GetServiceName() );
766 
767                 if ( xOldObj->IsModifyPasswordEntered() )
768                     xNewObj->SetModifyPasswordEntered();
769 
770                 uno::Sequence < beans::PropertyValue > aLoadArgs;
771                 TransformItems( SID_OPENDOC, *pNewSet, aLoadArgs );
772                 try
773                 {
774                     uno::Reference < frame::XLoadable > xLoad( xNewObj->GetModel(), uno::UNO_QUERY );
775                     xLoad->load( aLoadArgs );
776                 }
777                 catch ( uno::Exception& )
778                 {
779                     xNewObj->DoClose();
780                     xNewObj = nullptr;
781                 }
782 
783                 pNewSet.reset();
784 
785                 if( !xNewObj.Is() )
786                 {
787                     if( bHandsOff )
788                     {
789                         // back to old medium
790                         pMedium->ReOpen();
791                         pMedium->LockOrigFileOnDemand( false, true );
792 
793                         xOldObj->DoSaveCompleted( pMedium );
794                     }
795 
796                     // r/o-Doc couldn't be switched to writing mode
797                     if ( bForEdit && ( SID_EDITDOC == rReq.GetSlot() || SID_READONLYDOC == rReq.GetSlot() ) )
798                     {
799                         // ask user for opening as template
800                         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetWindow().GetFrameWeld(),
801                                                                                  VclMessageType::Question, VclButtonsType::YesNo,
802                                                                                  SfxResId(STR_QUERY_OPENASTEMPLATE)));
803                         if (RET_YES == xBox->run())
804                         {
805                             SfxAllItemSet aSet( pApp->GetPool() );
806                             aSet.Put( SfxStringItem( SID_FILE_NAME, pMedium->GetName() ) );
807                             aSet.Put( SfxStringItem( SID_TARGETNAME, "_blank" ) );
808                             if ( pSavedOptions )
809                                 aSet.Put( *pSavedOptions );
810                             if ( pSavedReferer )
811                                 aSet.Put( *pSavedReferer );
812                             aSet.Put( SfxBoolItem( SID_TEMPLATE, true ) );
813                             if( pFilter )
814                                 aSet.Put( SfxStringItem( SID_FILTER_NAME, pFilter->GetFilterName() ) );
815                             GetDispatcher()->Execute( SID_OPENDOC, SfxCallMode::ASYNCHRON, aSet );
816                         }
817                     }
818                 }
819                 else
820                 {
821                     if ( xNewObj->GetModifyPasswordHash() && xNewObj->GetModifyPasswordHash() != xOldObj->GetModifyPasswordHash() )
822                     {
823                         xNewObj->SetModifyPasswordEntered( false );
824                         xNewObj->SetReadOnly();
825                     }
826                     else if ( rReq.GetSlot() == SID_EDITDOC || rReq.GetSlot() == SID_READONLYDOC )
827                     {
828                         xNewObj->SetReadOnlyUI( !bForEdit );
829                     }
830 
831 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
832                     if ( xNewObj->IsDocShared() )
833                     {
834                         // the file is shared but the closing can change the sharing control file
835                         xOldObj->DoNotCleanShareControlFile();
836                     }
837 #endif
838                     // the Reload and Silent items were only temporary, remove them
839                     xNewObj->GetMedium()->GetItemSet()->ClearItem( SID_RELOAD );
840                     xNewObj->GetMedium()->GetItemSet()->ClearItem( SID_SILENT );
841                     TransformItems( SID_OPENDOC, *xNewObj->GetMedium()->GetItemSet(), aLoadArgs );
842 
843                     UpdateDocument_Impl();
844 
845                     try
846                     {
847                         for (auto const& viewFrame : aViewFrames)
848                         {
849                             LoadViewIntoFrame_Impl( *xNewObj, viewFrame.first, aLoadArgs, viewFrame.second, false );
850                         }
851                         aViewFrames.clear();
852                     }
853                     catch( const Exception& )
854                     {
855                         // close the remaining frames
856                         // Don't catch exceptions herein, if this fails, then we're left in an indetermined state, and
857                         // crashing is better than trying to proceed
858                         for (auto const& viewFrame : aViewFrames)
859                         {
860                             Reference< util::XCloseable > xClose( viewFrame.first, UNO_QUERY_THROW );
861                             xClose->close( true );
862                         }
863                         aViewFrames.clear();
864                     }
865 
866                     // Propagate document closure.
867                     SfxGetpApp()->NotifyEvent( SfxEventHint( SfxEventHintId::CloseDoc, GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ), xOldObj ) );
868                 }
869 
870                 // Record as done
871                 rReq.Done( true );
872                 rReq.SetReturnValue(SfxBoolItem(rReq.GetSlot(), true));
873                 return;
874             }
875             else
876             {
877                 // Record as not done
878                 rReq.Done();
879                 rReq.SetReturnValue(SfxBoolItem(rReq.GetSlot(), false));
880                 m_pImpl->bReloading = false;
881                 return;
882             }
883         }
884     }
885 }
886 
887 void SfxViewFrame::StateReload_Impl( SfxItemSet& rSet )
888 {
889     SfxObjectShell* pSh = GetObjectShell();
890     if ( !pSh )
891     {
892         // I'm just on reload and am yielding myself ...
893         return;
894     }
895 
896     SfxWhichIter aIter( rSet );
897     for ( sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich() )
898     {
899         switch ( nWhich )
900         {
901             case SID_EDITDOC:
902             case SID_READONLYDOC:
903             {
904                 const SfxViewShell *pVSh;
905                 const SfxShell *pFSh;
906                 if ( !pSh->HasName() ||
907                      !( pSh->Get_Impl()->nLoadedFlags &  SfxLoadedFlags::MAINDOCUMENT ) ||
908                      (GetViewShell() && GetViewShell()->isEditDocLocked()) ||
909                      ( pSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED &&
910                        ( !(pVSh = pSh->GetViewShell())  ||
911                          !(pFSh = pVSh->GetFormShell()) ||
912                          !pFSh->IsDesignMode())))
913                     rSet.DisableItem( nWhich );
914                 else
915                 {
916                     const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(pSh->GetMedium()->GetItemSet(), SID_EDITDOC, false);
917                     if ( pItem && !pItem->GetValue() )
918                         rSet.DisableItem( nWhich );
919                     else
920                     {
921                         if (nWhich==SID_EDITDOC)
922                             rSet.Put( SfxBoolItem( nWhich, !pSh->IsReadOnly() ) );
923                         else if (nWhich==SID_READONLYDOC)
924                             rSet.Put( SfxBoolItem( nWhich, pSh->IsReadOnly() ) );
925                     }
926                 }
927                 break;
928             }
929 
930             case SID_RELOAD:
931             {
932                 if ( !pSh->CanReload_Impl() || pSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
933                     rSet.DisableItem(nWhich);
934                 else
935                 {
936                     // If any ChildFrame is reloadable, the slot is enabled,
937                     // so you can perform CTRL-Reload
938                     rSet.Put( SfxBoolItem( nWhich, false));
939                 }
940 
941                 break;
942             }
943         }
944     }
945 }
946 
947 void SfxViewFrame::ExecHistory_Impl( SfxRequest &rReq )
948 {
949     // Is there an Undo-Manager on the top Shell?
950     SfxShell *pSh = GetDispatcher()->GetShell(0);
951     SfxUndoManager* pShUndoMgr = pSh->GetUndoManager();
952     bool bOK = false;
953     if ( pShUndoMgr )
954     {
955         switch ( rReq.GetSlot() )
956         {
957             case SID_CLEARHISTORY:
958                 pShUndoMgr->Clear();
959                 bOK = true;
960                 break;
961 
962             case SID_UNDO:
963                 pShUndoMgr->Undo();
964                 GetBindings().InvalidateAll(false);
965                 bOK = true;
966                 break;
967 
968             case SID_REDO:
969                 pShUndoMgr->Redo();
970                 GetBindings().InvalidateAll(false);
971                 bOK = true;
972                 break;
973 
974             case SID_REPEAT:
975                 if ( pSh->GetRepeatTarget() )
976                     pShUndoMgr->Repeat( *pSh->GetRepeatTarget() );
977                 bOK = true;
978                 break;
979         }
980     }
981     else if ( GetViewShell() )
982     {
983         // The SW has its own undo in the View
984         const SfxPoolItem *pRet = GetViewShell()->ExecuteSlot( rReq );
985         if ( pRet )
986             bOK = static_cast<const SfxBoolItem*>(pRet)->GetValue();
987     }
988 
989     rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), bOK ) );
990     rReq.Done();
991 }
992 
993 void SfxViewFrame::StateHistory_Impl( SfxItemSet &rSet )
994 {
995     // Search for Undo-Manager
996     SfxShell *pSh = GetDispatcher()->GetShell(0);
997     if ( !pSh )
998         // I'm just on reload and am yielding myself ...
999         return;
1000 
1001     SfxUndoManager *pShUndoMgr = pSh->GetUndoManager();
1002     if ( !pShUndoMgr )
1003     {
1004         // The SW has its own undo in the View
1005         SfxWhichIter aIter( rSet );
1006         SfxViewShell *pViewSh = GetViewShell();
1007         if( !pViewSh ) return;
1008         for ( sal_uInt16 nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() )
1009             pViewSh->GetSlotState( nSID, nullptr, &rSet );
1010         return;
1011     }
1012 
1013     if ( pShUndoMgr->GetUndoActionCount() == 0 &&
1014          pShUndoMgr->GetRedoActionCount() == 0 &&
1015          pShUndoMgr->GetRepeatActionCount() == 0 )
1016         rSet.DisableItem( SID_CLEARHISTORY );
1017 
1018     if (pShUndoMgr->GetUndoActionCount())
1019     {
1020         const SfxUndoAction* pAction = pShUndoMgr->GetUndoAction();
1021         SfxViewShell *pViewSh = GetViewShell();
1022         if (pViewSh && pAction->GetViewShellId() != pViewSh->GetViewShellId())
1023         {
1024             rSet.Put(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE)));
1025         }
1026         else
1027         {
1028             rSet.Put( SfxStringItem( SID_UNDO, SvtResId(STR_UNDO)+pShUndoMgr->GetUndoActionComment() ) );
1029         }
1030     }
1031     else
1032         rSet.DisableItem( SID_UNDO );
1033 
1034     if (pShUndoMgr->GetRedoActionCount())
1035     {
1036         const SfxUndoAction* pAction = pShUndoMgr->GetRedoAction();
1037         SfxViewShell *pViewSh = GetViewShell();
1038         if (pViewSh && pAction->GetViewShellId() != pViewSh->GetViewShellId())
1039         {
1040             rSet.Put(SfxUInt32Item(SID_REDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE)));
1041         }
1042         else
1043         {
1044             rSet.Put(SfxStringItem(SID_REDO, SvtResId(STR_REDO) + pShUndoMgr->GetRedoActionComment()));
1045         }
1046     }
1047     else
1048         rSet.DisableItem( SID_REDO );
1049 
1050     SfxRepeatTarget *pTarget = pSh->GetRepeatTarget();
1051     if (pTarget && pShUndoMgr->GetRepeatActionCount() && pShUndoMgr->CanRepeat(*pTarget))
1052         rSet.Put( SfxStringItem( SID_REPEAT, SvtResId(STR_REPEAT)+pShUndoMgr->GetRepeatActionComment(*pTarget) ) );
1053     else
1054         rSet.DisableItem( SID_REPEAT );
1055 }
1056 
1057 void SfxViewFrame::PopShellAndSubShells_Impl( SfxViewShell& i_rViewShell )
1058 {
1059     i_rViewShell.PopSubShells_Impl();
1060     sal_uInt16 nLevel = m_pDispatcher->GetShellLevel( i_rViewShell );
1061     if ( nLevel != USHRT_MAX )
1062     {
1063         if ( nLevel )
1064         {
1065             // more sub shells on the stack, which were not affected by PopSubShells_Impl
1066             SfxShell *pSubShell = m_pDispatcher->GetShell( nLevel-1 );
1067             m_pDispatcher->Pop( *pSubShell, SfxDispatcherPopFlags::POP_UNTIL | SfxDispatcherPopFlags::POP_DELETE );
1068         }
1069         m_pDispatcher->Pop( i_rViewShell );
1070         m_pDispatcher->Flush();
1071     }
1072 
1073 }
1074 
1075 /*  [Description]
1076 
1077     This method empties the SfxViewFrame, i.e. takes the <SfxObjectShell>
1078     from the dispatcher and ends its <SfxListener> Relationship to this
1079     SfxObjectShell (by which they may even destroy themselves).
1080 
1081     Thus, by invoking ReleaseObjectShell() and  SetObjectShell() the
1082     SfxObjectShell can be replaced.
1083 
1084     Between ReleaseObjectShell() and SetObjectShell() the control cannot
1085     be handed over to the system.
1086 
1087     [Cross-reference]
1088 
1089     <SfxViewFrame::SetObjectShell(SfxObjectShell&)>
1090 */
1091 void SfxViewFrame::ReleaseObjectShell_Impl()
1092 {
1093     DBG_ASSERT( m_xObjSh.is(), "no SfxObjectShell to release!" );
1094 
1095     GetFrame().ReleasingComponent_Impl();
1096     if ( GetWindow().HasChildPathFocus( true ) )
1097     {
1098         GetWindow().GrabFocus();
1099     }
1100 
1101     SfxViewShell *pDyingViewSh = GetViewShell();
1102     if ( pDyingViewSh )
1103     {
1104         PopShellAndSubShells_Impl( *pDyingViewSh );
1105         pDyingViewSh->DisconnectAllClients();
1106         SetViewShell_Impl(nullptr);
1107         delete pDyingViewSh;
1108     }
1109 #ifdef DBG_UTIL
1110     else
1111         OSL_FAIL("No Shell");
1112 #endif
1113 
1114     if ( m_xObjSh.is() )
1115     {
1116         m_pDispatcher->Pop( *m_xObjSh );
1117         SfxModule* pModule = m_xObjSh->GetModule();
1118         if( pModule )
1119             m_pDispatcher->RemoveShell_Impl( *pModule );
1120         m_pDispatcher->Flush();
1121         EndListening( *m_xObjSh );
1122 
1123         Notify( *m_xObjSh, SfxHint(SfxHintId::TitleChanged) );
1124         Notify( *m_xObjSh, SfxHint(SfxHintId::DocChanged) );
1125 
1126         if ( 1 == m_xObjSh->GetOwnerLockCount() && m_pImpl->bObjLocked && m_xObjSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1127             m_xObjSh->DoClose();
1128         SfxObjectShellRef xDyingObjSh = m_xObjSh;
1129         m_xObjSh.clear();
1130         if( GetFrame().GetHasTitle() && m_pImpl->nDocViewNo )
1131             xDyingObjSh->GetNoSet_Impl().ReleaseIndex(m_pImpl->nDocViewNo-1);
1132         if ( m_pImpl->bObjLocked )
1133         {
1134             xDyingObjSh->OwnerLock( false );
1135             m_pImpl->bObjLocked = false;
1136         }
1137     }
1138 
1139     GetDispatcher()->SetDisableFlags( SfxDisableFlags::NONE );
1140 }
1141 
1142 void SfxViewFrame::Close()
1143 {
1144 
1145     DBG_ASSERT( GetFrame().IsClosing_Impl() || !GetFrame().GetFrameInterface().is(), "ViewFrame closed too early!" );
1146 
1147     // If no saving have been made up until now, then embedded Objects should
1148     // not be saved automatically anymore.
1149     if ( GetViewShell() )
1150         GetViewShell()->DisconnectAllClients();
1151     Broadcast( SfxHint( SfxHintId::Dying ) );
1152 
1153     if (SfxViewFrame::Current() == this)
1154         SfxViewFrame::SetViewFrame( nullptr );
1155 
1156     // Since the Dispatcher is emptied, it can not be used in any reasonable
1157     // manner, thus it is better to let the dispatcher be.
1158     GetDispatcher()->Lock(true);
1159     delete this;
1160 }
1161 
1162 void SfxViewFrame::DoActivate( bool bUI )
1163 {
1164     m_pDispatcher->DoActivate_Impl( bUI );
1165 }
1166 
1167 void SfxViewFrame::DoDeactivate(bool bUI, SfxViewFrame const * pNewFrame )
1168 {
1169     m_pDispatcher->DoDeactivate_Impl( bUI, pNewFrame );
1170 }
1171 
1172 void SfxViewFrame::InvalidateBorderImpl( const SfxViewShell* pSh )
1173 {
1174     if( !pSh || m_nAdjustPosPixelLock )
1175         return;
1176 
1177     if ( GetViewShell() && GetWindow().IsVisible() )
1178     {
1179         if ( GetFrame().IsInPlace() )
1180         {
1181             return;
1182         }
1183 
1184         DoAdjustPosSizePixel( GetViewShell(), Point(),
1185                                         GetWindow().GetOutputSizePixel(),
1186                                         false );
1187     }
1188 }
1189 
1190 void SfxViewFrame::SetBorderPixelImpl
1191 (
1192     const SfxViewShell* pVSh,
1193     const SvBorder&     rBorder
1194 )
1195 
1196 {
1197     m_pImpl->aBorder = rBorder;
1198 
1199     if ( m_pImpl->bResizeInToOut && !GetFrame().IsInPlace() )
1200     {
1201         Size aSize = pVSh->GetWindow()->GetOutputSizePixel();
1202         if ( aSize.Width() && aSize.Height() )
1203         {
1204             aSize.AdjustWidth(rBorder.Left() + rBorder.Right() );
1205             aSize.AdjustHeight(rBorder.Top() + rBorder.Bottom() );
1206 
1207             Size aOldSize = GetWindow().GetOutputSizePixel();
1208             GetWindow().SetOutputSizePixel( aSize );
1209             vcl::Window* pParent = &GetWindow();
1210             while ( pParent->GetParent() )
1211                 pParent = pParent->GetParent();
1212             Size aOuterSize = pParent->GetOutputSizePixel();
1213             aOuterSize.AdjustWidth( aSize.Width() - aOldSize.Width() );
1214             aOuterSize.AdjustHeight( aSize.Height() - aOldSize.Height() );
1215             pParent->SetOutputSizePixel( aOuterSize );
1216         }
1217     }
1218     else
1219     {
1220         tools::Rectangle aEditArea( Point(), GetWindow().GetOutputSizePixel() );
1221         aEditArea.AdjustLeft(rBorder.Left() );
1222         aEditArea.AdjustRight( -(rBorder.Right()) );
1223         aEditArea.AdjustTop(rBorder.Top() );
1224         aEditArea.AdjustBottom( -(rBorder.Bottom()) );
1225         pVSh->GetWindow()->SetPosSizePixel( aEditArea.TopLeft(), aEditArea.GetSize() );
1226     }
1227 }
1228 
1229 const SvBorder& SfxViewFrame::GetBorderPixelImpl() const
1230 {
1231     return m_pImpl->aBorder;
1232 }
1233 
1234 void SfxViewFrame::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1235 {
1236     if(m_pImpl->bIsDowning)
1237         return;
1238 
1239     // we know only SfxEventHint or simple SfxHint
1240     if (const SfxEventHint* pEventHint = dynamic_cast<const SfxEventHint*>(&rHint))
1241     {
1242         // When the Document is loaded asynchronously, was the Dispatcher
1243         // set as ReadOnly, to what must be returned when the document itself
1244         // is not read only, and the loading is finished.
1245         switch ( pEventHint->GetEventId() )
1246         {
1247             case SfxEventHintId::ModifyChanged:
1248             {
1249                 SfxBindings& rBind = GetBindings();
1250                 rBind.Invalidate( SID_DOC_MODIFIED );
1251                 rBind.Invalidate( SID_RELOAD );
1252                 rBind.Invalidate( SID_EDITDOC );
1253                 break;
1254             }
1255 
1256             case SfxEventHintId::OpenDoc:
1257             case SfxEventHintId::CreateDoc:
1258             {
1259                 if ( !m_xObjSh.is() )
1260                     break;
1261 
1262                 SfxBindings& rBind = GetBindings();
1263                 rBind.Invalidate( SID_RELOAD );
1264                 rBind.Invalidate( SID_EDITDOC );
1265 
1266                 const auto t0 = std::chrono::system_clock::now().time_since_epoch();
1267 
1268                 bool bIsUITest = false; //uitest.uicheck fails when the dialog is open
1269                 for( sal_uInt16 i = 0; i < Application::GetCommandLineParamCount(); i++ )
1270                 {
1271                     if( Application::GetCommandLineParam(i) == "--nologo" )
1272                         bIsUITest = true;
1273                 }
1274 
1275                 //what's new infobar
1276                 if (!officecfg::Setup::Product::ooSetupLastVersion::isReadOnly()) //don't show/update when readonly
1277                 {
1278                     OUString sSetupVersion = utl::ConfigManager::getProductVersion();
1279                     sal_Int32 iCurrent = sSetupVersion.getToken(0,'.').toInt32() * 10 + sSetupVersion.getToken(1,'.').toInt32();
1280                     OUString sLastVersion
1281                         = officecfg::Setup::Product::ooSetupLastVersion::get().value_or("0.0");
1282                     sal_Int32 iLast = sLastVersion.getToken(0,'.').toInt32() * 10 + sLastVersion.getToken(1,'.').toInt32();
1283                     if ((iCurrent > iLast) && !Application::IsHeadlessModeEnabled() && !bIsUITest)
1284                     {
1285                         VclPtr<SfxInfoBarWindow> pInfoBar = AppendInfoBar("whatsnew", "", SfxResId(STR_WHATSNEW_TEXT), InfobarType::INFO);
1286                         if (pInfoBar)
1287                         {
1288                             VclPtrInstance<PushButton> xWhatsNewButton(&GetWindow());
1289                             xWhatsNewButton->SetText(SfxResId(STR_WHATSNEW_BUTTON));
1290                             xWhatsNewButton->SetSizePixel(xWhatsNewButton->GetOptimalSize());
1291                             xWhatsNewButton->SetClickHdl(LINK(this, SfxViewFrame, WhatsNewHandler));
1292                             pInfoBar->addButton(xWhatsNewButton);
1293 
1294                             //update lastversion
1295                             std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
1296                             officecfg::Setup::Product::ooSetupLastVersion::set(
1297                                 sSetupVersion, batch);
1298                             batch->commit();
1299                         }
1300                     }
1301                 }
1302 
1303                 // show tip-of-the-day dialog
1304                 const bool bShowTipOfTheDay = officecfg::Office::Common::Misc::ShowTipOfTheDay::get();
1305                 if (bShowTipOfTheDay && !Application::IsHeadlessModeEnabled() && !bIsUITest) {
1306                     const sal_Int32 nLastTipOfTheDay = officecfg::Office::Common::Misc::LastTipOfTheDayShown::get();
1307                     const sal_Int32 nDay = std::chrono::duration_cast<std::chrono::hours>(t0).count()/24; // days since 1970-01-01
1308                     if (nDay-nLastTipOfTheDay > 0) { //only once per day
1309                         // tdf#127946 pass in argument for dialog parent
1310                         SfxUnoFrameItem aDocFrame(SID_FILLFRAME, GetFrame().GetFrameInterface());
1311                         GetDispatcher()->ExecuteList(SID_TIPOFTHEDAY, SfxCallMode::SLOT, {}, { &aDocFrame });
1312                     }
1313                 } //bShowTipOfTheDay
1314 
1315                 // inform about the community involvement
1316                 const sal_Int64 nLastGetInvolvedShown = officecfg::Setup::Product::LastTimeGetInvolvedShown::get();
1317                 const sal_Int64 nNow = std::chrono::duration_cast<std::chrono::seconds>(t0).count();
1318                 const sal_Int64 nPeriodSec(60 * 60 * 24 * 180); // 180 days in seconds
1319                 bool bUpdateLastTimeGetInvolvedShown = false;
1320 
1321                 if (nLastGetInvolvedShown == 0)
1322                     bUpdateLastTimeGetInvolvedShown = true;
1323                 else if (nPeriodSec < nNow && nLastGetInvolvedShown < (nNow + nPeriodSec/2) - nPeriodSec) // 90d alternating with donation
1324                 {
1325                     bUpdateLastTimeGetInvolvedShown = true;
1326 
1327                     VclPtr<SfxInfoBarWindow> pInfoBar = AppendInfoBar("getinvolved", "", SfxResId(STR_GET_INVOLVED_TEXT), InfobarType::INFO);
1328 
1329                     VclPtrInstance<PushButton> xGetInvolvedButton(&GetWindow());
1330                     xGetInvolvedButton->SetText(SfxResId(STR_GET_INVOLVED_BUTTON));
1331                     xGetInvolvedButton->SetSizePixel(xGetInvolvedButton->GetOptimalSize());
1332                     xGetInvolvedButton->SetClickHdl(LINK(this, SfxViewFrame, GetInvolvedHandler));
1333                     pInfoBar->addButton(xGetInvolvedButton);
1334                 }
1335 
1336                 if (bUpdateLastTimeGetInvolvedShown
1337                     && !officecfg::Setup::Product::LastTimeGetInvolvedShown::isReadOnly())
1338                 {
1339                     std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
1340                     officecfg::Setup::Product::LastTimeGetInvolvedShown::set(nNow, batch);
1341                     batch->commit();
1342                 }
1343 
1344                 // inform about donations
1345                 const sal_Int64 nLastDonateShown = officecfg::Setup::Product::LastTimeDonateShown::get();
1346                 bool bUpdateLastTimeDonateShown = false;
1347 
1348                 if (nLastDonateShown == 0)
1349                     bUpdateLastTimeDonateShown = true;
1350                 else if (nPeriodSec < nNow && nLastDonateShown < nNow - nPeriodSec) // 90d alternating with getinvolved
1351                 {
1352                     bUpdateLastTimeDonateShown = true;
1353 
1354                     VclPtr<SfxInfoBarWindow> pInfoBar = AppendInfoBar("donate", "", SfxResId(STR_DONATE_TEXT), InfobarType::INFO);
1355 
1356                     VclPtrInstance<PushButton> xDonateButton(&GetWindow());
1357                     xDonateButton->SetText(SfxResId(STR_DONATE_BUTTON));
1358                     xDonateButton->SetSizePixel(xDonateButton->GetOptimalSize());
1359                     xDonateButton->SetClickHdl(LINK(this, SfxViewFrame, DonationHandler));
1360                     pInfoBar->addButton(xDonateButton);
1361                 }
1362 
1363                 if (bUpdateLastTimeDonateShown
1364                     && !officecfg::Setup::Product::LastTimeDonateShown::isReadOnly())
1365                 {
1366                     std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
1367                     officecfg::Setup::Product::LastTimeDonateShown::set(nNow, batch);
1368                     batch->commit();
1369                 }
1370 
1371                 // read-only infobar if necessary
1372                 const SfxViewShell *pVSh;
1373                 const SfxShell *pFSh;
1374                 if ( m_xObjSh->IsReadOnly() &&
1375                     ! m_xObjSh->IsSecurityOptOpenReadOnly() &&
1376                     ( m_xObjSh->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ||
1377                         (( pVSh = m_xObjSh->GetViewShell()) && (pFSh = pVSh->GetFormShell()) && pFSh->IsDesignMode())))
1378                 {
1379                     bool bSignPDF = IsSignPDF(m_xObjSh);
1380 
1381                     auto pInfoBar = AppendInfoBar("readonly", "", SfxResId(bSignPDF ? STR_READONLY_PDF : STR_READONLY_DOCUMENT), InfobarType::INFO);
1382                     if (pInfoBar)
1383                     {
1384                         if (bSignPDF)
1385                         {
1386                             // SID_SIGNPDF opened a read-write PDF
1387                             // read-only for signing purposes.
1388                             VclPtrInstance<PushButton> xSignButton(&GetWindow());
1389                             xSignButton->SetText(SfxResId(STR_READONLY_SIGN));
1390                             xSignButton->SetSizePixel(xSignButton->GetOptimalSize());
1391                             xSignButton->SetClickHdl(LINK(this, SfxViewFrame, SignDocumentHandler));
1392                             pInfoBar->addButton(xSignButton);
1393                         }
1394 
1395                         bool showEditDocumentButton = true;
1396                         if (m_xObjSh->GetViewShell() && m_xObjSh->GetViewShell()->isEditDocLocked())
1397                             showEditDocumentButton = false;
1398 
1399                         if (showEditDocumentButton)
1400                         {
1401                             VclPtrInstance<PushButton> xBtn(&GetWindow());
1402                             xBtn->SetText(SfxResId(STR_READONLY_EDIT));
1403                             xBtn->SetSizePixel(xBtn->GetOptimalSize());
1404                             xBtn->SetClickHdl(LINK(this, SfxViewFrame, SwitchReadOnlyHandler));
1405                             pInfoBar->addButton(xBtn);
1406                         }
1407                     }
1408                 }
1409 
1410                 if (SfxClassificationHelper::IsClassified(m_xObjSh->getDocProperties()))
1411                 {
1412                     // Document has BAILS properties, display an infobar accordingly.
1413                     SfxClassificationHelper aHelper(m_xObjSh->getDocProperties());
1414                     aHelper.UpdateInfobar(*this);
1415                 }
1416 
1417                 // Add pending infobars
1418                 std::vector<InfobarData>& aPendingInfobars = m_xObjSh->getPendingInfobars();
1419                 while (!aPendingInfobars.empty())
1420                 {
1421                     InfobarData& aInfobarData = aPendingInfobars.back();
1422                     AppendInfoBar(aInfobarData.msId, aInfobarData.msPrimaryMessage,
1423                                   aInfobarData.msSecondaryMessage, aInfobarData.maInfobarType,
1424                                   aInfobarData.mbShowCloseButton);
1425                     aPendingInfobars.pop_back();
1426                 }
1427 
1428                 break;
1429             }
1430             default: break;
1431         }
1432     }
1433     else
1434     {
1435         switch( rHint.GetId() )
1436         {
1437             case SfxHintId::ModeChanged:
1438             {
1439                 UpdateTitle();
1440 
1441                 if ( !m_xObjSh.is() )
1442                     break;
1443 
1444                 // Switch r/o?
1445                 SfxBindings& rBind = GetBindings();
1446                 rBind.Invalidate( SID_RELOAD );
1447                 SfxDispatcher *pDispat = GetDispatcher();
1448                 bool bWasReadOnly = pDispat->GetReadOnly_Impl();
1449                 bool bIsReadOnly = m_xObjSh->IsReadOnly();
1450                 if ( bWasReadOnly != bIsReadOnly )
1451                 {
1452                     // Then also TITLE_CHANGED
1453                     UpdateTitle();
1454                     rBind.Invalidate( SID_FILE_NAME );
1455                     rBind.Invalidate( SID_DOCINFO_TITLE );
1456                     rBind.Invalidate( SID_EDITDOC );
1457 
1458                     pDispat->GetBindings()->InvalidateAll(true);
1459                     pDispat->SetReadOnly_Impl( bIsReadOnly );
1460 
1461                     // Only force and Dispatcher-Update, if it is done next
1462                     // anyway, otherwise flickering or GPF is possibel since
1463                     // the Writer for example prefers in Resize perform some
1464                     // actions which has a SetReadOnlyUI in Dispatcher as a
1465                     // result!
1466 
1467                     if ( pDispat->IsUpdated_Impl() )
1468                         pDispat->Update_Impl(true);
1469                 }
1470 
1471                 Enable( !m_xObjSh->IsInModalMode() );
1472                 break;
1473             }
1474 
1475             case SfxHintId::TitleChanged:
1476             {
1477                 UpdateTitle();
1478                 SfxBindings& rBind = GetBindings();
1479                 rBind.Invalidate( SID_FILE_NAME );
1480                 rBind.Invalidate( SID_DOCINFO_TITLE );
1481                 rBind.Invalidate( SID_EDITDOC );
1482                 rBind.Invalidate( SID_RELOAD );
1483                 break;
1484             }
1485 
1486             case SfxHintId::DocumentRepair:
1487             {
1488                 GetBindings().Invalidate( SID_DOC_REPAIR );
1489                 break;
1490             }
1491 
1492             case SfxHintId::Deinitializing:
1493             {
1494                 vcl::Window* pFrameWin = GetWindow().GetFrameWindow();
1495                 if (pFrameWin && pFrameWin->GetLOKNotifier())
1496                     pFrameWin->ReleaseLOKNotifier();
1497 
1498                 GetFrame().DoClose();
1499                 break;
1500             }
1501             case SfxHintId::Dying:
1502                 // when the Object is being deleted, destroy the view too
1503                 if ( m_xObjSh.is() )
1504                     ReleaseObjectShell_Impl();
1505                 else
1506                     GetFrame().DoClose();
1507                 break;
1508             default: break;
1509         }
1510     }
1511 }
1512 
1513 IMPL_LINK_NOARG(SfxViewFrame, WhatsNewHandler, Button*, void)
1514 {
1515     GetDispatcher()->Execute(SID_WHATSNEW);
1516 }
1517 
1518 IMPL_LINK_NOARG(SfxViewFrame, GetInvolvedHandler, Button*, void)
1519 {
1520     GetDispatcher()->Execute(SID_GETINVOLVED);
1521 }
1522 
1523 IMPL_LINK_NOARG(SfxViewFrame, DonationHandler, Button*, void)
1524 {
1525     GetDispatcher()->Execute(SID_DONATION);
1526 }
1527 
1528 IMPL_LINK(SfxViewFrame, SwitchReadOnlyHandler, Button*, pButton, void)
1529 {
1530     if (m_xObjSh.is() && IsSignPDF(m_xObjSh))
1531     {
1532         SfxEditDocumentDialog aDialog(pButton->GetFrameWeld());
1533         if (aDialog.run() != RET_OK)
1534             return;
1535     }
1536     GetDispatcher()->Execute(SID_EDITDOC);
1537 }
1538 
1539 IMPL_LINK_NOARG(SfxViewFrame, SignDocumentHandler, Button*, void)
1540 {
1541     GetDispatcher()->Execute(SID_SIGNATURE);
1542 }
1543 
1544 void SfxViewFrame::Construct_Impl( SfxObjectShell *pObjSh )
1545 {
1546     m_pImpl->bResizeInToOut = true;
1547     m_pImpl->bObjLocked = false;
1548     m_pImpl->nCurViewId = SFX_INTERFACE_NONE;
1549     m_pImpl->bReloading = false;
1550     m_pImpl->bIsDowning = false;
1551     m_pImpl->bModal = false;
1552     m_pImpl->bEnabled = true;
1553     m_pImpl->nDocViewNo = 0;
1554     m_pImpl->aMargin = Size( -1, -1 );
1555     m_pImpl->pWindow = nullptr;
1556 
1557     SetPool( &SfxGetpApp()->GetPool() );
1558     m_pDispatcher.reset( new SfxDispatcher(this) );
1559     if ( !GetBindings().GetDispatcher() )
1560         GetBindings().SetDispatcher( m_pDispatcher.get() );
1561 
1562     m_xObjSh = pObjSh;
1563     if ( m_xObjSh.is() && m_xObjSh->IsPreview() )
1564         GetDispatcher()->SetQuietMode_Impl( true );
1565 
1566     if ( pObjSh )
1567     {
1568         m_pDispatcher->Push( *SfxGetpApp() );
1569         SfxModule* pModule = m_xObjSh->GetModule();
1570         if( pModule )
1571             m_pDispatcher->Push( *pModule );
1572         m_pDispatcher->Push( *this );
1573         m_pDispatcher->Push( *pObjSh );
1574         m_pDispatcher->Flush();
1575         StartListening( *pObjSh );
1576         Notify( *pObjSh, SfxHint(SfxHintId::TitleChanged) );
1577         Notify( *pObjSh, SfxHint(SfxHintId::DocChanged) );
1578         m_pDispatcher->SetReadOnly_Impl( pObjSh->IsReadOnly() );
1579     }
1580     else
1581     {
1582         m_pDispatcher->Push( *SfxGetpApp() );
1583         m_pDispatcher->Push( *this );
1584         m_pDispatcher->Flush();
1585     }
1586 
1587     SfxViewFrameArr_Impl &rViewArr = SfxGetpApp()->GetViewFrames_Impl();
1588     rViewArr.push_back( this );
1589 }
1590 
1591 /*  [Description]
1592 
1593     Constructor of SfxViewFrame for a <SfxObjectShell> from the Resource.
1594     The 'nViewId' to the created <SfxViewShell> can be returned.
1595     (default is the SfxViewShell-Subclass that was registered first).
1596 */
1597 SfxViewFrame::SfxViewFrame
1598 (
1599     SfxFrame&           rFrame,
1600     SfxObjectShell*     pObjShell
1601 )
1602     : m_pImpl( new SfxViewFrame_Impl( rFrame ) )
1603     , m_pBindings( new SfxBindings )
1604     , m_pHelpData(CreateSVHelpData())
1605     , m_pWinData(CreateSVWinData())
1606     , m_nAdjustPosPixelLock( 0 )
1607 {
1608 
1609     rFrame.SetCurrentViewFrame_Impl( this );
1610     rFrame.SetHasTitle( true );
1611     Construct_Impl( pObjShell );
1612 
1613     m_pImpl->pWindow = VclPtr<SfxFrameViewWindow_Impl>::Create( this, rFrame.GetWindow() );
1614     m_pImpl->pWindow->SetSizePixel( rFrame.GetWindow().GetOutputSizePixel() );
1615     rFrame.SetOwnsBindings_Impl( true );
1616     rFrame.CreateWorkWindow_Impl();
1617 }
1618 
1619 SfxViewFrame::~SfxViewFrame()
1620 {
1621     m_pImpl->bIsDowning = true;
1622 
1623     if ( SfxViewFrame::Current() == this )
1624         SfxViewFrame::SetViewFrame( nullptr );
1625 
1626     ReleaseObjectShell_Impl();
1627 
1628     if ( GetFrame().OwnsBindings_Impl() )
1629         // The Bindings delete the Frame!
1630         KillDispatcher_Impl();
1631 
1632     m_pImpl->pWindow.disposeAndClear();
1633 
1634     if ( GetFrame().GetCurrentViewFrame() == this )
1635         GetFrame().SetCurrentViewFrame_Impl( nullptr );
1636 
1637     // Unregister from the Frame List.
1638     SfxApplication *pSfxApp = SfxApplication::Get();
1639     if (pSfxApp)
1640     {
1641         SfxViewFrameArr_Impl &rFrames = pSfxApp->GetViewFrames_Impl();
1642         SfxViewFrameArr_Impl::iterator it = std::find( rFrames.begin(), rFrames.end(), this );
1643         rFrames.erase( it );
1644     }
1645 
1646     // Delete Member
1647     KillDispatcher_Impl();
1648 
1649     DestroySVHelpData(m_pHelpData);
1650     m_pHelpData = nullptr;
1651 
1652     DestroySVWinData(m_pWinData);
1653     m_pWinData = nullptr;
1654 }
1655 
1656 // Remove and delete the Dispatcher.
1657 void SfxViewFrame::KillDispatcher_Impl()
1658 {
1659 
1660     SfxModule* pModule = m_xObjSh.is() ? m_xObjSh->GetModule() : nullptr;
1661     if ( m_xObjSh.is() )
1662         ReleaseObjectShell_Impl();
1663     if ( m_pDispatcher )
1664     {
1665         if( pModule )
1666             m_pDispatcher->Pop( *pModule, SfxDispatcherPopFlags::POP_UNTIL );
1667         else
1668             m_pDispatcher->Pop( *this );
1669         m_pDispatcher.reset();
1670     }
1671 }
1672 
1673 SfxViewFrame* SfxViewFrame::Current()
1674 {
1675     SfxApplication* pApp = SfxApplication::Get();
1676     return pApp ? pApp->Get_Impl()->pViewFrame : nullptr;
1677 }
1678 
1679 // returns the first window of spec. type viewing the specified doc.
1680 SfxViewFrame* SfxViewFrame::GetFirst
1681 (
1682     const SfxObjectShell*   pDoc,
1683     bool                    bOnlyIfVisible
1684 )
1685 {
1686     SfxApplication *pSfxApp = SfxApplication::Get();
1687     if (!pSfxApp)
1688         return nullptr;
1689 
1690     SfxViewFrameArr_Impl &rFrames = pSfxApp->GetViewFrames_Impl();
1691 
1692     // search for a SfxDocument of the specified type
1693     for (SfxViewFrame* pFrame : rFrames)
1694     {
1695         if  (   ( !pDoc || pDoc == pFrame->GetObjectShell() )
1696             &&  ( !bOnlyIfVisible || pFrame->IsVisible() )
1697             )
1698             return pFrame;
1699     }
1700 
1701     return nullptr;
1702 }
1703 
1704 // returns the next window of spec. type viewing the specified doc.
1705 SfxViewFrame* SfxViewFrame::GetNext
1706 (
1707     const SfxViewFrame&     rPrev,
1708     const SfxObjectShell*   pDoc,
1709     bool                    bOnlyIfVisible
1710 )
1711 {
1712     SfxApplication *pSfxApp = SfxApplication::Get();
1713     if (!pSfxApp)
1714         return nullptr;
1715 
1716     SfxViewFrameArr_Impl &rFrames = pSfxApp->GetViewFrames_Impl();
1717 
1718     // refind the specified predecessor
1719     size_t nPos;
1720     for ( nPos = 0; nPos < rFrames.size(); ++nPos )
1721         if ( rFrames[nPos] == &rPrev )
1722             break;
1723 
1724     // search for a Frame of the specified type
1725     for ( ++nPos; nPos < rFrames.size(); ++nPos )
1726     {
1727         SfxViewFrame *pFrame = rFrames[nPos];
1728         if  (   ( !pDoc || pDoc == pFrame->GetObjectShell() )
1729             &&  ( !bOnlyIfVisible || pFrame->IsVisible() )
1730             )
1731             return pFrame;
1732     }
1733     return nullptr;
1734 }
1735 
1736 SfxProgress* SfxViewFrame::GetProgress() const
1737 {
1738     SfxObjectShell *pObjSh = m_xObjSh.get();
1739     return pObjSh ? pObjSh->GetProgress() : nullptr;
1740 }
1741 
1742 void SfxViewFrame::DoAdjustPosSizePixel //! divide on Inner.../Outer...
1743 (
1744     SfxViewShell*   pSh,
1745     const Point&    rPos,
1746     const Size&     rSize,
1747     bool inplaceEditModeChange
1748 )
1749 {
1750 
1751     // Components do not use this Method!
1752     if( pSh && pSh->GetWindow() && !m_nAdjustPosPixelLock )
1753     {
1754         m_nAdjustPosPixelLock++;
1755         if ( m_pImpl->bResizeInToOut )
1756             pSh->InnerResizePixel( rPos, rSize, inplaceEditModeChange );
1757         else
1758             pSh->OuterResizePixel( rPos, rSize );
1759         m_nAdjustPosPixelLock--;
1760     }
1761 }
1762 
1763 bool SfxViewFrameItem::operator==( const SfxPoolItem &rItem ) const
1764 {
1765     return SfxPoolItem::operator==(rItem) &&
1766         static_cast<const SfxViewFrameItem&>(rItem).pFrame == pFrame;
1767 }
1768 
1769 SfxViewFrameItem* SfxViewFrameItem::Clone( SfxItemPool *) const
1770 {
1771     return new SfxViewFrameItem( *this );
1772 }
1773 
1774 void SfxViewFrame::SetViewShell_Impl( SfxViewShell *pVSh )
1775 /*  [Description]
1776 
1777     Internal Method to set the current <SfxViewShell> Instance,
1778     that is active int this SfxViewFrame at the moment.
1779 */
1780 {
1781     SfxShell::SetViewShell_Impl( pVSh );
1782 
1783     // Hack: InPlaceMode
1784     if ( pVSh )
1785         m_pImpl->bResizeInToOut = false;
1786 }
1787 
1788 void SfxViewFrame::ForceOuterResize_Impl()
1789 {
1790     m_pImpl->bResizeInToOut = true;
1791 }
1792 
1793 void SfxViewFrame::GetDocNumber_Impl()
1794 {
1795     DBG_ASSERT( GetObjectShell(), "No Document!" );
1796     GetObjectShell()->SetNamedVisibility_Impl();
1797     m_pImpl->nDocViewNo = GetObjectShell()->GetNoSet_Impl().GetFreeIndex()+1;
1798 }
1799 
1800 void SfxViewFrame::Enable( bool bEnable )
1801 {
1802     if ( bEnable == m_pImpl->bEnabled )
1803         return;
1804 
1805     m_pImpl->bEnabled = bEnable;
1806 
1807     vcl::Window *pWindow = &GetFrame().GetWindow();
1808     if ( !bEnable )
1809         m_pImpl->bWindowWasEnabled = pWindow->IsInputEnabled();
1810     if ( !bEnable || m_pImpl->bWindowWasEnabled )
1811         pWindow->EnableInput( bEnable );
1812 
1813     // cursor and focus
1814     SfxViewShell* pViewSh = GetViewShell();
1815     if ( bEnable )
1816     {
1817         // show cursor
1818         if ( pViewSh )
1819             pViewSh->ShowCursor();
1820     }
1821     else
1822     {
1823         // hide cursor
1824         if ( pViewSh )
1825             pViewSh->ShowCursor(false);
1826     }
1827 }
1828 
1829 /*  [Description]
1830 
1831     This method makes the Frame-Window visible and before transmits the
1832     window name. In addition, the document is held. In general one can never
1833     show the window directly!
1834 */
1835 void SfxViewFrame::Show()
1836 {
1837     // First lock the objectShell so that UpdateTitle() is valid:
1838     // IsVisible() == true (:#)
1839     if ( m_xObjSh.is() )
1840     {
1841         m_xObjSh->GetMedium()->GetItemSet()->ClearItem( SID_HIDDEN );
1842         if ( !m_pImpl->bObjLocked )
1843             LockObjectShell_Impl();
1844 
1845         // Adjust Doc-Shell title number, get unique view-no
1846         if ( 0 == m_pImpl->nDocViewNo  )
1847         {
1848             GetDocNumber_Impl();
1849             UpdateTitle();
1850         }
1851     }
1852     else
1853         UpdateTitle();
1854 
1855     // Display Frame-window, but only if the ViewFrame has no window of its
1856     // own or if it does not contain a Component
1857     GetWindow().Show();
1858     GetFrame().GetWindow().Show();
1859 }
1860 
1861 
1862 bool SfxViewFrame::IsVisible() const
1863 {
1864     return m_pImpl->bObjLocked;
1865 }
1866 
1867 
1868 void SfxViewFrame::LockObjectShell_Impl()
1869 {
1870     DBG_ASSERT( !m_pImpl->bObjLocked, "Wrong Locked status!" );
1871 
1872     DBG_ASSERT( GetObjectShell(), "No Document!" );
1873     GetObjectShell()->OwnerLock(true);
1874     m_pImpl->bObjLocked = true;
1875 }
1876 
1877 
1878 void SfxViewFrame::MakeActive_Impl( bool bGrabFocus )
1879 {
1880     if ( !GetViewShell() || GetFrame().IsClosing_Impl() )
1881         return;
1882 
1883     if ( !IsVisible() )
1884         return;
1885 
1886     bool bPreview = false;
1887     if (GetObjectShell()->IsPreview())
1888     {
1889         bPreview = true;
1890     }
1891 
1892     css::uno::Reference<css::frame::XFrame> xFrame = GetFrame().GetFrameInterface();
1893     if (!bPreview)
1894     {
1895         SetViewFrame(this);
1896         GetBindings().SetActiveFrame(css::uno::Reference<css::frame::XFrame>());
1897         uno::Reference<frame::XFramesSupplier> xSupp(xFrame, uno::UNO_QUERY);
1898         if (xSupp.is())
1899             xSupp->setActiveFrame(uno::Reference<frame::XFrame>());
1900 
1901         css::uno::Reference< css::awt::XWindow > xContainerWindow = xFrame->getContainerWindow();
1902         VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xContainerWindow);
1903         if (pWindow && pWindow->HasChildPathFocus() && bGrabFocus)
1904         {
1905             SfxInPlaceClient *pCli = GetViewShell()->GetUIActiveClient();
1906             if (!pCli || !pCli->IsObjectUIActive())
1907                 GetFrame().GrabFocusOnComponent_Impl();
1908         }
1909     }
1910     else
1911     {
1912         GetBindings().SetDispatcher(GetDispatcher());
1913         GetBindings().SetActiveFrame(css::uno::Reference<css::frame::XFrame>());
1914         GetDispatcher()->Update_Impl();
1915     }
1916 }
1917 
1918 SfxObjectShell* SfxViewFrame::GetObjectShell()
1919 {
1920     return m_xObjSh.get();
1921 }
1922 
1923 const Size& SfxViewFrame::GetMargin_Impl() const
1924 {
1925     return m_pImpl->aMargin;
1926 }
1927 
1928 SfxViewFrame* SfxViewFrame::LoadViewIntoFrame_Impl_NoThrow( const SfxObjectShell& i_rDoc, const Reference< XFrame >& i_rFrame,
1929                                                    const SfxInterfaceId i_nViewId, const bool i_bHidden )
1930 {
1931     Reference< XFrame > xFrame( i_rFrame );
1932     bool bOwnFrame = false;
1933     SfxViewShell* pSuccessView = nullptr;
1934     try
1935     {
1936         if ( !xFrame.is() )
1937         {
1938             Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
1939 
1940             if ( !i_bHidden )
1941             {
1942                 try
1943                 {
1944                     // if there is a backing component, use it
1945                     ::framework::FrameListAnalyzer aAnalyzer( xDesktop, Reference< XFrame >(), FrameAnalyzerFlags::BackingComponent );
1946 
1947                     if ( aAnalyzer.m_xBackingComponent.is() )
1948                         xFrame = aAnalyzer.m_xBackingComponent;
1949                 }
1950                 catch( uno::Exception& )
1951                 {}
1952             }
1953 
1954             if ( !xFrame.is() )
1955                 xFrame.set( xDesktop->findFrame( "_blank", 0 ), UNO_SET_THROW );
1956 
1957             bOwnFrame = true;
1958         }
1959 
1960         pSuccessView = LoadViewIntoFrame_Impl(
1961             i_rDoc,
1962             xFrame,
1963             Sequence< PropertyValue >(),    // means "reuse existing model's args"
1964             i_nViewId,
1965             i_bHidden
1966         );
1967 
1968         if ( bOwnFrame && !i_bHidden )
1969         {
1970             // ensure the frame/window is visible
1971             Reference< XWindow > xContainerWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
1972             xContainerWindow->setVisible( true );
1973         }
1974     }
1975     catch( const Exception& )
1976     {
1977         DBG_UNHANDLED_EXCEPTION("sfx.view");
1978     }
1979 
1980     if ( pSuccessView )
1981         return pSuccessView->GetViewFrame();
1982 
1983     if ( bOwnFrame )
1984     {
1985         try
1986         {
1987             xFrame->dispose();
1988         }
1989         catch( const Exception& )
1990         {
1991             DBG_UNHANDLED_EXCEPTION("sfx.view");
1992         }
1993     }
1994 
1995     return nullptr;
1996 }
1997 
1998 SfxViewShell* SfxViewFrame::LoadViewIntoFrame_Impl( const SfxObjectShell& i_rDoc, const Reference< XFrame >& i_rFrame,
1999                                            const Sequence< PropertyValue >& i_rLoadArgs, const SfxInterfaceId i_nViewId,
2000                                            const bool i_bHidden )
2001 {
2002     Reference< XModel > xDocument( i_rDoc.GetModel(), UNO_SET_THROW );
2003 
2004     ::comphelper::NamedValueCollection aTransformLoadArgs( i_rLoadArgs.hasElements() ? i_rLoadArgs : xDocument->getArgs() );
2005     aTransformLoadArgs.put( "Model", xDocument );
2006     if ( i_nViewId )
2007         aTransformLoadArgs.put( "ViewId", sal_uInt16( i_nViewId ) );
2008     if ( i_bHidden )
2009         aTransformLoadArgs.put( "Hidden", i_bHidden );
2010     else
2011         aTransformLoadArgs.remove( "Hidden" );
2012 
2013     Reference< XComponentLoader > xLoader( i_rFrame, UNO_QUERY_THROW );
2014     xLoader->loadComponentFromURL( "private:object", "_self", 0,
2015         aTransformLoadArgs.getPropertyValues() );
2016 
2017     SfxViewShell* pViewShell = SfxViewShell::Get( i_rFrame->getController() );
2018     ENSURE_OR_THROW( pViewShell,
2019         "SfxViewFrame::LoadViewIntoFrame_Impl: loading an SFX doc into a frame resulted in a non-SFX view - quite impossible" );
2020     return pViewShell;
2021 }
2022 
2023 SfxViewFrame* SfxViewFrame::LoadHiddenDocument( SfxObjectShell const & i_rDoc, SfxInterfaceId i_nViewId )
2024 {
2025     return LoadViewIntoFrame_Impl_NoThrow( i_rDoc, Reference< XFrame >(), i_nViewId, true );
2026 }
2027 
2028 SfxViewFrame* SfxViewFrame::LoadDocument( SfxObjectShell const & i_rDoc, SfxInterfaceId i_nViewId )
2029 {
2030     return LoadViewIntoFrame_Impl_NoThrow( i_rDoc, Reference< XFrame >(), i_nViewId, false );
2031 }
2032 
2033 SfxViewFrame* SfxViewFrame::LoadDocumentIntoFrame( SfxObjectShell const & i_rDoc, const Reference< XFrame >& i_rTargetFrame )
2034 {
2035     return LoadViewIntoFrame_Impl_NoThrow( i_rDoc, i_rTargetFrame, SFX_INTERFACE_NONE, false );
2036 }
2037 
2038 SfxViewFrame* SfxViewFrame::LoadDocumentIntoFrame( SfxObjectShell const & i_rDoc, const SfxFrameItem* i_pFrameItem, SfxInterfaceId i_nViewId )
2039 {
2040     return LoadViewIntoFrame_Impl_NoThrow( i_rDoc, i_pFrameItem && i_pFrameItem->GetFrame() ? i_pFrameItem->GetFrame()->GetFrameInterface() : nullptr, i_nViewId, false );
2041 }
2042 
2043 SfxViewFrame* SfxViewFrame::DisplayNewDocument( SfxObjectShell const & i_rDoc, const SfxRequest& i_rCreateDocRequest )
2044 {
2045     const SfxUnoFrameItem* pFrameItem = i_rCreateDocRequest.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
2046     const SfxBoolItem* pHiddenItem = i_rCreateDocRequest.GetArg<SfxBoolItem>(SID_HIDDEN);
2047 
2048     return LoadViewIntoFrame_Impl_NoThrow(
2049         i_rDoc,
2050         pFrameItem ? pFrameItem->GetFrame() : nullptr,
2051         SFX_INTERFACE_NONE,
2052         pHiddenItem && pHiddenItem->GetValue()
2053     );
2054 }
2055 
2056 SfxViewFrame* SfxViewFrame::Get( const Reference< XController>& i_rController, const SfxObjectShell* i_pDoc )
2057 {
2058     if ( !i_rController.is() )
2059         return nullptr;
2060 
2061     const SfxObjectShell* pDoc = i_pDoc;
2062     if ( !pDoc )
2063     {
2064         Reference< XModel > xDocument( i_rController->getModel() );
2065         for (   pDoc = SfxObjectShell::GetFirst( nullptr, false );
2066                 pDoc;
2067                 pDoc = SfxObjectShell::GetNext( *pDoc, nullptr, false )
2068             )
2069         {
2070             if ( pDoc->GetModel() == xDocument )
2071                 break;
2072         }
2073     }
2074 
2075     SfxViewFrame* pViewFrame = nullptr;
2076     for (   pViewFrame = SfxViewFrame::GetFirst( pDoc, false );
2077             pViewFrame;
2078             pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDoc, false )
2079         )
2080     {
2081         if ( pViewFrame->GetViewShell()->GetController() == i_rController )
2082             break;
2083     }
2084 
2085     return pViewFrame;
2086 }
2087 
2088 void SfxViewFrame::SaveCurrentViewData_Impl( const SfxInterfaceId i_nNewViewId )
2089 {
2090     SfxViewShell* pCurrentShell = GetViewShell();
2091     ENSURE_OR_RETURN_VOID( pCurrentShell != nullptr, "SfxViewFrame::SaveCurrentViewData_Impl: no current view shell -> no current view data!" );
2092 
2093     // determine the logical (API) view name
2094     const SfxObjectFactory& rDocFactory( pCurrentShell->GetObjectShell()->GetFactory() );
2095     const sal_uInt16 nCurViewNo = rDocFactory.GetViewNo_Impl( GetCurViewId(), 0 );
2096     const OUString sCurrentViewName = rDocFactory.GetViewFactory( nCurViewNo ).GetAPIViewName();
2097     const sal_uInt16 nNewViewNo = rDocFactory.GetViewNo_Impl( i_nNewViewId, 0 );
2098     const OUString sNewViewName = rDocFactory.GetViewFactory( nNewViewNo ).GetAPIViewName();
2099     if ( sCurrentViewName.isEmpty() || sNewViewName.isEmpty() )
2100     {
2101         // can't say anything about the view, the respective application did not yet migrate its code to
2102         // named view factories => bail out
2103         OSL_FAIL( "SfxViewFrame::SaveCurrentViewData_Impl: views without API names? Shouldn't happen anymore?" );
2104         return;
2105     }
2106     SAL_WARN_IF(sNewViewName == sCurrentViewName, "sfx.view", "SfxViewFrame::SaveCurrentViewData_Impl: suspicious: new and old view name are identical!");
2107 
2108     // save the view data only when we're moving from a non-print-preview to the print-preview view
2109     if ( sNewViewName != "PrintPreview" )
2110         return;
2111 
2112     // retrieve the view data from the view
2113     Sequence< PropertyValue > aViewData;
2114     pCurrentShell->WriteUserDataSequence( aViewData );
2115 
2116     try
2117     {
2118         // retrieve view data (for *all* views) from the model
2119         const Reference< XController > xController( pCurrentShell->GetController(), UNO_SET_THROW );
2120         const Reference< XViewDataSupplier > xViewDataSupplier( xController->getModel(), UNO_QUERY_THROW );
2121         const Reference< XIndexContainer > xViewData( xViewDataSupplier->getViewData(), UNO_QUERY_THROW );
2122 
2123         // look up the one view data item which corresponds to our current view, and remove it
2124         const sal_Int32 nCount = xViewData->getCount();
2125         for ( sal_Int32 i=0; i<nCount; ++i )
2126         {
2127             const ::comphelper::NamedValueCollection aCurViewData( xViewData->getByIndex(i) );
2128             const OUString sViewId( aCurViewData.getOrDefault( "ViewId", OUString() ) );
2129             if ( sViewId.isEmpty() )
2130                 continue;
2131 
2132             const SfxViewFactory* pViewFactory = rDocFactory.GetViewFactoryByViewName( sViewId );
2133             if ( pViewFactory == nullptr )
2134                 continue;
2135 
2136             if ( pViewFactory->GetOrdinal() == GetCurViewId() )
2137             {
2138                 xViewData->removeByIndex(i);
2139                 break;
2140             }
2141         }
2142 
2143         // then replace it with the most recent view data we just obtained
2144         xViewData->insertByIndex( 0, makeAny( aViewData ) );
2145     }
2146     catch( const Exception& )
2147     {
2148         DBG_UNHANDLED_EXCEPTION("sfx.view");
2149     }
2150 }
2151 
2152 /*  [Description]
2153 
2154     Internal Method for switching to another <SfxViewShell> subclass,
2155     which should be created in this SfxMDIFrame. If no SfxViewShell exist
2156     in this SfxMDIFrame, then one will first be created.
2157 
2158 
2159     [Return Value]
2160 
2161     bool                        true
2162                                 requested SfxViewShell was created and a
2163                                 possibly existing one deleted
2164 
2165                                 false
2166                                 SfxViewShell requested could not be created,
2167                                 the existing SfxViewShell thus continue to exist
2168 */
2169 bool SfxViewFrame::SwitchToViewShell_Impl
2170 (
2171     sal_uInt16  nViewIdOrNo,    /*  > 0
2172                                 Registration-Id of the View, to which the
2173                                 method should switch, for example the one
2174                                 that will be created.
2175 
2176                                 == 0
2177                                 First use the Default view. */
2178 
2179     bool        bIsIndex        /*  true
2180                                 'nViewIdOrNo' is no Registration-Id instead
2181                                 an Index of <SfxViewFrame> in <SfxObjectShell>.
2182                                 */
2183 )
2184 {
2185     try
2186     {
2187         ENSURE_OR_THROW( GetObjectShell() != nullptr, "not possible without a document" );
2188 
2189         // if we already have a view shell, remove it
2190         SfxViewShell* pOldSh = GetViewShell();
2191         OSL_PRECOND( pOldSh, "SfxViewFrame::SwitchToViewShell_Impl: that's called *switch* (not for *initial-load*) for a reason" );
2192         if ( pOldSh )
2193         {
2194             // ask whether it can be closed
2195             if ( !pOldSh->PrepareClose() )
2196                 return false;
2197 
2198             // remove sub shells from Dispatcher before switching to new ViewShell
2199             PopShellAndSubShells_Impl( *pOldSh );
2200         }
2201 
2202         GetBindings().ENTERREGISTRATIONS();
2203         LockAdjustPosSizePixel();
2204 
2205         // ID of the new view
2206         SfxObjectFactory& rDocFact = GetObjectShell()->GetFactory();
2207         const SfxInterfaceId nViewId = ( bIsIndex || !nViewIdOrNo ) ? rDocFact.GetViewFactory( nViewIdOrNo ).GetOrdinal() : SfxInterfaceId(nViewIdOrNo);
2208 
2209         // save the view data of the old view, so it can be restored later on (when needed)
2210         SaveCurrentViewData_Impl( nViewId );
2211 
2212         // create and load new ViewShell
2213         SfxViewShell* pNewSh = LoadViewIntoFrame_Impl(
2214             *GetObjectShell(),
2215             GetFrame().GetFrameInterface(),
2216             Sequence< PropertyValue >(),    // means "reuse existing model's args"
2217             nViewId,
2218             false
2219         );
2220 
2221         // allow resize events to be processed
2222         UnlockAdjustPosSizePixel();
2223 
2224         if ( GetWindow().IsReallyVisible() )
2225             DoAdjustPosSizePixel( pNewSh, Point(), GetWindow().GetOutputSizePixel(), false );
2226 
2227         GetBindings().LEAVEREGISTRATIONS();
2228         delete pOldSh;
2229     }
2230     catch ( const css::uno::Exception& )
2231     {
2232         // the SfxCode is not able to cope with exceptions thrown while creating views
2233         // the code will crash in the stack unwinding procedure, so we shouldn't let exceptions go through here
2234         DBG_UNHANDLED_EXCEPTION("sfx.view");
2235         return false;
2236     }
2237 
2238     DBG_ASSERT( SfxGetpApp()->GetViewFrames_Impl().size() == SfxGetpApp()->GetViewShells_Impl().size(), "Inconsistent view arrays!" );
2239     return true;
2240 }
2241 
2242 void SfxViewFrame::SetCurViewId_Impl( const SfxInterfaceId i_nID )
2243 {
2244     m_pImpl->nCurViewId = i_nID;
2245 }
2246 
2247 SfxInterfaceId SfxViewFrame::GetCurViewId() const
2248 {
2249     return m_pImpl->nCurViewId;
2250 }
2251 
2252 /*  [Description]
2253 
2254     Internal method to run the slot for the <SfxShell> Subclass in the
2255     SfxViewFrame <SVIDL> described slots.
2256 */
2257 void SfxViewFrame::ExecView_Impl
2258 (
2259     SfxRequest& rReq        // The executable <SfxRequest>
2260 )
2261 {
2262 
2263     // If the Shells are just being replaced...
2264     if ( !GetObjectShell() || !GetViewShell() )
2265         return;
2266 
2267     switch ( rReq.GetSlot() )
2268     {
2269         case SID_TERMINATE_INPLACEACTIVATION :
2270         {
2271             SfxInPlaceClient* pClient = GetViewShell()->GetUIActiveClient();
2272             if ( pClient )
2273                 pClient->DeactivateObject();
2274             break;
2275         }
2276 
2277         case SID_VIEWSHELL:
2278         {
2279             const SfxPoolItem *pItem = nullptr;
2280             if  (   rReq.GetArgs()
2281                 &&  SfxItemState::SET == rReq.GetArgs()->GetItemState( SID_VIEWSHELL, false, &pItem )
2282                 )
2283             {
2284                 const sal_uInt16 nViewId = static_cast< const SfxUInt16Item* >( pItem )->GetValue();
2285                 bool bSuccess = SwitchToViewShell_Impl( nViewId );
2286                 rReq.SetReturnValue( SfxBoolItem( 0, bSuccess ) );
2287             }
2288             break;
2289         }
2290 
2291         case SID_VIEWSHELL0:
2292         case SID_VIEWSHELL1:
2293         case SID_VIEWSHELL2:
2294         case SID_VIEWSHELL3:
2295         case SID_VIEWSHELL4:
2296         {
2297             const sal_uInt16 nViewNo = rReq.GetSlot() - SID_VIEWSHELL0;
2298             bool bSuccess = SwitchToViewShell_Impl( nViewNo, true );
2299             rReq.SetReturnValue( SfxBoolItem( 0, bSuccess ) );
2300             break;
2301         }
2302 
2303         case SID_NEWWINDOW:
2304         {
2305             // Hack. at the moment a virtual Function
2306             if ( !GetViewShell()->NewWindowAllowed() )
2307             {
2308                 OSL_FAIL( "You should have disabled the 'Window/New Window' slot!" );
2309                 return;
2310             }
2311 
2312             // Get ViewData of FrameSets recursively.
2313             GetFrame().GetViewData_Impl();
2314             SfxMedium* pMed = GetObjectShell()->GetMedium();
2315 
2316             // do not open the new window hidden
2317             pMed->GetItemSet()->ClearItem( SID_HIDDEN );
2318 
2319             // the view ID (optional arg. TODO: this is currently not supported in the slot definition ...)
2320             const SfxUInt16Item* pViewIdItem = rReq.GetArg<SfxUInt16Item>(SID_VIEW_ID);
2321             const SfxInterfaceId nViewId = pViewIdItem ? SfxInterfaceId(pViewIdItem->GetValue()) : GetCurViewId();
2322 
2323             Reference < XFrame > xFrame;
2324             // the frame (optional arg. TODO: this is currently not supported in the slot definition ...)
2325             const SfxUnoFrameItem* pFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
2326             if ( pFrameItem )
2327                 xFrame = pFrameItem->GetFrame();
2328 
2329             LoadViewIntoFrame_Impl_NoThrow( *GetObjectShell(), xFrame, nViewId, false );
2330 
2331             rReq.Done();
2332             break;
2333         }
2334 
2335         case SID_OBJECT:
2336         {
2337             const SfxInt16Item* pItem = rReq.GetArg<SfxInt16Item>(SID_OBJECT);
2338 
2339             if (pItem)
2340             {
2341                 GetViewShell()->DoVerb( pItem->GetValue() );
2342                 rReq.Done();
2343                 break;
2344             }
2345         }
2346     }
2347 }
2348 
2349 /* TODO as96863:
2350         This method try to collect information about the count of currently open documents.
2351         But the algorithm is implemented very simple ...
2352         E.g. hidden documents should be ignored here ... but they are counted.
2353         TODO: export special helper "framework::FrameListAnalyzer" within the framework module
2354         and use it here.
2355 */
2356 static bool impl_maxOpenDocCountReached()
2357 {
2358     css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2359     std::optional<sal_Int32> x(officecfg::Office::Common::Misc::MaxOpenDocuments::get(xContext));
2360     // NIL means: count of allowed documents = infinite !
2361     if (!x)
2362         return false;
2363     sal_Int32 nMaxDocs(*x);
2364     sal_Int32 nOpenDocs = 0;
2365 
2366     css::uno::Reference< css::frame::XDesktop2 >  xDesktop = css::frame::Desktop::create(xContext);
2367     css::uno::Reference< css::container::XIndexAccess > xCont(xDesktop->getFrames(), css::uno::UNO_QUERY_THROW);
2368 
2369     sal_Int32 c = xCont->getCount();
2370     sal_Int32 i = 0;
2371 
2372     for (i=0; i<c; ++i)
2373     {
2374         try
2375         {
2376             css::uno::Reference< css::frame::XFrame > xFrame;
2377             xCont->getByIndex(i) >>= xFrame;
2378             if ( ! xFrame.is())
2379                 continue;
2380 
2381             // a) do not count the help window
2382             if ( xFrame->getName() == "OFFICE_HELP_TASK" )
2383                 continue;
2384 
2385             // b) count all other frames
2386             ++nOpenDocs;
2387         }
2388         catch(const css::uno::Exception&)
2389             // An IndexOutOfBoundsException can happen in multithreaded
2390             // environments, where any other thread can change this
2391             // container !
2392             { continue; }
2393     }
2394 
2395     return (nOpenDocs >= nMaxDocs);
2396 }
2397 
2398 /*  [Description]
2399 
2400     This internal method returns in 'rSet' the Status for the  <SfxShell>
2401     Subclass SfxViewFrame in the <SVIDL> described <Slots>.
2402 
2403     Thus exactly those Slots-IDs that are recognized as being invalid by Sfx
2404     are included as Which-ranges in 'rSet'. If there exists a mapping for
2405     single slot-IDs of the <SfxItemPool> set in the shell, then the respective
2406     Which-IDs are used so that items can be replaced directly with a working
2407     Core::sun::com::star::script::Engine of the Which-IDs if possible. .
2408 */
2409 void SfxViewFrame::StateView_Impl
2410 (
2411     SfxItemSet&     rSet            /*  empty <SfxItemSet> with <Which-Ranges>,
2412                                         which describes the Slot Ids */
2413 )
2414 {
2415 
2416     SfxObjectShell *pDocSh = GetObjectShell();
2417 
2418     if ( !pDocSh )
2419         // I'm just on reload and am yielding myself ...
2420         return;
2421 
2422     const sal_uInt16 *pRanges = rSet.GetRanges();
2423     assert(pRanges && "Set with no Range");
2424     while ( *pRanges )
2425     {
2426         sal_uInt16 nStartWhich = *pRanges++;
2427         sal_uInt16 nEndWhich = *pRanges++;
2428         for ( sal_uInt16 nWhich = nStartWhich; nWhich <= nEndWhich; ++nWhich )
2429         {
2430             switch(nWhich)
2431             {
2432                 case SID_VIEWSHELL:
2433                 {
2434                     rSet.Put( SfxUInt16Item( nWhich, sal_uInt16(m_pImpl->nCurViewId )) );
2435                     break;
2436                 }
2437 
2438                 case SID_VIEWSHELL0:
2439                 case SID_VIEWSHELL1:
2440                 case SID_VIEWSHELL2:
2441                 case SID_VIEWSHELL3:
2442                 case SID_VIEWSHELL4:
2443                 {
2444                     sal_uInt16 nViewNo = nWhich - SID_VIEWSHELL0;
2445                     if ( GetObjectShell()->GetFactory().GetViewFactoryCount() >
2446                          nViewNo && !GetObjectShell()->IsInPlaceActive() )
2447                     {
2448                         SfxViewFactory &rViewFactory =
2449                             GetObjectShell()->GetFactory().GetViewFactory(nViewNo);
2450                         rSet.Put( SfxBoolItem(
2451                             nWhich, m_pImpl->nCurViewId == rViewFactory.GetOrdinal() ) );
2452                     }
2453                     else
2454                         rSet.DisableItem( nWhich );
2455                     break;
2456                 }
2457 
2458                 case SID_NEWWINDOW:
2459                 {
2460                     if  (   !GetViewShell()->NewWindowAllowed()
2461                         ||  impl_maxOpenDocCountReached()
2462                         )
2463                         rSet.DisableItem( nWhich );
2464                     break;
2465                 }
2466             }
2467         }
2468     }
2469 }
2470 
2471 
2472 void SfxViewFrame::ToTop()
2473 {
2474     GetFrame().Appear();
2475 }
2476 
2477 
2478 /*  [Description]
2479 
2480     GetFrame returns the Frame, in which the ViewFrame is located.
2481 */
2482 SfxFrame& SfxViewFrame::GetFrame() const
2483 {
2484     return m_pImpl->rFrame;
2485 }
2486 
2487 SfxViewFrame* SfxViewFrame::GetTopViewFrame() const
2488 {
2489     return GetFrame().GetCurrentViewFrame();
2490 }
2491 
2492 vcl::Window& SfxViewFrame::GetWindow() const
2493 {
2494     return m_pImpl->pWindow ? *m_pImpl->pWindow : GetFrame().GetWindow();
2495 }
2496 
2497 bool SfxViewFrame::DoClose()
2498 {
2499     return GetFrame().DoClose();
2500 }
2501 
2502 OUString SfxViewFrame::GetActualPresentationURL_Impl() const
2503 {
2504     if ( m_xObjSh.is() )
2505         return m_xObjSh->GetMedium()->GetName();
2506     return OUString();
2507 }
2508 
2509 void SfxViewFrame::SetModalMode( bool bModal )
2510 {
2511     // no real modality for LOK
2512     if (comphelper::LibreOfficeKit::isActive())
2513         return;
2514 
2515     m_pImpl->bModal = bModal;
2516     if ( m_xObjSh.is() )
2517     {
2518         for ( SfxViewFrame* pFrame = SfxViewFrame::GetFirst( m_xObjSh.get() );
2519               !bModal && pFrame; pFrame = SfxViewFrame::GetNext( *pFrame, m_xObjSh.get() ) )
2520             bModal = pFrame->m_pImpl->bModal;
2521         m_xObjSh->SetModalMode_Impl( bModal );
2522     }
2523 }
2524 
2525 bool SfxViewFrame::IsInModalMode() const
2526 {
2527     return m_pImpl->bModal || GetFrame().GetWindow().IsInModalMode();
2528 }
2529 
2530 void SfxViewFrame::Resize( bool bForce )
2531 {
2532     Size aSize = GetWindow().GetOutputSizePixel();
2533     if ( !bForce && aSize == m_pImpl->aSize )
2534         return;
2535 
2536     m_pImpl->aSize = aSize;
2537     SfxViewShell *pShell = GetViewShell();
2538     if ( pShell )
2539     {
2540         if ( GetFrame().IsInPlace() )
2541         {
2542             Point aPoint = GetWindow().GetPosPixel();
2543             DoAdjustPosSizePixel( pShell, aPoint, aSize, true );
2544         }
2545         else
2546         {
2547             DoAdjustPosSizePixel( pShell, Point(), aSize, false );
2548         }
2549     }
2550 }
2551 
2552 #if HAVE_FEATURE_SCRIPTING
2553 
2554 #define LINE_SEP 0x0A
2555 
2556 static void CutLines( OUString& rStr, sal_Int32 nStartLine, sal_Int32 nLines )
2557 {
2558     sal_Int32 nStartPos = 0;
2559     sal_Int32 nLine = 0;
2560     while ( nLine < nStartLine )
2561     {
2562         nStartPos = rStr.indexOf( LINE_SEP, nStartPos );
2563         if( nStartPos == -1 )
2564             break;
2565         nStartPos++;    // not the \n.
2566         nLine++;
2567     }
2568 
2569     SAL_WARN_IF(nStartPos == -1, "sfx.view", "CutLines: Start row not found!");
2570 
2571     if ( nStartPos != -1 )
2572     {
2573         sal_Int32 nEndPos = nStartPos;
2574         for ( sal_Int32 i = 0; i < nLines; i++ )
2575             nEndPos = rStr.indexOf( LINE_SEP, nEndPos+1 );
2576 
2577         if ( nEndPos == -1 ) // Can happen at the last row.
2578             nEndPos = rStr.getLength();
2579         else
2580             nEndPos++;
2581 
2582         rStr = rStr.copy( 0, nStartPos ) + rStr.copy( nEndPos );
2583     }
2584     // erase trailing lines
2585     if ( nStartPos != -1 )
2586     {
2587         sal_Int32 n = nStartPos;
2588         sal_Int32 nLen = rStr.getLength();
2589         while ( ( n < nLen ) && ( rStr[ n ] == LINE_SEP ) )
2590             n++;
2591 
2592         if ( n > nStartPos )
2593             rStr = rStr.copy( 0, nStartPos ) + rStr.copy( n );
2594     }
2595 }
2596 
2597 #endif
2598 
2599 /*
2600     add new recorded dispatch macro script into the application global basic
2601     lib container. It generates a new unique id for it and insert the macro
2602     by using this number as name for the module
2603  */
2604 void SfxViewFrame::AddDispatchMacroToBasic_Impl( const OUString& sMacro )
2605 {
2606 #if !HAVE_FEATURE_SCRIPTING
2607     (void) sMacro;
2608 #else
2609     if ( sMacro.isEmpty() )
2610         return;
2611 
2612     SfxApplication* pSfxApp = SfxGetpApp();
2613     SfxItemPool& rPool = pSfxApp->GetPool();
2614     SfxRequest aReq(SID_BASICCHOOSER, SfxCallMode::SYNCHRON, rPool);
2615 
2616     //seen in tdf#122598, no parent for subsequent dialog
2617     SfxAllItemSet aSet(rPool);
2618     css::uno::Reference< css::frame::XFrame > xFrame =
2619             GetFrame().GetFrameInterface();
2620     aSet.Put(SfxUnoFrameItem(SID_FILLFRAME, xFrame));
2621     aReq.SetInternalArgs_Impl(aSet);
2622 
2623     aReq.AppendItem( SfxBoolItem(SID_RECORDMACRO,true) );
2624     const SfxPoolItem* pRet = SfxGetpApp()->ExecuteSlot( aReq );
2625     OUString aScriptURL;
2626     if ( pRet )
2627         aScriptURL = static_cast<const SfxStringItem*>(pRet)->GetValue();
2628     if ( !aScriptURL.isEmpty() )
2629     {
2630         // parse scriptURL
2631         OUString aLibName;
2632         OUString aModuleName;
2633         OUString aMacroName;
2634         OUString aLocation;
2635         Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2636         Reference< css::uri::XUriReferenceFactory > xFactory =
2637             css::uri::UriReferenceFactory::create( xContext );
2638         Reference< css::uri::XVndSunStarScriptUrl > xUrl( xFactory->parse( aScriptURL ), UNO_QUERY );
2639         if ( xUrl.is() )
2640         {
2641             // get name
2642             const OUString aName = xUrl->getName();
2643             const sal_Unicode cTok = '.';
2644             sal_Int32 nIndex = 0;
2645             aLibName = aName.getToken( 0, cTok, nIndex );
2646             if ( nIndex != -1 )
2647                 aModuleName = aName.getToken( 0, cTok, nIndex );
2648             if ( nIndex != -1 )
2649                 aMacroName = aName.getToken( 0, cTok, nIndex );
2650 
2651             // get location
2652             aLocation = xUrl->getParameter( "location" );
2653         }
2654 
2655         BasicManager* pBasMgr = nullptr;
2656         if ( aLocation == "application" )
2657         {
2658             // application basic
2659             pBasMgr = SfxApplication::GetBasicManager();
2660         }
2661         else if ( aLocation == "document" )
2662         {
2663             pBasMgr = GetObjectShell()->GetBasicManager();
2664         }
2665 
2666         OUString aOUSource;
2667         if ( pBasMgr)
2668         {
2669             StarBASIC* pBasic = pBasMgr->GetLib( aLibName );
2670             if ( pBasic )
2671             {
2672                 SbModule* pModule = pBasic->FindModule( aModuleName );
2673                 SbMethod* pMethod = pModule ? pModule->FindMethod(aMacroName, SbxClassType::Method) : nullptr;
2674                 if (pMethod)
2675                 {
2676                     aOUSource = pModule->GetSource32();
2677                     sal_uInt16 nStart, nEnd;
2678                     pMethod->GetLineRange( nStart, nEnd );
2679                     sal_uInt16 nlStart = nStart;
2680                     sal_uInt16 nlEnd = nEnd;
2681                     CutLines( aOUSource, nlStart-1, nlEnd-nlStart+1 );
2682                 }
2683             }
2684         }
2685 
2686         // open lib container and break operation if it couldn't be opened
2687         css::uno::Reference< css::script::XLibraryContainer > xLibCont;
2688         if ( aLocation == "application" )
2689         {
2690             xLibCont = SfxGetpApp()->GetBasicContainer();
2691         }
2692         else if ( aLocation == "document" )
2693         {
2694             xLibCont = GetObjectShell()->GetBasicContainer();
2695         }
2696 
2697         if(!xLibCont.is())
2698         {
2699             SAL_WARN("sfx.view", "couldn't get access to the basic lib container. Adding of macro isn't possible.");
2700             return;
2701         }
2702 
2703         // get LibraryContainer
2704         css::uno::Any aTemp;
2705 
2706         css::uno::Reference< css::container::XNameAccess > xLib;
2707         if(xLibCont->hasByName(aLibName))
2708         {
2709             // library must be loaded
2710             aTemp = xLibCont->getByName(aLibName);
2711             xLibCont->loadLibrary(aLibName);
2712             aTemp >>= xLib;
2713         }
2714         else
2715         {
2716             xLib = xLibCont->createLibrary(aLibName);
2717         }
2718 
2719         // pack the macro as direct usable "sub" routine
2720         OUStringBuffer sRoutine(10000);
2721         bool bReplace = false;
2722 
2723         // get module
2724         if(xLib->hasByName(aModuleName))
2725         {
2726             if ( !aOUSource.isEmpty() )
2727             {
2728                 sRoutine.append( aOUSource );
2729             }
2730             else
2731             {
2732                 OUString sCode;
2733                 aTemp = xLib->getByName(aModuleName);
2734                 aTemp >>= sCode;
2735                 sRoutine.append( sCode );
2736             }
2737 
2738             bReplace = true;
2739         }
2740 
2741         // append new method
2742         sRoutine.append( "\nsub " );
2743         sRoutine.append(aMacroName);
2744         sRoutine.append( "\n" );
2745         sRoutine.append(sMacro);
2746         sRoutine.append( "\nend sub\n" );
2747 
2748         // create the module inside the library and insert the macro routine
2749         aTemp <<= sRoutine.makeStringAndClear();
2750         if ( bReplace )
2751         {
2752             css::uno::Reference< css::container::XNameContainer > xModulCont(
2753                 xLib,
2754                 css::uno::UNO_QUERY);
2755             xModulCont->replaceByName(aModuleName,aTemp);
2756         }
2757         else
2758         {
2759             css::uno::Reference< css::container::XNameContainer > xModulCont(
2760                 xLib,
2761                 css::uno::UNO_QUERY);
2762             xModulCont->insertByName(aModuleName,aTemp);
2763         }
2764 
2765         // #i17355# update the Basic IDE
2766         for ( SfxViewShell* pViewShell = SfxViewShell::GetFirst(); pViewShell; pViewShell = SfxViewShell::GetNext( *pViewShell ) )
2767         {
2768             if ( pViewShell->GetName() == "BasicIDE" )
2769             {
2770                 SfxViewFrame* pViewFrame = pViewShell->GetViewFrame();
2771                 SfxDispatcher* pDispat = pViewFrame ? pViewFrame->GetDispatcher() : nullptr;
2772                 if ( pDispat )
2773                 {
2774                     SfxMacroInfoItem aInfoItem( SID_BASICIDE_ARG_MACROINFO, pBasMgr, aLibName, aModuleName, OUString(), OUString() );
2775                     pDispat->ExecuteList(SID_BASICIDE_UPDATEMODULESOURCE,
2776                             SfxCallMode::SYNCHRON, { &aInfoItem });
2777                 }
2778             }
2779         }
2780     }
2781     else
2782     {
2783         // add code for "session only" macro
2784     }
2785 #endif
2786 }
2787 
2788 void SfxViewFrame::MiscExec_Impl( SfxRequest& rReq )
2789 {
2790     switch ( rReq.GetSlot() )
2791     {
2792         case SID_STOP_RECORDING :
2793         case SID_RECORDMACRO :
2794         {
2795             // try to find any active recorder on this frame
2796             const OUString sProperty("DispatchRecorderSupplier");
2797             css::uno::Reference< css::frame::XFrame > xFrame =
2798                     GetFrame().GetFrameInterface();
2799 
2800             css::uno::Reference< css::beans::XPropertySet > xSet(xFrame,css::uno::UNO_QUERY);
2801             css::uno::Any aProp = xSet->getPropertyValue(sProperty);
2802             css::uno::Reference< css::frame::XDispatchRecorderSupplier > xSupplier;
2803             aProp >>= xSupplier;
2804             css::uno::Reference< css::frame::XDispatchRecorder > xRecorder;
2805             if (xSupplier.is())
2806                 xRecorder = xSupplier->getDispatchRecorder();
2807 
2808             bool bIsRecording = xRecorder.is();
2809             const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(SID_RECORDMACRO);
2810             if ( pItem && pItem->GetValue() == bIsRecording )
2811                 return;
2812 
2813             if ( xRecorder.is() )
2814             {
2815                 // disable active recording
2816                 aProp <<= css::uno::Reference< css::frame::XDispatchRecorderSupplier >();
2817                 xSet->setPropertyValue(sProperty,aProp);
2818 
2819                 const SfxBoolItem* pRecordItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_1);
2820                 if ( !pRecordItem || !pRecordItem->GetValue() )
2821                     // insert script into basic library container of application
2822                     AddDispatchMacroToBasic_Impl(xRecorder->getRecordedMacro());
2823 
2824                 xRecorder->endRecording();
2825                 xRecorder = nullptr;
2826                 GetBindings().SetRecorder_Impl( xRecorder );
2827 
2828                 SetChildWindow( SID_RECORDING_FLOATWINDOW, false );
2829                 if ( rReq.GetSlot() != SID_RECORDMACRO )
2830                     GetBindings().Invalidate( SID_RECORDMACRO );
2831             }
2832             else if ( rReq.GetSlot() == SID_RECORDMACRO )
2833             {
2834                 // enable recording
2835                 css::uno::Reference< css::uno::XComponentContext > xContext(
2836                         ::comphelper::getProcessComponentContext());
2837 
2838                 xRecorder = css::frame::DispatchRecorder::create( xContext );
2839 
2840                 xSupplier = css::frame::DispatchRecorderSupplier::create( xContext );
2841 
2842                 xSupplier->setDispatchRecorder(xRecorder);
2843                 xRecorder->startRecording(xFrame);
2844                 aProp <<= xSupplier;
2845                 xSet->setPropertyValue(sProperty,aProp);
2846                 GetBindings().SetRecorder_Impl( xRecorder );
2847                 SetChildWindow( SID_RECORDING_FLOATWINDOW, true );
2848             }
2849 
2850             rReq.Done();
2851             break;
2852         }
2853 
2854         case SID_TOGGLESTATUSBAR:
2855         {
2856             css::uno::Reference< css::frame::XFrame > xFrame =
2857                     GetFrame().GetFrameInterface();
2858 
2859             Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
2860             Reference< css::frame::XLayoutManager > xLayoutManager;
2861             if ( xPropSet.is() )
2862             {
2863                 try
2864                 {
2865                     Any aValue = xPropSet->getPropertyValue("LayoutManager");
2866                     aValue >>= xLayoutManager;
2867                 }
2868                 catch ( Exception& )
2869                 {
2870                 }
2871             }
2872 
2873             if ( xLayoutManager.is() )
2874             {
2875                 const OUString aStatusbarResString( "private:resource/statusbar/statusbar" );
2876                 // Evaluate parameter.
2877                 const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(rReq.GetSlot());
2878                 bool bShow( true );
2879                 if ( !pShowItem )
2880                     bShow = xLayoutManager->isElementVisible( aStatusbarResString );
2881                 else
2882                     bShow = pShowItem->GetValue();
2883 
2884                 if ( bShow )
2885                 {
2886                     xLayoutManager->createElement( aStatusbarResString );
2887                     xLayoutManager->showElement( aStatusbarResString );
2888                 }
2889                 else
2890                     xLayoutManager->hideElement( aStatusbarResString );
2891 
2892                 if ( !pShowItem )
2893                     rReq.AppendItem( SfxBoolItem( SID_TOGGLESTATUSBAR, bShow ) );
2894             }
2895             rReq.Done();
2896             break;
2897         }
2898 
2899         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2900         case SID_WIN_FULLSCREEN:
2901         {
2902             const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(rReq.GetSlot());
2903             SfxViewFrame *pTop = GetTopViewFrame();
2904             if ( pTop )
2905             {
2906                 WorkWindow* pWork = static_cast<WorkWindow*>( pTop->GetFrame().GetTopWindow_Impl() );
2907                 if ( pWork )
2908                 {
2909                     css::uno::Reference< css::frame::XFrame > xFrame =
2910                             GetFrame().GetFrameInterface();
2911 
2912                     Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
2913                     Reference< css::frame::XLayoutManager > xLayoutManager;
2914                     if ( xPropSet.is() )
2915                     {
2916                         try
2917                         {
2918                             Any aValue = xPropSet->getPropertyValue("LayoutManager");
2919                             aValue >>= xLayoutManager;
2920                         }
2921                         catch ( Exception& )
2922                         {
2923                         }
2924                     }
2925 
2926                     bool bNewFullScreenMode = pItem ? pItem->GetValue() : !pWork->IsFullScreenMode();
2927                     if ( bNewFullScreenMode != pWork->IsFullScreenMode() )
2928                     {
2929                         if ( bNewFullScreenMode )
2930                             sfx2::SfxNotebookBar::LockNotebookBar();
2931                         else
2932                             sfx2::SfxNotebookBar::UnlockNotebookBar();
2933 
2934                         Reference< css::beans::XPropertySet > xLMPropSet( xLayoutManager, UNO_QUERY );
2935                         if ( xLMPropSet.is() )
2936                         {
2937                             try
2938                             {
2939                                 xLMPropSet->setPropertyValue(
2940                                     "HideCurrentUI",
2941                                     makeAny( bNewFullScreenMode ));
2942                             }
2943                             catch ( css::beans::UnknownPropertyException& )
2944                             {
2945                             }
2946                         }
2947                         pWork->ShowFullScreenMode( bNewFullScreenMode );
2948                         pWork->SetMenuBarMode( bNewFullScreenMode ? MenuBarMode::Hide : MenuBarMode::Normal );
2949                         GetFrame().GetWorkWindow_Impl()->SetFullScreen_Impl( bNewFullScreenMode );
2950                         if ( !pItem )
2951                             rReq.AppendItem( SfxBoolItem( SID_WIN_FULLSCREEN, bNewFullScreenMode ) );
2952                         rReq.Done();
2953                     }
2954                     else
2955                         rReq.Ignore();
2956                 }
2957             }
2958             else
2959                 rReq.Ignore();
2960 
2961             GetDispatcher()->Update_Impl( true );
2962             break;
2963         }
2964     }
2965 }
2966 
2967 void SfxViewFrame::MiscState_Impl(SfxItemSet &rSet)
2968 {
2969     const sal_uInt16 *pRanges = rSet.GetRanges();
2970     DBG_ASSERT(pRanges && *pRanges, "Set without range");
2971     while ( *pRanges )
2972     {
2973         for(sal_uInt16 nWhich = *pRanges++; nWhich <= *pRanges; ++nWhich)
2974         {
2975             switch(nWhich)
2976             {
2977                 case SID_CURRENT_URL:
2978                 {
2979                     rSet.Put( SfxStringItem( nWhich, GetActualPresentationURL_Impl() ) );
2980                     break;
2981                 }
2982 
2983                 case SID_RECORDMACRO :
2984                 {
2985                     SvtMiscOptions aMiscOptions;
2986                     const OUString& sName{GetObjectShell()->GetFactory().GetFactoryName()};
2987                     bool bMacrosDisabled = officecfg::Office::Common::Security::Scripting::DisableMacrosExecution::get();
2988                     if (bMacrosDisabled || !aMiscOptions.IsMacroRecorderMode() ||
2989                          ( sName!="swriter" && sName!="scalc" ) )
2990                     {
2991                         rSet.DisableItem( nWhich );
2992                         rSet.Put(SfxVisibilityItem(nWhich, false));
2993                         break;
2994                     }
2995 
2996                     css::uno::Reference< css::beans::XPropertySet > xSet(
2997                             GetFrame().GetFrameInterface(),
2998                             css::uno::UNO_QUERY);
2999 
3000                     css::uno::Any aProp = xSet->getPropertyValue("DispatchRecorderSupplier");
3001                     css::uno::Reference< css::frame::XDispatchRecorderSupplier > xSupplier;
3002                     if ( aProp >>= xSupplier )
3003                         rSet.Put( SfxBoolItem( nWhich, xSupplier.is() ) );
3004                     else
3005                         rSet.DisableItem( nWhich );
3006                     break;
3007                 }
3008 
3009                 case SID_STOP_RECORDING :
3010                 {
3011                     SvtMiscOptions aMiscOptions;
3012                     const OUString& sName{GetObjectShell()->GetFactory().GetFactoryName()};
3013                     if ( !aMiscOptions.IsMacroRecorderMode() ||
3014                          ( sName!="swriter" && sName!="scalc" ) )
3015                     {
3016                         rSet.DisableItem( nWhich );
3017                         break;
3018                     }
3019 
3020                     css::uno::Reference< css::beans::XPropertySet > xSet(
3021                             GetFrame().GetFrameInterface(),
3022                             css::uno::UNO_QUERY);
3023 
3024                     css::uno::Any aProp = xSet->getPropertyValue("DispatchRecorderSupplier");
3025                     css::uno::Reference< css::frame::XDispatchRecorderSupplier > xSupplier;
3026                     if ( !(aProp >>= xSupplier) || !xSupplier.is() )
3027                         rSet.DisableItem( nWhich );
3028                     break;
3029                 }
3030 
3031                 case SID_TOGGLESTATUSBAR:
3032                 {
3033                     css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
3034                     css::uno::Reference< css::beans::XPropertySet > xSet(
3035                             GetFrame().GetFrameInterface(),
3036                             css::uno::UNO_QUERY);
3037                     css::uno::Any aProp = xSet->getPropertyValue( "LayoutManager" );
3038 
3039                     if ( !( aProp >>= xLayoutManager ))
3040                         rSet.Put( SfxBoolItem( nWhich, false ));
3041                     else
3042                     {
3043                         bool bShow = xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" );
3044                         rSet.Put( SfxBoolItem( nWhich, bShow ));
3045                     }
3046                     break;
3047                 }
3048 
3049                 case SID_WIN_FULLSCREEN:
3050                 {
3051                     SfxViewFrame* pTop = GetTopViewFrame();
3052                     if ( pTop )
3053                     {
3054                         WorkWindow* pWork = static_cast<WorkWindow*>( pTop->GetFrame().GetTopWindow_Impl() );
3055                         if ( pWork )
3056                         {
3057                             rSet.Put( SfxBoolItem( nWhich, pWork->IsFullScreenMode() ) );
3058                             break;
3059                         }
3060                     }
3061 
3062                     rSet.DisableItem( nWhich );
3063                     break;
3064                 }
3065 
3066                 default:
3067                     break;
3068             }
3069         }
3070 
3071         ++pRanges;
3072     }
3073 }
3074 
3075 /*  [Description]
3076 
3077     This method can be included in the Execute method for the on- and off-
3078     switching of ChildWindows, to implement this and API-bindings.
3079 
3080     Simply include as 'ExecuteMethod' in the IDL.
3081 */
3082 void SfxViewFrame::ChildWindowExecute( SfxRequest &rReq )
3083 {
3084     // Evaluate Parameter
3085     sal_uInt16 nSID = rReq.GetSlot();
3086 
3087     const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(nSID);
3088     if ( nSID == SID_VIEW_DATA_SOURCE_BROWSER )
3089     {
3090         if (!SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::DATABASE))
3091             return;
3092         Reference < XFrame > xFrame = GetFrame().GetFrameInterface();
3093         Reference < XFrame > xBeamer( xFrame->findFrame( "_beamer", FrameSearchFlag::CHILDREN ) );
3094         bool bHasChild = xBeamer.is();
3095         bool bShow = pShowItem ? pShowItem->GetValue() : !bHasChild;
3096         if ( pShowItem )
3097         {
3098             if( bShow == bHasChild )
3099                 return;
3100         }
3101         else
3102             rReq.AppendItem( SfxBoolItem( nSID, bShow ) );
3103 
3104         if ( !bShow )
3105         {
3106             SetChildWindow( SID_BROWSER, false );
3107         }
3108         else
3109         {
3110             css::util::URL aTargetURL;
3111             aTargetURL.Complete = ".component:DB/DataSourceBrowser";
3112             Reference < css::util::XURLTransformer > xTrans(
3113                     css::util::URLTransformer::create(
3114                          ::comphelper::getProcessComponentContext() ) );
3115             xTrans->parseStrict( aTargetURL );
3116 
3117             Reference < XDispatchProvider > xProv( xFrame, UNO_QUERY );
3118             Reference < css::frame::XDispatch > xDisp;
3119             if ( xProv.is() )
3120                 xDisp = xProv->queryDispatch( aTargetURL, "_beamer", 31 );
3121             if ( xDisp.is() )
3122             {
3123                 Sequence < css::beans::PropertyValue > aArgs(1);
3124                 css::beans::PropertyValue* pArg = aArgs.getArray();
3125                 pArg[0].Name = "Referer";
3126                 pArg[0].Value <<= OUString("private:user");
3127                 xDisp->dispatch( aTargetURL, aArgs );
3128             }
3129         }
3130 
3131         rReq.Done();
3132         return;
3133     }
3134     if (nSID == SID_STYLE_DESIGNER)
3135     {
3136         // First make sure that the sidebar is visible
3137         ShowChildWindow(SID_SIDEBAR);
3138 
3139         ::sfx2::sidebar::Sidebar::ShowPanel("StyleListPanel",
3140                                             GetFrame().GetFrameInterface(), true);
3141         rReq.Done();
3142         return;
3143     }
3144 
3145     bool bHasChild = HasChildWindow(nSID);
3146     bool bShow = pShowItem ? pShowItem->GetValue() : !bHasChild;
3147     GetDispatcher()->Update_Impl( true );
3148 
3149     // Perform action.
3150     if ( !pShowItem || bShow != bHasChild )
3151         ToggleChildWindow( nSID );
3152 
3153     GetBindings().Invalidate( nSID );
3154 
3155     // Record if possible.
3156     if ( nSID == SID_HYPERLINK_DIALOG || nSID == SID_SEARCH_DLG )
3157     {
3158         rReq.Ignore();
3159     }
3160     else
3161     {
3162         rReq.AppendItem( SfxBoolItem( nSID, bShow ) );
3163         rReq.Done();
3164     }
3165 }
3166 
3167 /*  [Description]
3168 
3169     This method can be used in the state method for the on and off-state
3170     of child-windows, in order to implement this.
3171 
3172     Just register the IDL as 'StateMethod'.
3173 */
3174 void SfxViewFrame::ChildWindowState( SfxItemSet& rState )
3175 {
3176     SfxWhichIter aIter( rState );
3177     for ( sal_uInt16 nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() )
3178     {
3179         if ( nSID == SID_VIEW_DATA_SOURCE_BROWSER )
3180         {
3181             rState.Put( SfxBoolItem( nSID, HasChildWindow( SID_BROWSER ) ) );
3182         }
3183         else if ( nSID == SID_HYPERLINK_DIALOG )
3184         {
3185             const SfxPoolItem* pDummy = nullptr;
3186             SfxItemState eState = GetDispatcher()->QueryState( SID_HYPERLINK_SETLINK, pDummy );
3187             if ( SfxItemState::DISABLED == eState )
3188                 rState.DisableItem(nSID);
3189             else
3190             {
3191                 if ( KnowsChildWindow(nSID) )
3192                     rState.Put( SfxBoolItem( nSID, HasChildWindow(nSID)) );
3193                 else
3194                     rState.DisableItem(nSID);
3195             }
3196         }
3197         else if ( nSID == SID_BROWSER )
3198         {
3199             Reference < XFrame > xFrame = GetFrame().GetFrameInterface()->
3200                             findFrame( "_beamer", FrameSearchFlag::CHILDREN );
3201             if ( !xFrame.is() )
3202                 rState.DisableItem( nSID );
3203             else if ( KnowsChildWindow(nSID) )
3204                 rState.Put( SfxBoolItem( nSID, HasChildWindow(nSID) ) );
3205         }
3206         else if ( nSID == SID_SIDEBAR )
3207         {
3208             if  ( !KnowsChildWindow( nSID ) )
3209             {
3210                 SAL_WARN("sfx.view", "SID_SIDEBAR state requested, but no task pane child window exists for this ID!");
3211                 rState.DisableItem( nSID );
3212             }
3213             else
3214             {
3215                 rState.Put( SfxBoolItem( nSID, HasChildWindow( nSID ) ) );
3216             }
3217         }
3218         else if ( KnowsChildWindow(nSID) )
3219             rState.Put( SfxBoolItem( nSID, HasChildWindow(nSID) ) );
3220         else
3221             rState.DisableItem(nSID);
3222     }
3223 }
3224 
3225 SfxWorkWindow* SfxViewFrame::GetWorkWindow_Impl()
3226 {
3227     SfxWorkWindow* pWork = GetFrame().GetWorkWindow_Impl();
3228     return pWork;
3229 }
3230 
3231 void SfxViewFrame::SetChildWindow(sal_uInt16 nId, bool bOn, bool bSetFocus )
3232 {
3233     SfxWorkWindow* pWork = GetWorkWindow_Impl();
3234     if ( pWork )
3235         pWork->SetChildWindow_Impl( nId, bOn, bSetFocus );
3236 }
3237 
3238 void SfxViewFrame::ToggleChildWindow(sal_uInt16 nId)
3239 {
3240     SfxWorkWindow* pWork = GetWorkWindow_Impl();
3241     if ( pWork )
3242         pWork->ToggleChildWindow_Impl( nId, true );
3243 }
3244 
3245 bool SfxViewFrame::HasChildWindow( sal_uInt16 nId )
3246 {
3247     SfxWorkWindow* pWork = GetWorkWindow_Impl();
3248     return pWork && pWork->HasChildWindow_Impl(nId);
3249 }
3250 
3251 bool SfxViewFrame::KnowsChildWindow( sal_uInt16 nId )
3252 {
3253     SfxWorkWindow* pWork = GetWorkWindow_Impl();
3254     return pWork && pWork->KnowsChildWindow_Impl(nId);
3255 }
3256 
3257 void SfxViewFrame::ShowChildWindow( sal_uInt16 nId, bool bVisible )
3258 {
3259     SfxWorkWindow* pWork = GetWorkWindow_Impl();
3260     if ( pWork )
3261     {
3262         GetDispatcher()->Update_Impl(true);
3263         pWork->ShowChildWindow_Impl(nId, bVisible, true );
3264     }
3265 }
3266 
3267 SfxChildWindow* SfxViewFrame::GetChildWindow(sal_uInt16 nId)
3268 {
3269     SfxWorkWindow* pWork = GetWorkWindow_Impl();
3270     return pWork ? pWork->GetChildWindow_Impl(nId) : nullptr;
3271 }
3272 
3273 void SfxViewFrame::UpdateDocument_Impl()
3274 {
3275     SfxObjectShell* pDoc = GetObjectShell();
3276     if ( pDoc->IsLoadingFinished() )
3277         pDoc->CheckSecurityOnLoading_Impl();
3278 
3279     // check if document depends on a template
3280     pDoc->UpdateFromTemplate_Impl();
3281 }
3282 
3283 void SfxViewFrame::SetViewFrame( SfxViewFrame* pFrame )
3284 {
3285     if(pFrame)
3286         SetSVHelpData(pFrame->m_pHelpData);
3287 
3288     SetSVWinData(pFrame ? pFrame->m_pWinData : nullptr);
3289 
3290     SfxGetpApp()->SetViewFrame_Impl( pFrame );
3291 }
3292 
3293 VclPtr<SfxInfoBarWindow> SfxViewFrame::AppendInfoBar(const OUString& sId,
3294                                                const OUString& sPrimaryMessage,
3295                                                const OUString& sSecondaryMessage,
3296                                                InfobarType aInfobarType, bool bShowCloseButton)
3297 {
3298     SfxChildWindow* pChild = GetChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
3299     if (!pChild)
3300         return nullptr;
3301 
3302     if (HasInfoBarWithID(sId))
3303         return nullptr;
3304 
3305     SfxInfoBarContainerWindow* pInfoBarContainer = static_cast<SfxInfoBarContainerWindow*>(pChild->GetWindow());
3306     auto pInfoBar = pInfoBarContainer->appendInfoBar(sId, sPrimaryMessage, sSecondaryMessage,
3307                                                      aInfobarType, WB_LEFT | WB_VCENTER, bShowCloseButton);
3308     ShowChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
3309     return pInfoBar;
3310 }
3311 
3312 void SfxViewFrame::UpdateInfoBar(const OUString& sId, const OUString& sPrimaryMessage,
3313                                  const OUString& sSecondaryMessage, InfobarType eType)
3314 {
3315     const sal_uInt16 nId = SfxInfoBarContainerChild::GetChildWindowId();
3316 
3317     // Make sure the InfoBar container is visible
3318     if (!HasChildWindow(nId))
3319         ToggleChildWindow(nId);
3320 
3321     SfxChildWindow* pChild = GetChildWindow(nId);
3322     if (pChild)
3323     {
3324         SfxInfoBarContainerWindow* pInfoBarContainer = static_cast<SfxInfoBarContainerWindow*>(pChild->GetWindow());
3325         auto pInfoBar = pInfoBarContainer->getInfoBar(sId);
3326 
3327         if (pInfoBar)
3328              pInfoBar->Update(sPrimaryMessage, sSecondaryMessage, eType);
3329     }
3330 }
3331 
3332 void SfxViewFrame::RemoveInfoBar( const OUString& sId )
3333 {
3334     const sal_uInt16 nId = SfxInfoBarContainerChild::GetChildWindowId();
3335 
3336     // Make sure the InfoBar container is visible
3337     if (!HasChildWindow(nId))
3338         ToggleChildWindow(nId);
3339 
3340     SfxChildWindow* pChild = GetChildWindow(nId);
3341     if (pChild)
3342     {
3343         SfxInfoBarContainerWindow* pInfoBarContainer = static_cast<SfxInfoBarContainerWindow*>(pChild->GetWindow());
3344         auto pInfoBar = pInfoBarContainer->getInfoBar(sId);
3345         pInfoBarContainer->removeInfoBar(pInfoBar);
3346         ShowChildWindow(nId);
3347     }
3348 }
3349 
3350 bool SfxViewFrame::HasInfoBarWithID( const OUString& sId )
3351 {
3352     const sal_uInt16 nId = SfxInfoBarContainerChild::GetChildWindowId();
3353 
3354     SfxChildWindow* pChild = GetChildWindow(nId);
3355     if (pChild)
3356     {
3357         SfxInfoBarContainerWindow* pInfoBarContainer = static_cast<SfxInfoBarContainerWindow*>(pChild->GetWindow());
3358         return pInfoBarContainer->hasInfoBarWithID(sId);
3359     }
3360 
3361     return false;
3362 }
3363 
3364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3365