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
