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 <com/sun/star/embed/VerbDescriptor.hpp> 21 #include <com/sun/star/embed/VerbAttributes.hpp> 22 #include <officecfg/Office/Common.hxx> 23 #include <rtl/ustring.hxx> 24 #include <sal/log.hxx> 25 #include <osl/diagnose.h> 26 #include <svl/itempool.hxx> 27 #include <svl/undo.hxx> 28 #include <itemdel.hxx> 29 #include <svtools/asynclink.hxx> 30 #include <unotools/configmgr.hxx> 31 #include <comphelper/lok.hxx> 32 #include <sfx2/shell.hxx> 33 #include <sfx2/bindings.hxx> 34 #include <sfx2/dispatch.hxx> 35 #include <sfx2/viewfrm.hxx> 36 #include <sfx2/objface.hxx> 37 #include <sfx2/objsh.hxx> 38 #include <sfx2/viewsh.hxx> 39 #include <sfx2/request.hxx> 40 #include <sfx2/sfxsids.hrc> 41 #include <statcach.hxx> 42 #include <sidebar/ContextChangeBroadcaster.hxx> 43 #include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp> 44 #include <tools/debug.hxx> 45 46 #include <memory> 47 #include <vector> 48 #include <map> 49 50 #include <desktop/crashreport.hxx> 51 52 using namespace com::sun::star; 53 54 struct SfxShell_Impl: public SfxBroadcaster 55 { 56 OUString aObjectName; // Name of Sbx-Objects 57 // Maps the Which() field to a pointer to a SfxPoolItem 58 std::map<sal_uInt16, std::unique_ptr<SfxPoolItem>> 59 m_Items; // Data exchange on Item level 60 SfxViewShell* pViewSh; // SfxViewShell if Shell is 61 // ViewFrame/ViewShell/SubShell list 62 SfxViewFrame* pFrame; // Frame, if <UI-active> 63 SfxRepeatTarget* pRepeatTarget; // SbxObjectRef xParent; 64 bool bActive; 65 SfxDisableFlags nDisableFlags; 66 std::unique_ptr<svtools::AsynchronLink> pExecuter; 67 std::unique_ptr<svtools::AsynchronLink> pUpdater; 68 std::vector<std::unique_ptr<SfxSlot> > aSlotArr; 69 70 css::uno::Sequence < css::embed::VerbDescriptor > aVerbList; 71 ::sfx2::sidebar::ContextChangeBroadcaster maContextChangeBroadcaster; 72 73 SfxShell_Impl() 74 : pViewSh(nullptr) 75 , pFrame(nullptr) 76 , pRepeatTarget(nullptr) 77 , bActive(false) 78 , nDisableFlags(SfxDisableFlags::NONE) 79 { 80 } 81 82 virtual ~SfxShell_Impl() override { pExecuter.reset(); pUpdater.reset();} 83 }; 84 85 86 void SfxShell::EmptyExecStub(SfxShell *, SfxRequest &) 87 { 88 } 89 90 void SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &) 91 { 92 } 93 94 SfxShell::SfxShell() 95 : pImpl(new SfxShell_Impl), 96 pPool(nullptr), 97 pUndoMgr(nullptr) 98 { 99 } 100 101 SfxShell::SfxShell( SfxViewShell *pViewSh ) 102 : pImpl(new SfxShell_Impl), 103 pPool(nullptr), 104 pUndoMgr(nullptr) 105 { 106 pImpl->pViewSh = pViewSh; 107 } 108 109 SfxShell::~SfxShell() 110 { 111 } 112 113 void SfxShell::SetName( const OUString &rName ) 114 { 115 pImpl->aObjectName = rName; 116 } 117 118 const OUString& SfxShell::GetName() const 119 { 120 return pImpl->aObjectName; 121 } 122 123 SfxDispatcher* SfxShell::GetDispatcher() const 124 { 125 return pImpl->pFrame ? pImpl->pFrame->GetDispatcher() : nullptr; 126 } 127 128 SfxViewShell* SfxShell::GetViewShell() const 129 { 130 return pImpl->pViewSh; 131 } 132 133 SfxViewFrame* SfxShell::GetFrame() const 134 { 135 if ( pImpl->pFrame ) 136 return pImpl->pFrame; 137 if ( pImpl->pViewSh ) 138 return pImpl->pViewSh->GetViewFrame(); 139 return nullptr; 140 } 141 142 const SfxPoolItem* SfxShell::GetItem 143 ( 144 sal_uInt16 nSlotId // Slot-Id of the querying <SfxPoolItem>s 145 ) const 146 { 147 auto const it = pImpl->m_Items.find( nSlotId ); 148 if (it != pImpl->m_Items.end()) 149 return it->second.get(); 150 return nullptr; 151 } 152 153 void SfxShell::PutItem 154 ( 155 const SfxPoolItem& rItem /* Instance, of which a copy is created, 156 which is stored in the SfxShell in a list. */ 157 ) 158 { 159 DBG_ASSERT( dynamic_cast< const SfxSetItem* >( &rItem) == nullptr, "SetItems aren't allowed here" ); 160 DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ), 161 "items with Which-Ids aren't allowed here" ); 162 163 // MSC made a mess here of WNT/W95, beware of changes 164 SfxPoolItem *pItem = rItem.Clone(); 165 SfxPoolItemHint aItemHint( pItem ); 166 sal_uInt16 nWhich = rItem.Which(); 167 168 auto const it = pImpl->m_Items.find(nWhich); 169 if (it != pImpl->m_Items.end()) 170 { 171 // Replace Item 172 pImpl->m_Items.erase( it ); 173 pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem))); 174 175 // if active, notify Bindings 176 SfxDispatcher *pDispat = GetDispatcher(); 177 if ( pDispat ) 178 { 179 SfxBindings* pBindings = pDispat->GetBindings(); 180 pBindings->Broadcast( aItemHint ); 181 sal_uInt16 nSlotId = nWhich; //pItem->GetSlotId(); 182 SfxStateCache* pCache = pBindings->GetStateCache( nSlotId ); 183 if ( pCache ) 184 { 185 pCache->SetState( SfxItemState::DEFAULT, pItem, true ); 186 pCache->SetCachedState( true ); 187 } 188 } 189 return; 190 } 191 else 192 { 193 Broadcast( aItemHint ); 194 pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem))); 195 } 196 } 197 198 SfxInterface* SfxShell::GetInterface() const 199 { 200 return GetStaticInterface(); 201 } 202 203 SfxUndoManager* SfxShell::GetUndoManager() 204 { 205 return pUndoMgr; 206 } 207 208 void SfxShell::SetUndoManager( SfxUndoManager *pNewUndoMgr ) 209 { 210 OSL_ENSURE( ( pUndoMgr == nullptr ) || ( pNewUndoMgr == nullptr ) || ( pUndoMgr == pNewUndoMgr ), 211 "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" ); 212 // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which 213 // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really 214 // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances. 215 216 pUndoMgr = pNewUndoMgr; 217 if (pUndoMgr && !utl::ConfigManager::IsFuzzing()) 218 { 219 pUndoMgr->SetMaxUndoActionCount( 220 officecfg::Office::Common::Undo::Steps::get()); 221 } 222 } 223 224 SfxRepeatTarget* SfxShell::GetRepeatTarget() const 225 { 226 return pImpl->pRepeatTarget; 227 } 228 229 void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget ) 230 { 231 pImpl->pRepeatTarget = pTarget; 232 } 233 234 void SfxShell::Invalidate 235 ( 236 sal_uInt16 nId /* Invalidated Slot-Id or Which-Id. 237 If these are 0 (default), then all 238 by this Shell currently handled Slot-Ids are 239 invalidated. */ 240 ) 241 { 242 if ( !GetViewShell() ) 243 { 244 OSL_FAIL( "wrong Invalidate method called!" ); 245 return; 246 } 247 248 Invalidate_Impl( GetViewShell()->GetViewFrame()->GetBindings(), nId ); 249 } 250 251 void SfxShell::Invalidate_Impl( SfxBindings& rBindings, sal_uInt16 nId ) 252 { 253 if ( nId == 0 ) 254 { 255 rBindings.InvalidateShell( *this ); 256 } 257 else 258 { 259 const SfxInterface *pIF = GetInterface(); 260 do 261 { 262 const SfxSlot *pSlot = pIF->GetSlot(nId); 263 if ( pSlot ) 264 { 265 // Invalidate the Slot itself 266 rBindings.Invalidate( pSlot->GetSlotId() ); 267 return; 268 } 269 270 pIF = pIF->GetGenoType(); 271 } 272 273 while ( pIF ); 274 275 SAL_INFO( "sfx.control", "W3: invalidating slot-id unknown in shell" ); 276 } 277 } 278 279 void SfxShell::HandleOpenXmlFilterSettings(SfxRequest & rReq) 280 { 281 try 282 { 283 uno::Reference < ui::dialogs::XExecutableDialog > xDialog = ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() ); 284 xDialog->execute(); 285 } 286 catch (const uno::Exception&) 287 { 288 } 289 rReq.Ignore (); 290 } 291 292 void SfxShell::DoActivate_Impl( SfxViewFrame *pFrame, bool bMDI ) 293 { 294 SfxObjectShell* pObjectShell = GetObjectShell(); 295 if ( pObjectShell ) 296 { 297 const OUString sActiveDocName = pObjectShell->GetTitle(); 298 if( !pImpl->aObjectName.startsWith(sActiveDocName) ) 299 { 300 CrashReporter::setActiveSfxObjectName(pImpl->aObjectName); 301 } 302 } 303 else 304 { 305 CrashReporter::setActiveSfxObjectName(pImpl->aObjectName); 306 } 307 308 #ifdef DBG_UTIL 309 const SfxInterface *p_IF = GetInterface(); 310 if ( !p_IF ) 311 return; 312 #endif 313 SAL_INFO( 314 "sfx.control", 315 "SfxShell::DoActivate() " << this << " " << GetInterface()->GetClassName() 316 << " bMDI " << (bMDI ? "MDI" : "")); 317 318 if ( bMDI ) 319 { 320 // Remember Frame, in which it was activated 321 pImpl->pFrame = pFrame; 322 pImpl->bActive = true; 323 } 324 325 // Notify Subclass 326 Activate(bMDI); 327 } 328 329 void SfxShell::DoDeactivate_Impl( SfxViewFrame const *pFrame, bool bMDI ) 330 { 331 #ifdef DBG_UTIL 332 const SfxInterface *p_IF = GetInterface(); 333 if ( !p_IF ) 334 return; 335 #endif 336 SAL_INFO( 337 "sfx.control", 338 "SfxShell::DoDeactivate()" << this << " " << GetInterface()->GetClassName() 339 << " bMDI " << (bMDI ? "MDI" : "")); 340 341 // Only when it comes from a Frame 342 // (not when for instance by popping BASIC-IDE from AppDisp) 343 if ( bMDI && pImpl->pFrame == pFrame ) 344 { 345 // deliver 346 pImpl->pFrame = nullptr; 347 pImpl->bActive = false; 348 } 349 350 // Notify Subclass 351 Deactivate(bMDI); 352 } 353 354 bool SfxShell::IsActive() const 355 { 356 return pImpl->bActive; 357 } 358 359 void SfxShell::Activate 360 ( 361 bool /*bMDI*/ /* TRUE 362 the <SfxDispatcher>, on which the SfxShell is 363 located, is activated or the SfxShell instance 364 was pushed on an active SfxDispatcher. 365 (compare with SystemWindow::IsMDIActivate()) 366 367 FALSE 368 the <SfxViewFrame>, on which SfxDispatcher 369 the SfxShell instance is located, was 370 activated. (for example by a closing dialog) */ 371 ) 372 { 373 BroadcastContextForActivation(true); 374 } 375 376 void SfxShell::Deactivate 377 ( 378 bool /*bMDI*/ /* TRUE 379 the <SfxDispatcher>, on which the SfxShell is 380 located, is inactivated or the SfxShell instance 381 was popped on an active SfxDispatcher. 382 (compare with SystemWindow::IsMDIActivate()) 383 384 FALSE 385 the <SfxViewFrame>, on which SfxDispatcher 386 the SfxShell instance is located, was 387 deactivated. (for example by a dialog) */ 388 ) 389 { 390 BroadcastContextForActivation(false); 391 } 392 393 bool SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot ) 394 { 395 // Get Slot status 396 SfxItemPool &rPool = GetPool(); 397 const sal_uInt16 nId = rSlot.GetWhich( rPool ); 398 SfxItemSet aSet(rPool, {{nId, nId}}); 399 SfxStateFunc pFunc = rSlot.GetStateFnc(); 400 (*pFunc)( this, aSet ); 401 return aSet.GetItemState(nId) != SfxItemState::DISABLED; 402 } 403 404 bool SfxShell::IsConditionalFastCall( const SfxRequest &rReq ) 405 { 406 sal_uInt16 nId = rReq.GetSlot(); 407 bool bRet = false; 408 409 if (nId == SID_UNDO || nId == SID_REDO) 410 { 411 const SfxItemSet* pArgs = rReq.GetArgs(); 412 if (pArgs && pArgs->HasItem(SID_REPAIRPACKAGE)) 413 bRet = true; 414 } 415 return bRet; 416 } 417 418 419 static void ShellCall_Impl( void* pObj, void* pArg ) 420 { 421 static_cast<SfxShell*>(pObj)->ExecuteSlot( *static_cast<SfxRequest*>(pArg) ); 422 } 423 424 void SfxShell::ExecuteSlot( SfxRequest& rReq, bool bAsync ) 425 { 426 if( !bAsync ) 427 ExecuteSlot( rReq ); 428 else 429 { 430 if( !pImpl->pExecuter ) 431 pImpl->pExecuter.reset( new svtools::AsynchronLink( 432 Link<void*,void>( this, ShellCall_Impl ) ) ); 433 pImpl->pExecuter->Call( new SfxRequest( rReq ) ); 434 } 435 } 436 437 const SfxPoolItem* SfxShell::ExecuteSlot 438 ( 439 SfxRequest &rReq, // the relayed <SfxRequest> 440 const SfxInterface* pIF // default = 0 means get virtually 441 ) 442 { 443 if ( !pIF ) 444 pIF = GetInterface(); 445 446 sal_uInt16 nSlot = rReq.GetSlot(); 447 const SfxSlot* pSlot = nullptr; 448 if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END ) 449 pSlot = GetVerbSlot_Impl(nSlot); 450 if ( !pSlot ) 451 pSlot = pIF->GetSlot(nSlot); 452 DBG_ASSERT( pSlot, "slot not supported" ); 453 454 SfxExecFunc pFunc = pSlot->GetExecFnc(); 455 if ( pFunc ) 456 (*pFunc)( this, rReq ); 457 458 return rReq.GetReturnValue(); 459 } 460 461 const SfxPoolItem* SfxShell::GetSlotState 462 ( 463 sal_uInt16 nSlotId, // Slot-Id to the Slots in question 464 const SfxInterface* pIF, // default = 0 means get virtually 465 SfxItemSet* pStateSet // SfxItemSet of the Slot-State method 466 ) 467 { 468 // Get Slot on the given Interface 469 if ( !pIF ) 470 pIF = GetInterface(); 471 SfxItemState eState(SfxItemState::DEFAULT); 472 bool bItemStateSet(false); 473 SfxItemPool &rPool = GetPool(); 474 475 const SfxSlot* pSlot = nullptr; 476 if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END ) 477 pSlot = GetVerbSlot_Impl(nSlotId); 478 if ( !pSlot ) 479 pSlot = pIF->GetSlot(nSlotId); 480 if ( pSlot ) 481 // Map on Which-Id if possible 482 nSlotId = pSlot->GetWhich( rPool ); 483 484 // Get Item and Item status 485 const SfxPoolItem *pItem = nullptr; 486 SfxItemSet aSet( rPool, {{nSlotId, nSlotId}} ); // else pItem dies too soon 487 if ( nullptr != pSlot ) 488 { 489 // Call Status method 490 SfxStateFunc pFunc = pSlot->GetStateFnc(); 491 if ( pFunc ) 492 (*pFunc)( this, aSet ); 493 eState = aSet.GetItemState( nSlotId, true, &pItem ); 494 bItemStateSet = true; 495 496 // get default Item if possible 497 if ( eState == SfxItemState::DEFAULT ) 498 { 499 if ( SfxItemPool::IsWhich(nSlotId) ) 500 pItem = &rPool.GetDefaultItem(nSlotId); 501 else 502 eState = SfxItemState::DONTCARE; 503 } 504 } 505 506 // Evaluate Item and item status and possibly maintain them in pStateSet 507 std::unique_ptr<SfxPoolItem> pRetItem; 508 if ( !bItemStateSet || eState <= SfxItemState::DISABLED ) 509 { 510 if ( pStateSet ) 511 pStateSet->DisableItem(nSlotId); 512 return nullptr; 513 } 514 else if ( bItemStateSet && eState == SfxItemState::DONTCARE ) 515 { 516 if ( pStateSet ) 517 pStateSet->ClearItem(nSlotId); 518 pRetItem.reset( new SfxVoidItem(0) ); 519 } 520 else // bItemStateSet && eState >= SfxItemState::DEFAULT 521 { 522 if ( pStateSet && pStateSet->Put( *pItem ) ) 523 return &pStateSet->Get( pItem->Which() ); 524 pRetItem.reset(pItem->Clone()); 525 } 526 auto pTemp = pRetItem.get(); 527 DeleteItemOnIdle(std::move(pRetItem)); 528 529 return pTemp; 530 } 531 532 static SFX_EXEC_STUB(SfxShell, VerbExec) 533 static void SfxStubSfxShellVerbState(SfxShell *, SfxItemSet& rSet) 534 { 535 SfxShell::VerbState( rSet ); 536 } 537 538 void SfxShell::SetVerbs(const css::uno::Sequence < css::embed::VerbDescriptor >& aVerbs) 539 { 540 SfxViewShell *pViewSh = dynamic_cast<SfxViewShell*>( this ); 541 542 DBG_ASSERT(pViewSh, "Only call SetVerbs at the ViewShell!"); 543 if ( !pViewSh ) 544 return; 545 546 // First make all Statecaches dirty, so that no-one no longer tries to use 547 // the Slots 548 { 549 SfxBindings *pBindings = 550 pViewSh->GetViewFrame()->GetDispatcher()->GetBindings(); 551 sal_uInt16 nCount = pImpl->aSlotArr.size(); 552 for (sal_uInt16 n1=0; n1<nCount ; n1++) 553 { 554 sal_uInt16 nId = SID_VERB_START + n1; 555 pBindings->Invalidate(nId, false, true); 556 } 557 } 558 559 sal_uInt16 nr=0; 560 for (sal_Int32 n=0; n<aVerbs.getLength(); n++) 561 { 562 sal_uInt16 nSlotId = SID_VERB_START + nr++; 563 DBG_ASSERT(nSlotId <= SID_VERB_END, "Too many Verbs!"); 564 if (nSlotId > SID_VERB_END) 565 break; 566 567 SfxSlot *pNewSlot = new SfxSlot; 568 pNewSlot->nSlotId = nSlotId; 569 pNewSlot->nGroupId = SfxGroupId::NONE; 570 571 // Verb slots must be executed asynchronously, so that they can be 572 // destroyed while executing. 573 pNewSlot->nFlags = SfxSlotMode::ASYNCHRON | SfxSlotMode::CONTAINER; 574 pNewSlot->nMasterSlotId = 0; 575 pNewSlot->nValue = 0; 576 pNewSlot->fnExec = SFX_STUB_PTR(SfxShell,VerbExec); 577 pNewSlot->fnState = SFX_STUB_PTR(SfxShell,VerbState); 578 pNewSlot->pType = nullptr; // HACK(SFX_TYPE(SfxVoidItem)) ??? 579 pNewSlot->nArgDefCount = 0; 580 pNewSlot->pFirstArgDef = nullptr; 581 pNewSlot->pUnoName = nullptr; 582 583 if (!pImpl->aSlotArr.empty()) 584 { 585 SfxSlot& rSlot = *pImpl->aSlotArr[0]; 586 pNewSlot->pNextSlot = rSlot.pNextSlot; 587 rSlot.pNextSlot = pNewSlot; 588 } 589 else 590 pNewSlot->pNextSlot = pNewSlot; 591 592 pImpl->aSlotArr.insert(pImpl->aSlotArr.begin() + static_cast<sal_uInt16>(n), std::unique_ptr<SfxSlot>(pNewSlot)); 593 } 594 595 pImpl->aVerbList = aVerbs; 596 597 // The status of SID_OBJECT is collected in the controller directly on 598 // the Shell, it is thus enough to encourage a new status update 599 SfxBindings* pBindings = pViewSh->GetViewFrame()->GetDispatcher()->GetBindings(); 600 pBindings->Invalidate(SID_OBJECT, true, true); 601 } 602 603 const css::uno::Sequence < css::embed::VerbDescriptor >& SfxShell::GetVerbs() const 604 { 605 return pImpl->aVerbList; 606 } 607 608 void SfxShell::VerbExec(SfxRequest& rReq) 609 { 610 sal_uInt16 nId = rReq.GetSlot(); 611 SfxViewShell *pViewShell = GetViewShell(); 612 if ( !pViewShell ) 613 return; 614 615 bool bReadOnly = pViewShell->GetObjectShell()->IsReadOnly(); 616 const css::uno::Sequence < css::embed::VerbDescriptor > aList = pViewShell->GetVerbs(); 617 sal_Int32 nVerb = 0; 618 for (const auto& rVerb : aList) 619 { 620 // check for ReadOnly verbs 621 if ( bReadOnly && !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) ) 622 continue; 623 624 // check for verbs that shouldn't appear in the menu 625 if ( !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) ) 626 continue; 627 628 if (nId == SID_VERB_START + nVerb++) 629 { 630 pViewShell->DoVerb(rVerb.VerbID); 631 rReq.Done(); 632 return; 633 } 634 } 635 } 636 637 void SfxShell::VerbState(SfxItemSet& ) 638 { 639 } 640 641 const SfxSlot* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId) const 642 { 643 css::uno::Sequence < css::embed::VerbDescriptor > rList = pImpl->aVerbList; 644 645 DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Wrong VerbId!"); 646 sal_uInt16 nIndex = nId - SID_VERB_START; 647 DBG_ASSERT(nIndex < rList.getLength(),"Wrong VerbId!"); 648 649 if (nIndex < rList.getLength()) 650 return pImpl->aSlotArr[nIndex].get(); 651 else 652 return nullptr; 653 } 654 655 SfxObjectShell* SfxShell::GetObjectShell() 656 { 657 if ( GetViewShell() ) 658 return GetViewShell()->GetViewFrame()->GetObjectShell(); 659 else 660 return nullptr; 661 } 662 663 bool SfxShell::HasUIFeature(SfxShellFeature) const 664 { 665 return false; 666 } 667 668 static void DispatcherUpdate_Impl( void*, void* pArg ) 669 { 670 static_cast<SfxDispatcher*>(pArg)->Update_Impl( true ); 671 static_cast<SfxDispatcher*>(pArg)->GetBindings()->InvalidateAll(false); 672 } 673 674 void SfxShell::UIFeatureChanged() 675 { 676 SfxViewFrame *pFrame = GetFrame(); 677 if ( pFrame && pFrame->IsVisible() ) 678 { 679 // Also force an update, if dispatcher is already updated otherwise 680 // something my get stuck in the bunkered tools. Asynchronous call to 681 // prevent recursion. 682 if ( !pImpl->pUpdater ) 683 pImpl->pUpdater.reset( new svtools::AsynchronLink( Link<void*,void>( this, DispatcherUpdate_Impl ) ) ); 684 685 // Multiple views allowed 686 pImpl->pUpdater->Call( pFrame->GetDispatcher(), true ); 687 } 688 } 689 690 void SfxShell::SetDisableFlags( SfxDisableFlags nFlags ) 691 { 692 pImpl->nDisableFlags = nFlags; 693 } 694 695 SfxDisableFlags SfxShell::GetDisableFlags() const 696 { 697 return pImpl->nDisableFlags; 698 } 699 700 std::unique_ptr<SfxItemSet> SfxShell::CreateItemSet( sal_uInt16 ) 701 { 702 return nullptr; 703 } 704 705 void SfxShell::ApplyItemSet( sal_uInt16, const SfxItemSet& ) 706 { 707 } 708 709 void SfxShell::SetContextName (const OUString& rsContextName) 710 { 711 pImpl->maContextChangeBroadcaster.Initialize(rsContextName); 712 } 713 714 void SfxShell::SetViewShell_Impl( SfxViewShell* pView ) 715 { 716 pImpl->pViewSh = pView; 717 } 718 719 void SfxShell::BroadcastContextForActivation (const bool bIsActivated) 720 { 721 // Avoids activation and de-activation (can be seen on switching view) from causing 722 // the sidebar to re-build. Such switching can happen as we change view to render 723 // using LOK for example, and is un-necessary for Online. 724 if (comphelper::LibreOfficeKit::isDialogPainting()) 725 return; 726 727 SfxViewFrame* pViewFrame = GetFrame(); 728 if (pViewFrame != nullptr) 729 { 730 if (bIsActivated) 731 pImpl->maContextChangeBroadcaster.Activate(pViewFrame->GetFrame().GetFrameInterface()); 732 else 733 pImpl->maContextChangeBroadcaster.Deactivate(pViewFrame->GetFrame().GetFrameInterface()); 734 } 735 } 736 737 bool SfxShell::SetContextBroadcasterEnabled (const bool bIsEnabled) 738 { 739 return pImpl->maContextChangeBroadcaster.SetBroadcasterEnabled(bIsEnabled); 740 } 741 742 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 743
