nss: upgrade to release 3.73
[LibreOffice.git] / sfx2 / source / control / dispatch.cxx
blobde98fb5e228a14f06e151e75f27f5cb963ac4181
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_feature_desktop.h>
22 #include <algorithm>
23 #include <cstddef>
24 #include <deque>
25 #include <vector>
27 #include <stdlib.h>
29 #include <boost/property_tree/json_parser.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/frame/XDispatchRecorderSupplier.hpp>
33 #include <com/sun/star/frame/XLayoutManager.hpp>
34 #include <com/sun/star/frame/XPopupMenuController.hpp>
35 #include <com/sun/star/uno/XComponentContext.hpp>
36 #include <com/sun/star/ui/ContextMenuExecuteEvent.hpp>
38 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
39 #include <comphelper/lok.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/propertyvalue.hxx>
42 #include <rtl/strbuf.hxx>
43 #include <sal/log.hxx>
44 #include <sfx2/app.hxx>
45 #include <sfx2/bindings.hxx>
46 #include <sfx2/childwin.hxx>
47 #include <sfx2/dispatch.hxx>
48 #include <sfx2/docfile.hxx>
49 #include <hintpost.hxx>
50 #include <sfx2/ipclient.hxx>
51 #include <sfx2/module.hxx>
52 #include <sfx2/msg.hxx>
53 #include <sfx2/msgpool.hxx>
54 #include <sfx2/objface.hxx>
55 #include <sfx2/request.hxx>
56 #include <sfx2/sfxsids.hrc>
57 #include <sfx2/viewfrm.hxx>
58 #include <sfx2/viewsh.hxx>
59 #include <svl/eitem.hxx>
60 #include <svl/itemiter.hxx>
61 #include <svl/itempool.hxx>
62 #include <toolkit/awt/vclxmenu.hxx>
63 #include <toolkit/helper/vclunohelper.hxx>
64 #include <tools/debug.hxx>
65 #include <vcl/idle.hxx>
67 #include <sfxtypes.hxx>
68 #include <slotserv.hxx>
69 #include <workwin.hxx>
71 typedef std::vector<SfxShell*> SfxShellStack_Impl;
73 namespace {
75 struct SfxToDo_Impl
77 SfxShell* pCluster;
78 bool bPush;
79 bool bDelete;
80 bool bDeleted;
81 bool bUntil;
83 SfxToDo_Impl( bool bOpPush, bool bOpDelete, bool bOpUntil, SfxShell& rCluster )
84 : pCluster(&rCluster)
85 , bPush(bOpPush)
86 , bDelete(bOpDelete)
87 , bDeleted(false)
88 , bUntil(bOpUntil)
92 struct SfxObjectBars_Impl
94 ToolbarId eId; // ConfigId of the Toolbox
95 sal_uInt16 nPos;
96 SfxVisibilityFlags nFlags; // special visibility flags
98 SfxObjectBars_Impl() : eId(ToolbarId::None), nPos(0), nFlags(SfxVisibilityFlags::Invisible) {}
103 struct SfxDispatcher_Impl
105 //When the dispatched is locked, SfxRequests accumulate in aReqArr for
106 //later dispatch when unlocked via Post
108 //The pointers are typically deleted in Post, only if we never get around
109 //to posting them do we delete the unposted requests.
110 std::vector<std::unique_ptr<SfxRequest>>
111 aReqArr;
112 SfxShellStack_Impl aStack; // active functionality
113 Idle aIdle; // for Flush
114 std::deque<SfxToDo_Impl> aToDoStack; // not processed Push/Pop
115 SfxViewFrame* pFrame; // NULL or associated Frame
116 tools::SvRef<SfxHintPoster>
117 xPoster; // Execute asynchronous
118 bool bFlushing; // sal_True during Flush //?
119 bool bUpdated; // Update_Impl has run
120 bool bLocked; // No Execute
121 bool bInvalidateOnUnlock; // because someone asked
122 bool bActive; // not to be confused with set!
123 bool* pInCallAliveFlag; // view the Destructor Stack
124 SfxObjectBars_Impl aObjBars[SFX_OBJECTBAR_MAX];
125 SfxObjectBars_Impl aFixedObjBars[SFX_OBJECTBAR_MAX];
126 std::vector<sal_uInt32> aChildWins;
127 bool bNoUI; // UI only from Parent Dispatcher
128 bool bReadOnly; // Document is ReadOnly
129 bool bQuiet; // Only use parent dispatcher
131 SfxSlotFilterState nFilterEnabling; // 1==filter enabled slots,
132 // 2==ReadOnlyDoc overturned
133 o3tl::span<sal_uInt16 const>
134 pFilterSIDs; // sorted Array of SIDs
135 SfxDisableFlags nDisableFlags;
136 bool bFlushed;
137 std::deque< std::deque<SfxToDo_Impl> > aToDoCopyStack;
140 /** This method checks if the stack of the SfxDispatchers is flushed, or if
141 push- or pop- commands are pending.
143 bool SfxDispatcher::IsFlushed() const
145 return xImp->bFlushed;
148 /** This method performs outstanding push- and pop- commands. For <SfxShell>s,
149 which are new on the stack, the <SfxShell::Activate(bool)> is invoked
150 with bMDI == sal_True, for SfxShells that are removed from the stack, the
151 <SfxShell::Deactivate(bool)> is invoked with bMDI == sal_True
153 void SfxDispatcher::Flush()
155 if (!xImp->bFlushed) FlushImpl();
158 /** With this method, a <SfxShell> pushed on to the SfxDispatcher.
159 The SfxShell is first marked for push and a timer is set up.
160 First when the timer has counted down to zero the push
161 ( <SfxDispatcher::Flush()> ) is actually performed and the
162 <SfxBindings> is invalidated. While the timer is counting down
163 the opposing push and pop commands on the same SfxShell are
164 leveled out.
166 void SfxDispatcher::Push(SfxShell& rShell)
169 Pop( rShell, SfxDispatcherPopFlags::PUSH );
172 /** This method checks whether a particular <SfxShell> instance is
173 on the SfxDispatcher.
175 @returns true The SfxShell instance is on the SfxDispatcher.
176 false The SfxShell instance is not on the SfxDispatcher.
178 bool SfxDispatcher::IsActive(const SfxShell& rShell)
181 return CheckVirtualStack(rShell);
184 /** With this method it can be determined whether the SfxDispatcher is
185 locked or unlocked. A locked SfxDispatcher does not perform <SfxRequest>s
186 and no longer provides any status information. It behaves as if all the
187 slots are disabled.
189 The dispatcher is also marked as blocked, if all Dispatcher are locked
190 (<SfxApplication::LockDispatcher()>) or the associated top frame is in the
191 modal-mode and if the specified slot are handled as frame-specific
192 (ie, not served by the application).
194 bool SfxDispatcher::IsLocked() const
196 return xImp->bLocked;
199 /** With this method it can be determined if the SfxDispacher is the
200 applications dispatcher.
202 @return bool it is the application dispatcher.
204 bool SfxDispatcher::IsAppDispatcher() const
206 return !xImp->pFrame;
209 /** Helper function to check whether a slot can be executed and
210 check the execution itself
212 void SfxDispatcher::Call_Impl(SfxShell& rShell, const SfxSlot &rSlot, SfxRequest &rReq, bool bRecord)
214 SFX_STACK(SfxDispatcher::Call_Impl);
216 // The slot may be called (meaning enabled)
217 if ( !rSlot.IsMode(SfxSlotMode::FASTCALL) && !rShell.CanExecuteSlot_Impl(rSlot) && !rShell.IsConditionalFastCall(rReq) )
218 return;
220 if ( GetFrame() )
222 // Recording may start
223 css::uno::Reference< css::beans::XPropertySet > xSet(
224 GetFrame()->GetFrame().GetFrameInterface(),
225 css::uno::UNO_QUERY);
227 if ( xSet.is() )
229 css::uno::Any aProp = xSet->getPropertyValue("DispatchRecorderSupplier");
230 css::uno::Reference< css::frame::XDispatchRecorderSupplier > xSupplier;
231 css::uno::Reference< css::frame::XDispatchRecorder > xRecorder;
232 aProp >>= xSupplier;
233 if(xSupplier.is())
234 xRecorder = xSupplier->getDispatchRecorder();
236 if ( bRecord && xRecorder.is() && !rSlot.IsMode(SfxSlotMode::NORECORD) )
237 rReq.Record_Impl( rShell, rSlot, xRecorder, GetFrame() );
240 // Get all that is needed, because the slot may not have survived the
241 // Execute if it is a 'pseudo slot' for macros or verbs.
242 bool bAutoUpdate = rSlot.IsMode(SfxSlotMode::AUTOUPDATE);
244 // API-call parentheses and document-lock during the calls
246 // 'this' must respond in the Destructor
247 bool bThisDispatcherAlive = true;
248 bool *pOldInCallAliveFlag = xImp->pInCallAliveFlag;
249 xImp->pInCallAliveFlag = &bThisDispatcherAlive;
251 SfxExecFunc pFunc = rSlot.GetExecFnc();
252 rShell.CallExec( pFunc, rReq );
254 // If 'this' is still alive
255 if ( bThisDispatcherAlive )
256 xImp->pInCallAliveFlag = pOldInCallAliveFlag;
257 else
259 if ( pOldInCallAliveFlag )
261 // also protect nested stack frames
262 *pOldInCallAliveFlag = false;
265 // do nothing after this object is dead
266 return;
270 if ( rReq.IsDone() )
272 SfxBindings *pBindings = GetBindings();
274 // When AutoUpdate update immediately
275 if ( bAutoUpdate && pBindings )
277 pBindings->Invalidate(rSlot.GetSlotId());
278 pBindings->Update(rSlot.GetSlotId());
283 void SfxDispatcher::Construct_Impl()
285 xImp.reset(new SfxDispatcher_Impl);
286 xImp->bFlushed = true;
288 xImp->bFlushing = false;
289 xImp->bUpdated = false;
290 xImp->bLocked = false;
291 xImp->bActive = false;
292 xImp->bNoUI = false;
293 xImp->bReadOnly = false;
294 xImp->bQuiet = false;
295 xImp->pInCallAliveFlag = nullptr;
296 xImp->nFilterEnabling = SfxSlotFilterState::DISABLED;
297 xImp->nDisableFlags = SfxDisableFlags::NONE;
299 xImp->bInvalidateOnUnlock = false;
301 for (SfxObjectBars_Impl & rObjBar : xImp->aObjBars)
302 rObjBar.eId = ToolbarId::None;
304 xImp->xPoster = new SfxHintPoster(std::bind(&SfxDispatcher::PostMsgHandler, this, std::placeholders::_1));
306 xImp->aIdle.SetPriority(TaskPriority::HIGH_IDLE );
307 xImp->aIdle.SetInvokeHandler( LINK(this, SfxDispatcher, EventHdl_Impl ) );
308 xImp->aIdle.SetDebugName( "sfx::SfxDispatcher_Impl aIdle" );
311 SfxDispatcher::SfxDispatcher()
313 Construct_Impl();
314 xImp->pFrame = nullptr;
317 /** The constructor of the SfxDispatcher class places a stack of empty
318 <SfxShell> pointers. It is not initially locked and is considered flushed.
320 SfxDispatcher::SfxDispatcher(SfxViewFrame *pViewFrame)
322 Construct_Impl();
323 xImp->pFrame = pViewFrame;
326 /** The destructor of the SfxDispatcher class should not be called when the
327 SfxDispatcher instance is active. It may, however, still be a <SfxShell>
328 pointer on the stack.
330 SfxDispatcher::~SfxDispatcher()
332 SAL_INFO("sfx.control", "Delete Dispatcher " << reinterpret_cast<sal_Int64>(this));
333 DBG_ASSERT( !xImp->bActive, "deleting active Dispatcher" );
335 // So that no timer by Reschedule in PlugComm strikes the LeaveRegistrations
336 xImp->aIdle.Stop();
337 xImp->xPoster->SetEventHdl( std::function<void (std::unique_ptr<SfxRequest>)>() );
339 // Notify the stack variables in Call_Impl
340 if ( xImp->pInCallAliveFlag )
341 *xImp->pInCallAliveFlag = false;
343 // Get bindings and application
344 SfxApplication *pSfxApp = SfxGetpApp();
345 SfxBindings* pBindings = GetBindings();
347 // When not flushed, revive the bindings
348 if (pBindings && !pSfxApp->IsDowning() && !xImp->bFlushed)
349 pBindings->DLEAVEREGISTRATIONS();
351 // may unregister the bindings
352 while ( pBindings )
354 if ( pBindings->GetDispatcher_Impl() == this)
355 pBindings->SetDispatcher(nullptr);
356 pBindings = pBindings->GetSubBindings_Impl();
360 /** With this method, one or more <SfxShell> are popped from the SfxDispatcher.
361 The SfxShell is marked for popping and a timer is set up. Only when the
362 timer has reached the end, the pop is actually performed
363 ( <SfxDispatcher::Flush()> ) and the <SfxBindings> is invalidated.
364 While the timer is running the opposing push and pop commands on one
365 SfxShell cancel each other out.
367 @param rShell the stack to take the SfxShell instance.
368 @param nMode SfxDispatcherPopFlags::POP_UNTIL
369 Also all 'rShell' of SfxShells are taken from the
370 stack.
372 SfxDispatcherPopFlags::POP_DELETE
373 All SfxShells actually taken from the stack
374 will be deleted.
376 SfxDispatcherPopFlags::PUSH (InPlace use only)
377 The Shell is pushed.
379 void SfxDispatcher::Pop(SfxShell& rShell, SfxDispatcherPopFlags nMode)
381 DBG_ASSERT( rShell.GetInterface(),
382 "pushing SfxShell without previous RegisterInterface()" );
384 bool bDelete = bool(nMode & SfxDispatcherPopFlags::POP_DELETE);
385 bool bUntil = bool(nMode & SfxDispatcherPopFlags::POP_UNTIL);
386 bool bPush = bool(nMode & SfxDispatcherPopFlags::PUSH);
388 SfxApplication *pSfxApp = SfxGetpApp();
390 SAL_INFO(
391 "sfx.control",
392 "-SfxDispatcher(" << this << (bPush ? ")::Push(" : ")::Pop(")
393 << (rShell.GetInterface()
394 ? rShell.GetInterface()->GetClassName() : SAL_STREAM(&rShell))
395 << (bDelete ? ") with delete" : ")")
396 << (bUntil ? " (up to)" : ""));
398 // same shell as on top of the to-do stack?
399 if(!xImp->aToDoStack.empty() && xImp->aToDoStack.front().pCluster == &rShell)
401 // cancel inverse actions
402 if ( xImp->aToDoStack.front().bPush != bPush )
403 xImp->aToDoStack.pop_front();
404 else
406 DBG_ASSERT( bPush, "SfxInterface pushed more than once" );
407 DBG_ASSERT( !bPush, "SfxInterface popped more than once" );
410 else
412 // Remember Action
413 xImp->aToDoStack.push_front( SfxToDo_Impl(bPush, bDelete, bUntil, rShell) );
414 if (xImp->bFlushed)
416 SAL_INFO("sfx.control", "Unflushed dispatcher!");
417 xImp->bFlushed = false;
418 xImp->bUpdated = false;
420 // Put bindings to sleep
421 SfxBindings* pBindings = GetBindings();
422 if ( pBindings )
423 pBindings->DENTERREGISTRATIONS();
427 if(!pSfxApp->IsDowning() && !xImp->aToDoStack.empty())
429 // No immediate update is requested
430 xImp->aIdle.Start();
432 else
434 // but to do nothing
435 xImp->aIdle.Stop();
437 // Bindings may wake up again
438 if(xImp->aToDoStack.empty())
440 SfxBindings* pBindings = GetBindings();
441 if ( pBindings )
442 pBindings->DLEAVEREGISTRATIONS();
448 /** This handler is called after <SfxDispatcher::Invalidate()> or after
449 changes on the stack (<SfxDispatcher::Push()> and <SfxDispatcher::Pop())
451 It flushes the Stack, if it is dirty, thus it actually executes the
452 pending Push and Pop commands.
454 IMPL_LINK_NOARG( SfxDispatcher, EventHdl_Impl, Timer *, void )
456 Flush();
457 Update_Impl();
458 SfxBindings* pBindings = GetBindings();
459 if ( pBindings )
460 pBindings->StartUpdate_Impl();
463 /** With this method it can be tested whether the <SfxShell> rShell is on the
464 stack, when it was flushed. This way the SfxDispatcher is not actually
465 flushed.
467 This method is intended among other things to make assertions possible
468 without the side effect of having to flush the SfxDispatcher.
470 bool SfxDispatcher::CheckVirtualStack(const SfxShell& rShell)
472 SFX_STACK(SfxDispatcher::CheckVirtualStack);
474 SfxShellStack_Impl aStack( xImp->aStack );
475 for(std::deque<SfxToDo_Impl>::reverse_iterator i = xImp->aToDoStack.rbegin(); i != xImp->aToDoStack.rend(); ++i)
477 if(i->bPush)
478 aStack.push_back(i->pCluster);
479 else
481 SfxShell* pPopped(nullptr);
484 DBG_ASSERT( !aStack.empty(), "popping from empty stack" );
485 pPopped = aStack.back();
486 aStack.pop_back();
488 while(i->bUntil && pPopped != i->pCluster);
489 DBG_ASSERT(pPopped == i->pCluster, "popping unpushed SfxInterface");
493 bool bReturn = std::find(aStack.begin(), aStack.end(), &rShell) != aStack.end();
494 return bReturn;
497 /** Determines the position of a given SfxShell in the stack of the dispatcher.
498 If possible this is flushed before.
500 [Return value]
502 sal_uInt16 == USRT_MAX
503 The SfxShell is not on this SfxDispatcher.
505 < USHRT_MAX
506 Position of the SfxShell on the Dispatcher
507 from the top count stating with 0.
509 sal_uInt16 SfxDispatcher::GetShellLevel(const SfxShell& rShell)
511 SFX_STACK(SfxDispatcher::GetShellLevel);
512 Flush();
514 for ( size_t n = 0; n < xImp->aStack.size(); ++n )
515 if ( *( xImp->aStack.rbegin() + n ) == &rShell )
516 return n;
518 return USHRT_MAX;
521 /** Returns a pointer to the <SfxShell> which is at the position nIdx
522 (from the top, last pushed is 0) on the stack.
524 Thus the SfxDispatcher is not flushed.
526 Is the stack not deep enough a NULL-Pointer is returned.
528 SfxShell *SfxDispatcher::GetShell(sal_uInt16 nIdx) const
530 sal_uInt16 nShellCount = xImp->aStack.size();
531 if ( nIdx < nShellCount )
532 return *(xImp->aStack.rbegin() + nIdx);
533 return nullptr;
536 /** This method returns a pointer to the <SfxBinding> Instance on which the
537 SfxDispatcher is currently bound. A SfxDispatcher is only bound to
538 the SfxBindings when it is <UI-aktiv>. If it is not UI-active,
539 a NULL-pointer is returned.
541 The returned pointer is only valid in the immediate context of the method
542 call.
544 SfxBindings* SfxDispatcher::GetBindings() const
546 if ( xImp->pFrame )
547 return &xImp->pFrame->GetBindings();
548 else
549 return nullptr;
552 /** Returns a pointer to the <SfxViewFrame> instance, which belongs to
553 this SfxDispatcher. If it is about the application dispatcher,
554 a NULL-pointer is returned.
556 SfxViewFrame* SfxDispatcher::GetFrame() const
558 return xImp->pFrame;
561 /** This method controls the activation of a dispatcher.
563 Since the application dispatcher is always active, either as a sub
564 dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
565 activated as a whole, instead only its individual <SfxShell>s at
566 <SfxDispatcher::Push(SfxShell&)>.
568 When activating a SfxDispatcher all of the SfxShells located on its stack
569 are called with the handler <SfxShell::Activate(bool)>, starting with
570 the lowest.
572 void SfxDispatcher::DoActivate_Impl(bool bMDI)
574 SFX_STACK(SfxDispatcher::DoActivate);
575 if ( bMDI )
577 SAL_INFO("sfx.control", "Activate Dispatcher " << reinterpret_cast<sal_Int64>(this));
578 DBG_ASSERT( !xImp->bActive, "Activation error" );
580 xImp->bActive = true;
581 xImp->bUpdated = false;
582 SfxBindings* pBindings = GetBindings();
583 if ( pBindings )
585 pBindings->SetDispatcher(this);
586 pBindings->SetActiveFrame( xImp->pFrame->GetFrame().GetFrameInterface() );
589 else
591 SAL_INFO("sfx.control", "Non-MDI-Activate Dispatcher " << reinterpret_cast<sal_Int64>(this));
594 if ( IsAppDispatcher() )
595 return;
597 for ( int i = int(xImp->aStack.size()) - 1; i >= 0; --i )
598 (*(xImp->aStack.rbegin() + i ))->DoActivate_Impl(xImp->pFrame, bMDI);
600 if ( bMDI && xImp->pFrame )
602 xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( false, 1 );
605 if(!xImp->aToDoStack.empty())
607 // No immediate update is requested
608 xImp->aIdle.Start();
612 /** This method controls the deactivation of a dispatcher.
614 Since the application dispatcher is always active, either as a sub
615 dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
616 deactivated as a whole, instead only its individual <SfxShell>s at
617 <SfxDispatcher::Pop(SfxShell&)>.
619 When deactivating a SfxDispatcher all of the SfxShells located on its stack
620 are called with the handler <SfxShell::Deactivate(bool)>, starting with
621 the lowest.
623 void SfxDispatcher::DoDeactivate_Impl(bool bMDI, SfxViewFrame const * pNew)
625 SFX_STACK(SfxDispatcher::DoDeactivate);
627 SfxApplication *pSfxApp = SfxGetpApp();
629 if ( bMDI )
631 SAL_INFO("sfx.control", "Deactivate Dispatcher " << this);
632 DBG_ASSERT( xImp->bActive, "Deactivate error" );
633 xImp->bActive = false;
635 if ( xImp->pFrame && !(xImp->pFrame->GetObjectShell()->IsInPlaceActive() ) )
637 SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
638 if ( pWorkWin )
640 for (size_t n=0; n<xImp->aChildWins.size();)
642 SfxChildWindow *pWin = pWorkWin->GetChildWindow_Impl( static_cast<sal_uInt16>( xImp->aChildWins[n] & 0xFFFF ) );
643 if (!pWin || pWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT)
644 xImp->aChildWins.erase(xImp->aChildWins.begin()+n);
645 else
646 n++;
651 else {
652 SAL_INFO("sfx.control", "Non-MDI-DeActivate Dispatcher " << this);
655 if ( IsAppDispatcher() && !pSfxApp->IsDowning() )
656 return;
658 for ( size_t i = 0; i < xImp->aStack.size(); ++i )
659 (*(xImp->aStack.rbegin() + i))->DoDeactivate_Impl(xImp->pFrame, bMDI);
661 bool bHidePopups = bMDI && xImp->pFrame;
662 if ( pNew && xImp->pFrame )
664 css::uno::Reference< css::frame::XFrame > xOldFrame =
665 pNew->GetFrame().GetFrameInterface()->getCreator();
667 css::uno::Reference< css::frame::XFrame > xMyFrame =
668 GetFrame()->GetFrame().GetFrameInterface();
670 if ( xOldFrame == xMyFrame )
671 bHidePopups = false;
674 if ( bHidePopups )
676 xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( true, 1 );
679 Flush();
682 /** This method searches in SfxDispatcher after <SfxShell> , from the Slot Id
683 nSlot currently being handled. For this, the dispatcher is first flushed.
685 @param nSlot the searchable Slot-Id
686 @param ppShell the SfxShell, which are currently handled the nSlot
687 @param ppSlot the SfxSlot, which are currently handled the nSlot
689 @return int sal_True
690 The SfxShell was found, ppShell and ppSlot are valid.
692 sal_False
693 The SfxShell was not found, ppShell and ppSlot are invalid.
695 bool SfxDispatcher::GetShellAndSlot_Impl(sal_uInt16 nSlot, SfxShell** ppShell,
696 const SfxSlot** ppSlot, bool bOwnShellsOnly, bool bRealSlot)
698 SFX_STACK(SfxDispatcher::GetShellAndSlot_Impl);
700 Flush();
701 SfxSlotServer aSvr;
702 if ( FindServer_(nSlot, aSvr) )
704 if ( bOwnShellsOnly && aSvr.GetShellLevel() >= xImp->aStack.size() )
705 return false;
707 *ppShell = GetShell(aSvr.GetShellLevel());
708 *ppSlot = aSvr.GetSlot();
709 if ( nullptr == (*ppSlot)->GetExecFnc() && bRealSlot )
710 *ppSlot = (*ppShell)->GetInterface()->GetRealSlot(*ppSlot);
711 // Check only real slots as enum slots don't have an execute function!
712 return !bRealSlot || ((nullptr != *ppSlot) && (nullptr != (*ppSlot)->GetExecFnc()) );
715 return false;
718 /** This method performs a request for a cached <Slot-Server>.
720 @param rShell to the calling <SfxShell>
721 @param rSlot to the calling <SfxSlot>
722 @param rReq function to be performed (Id and optional parameters)
723 @param eCallMode Synchronously, asynchronously or as shown in the slot
725 void SfxDispatcher::Execute_(SfxShell& rShell, const SfxSlot& rSlot,
726 SfxRequest& rReq, SfxCallMode eCallMode)
728 SFX_STACK(SfxDispatcher::Execute_);
729 DBG_ASSERT( !xImp->bFlushing, "recursive call to dispatcher" );
730 DBG_ASSERT( xImp->aToDoStack.empty(), "unprepared InPlace _Execute" );
732 if ( IsLocked() )
733 return;
735 if ( bool(eCallMode & SfxCallMode::ASYNCHRON) ||
736 ( (eCallMode & SfxCallMode::SYNCHRON) == SfxCallMode::SLOT &&
737 rSlot.IsMode(SfxSlotMode::ASYNCHRON) ) )
739 sal_uInt16 nShellCount = xImp->aStack.size();
740 for ( sal_uInt16 n=0; n<nShellCount; n++ )
742 if ( &rShell == *(xImp->aStack.rbegin() + n) )
744 if ( bool(eCallMode & SfxCallMode::RECORD) )
745 rReq.AllowRecording( true );
746 xImp->xPoster->Post(std::make_unique<SfxRequest>(rReq));
747 return;
751 else
752 Call_Impl( rShell, rSlot, rReq, SfxCallMode::RECORD==(eCallMode&SfxCallMode::RECORD) );
755 /** Helper function to put from rItem below the Which-ID in the pool of the
756 Item Sets rSet.
758 static void MappedPut_Impl(SfxAllItemSet &rSet, const SfxPoolItem &rItem)
760 // Put with mapped Which-Id if possible
761 const SfxItemPool *pPool = rSet.GetPool();
762 sal_uInt16 nWhich = rItem.Which();
763 if ( SfxItemPool::IsSlot(nWhich) )
764 nWhich = pPool->GetWhich(nWhich);
765 rSet.Put( rItem, nWhich );
768 const SfxSlot* SfxDispatcher::GetSlot( const OUString& rCommand )
770 // Count the number of Shells on the linked Dispatcher
771 Flush();
772 sal_uInt16 nTotCount = xImp->aStack.size();
774 for ( sal_uInt16 i = 0; i < nTotCount; ++i )
776 SfxShell *pObjShell = GetShell(i);
777 SfxInterface *pIFace = pObjShell->GetInterface();
778 const SfxSlot *pSlot = pIFace->GetSlot( rCommand );
779 if ( pSlot )
780 return pSlot;
783 return nullptr;
786 const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode nCall,
787 SfxItemSet const * pArgs, SfxItemSet const * pInternalArgs, sal_uInt16 nModi)
789 if ( IsLocked() )
790 return nullptr;
792 SfxShell *pShell = nullptr;
793 const SfxSlot *pSlot = nullptr;
794 if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
796 SfxAllItemSet aSet( pShell->GetPool() );
797 if ( pArgs )
799 SfxItemIter aIter(*pArgs);
800 for ( const SfxPoolItem *pArg = aIter.GetCurItem();
801 pArg;
802 pArg = aIter.NextItem() )
803 MappedPut_Impl( aSet, *pArg );
805 SfxRequest aReq(nSlot, nCall, aSet);
806 if (pInternalArgs)
807 aReq.SetInternalArgs_Impl( *pInternalArgs );
808 aReq.SetModifier( nModi );
810 Execute_( *pShell, *pSlot, aReq, nCall );
811 return aReq.GetReturnValue();
813 return nullptr;
816 /** Method to execute a <SfxSlot>s over the Slot-Id.
818 @param nSlot the Id of the executing function
819 @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
820 @param pArgs Zero terminated C-Array of Parameters
821 @param pInternalArgs Zero terminated C-Array of Parameters
823 @return const SfxPoolItem* Pointer to the SfxPoolItem valid to the next run
824 though the Message-Loop, which contains the return
825 value.
827 Or a NULL-Pointer, when the function was not
828 executed (for example canceled by the user).
830 const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
831 const SfxPoolItem **pArgs, sal_uInt16 nModi, const SfxPoolItem **pInternalArgs)
833 if ( IsLocked() )
834 return nullptr;
836 SfxShell *pShell = nullptr;
837 const SfxSlot *pSlot = nullptr;
838 if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
840 std::unique_ptr<SfxRequest> pReq;
841 if ( pArgs && *pArgs )
843 SfxAllItemSet aSet( pShell->GetPool() );
844 for ( const SfxPoolItem **pArg = pArgs; *pArg; ++pArg )
845 MappedPut_Impl( aSet, **pArg );
846 pReq.reset(new SfxRequest( nSlot, eCall, aSet ));
848 else
849 pReq.reset(new SfxRequest( nSlot, eCall, pShell->GetPool() ));
850 pReq->SetModifier( nModi );
851 if( pInternalArgs && *pInternalArgs)
853 SfxAllItemSet aSet( SfxGetpApp()->GetPool() );
854 for ( const SfxPoolItem **pArg = pInternalArgs; *pArg; ++pArg )
855 aSet.Put( **pArg );
856 pReq->SetInternalArgs_Impl( aSet );
858 Execute_( *pShell, *pSlot, *pReq, eCall );
859 const SfxPoolItem* pRet = pReq->GetReturnValue();
860 return pRet;
862 return nullptr;
865 /** Method to execute a <SfxSlot>s over the Slot-Id.
867 @param nSlot the Id of the executing function
868 @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
869 @param rArgs <SfxItemSet> with the parameters
871 @return const SfxPoolItem* Pointer to the SfxPoolItem valid to the next run
872 though the Message-Loop, which contains the return
873 value.
875 Or a NULL-Pointer, when the function was not
876 executed (for example canceled by the user).
878 const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
879 const SfxItemSet &rArgs)
881 if ( IsLocked() )
882 return nullptr;
884 SfxShell *pShell = nullptr;
885 const SfxSlot *pSlot = nullptr;
886 if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
888 SfxAllItemSet aSet( pShell->GetPool() );
889 SfxItemIter aIter(rArgs);
890 for ( const SfxPoolItem *pArg = aIter.GetCurItem();
891 pArg;
892 pArg = aIter.NextItem() )
893 MappedPut_Impl( aSet, *pArg );
894 SfxRequest aReq( nSlot, eCall, aSet );
895 aReq.SetModifier( 0 );
896 Execute_( *pShell, *pSlot, aReq, eCall );
897 return aReq.GetReturnValue();
899 return nullptr;
902 /** Method to execute a <SfxSlot>s over the Slot-Id.
904 [Note]
906 The parameters are copied, can therefore be passed on as the address
907 of stack objects.
909 @param nSlot the Id of the executing function
910 @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
911 @param args list of SfxPoolItem arguments
913 @return Pointer to the SfxPoolItem valid to the next run
914 though the Message-Loop, which contains the return
915 value.
917 Or a NULL-Pointer, when the function was not
918 executed (for example canceled by the user).
920 [Example]
922 pDispatcher->Execute( SID_OPENDOCUMENT, SfxCallMode::SYNCHRON,
923 { &SfxStringItem( SID_FILE_NAME, "\\tmp\\temp.sdd" ),
924 &SfxStringItem( SID_FILTER_NAME, "StarDraw Presentation" ),
925 &SfxBoolItem( SID_DOC_READONLY, sal_False ),
928 const SfxPoolItem* SfxDispatcher::ExecuteList(sal_uInt16 nSlot, SfxCallMode eCall,
929 std::initializer_list<SfxPoolItem const*> args,
930 std::initializer_list<SfxPoolItem const*> internalargs)
932 if ( IsLocked() )
933 return nullptr;
935 SfxShell *pShell = nullptr;
936 const SfxSlot *pSlot = nullptr;
937 if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
939 SfxAllItemSet aSet( pShell->GetPool() );
941 for (const SfxPoolItem *pArg : args)
943 assert(pArg);
944 MappedPut_Impl( aSet, *pArg );
947 SfxRequest aReq(nSlot, eCall, aSet);
949 if (internalargs.begin() != internalargs.end())
951 SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool());
952 for (const SfxPoolItem *pArg : internalargs)
954 assert(pArg);
955 aInternalSet.Put(*pArg);
957 aReq.SetInternalArgs_Impl(aInternalSet);
960 Execute_( *pShell, *pSlot, aReq, eCall );
961 return aReq.GetReturnValue();
963 return nullptr;
966 /** Helper method to receive the asynchronously executed <SfxRequest>s.
968 void SfxDispatcher::PostMsgHandler(std::unique_ptr<SfxRequest> pReq)
970 DBG_ASSERT( !xImp->bFlushing, "recursive call to dispatcher" );
971 SFX_STACK(SfxDispatcher::PostMsgHandler);
973 // Has also the Pool not yet died?
974 if ( pReq->IsCancelled() )
975 return;
977 if ( !IsLocked() )
979 Flush();
980 SfxSlotServer aSvr;
981 if ( FindServer_(pReq->GetSlot(), aSvr ) ) // HACK(x), whatever that was supposed to mean
983 const SfxSlot *pSlot = aSvr.GetSlot();
984 SfxShell *pSh = GetShell(aSvr.GetShellLevel());
986 // When the pSlot is a "Pseudoslot" for macros or Verbs, it can
987 // be destroyed in the Call_Impl, thus do not use it anymore!
988 pReq->SetSynchronCall( false );
989 Call_Impl( *pSh, *pSlot, *pReq, pReq->AllowsRecording() ); //! why bRecord?
992 else
994 if ( xImp->bLocked )
995 xImp->aReqArr.emplace_back(std::move(pReq));
996 else
997 xImp->xPoster->Post(std::move(pReq));
1001 void SfxDispatcher::SetMenu_Impl()
1003 #if HAVE_FEATURE_DESKTOP
1004 if ( !xImp->pFrame )
1005 return;
1007 SfxViewFrame* pTop = xImp->pFrame->GetTopViewFrame();
1008 if ( !pTop || pTop->GetBindings().GetDispatcher() != this )
1009 return;
1011 SfxFrame& rFrame = pTop->GetFrame();
1012 if ( !rFrame.IsMenuBarOn_Impl() )
1013 return;
1015 css::uno::Reference < css::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), css::uno::UNO_QUERY );
1016 if ( xPropSet.is() )
1018 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1019 css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
1020 aValue >>= xLayoutManager;
1021 if ( xLayoutManager.is() )
1023 OUString aMenuBarURL( "private:resource/menubar/menubar" );
1024 if ( !xLayoutManager->isElementVisible( aMenuBarURL ) )
1025 xLayoutManager->createElement( aMenuBarURL );
1028 #endif
1031 void SfxDispatcher::Update_Impl( bool bForce )
1033 SFX_STACK(SfxDispatcher::Update_Impl);
1035 Flush();
1037 if ( !xImp->pFrame )
1038 return;
1040 bool bUpdate = bForce;
1041 if ( xImp->pFrame )
1043 SfxWorkWindow *pWork = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1044 SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1045 if (pAct == this)
1047 if ( !bUpdate )
1048 bUpdate = !xImp->bUpdated;
1049 xImp->bUpdated = true;
1053 if ( !bUpdate || xImp->pFrame->GetFrame().IsClosing_Impl() )
1054 return;
1056 SfxViewFrame* pTop = xImp->pFrame ? xImp->pFrame->GetTopViewFrame() : nullptr;
1057 bool bUIActive = pTop && pTop->GetBindings().GetDispatcher() == this;
1059 if ( !bUIActive && pTop && GetBindings() == &pTop->GetBindings() )
1060 // keep own tools internally for collecting
1061 GetBindings()->GetDispatcher()->xImp->bUpdated = false;
1063 css::uno::Reference< css::frame::XFrame > xFrame;
1064 SfxBindings* pBindings = GetBindings();
1065 if (pBindings)
1067 pBindings->DENTERREGISTRATIONS();
1068 xFrame = pBindings->GetActiveFrame();
1070 css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY );
1071 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1072 if ( xPropSet.is() )
1076 css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
1077 aValue >>= xLayoutManager;
1079 catch (const css::uno::Exception&)
1084 if ( xLayoutManager.is() )
1085 xLayoutManager->lock();
1087 bool bIsIPActive = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1088 SfxInPlaceClient *pClient = xImp->pFrame ? xImp->pFrame->GetViewShell()->GetUIActiveClient() : nullptr;
1089 if ( bUIActive && /* !bIsIPActive && */ ( !pClient || !pClient->IsObjectUIActive() ) )
1090 SetMenu_Impl();
1092 SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1093 pWorkWin->ResetStatusBar_Impl();
1096 SfxWorkWindow *pWork = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1097 SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1098 if (pAct == this)
1100 pWork->ResetObjectBars_Impl();
1101 pWork->ResetChildWindows_Impl();
1105 bool bIsActive = false;
1106 SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1107 if ( !bIsActive && this == pActDispat )
1108 bIsActive = true;
1110 Update_Impl_( bUIActive, !bIsIPActive, bIsIPActive, pWorkWin );
1111 if (bUIActive || bIsActive)
1112 pWorkWin->UpdateObjectBars_Impl();
1114 if ( pBindings )
1115 pBindings->DLEAVEREGISTRATIONS();
1117 if ( xLayoutManager.is() )
1118 xLayoutManager->unlock();
1120 if ( SfxViewShell::Current() && SfxViewShell::Current()->GetDispatcher() )
1122 const SfxPoolItem *pItem;
1123 SfxViewShell::Current()->GetDispatcher()->QueryState(SID_NOTEBOOKBAR, pItem);
1127 void SfxDispatcher::Update_Impl_( bool bUIActive, bool bIsMDIApp, bool bIsIPOwner, SfxWorkWindow *pTaskWin )
1129 SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1130 bool bIsActive = false;
1131 SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1132 if ( pActDispat && !bIsActive )
1134 if ( this == pActDispat )
1135 bIsActive = true;
1138 for (SfxObjectBars_Impl & rObjBar : xImp->aObjBars)
1139 rObjBar.eId = ToolbarId::None;
1140 xImp->aChildWins.clear();
1142 // bQuiet: own shells aren't considered for UI and SlotServer
1143 // bNoUI: own Shells aren't considered forms UI
1144 if ( xImp->bQuiet || xImp->bNoUI || (xImp->pFrame && xImp->pFrame->GetObjectShell()->IsPreview()) )
1145 return;
1147 StatusBarId eStatBarId = StatusBarId::None;
1149 SfxSlotPool* pSlotPool = &SfxSlotPool::GetSlotPool( GetFrame() );
1150 sal_uInt16 nTotCount = xImp->aStack.size();
1151 for ( sal_uInt16 nShell = nTotCount; nShell > 0; --nShell )
1153 SfxShell *pShell = GetShell( nShell-1 );
1154 SfxInterface *pIFace = pShell->GetInterface();
1156 // don't consider shells if "Hidden" or "Quiet"
1157 bool bReadOnlyShell = IsReadOnlyShell_Impl( nShell-1 );
1158 sal_uInt16 nNo;
1159 for ( nNo = 0; pIFace && nNo<pIFace->GetObjectBarCount(); ++nNo )
1161 sal_uInt16 nPos = pIFace->GetObjectBarPos(nNo);
1162 SfxVisibilityFlags nFlags = pIFace->GetObjectBarFlags(nNo);
1163 if ( bReadOnlyShell && !( nFlags & SfxVisibilityFlags::ReadonlyDoc ) )
1164 continue;
1166 // check whether toolbar needs activation of a special feature
1167 SfxShellFeature nFeature = pIFace->GetObjectBarFeature(nNo);
1168 if ((nFeature != SfxShellFeature::NONE) && !pShell->HasUIFeature(nFeature))
1169 continue;
1171 // check for toolboxes that are exclusively for a viewer
1172 if ( xImp->pFrame)
1174 bool bViewerTbx( nFlags & SfxVisibilityFlags::Viewer );
1175 SfxObjectShell* pSh = xImp->pFrame->GetObjectShell();
1176 const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(pSh->GetMedium()->GetItemSet(), SID_VIEWONLY, false);
1177 bool bIsViewer = pItem && pItem->GetValue();
1178 if ( bIsViewer != bViewerTbx )
1179 continue;
1182 // always register toolbars, allows to switch them on
1183 bool bVisible = pIFace->IsObjectBarVisible(nNo);
1184 if ( !bVisible )
1185 nFlags = SfxVisibilityFlags::Invisible;
1187 SfxObjectBars_Impl& rBar = xImp->aObjBars[nPos];
1188 rBar.nPos = nPos;
1189 rBar.nFlags = nFlags;
1190 rBar.eId = pIFace->GetObjectBarId(nNo);
1192 if ( bUIActive || bIsActive )
1194 pWorkWin->SetObjectBar_Impl(nPos, nFlags, rBar.eId);
1197 if ( !bVisible )
1198 rBar.eId = ToolbarId::None;
1201 for ( nNo=0; pIFace && nNo<pIFace->GetChildWindowCount(); nNo++ )
1203 sal_uInt32 nId = pIFace->GetChildWindowId(nNo);
1204 const SfxSlot *pSlot = pSlotPool->GetSlot( static_cast<sal_uInt16>(nId) );
1205 SAL_WARN_IF( !pSlot, "sfx.control", "Childwindow slot missing: " << nId );
1206 if ( bReadOnlyShell )
1208 // only show ChildWindows if their slot is allowed for readonly documents
1209 if ( pSlot && !pSlot->IsMode( SfxSlotMode::READONLYDOC ) )
1210 continue;
1213 SfxShellFeature nFeature = pIFace->GetChildWindowFeature(nNo);
1214 if ((nFeature != SfxShellFeature::NONE) && !pShell->HasUIFeature(nFeature))
1215 continue;
1217 // slot decides whether a ChildWindow is shown when document is OLE server or OLE client
1218 SfxVisibilityFlags nMode = SfxVisibilityFlags::Standard;
1219 if( pSlot )
1221 if ( pSlot->IsMode(SfxSlotMode::CONTAINER) )
1223 if ( pWorkWin->IsVisible_Impl( SfxVisibilityFlags::Client ) )
1224 nMode |= SfxVisibilityFlags::Client;
1226 else
1228 if ( pWorkWin->IsVisible_Impl( SfxVisibilityFlags::Server ) )
1229 nMode |= SfxVisibilityFlags::Server;
1233 if ( bUIActive || bIsActive )
1234 pWorkWin->SetChildWindowVisible_Impl( nId, true, nMode );
1235 if ( bUIActive || bIsActive || !pWorkWin->IsFloating( static_cast<sal_uInt16>( nId & 0xFFFF ) ) )
1236 xImp->aChildWins.push_back( nId );
1239 if ( bIsMDIApp || bIsIPOwner )
1241 StatusBarId eId = pIFace ? pIFace->GetStatusBarId() : StatusBarId::None;
1242 if (eId != StatusBarId::None)
1243 eStatBarId = eId;
1247 for ( sal_uInt16 nPos=0; nPos<SFX_OBJECTBAR_MAX; nPos++ )
1249 SfxObjectBars_Impl& rFixed = xImp->aFixedObjBars[nPos];
1250 if (rFixed.eId != ToolbarId::None)
1252 SfxObjectBars_Impl& rBar = xImp->aObjBars[nPos];
1253 rBar = rFixed;
1254 pWorkWin->SetObjectBar_Impl(rFixed.nPos, rFixed.nFlags,
1255 rFixed.eId);
1259 if ( !pTaskWin || ( !bIsMDIApp && !bIsIPOwner ) )
1260 return;
1262 bool bIsTaskActive = false;
1264 SfxDispatcher *pActDispatcher = pTaskWin->GetBindings().GetDispatcher_Impl();
1265 if ( pActDispatcher && !bIsTaskActive )
1267 if ( this == pActDispatcher )
1268 bIsTaskActive = true;
1271 if (bIsTaskActive && eStatBarId != StatusBarId::None && xImp->pFrame)
1273 // internal frames also may control statusbar
1274 xImp->pFrame->GetFrame().GetWorkWindow_Impl()->SetStatusBar_Impl(eStatBarId);
1278 /** Helper method to execute the outstanding push and pop commands.
1280 void SfxDispatcher::FlushImpl()
1282 SFX_STACK(SfxDispatcher::FlushImpl);
1284 SAL_INFO("sfx.control", "Flushing dispatcher!");
1286 xImp->aIdle.Stop();
1288 xImp->bFlushing = !xImp->bFlushing;
1289 if ( !xImp->bFlushing )
1291 xImp->bFlushing = true;
1292 return;
1295 SfxApplication *pSfxApp = SfxGetpApp();
1297 // Re-build the true stack in the first round
1298 std::deque<SfxToDo_Impl> aToDoCopy;
1299 bool bModify = false;
1300 for(std::deque<SfxToDo_Impl>::reverse_iterator i = xImp->aToDoStack.rbegin(); i != xImp->aToDoStack.rend(); ++i)
1302 bModify = true;
1304 if(i->bPush)
1306 // Actually push
1307 DBG_ASSERT( std::find(xImp->aStack.begin(), xImp->aStack.end(), i->pCluster) == xImp->aStack.end(),
1308 "pushed SfxShell already on stack" );
1309 xImp->aStack.push_back(i->pCluster);
1310 i->pCluster->SetDisableFlags(xImp->nDisableFlags);
1312 // Mark the moved shell
1313 aToDoCopy.push_front(*i);
1315 else
1317 // Actually pop
1318 SfxShell* pPopped = nullptr;
1319 bool bFound = false;
1322 DBG_ASSERT( !xImp->aStack.empty(), "popping from empty stack" );
1323 pPopped = xImp->aStack.back();
1324 xImp->aStack.pop_back();
1325 pPopped->SetDisableFlags( SfxDisableFlags::NONE );
1326 bFound = (pPopped == i->pCluster);
1328 // Mark the moved Shell
1329 aToDoCopy.push_front(SfxToDo_Impl(false, i->bDelete, false, *pPopped));
1331 while(i->bUntil && !bFound);
1332 DBG_ASSERT( bFound, "wrong SfxShell popped" );
1335 xImp->aToDoStack.clear();
1337 // Invalidate bindings, if possible
1338 if ( !pSfxApp->IsDowning() )
1340 InvalidateBindings_Impl( bModify );
1343 xImp->bFlushing = false;
1344 xImp->bUpdated = false; // not only when bModify, if Doc/Template-Config
1345 xImp->bFlushed = true;
1346 SAL_INFO("sfx.control", "Successfully flushed dispatcher!");
1348 //fdo#70703 FlushImpl may call back into itself so use aToDoCopyStack to talk
1349 //to outer levels of ourself. If DoActivate_Impl/DoDeactivate_Impl deletes
1350 //an entry, then they will walk back up aToDoCopyStack and set outer
1351 //levels's entries to bDeleted
1352 xImp->aToDoCopyStack.push_back(aToDoCopy);
1353 std::deque<SfxToDo_Impl>& rToDoCopy = xImp->aToDoCopyStack.back();
1354 // Activate the Shells and possible delete them in the 2nd round
1355 for(std::deque<SfxToDo_Impl>::reverse_iterator i = rToDoCopy.rbegin(); i != rToDoCopy.rend(); ++i)
1357 if (i->bDeleted)
1358 continue;
1359 if (!xImp->bActive)
1360 continue;
1361 if (i->bPush)
1362 i->pCluster->DoActivate_Impl(xImp->pFrame, true);
1363 else
1364 i->pCluster->DoDeactivate_Impl(xImp->pFrame, true);
1367 aToDoCopy = xImp->aToDoCopyStack.back();
1368 xImp->aToDoCopyStack.pop_back();
1370 for(std::deque<SfxToDo_Impl>::reverse_iterator i = aToDoCopy.rbegin(); i != aToDoCopy.rend(); ++i)
1372 if (i->bDelete && !i->bDeleted)
1374 if (!xImp->aToDoCopyStack.empty())
1376 //fdo#70703 if there is an outer FlushImpl then inform it that
1377 //we have deleted this cluster
1378 for (auto & elem : xImp->aToDoCopyStack)
1380 for (auto & subelem : elem)
1382 if (subelem.pCluster == i->pCluster)
1383 subelem.bDeleted = true;
1387 delete i->pCluster;
1390 bool bAwakeBindings = !aToDoCopy.empty();
1391 if( bAwakeBindings )
1392 aToDoCopy.clear();
1394 // If more changes have occurred on the stack when
1395 // Activate/Deactivate/Delete:
1396 if (!xImp->bFlushed)
1397 // If Push/Pop has been called by someone, then also EnterReg was called!
1398 FlushImpl();
1400 if( bAwakeBindings && GetBindings() )
1401 GetBindings()->DLEAVEREGISTRATIONS();
1403 for (SfxObjectBars_Impl & rFixedObjBar : xImp->aFixedObjBars)
1404 rFixedObjBar.eId = ToolbarId::None;
1406 SAL_INFO("sfx.control", "SfxDispatcher(" << this << ")::Flush() done");
1409 /** With this method a filter set, the target slots can be enabled or disabled.
1410 The passed array must be retained until the destructor or the next
1411 <SetSlotFilter()>, it is not deleted from the dispatcher, so it can thus be
1412 static.
1414 In read-only documents the quasi ReadOnlyDoc Flag of slots can be
1415 overturned by the use of 'bEnable == 2', so this will be displayed again.
1416 On the other slots it has no effect.
1418 // HACK(here should be used an enum) ???
1419 @param nEnable 1==true: only enable specified slots, disable all other
1420 0==false: disable specified slots, first enable all other
1421 @param nCount Number of SIDs in the following Array
1422 @param pSIDs sorted Array of 'nCount' SIDs
1424 [Example]
1426 Targeted disabling of Slots 1, 2 and 3:
1428 static sal_uInt16 const pSIDs[] = { 1, 2, 3 };
1429 pDisp->SetSlotFilter( sal_False, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );
1431 only permit Slots 5, 6 and 7:
1433 static sal_uInt16 const pSIDs[] = { 5, 6, 7 };
1434 pDisp->SetSlotFilter( sal_True, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );
1436 Turn-off Filter:
1438 pDisp->SetSlotFilter();
1440 void SfxDispatcher::SetSlotFilter(SfxSlotFilterState nEnable,
1441 o3tl::span<sal_uInt16 const> pSIDs)
1443 #ifdef DBG_UTIL
1444 // Check Array
1445 for ( std::size_t n = 1; n < pSIDs.size(); ++n )
1446 DBG_ASSERT( pSIDs[n] > pSIDs[n-1], "SetSlotFilter: SIDs not sorted" );
1447 #endif
1449 xImp->nFilterEnabling = nEnable;
1450 xImp->pFilterSIDs = pSIDs;
1452 GetBindings()->InvalidateAll(true);
1455 extern "C" {
1457 static int SfxCompareSIDs_Impl(const void* pSmaller, const void* pBigger)
1459 return static_cast<tools::Long>(*static_cast<sal_uInt16 const *>(pSmaller)) - static_cast<tools::Long>(*static_cast<sal_uInt16 const *>(pBigger));
1464 /** Searches for 'nSID' in the Filter set by <SetSlotFilter()> and
1465 returns sal_True, if the SIDis allowed, or sal_False, if it is
1466 disabled by the Filter.
1468 @return 0 => disabled
1469 1 => enabled
1470 2 => enabled even if ReadOnlyDoc
1472 SfxSlotFilterState SfxDispatcher::IsSlotEnabledByFilter_Impl( sal_uInt16 nSID ) const
1474 // no filter?
1475 if ( xImp->pFilterSIDs.empty() )
1476 // => all SIDs allowed
1477 return SfxSlotFilterState::ENABLED;
1479 // search
1480 bool bFound = nullptr != bsearch( &nSID, xImp->pFilterSIDs.data(), xImp->pFilterSIDs.size(),
1481 sizeof(sal_uInt16), SfxCompareSIDs_Impl );
1483 // even if ReadOnlyDoc
1484 if ( SfxSlotFilterState::ENABLED_READONLY == xImp->nFilterEnabling )
1485 return bFound ? SfxSlotFilterState::ENABLED_READONLY : SfxSlotFilterState::ENABLED;
1486 // Otherwise after Negative/Positive Filter
1487 else if ( SfxSlotFilterState::ENABLED == xImp->nFilterEnabling )
1488 return bFound ? SfxSlotFilterState::ENABLED : SfxSlotFilterState::DISABLED;
1489 else
1490 return bFound ? SfxSlotFilterState::DISABLED : SfxSlotFilterState::ENABLED;
1493 /** This helper method searches for the <Slot-Server> which currently serves
1494 the nSlot. As the result, rServe is filled accordingly.
1496 If known the SfxInterface which is currently served by nSlot can be
1497 passed along.
1499 The SfxDispatcher is flushed while searching for nSlot.
1501 @param nSlot Slot-Id to search for
1502 @param rServer <SfxSlotServer>-Instance to fill
1504 @return true
1505 The Slot was found, rServer is valid.
1507 false
1508 The Slot is currently not served, rServer is invalid.
1510 bool SfxDispatcher::FindServer_(sal_uInt16 nSlot, SfxSlotServer& rServer)
1512 SFX_STACK(SfxDispatcher::FindServer_);
1514 // Dispatcher locked? (nevertheless let SID_HELP_PI through)
1515 if ( IsLocked() )
1517 xImp->bInvalidateOnUnlock = true;
1518 return false;
1521 // Count the number of Shells in the linked dispatchers.
1522 Flush();
1523 sal_uInt16 nTotCount = xImp->aStack.size();
1525 // Verb-Slot?
1526 if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END)
1528 for ( sal_uInt16 nShell = 0;; ++nShell )
1530 SfxShell *pSh = GetShell(nShell);
1531 if ( pSh == nullptr )
1532 return false;
1533 if ( dynamic_cast< const SfxViewShell *>( pSh ) != nullptr )
1535 const SfxSlot* pSlot = pSh->GetVerbSlot_Impl(nSlot);
1536 if ( pSlot )
1538 rServer.SetShellLevel(nShell);
1539 rServer.SetSlot( pSlot );
1540 return true;
1546 // SID check against set filter
1547 SfxSlotFilterState nSlotEnableMode = SfxSlotFilterState::DISABLED;
1548 if ( xImp->pFrame )
1550 nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot );
1551 if ( SfxSlotFilterState::DISABLED == nSlotEnableMode )
1552 return false;
1555 // In Quiet-Mode only Parent-Dispatcher
1556 if ( xImp->bQuiet )
1558 return false;
1561 bool bReadOnly = ( SfxSlotFilterState::ENABLED_READONLY != nSlotEnableMode && xImp->bReadOnly );
1563 // search through all the shells of the chained dispatchers
1564 // from top to bottom
1565 sal_uInt16 nFirstShell = 0;
1566 for ( sal_uInt16 i = nFirstShell; i < nTotCount; ++i )
1568 SfxShell *pObjShell = GetShell(i);
1569 SfxInterface *pIFace = pObjShell->GetInterface();
1570 const SfxSlot *pSlot = pIFace->GetSlot(nSlot);
1572 if ( pSlot && pSlot->nDisableFlags != SfxDisableFlags::NONE &&
1573 ( static_cast<int>(pSlot->nDisableFlags) & static_cast<int>(pObjShell->GetDisableFlags()) ) != 0 )
1574 return false;
1576 if ( pSlot && !( pSlot->nFlags & SfxSlotMode::READONLYDOC ) && bReadOnly )
1577 return false;
1579 if ( pSlot )
1581 // Slot belongs to Container?
1582 bool bIsContainerSlot = pSlot->IsMode(SfxSlotMode::CONTAINER);
1583 bool bIsInPlace = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1585 // Shell belongs to Server?
1586 // AppDispatcher or IPFrame-Dispatcher
1587 bool bIsServerShell = !xImp->pFrame || bIsInPlace;
1589 // Of course ShellServer-Slots are also executable even when it is
1590 // executed on a container dispatcher without an IPClient.
1591 if ( !bIsServerShell )
1593 SfxViewShell *pViewSh = xImp->pFrame->GetViewShell();
1594 bIsServerShell = !pViewSh || !pViewSh->GetUIActiveClient();
1597 // Shell belongs to Container?
1598 // AppDispatcher or no IPFrameDispatcher
1599 bool bIsContainerShell = !xImp->pFrame || !bIsInPlace;
1600 // Shell and Slot match
1601 if ( !( ( bIsContainerSlot && bIsContainerShell ) ||
1602 ( !bIsContainerSlot && bIsServerShell ) ) )
1603 pSlot = nullptr;
1606 if ( pSlot )
1608 rServer.SetSlot(pSlot);
1609 rServer.SetShellLevel(i);
1610 return true;
1614 return false;
1617 /** Helper method to obtain the status of the <Slot-Server>s rSvr.
1618 The required slots IDs (partly converted to Which-IDs of the pool)
1619 must be present in rstate.
1621 The SfxDispatcher is flushed before the query.
1623 @param rSvr Slot-Server to query
1624 @param rState SfxItemSet to be filled
1625 @param pRealSlot The actual Slot if possible
1627 bool SfxDispatcher::FillState_(const SfxSlotServer& rSvr, SfxItemSet& rState,
1628 const SfxSlot* pRealSlot)
1630 SFX_STACK(SfxDispatcher::FillState_);
1632 const SfxSlot *pSlot = rSvr.GetSlot();
1633 if ( pSlot && IsLocked() )
1635 xImp->bInvalidateOnUnlock = true;
1636 return false;
1639 if ( pSlot )
1641 DBG_ASSERT(xImp->bFlushed,
1642 "Dispatcher not flushed after retrieving slot servers!");
1643 if (!xImp->bFlushed)
1644 return false;
1646 // Determine the object and call the Message of this object
1647 SfxShell *pSh = GetShell(rSvr.GetShellLevel());
1648 DBG_ASSERT(pSh, "ObjectShell not found");
1650 SfxStateFunc pFunc;
1652 if (pRealSlot)
1653 pFunc = pRealSlot->GetStateFnc();
1654 else
1655 pFunc = pSlot->GetStateFnc();
1657 pSh->CallState( pFunc, rState );
1658 #ifdef DBG_UTIL
1659 // To examine the conformity of IDL (SlotMap) and current Items
1660 if ( rState.Count() )
1662 SfxInterface *pIF = pSh->GetInterface();
1663 SfxItemIter aIter( rState );
1664 for ( const SfxPoolItem *pItem = aIter.GetCurItem();
1665 pItem;
1666 pItem = aIter.NextItem() )
1668 if ( !IsInvalidItem(pItem) && !pItem->IsVoidItem() )
1670 sal_uInt16 nSlotId = rState.GetPool()->GetSlotId(pItem->Which());
1671 SAL_INFO_IF(
1672 typeid(pItem) != *pIF->GetSlot(nSlotId)->GetType()->Type(),
1673 "sfx.control",
1674 "item-type unequal to IDL (=> no BASIC) with SID: "
1675 << nSlotId << " in " << pIF->GetClassName());
1679 #endif
1681 return true;
1684 return false;
1687 void SfxDispatcher::ExecutePopup( vcl::Window *pWin, const Point *pPos )
1689 SfxDispatcher &rDisp = *SfxGetpApp()->GetDispatcher_Impl();
1690 sal_uInt16 nShLevel = 0;
1691 SfxShell *pSh;
1693 if ( rDisp.xImp->bQuiet )
1694 nShLevel = rDisp.xImp->aStack.size();
1696 for ( pSh = rDisp.GetShell(nShLevel); pSh; ++nShLevel, pSh = rDisp.GetShell(nShLevel) )
1698 const OUString& rResName = pSh->GetInterface()->GetPopupMenuName();
1699 if ( !rResName.isEmpty() )
1701 rDisp.ExecutePopup( rResName, pWin, pPos );
1702 return;
1707 void SfxDispatcher::ExecutePopup( const OUString& rResName, vcl::Window* pWin, const Point* pPos )
1709 css::uno::Sequence< css::uno::Any > aArgs( 3 );
1710 aArgs[0] <<= comphelper::makePropertyValue( "Value", rResName );
1711 aArgs[1] <<= comphelper::makePropertyValue( "Frame", GetFrame()->GetFrame().GetFrameInterface() );
1712 aArgs[2] <<= comphelper::makePropertyValue( "IsContextMenu", true );
1714 css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
1715 css::uno::Reference< css::frame::XPopupMenuController > xPopupController(
1716 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
1717 "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext ), css::uno::UNO_QUERY );
1719 css::uno::Reference< css::awt::XPopupMenu > xPopupMenu( xContext->getServiceManager()->createInstanceWithContext(
1720 "com.sun.star.awt.PopupMenu", xContext ), css::uno::UNO_QUERY );
1722 if ( !xPopupController.is() || !xPopupMenu.is() )
1723 return;
1725 vcl::Window* pWindow = pWin ? pWin : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
1726 Point aPos = pPos ? *pPos : pWindow->GetPointerPosPixel();
1728 css::ui::ContextMenuExecuteEvent aEvent;
1729 aEvent.SourceWindow = VCLUnoHelper::GetInterface( pWindow );
1730 aEvent.ExecutePosition.X = aPos.X();
1731 aEvent.ExecutePosition.Y = aPos.Y();
1733 xPopupController->setPopupMenu( xPopupMenu );
1734 VCLXMenu* pAwtMenu = comphelper::getUnoTunnelImplementation<VCLXMenu>( xPopupMenu );
1735 PopupMenu* pVCLMenu = static_cast< PopupMenu* >( pAwtMenu->GetMenu() );
1736 if (comphelper::LibreOfficeKit::isActive())
1738 boost::property_tree::ptree aMenu = fillPopupMenu(pVCLMenu);
1739 boost::property_tree::ptree aRoot;
1740 aRoot.add_child("menu", aMenu);
1742 std::stringstream aStream;
1743 boost::property_tree::write_json(aStream, aRoot, true);
1744 if (SfxViewShell* pViewShell = xImp->pFrame->GetViewShell())
1745 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, aStream.str().c_str());
1747 else
1749 OUString aMenuURL = "private:resource/popupmenu/" + rResName;
1750 if (pVCLMenu && GetFrame()->GetViewShell()->TryContextMenuInterception(*pVCLMenu, aMenuURL, aEvent))
1752 pVCLMenu->Execute(pWindow, aPos);
1756 css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY );
1757 if ( xComponent.is() )
1758 xComponent->dispose();
1761 /** With this method the SfxDispatcher can be locked and released. A locked
1762 SfxDispatcher does not perform <SfxRequest>s and does no longer provide
1763 status information. It behaves as if all the slots were disabled.
1765 void SfxDispatcher::Lock( bool bLock )
1767 SfxBindings* pBindings = GetBindings();
1768 if ( !bLock && xImp->bLocked && xImp->bInvalidateOnUnlock )
1770 if ( pBindings )
1771 pBindings->InvalidateAll(true);
1772 xImp->bInvalidateOnUnlock = false;
1774 else if ( pBindings )
1775 pBindings->InvalidateAll(false);
1776 xImp->bLocked = bLock;
1777 if ( !bLock )
1779 for(size_t i = 0; i < xImp->aReqArr.size(); ++i)
1780 xImp->xPoster->Post(std::move(xImp->aReqArr[i]));
1781 xImp->aReqArr.clear();
1785 ToolbarId SfxDispatcher::GetObjectBarId( sal_uInt16 nPos ) const
1787 return xImp->aObjBars[nPos].eId;
1790 void SfxDispatcher::HideUI( bool bHide )
1792 bool bWasHidden = xImp->bNoUI;
1793 xImp->bNoUI = bHide;
1794 if ( xImp->pFrame )
1796 SfxViewFrame* pTop = xImp->pFrame->GetTopViewFrame();
1797 if ( pTop && pTop->GetBindings().GetDispatcher() == this )
1799 SfxFrame& rFrame = pTop->GetFrame();
1800 if ( rFrame.IsMenuBarOn_Impl() )
1802 css::uno::Reference < css::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), css::uno::UNO_QUERY );
1803 if ( xPropSet.is() )
1805 css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1806 css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
1807 aValue >>= xLayoutManager;
1808 if ( xLayoutManager.is() )
1809 xLayoutManager->setVisible( !bHide );
1815 if ( bHide != bWasHidden )
1816 Update_Impl( true );
1819 void SfxDispatcher::SetReadOnly_Impl( bool bOn )
1821 xImp->bReadOnly = bOn;
1824 bool SfxDispatcher::GetReadOnly_Impl() const
1826 return xImp->bReadOnly;
1829 /** With 'bOn' the Dispatcher is quasi dead and transfers everything to the
1830 Parent-Dispatcher.
1832 void SfxDispatcher::SetQuietMode_Impl( bool bOn )
1834 xImp->bQuiet = bOn;
1835 SfxBindings* pBindings = GetBindings();
1836 if ( pBindings )
1837 pBindings->InvalidateAll(true);
1840 SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSlot, const SfxPoolItem* &rpState )
1842 SfxShell *pShell = nullptr;
1843 const SfxSlot *pSlot = nullptr;
1844 if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
1846 rpState = pShell->GetSlotState(nSlot);
1847 if ( !rpState )
1848 return SfxItemState::DISABLED;
1849 else
1850 return SfxItemState::DEFAULT;
1853 return SfxItemState::DISABLED;
1856 SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSID, css::uno::Any& rAny )
1858 SfxShell *pShell = nullptr;
1859 const SfxSlot *pSlot = nullptr;
1860 if ( GetShellAndSlot_Impl( nSID, &pShell, &pSlot, false, true ) )
1862 const SfxPoolItem* pItem = pShell->GetSlotState( nSID );
1863 if ( !pItem )
1864 return SfxItemState::DISABLED;
1865 else
1867 css::uno::Any aState;
1868 if ( !pItem->IsVoidItem() )
1870 sal_uInt16 nSubId( 0 );
1871 SfxItemPool& rPool = pShell->GetPool();
1872 sal_uInt16 nWhich = rPool.GetWhich( nSID );
1873 if ( rPool.GetMetric( nWhich ) == MapUnit::MapTwip )
1874 nSubId |= CONVERT_TWIPS;
1875 pItem->QueryValue( aState, static_cast<sal_uInt8>(nSubId) );
1877 rAny = aState;
1879 return SfxItemState::DEFAULT;
1883 return SfxItemState::DISABLED;
1886 bool SfxDispatcher::IsReadOnlyShell_Impl( sal_uInt16 nShell ) const
1888 sal_uInt16 nShellCount = xImp->aStack.size();
1889 if ( nShell < nShellCount )
1891 SfxShell* pShell = *( xImp->aStack.rbegin() + nShell );
1892 if( dynamic_cast< const SfxModule *>( pShell ) != nullptr || dynamic_cast< const SfxApplication *>( pShell ) != nullptr || dynamic_cast< const SfxViewFrame *>( pShell ) != nullptr )
1893 return false;
1894 else
1895 return xImp->bReadOnly;
1897 return true;
1900 void SfxDispatcher::RemoveShell_Impl( SfxShell& rShell )
1902 Flush();
1904 sal_uInt16 nCount = xImp->aStack.size();
1905 for ( sal_uInt16 n=0; n<nCount; ++n )
1907 if ( xImp->aStack[n] == &rShell )
1909 xImp->aStack.erase( xImp->aStack.begin() + n );
1910 rShell.SetDisableFlags( SfxDisableFlags::NONE );
1911 rShell.DoDeactivate_Impl(xImp->pFrame, true);
1912 break;
1916 if ( !SfxGetpApp()->IsDowning() )
1918 xImp->bUpdated = false;
1919 InvalidateBindings_Impl(true);
1923 void SfxDispatcher::InvalidateBindings_Impl( bool bModify )
1925 // App-Dispatcher?
1926 if ( IsAppDispatcher() )
1928 for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst();
1929 pFrame;
1930 pFrame = SfxViewFrame::GetNext( *pFrame ) )
1931 pFrame->GetBindings().InvalidateAll(bModify);
1933 else
1935 SfxDispatcher *pDisp = GetBindings()->GetDispatcher_Impl();
1936 if ( pDisp == this )
1938 GetBindings()->InvalidateAll( bModify );
1943 bool SfxDispatcher::IsUpdated_Impl() const
1945 return xImp->bUpdated;
1948 void SfxDispatcher::SetDisableFlags( SfxDisableFlags nFlags )
1950 xImp->nDisableFlags = nFlags;
1951 for ( SfxShellStack_Impl::reverse_iterator it = xImp->aStack.rbegin(); it != xImp->aStack.rend(); ++it )
1952 (*it)->SetDisableFlags( nFlags );
1955 SfxDisableFlags SfxDispatcher::GetDisableFlags() const
1957 return xImp->nDisableFlags;
1960 SfxModule* SfxDispatcher::GetModule() const
1962 for ( sal_uInt16 nShell = 0;; ++nShell )
1964 SfxShell *pSh = GetShell(nShell);
1965 if ( pSh == nullptr )
1966 return nullptr;
1967 if ( auto pModule = dynamic_cast<SfxModule *>( pSh ) )
1968 return pModule;
1972 boost::property_tree::ptree SfxDispatcher::fillPopupMenu(Menu* pMenu)
1974 // Activate this menu first
1975 pMenu->HandleMenuActivateEvent(pMenu);
1976 pMenu->HandleMenuDeActivateEvent(pMenu);
1978 boost::property_tree::ptree aTree;
1979 // If last item inserted is some valid text
1980 bool bIsLastItemText = false;
1981 sal_uInt16 nCount = pMenu->GetItemCount();
1982 for (sal_uInt16 nPos = 0; nPos < nCount; nPos++)
1984 boost::property_tree::ptree aItemTree;
1985 const MenuItemType aItemType = pMenu->GetItemType(nPos);
1987 if (aItemType == MenuItemType::DONTKNOW)
1988 continue;
1990 if (aItemType == MenuItemType::SEPARATOR)
1992 if (bIsLastItemText)
1993 aItemTree.put("type", "separator");
1994 bIsLastItemText = false;
1996 else
1998 const sal_uInt16 nItemId = pMenu->GetItemId(nPos);
1999 OUString aCommandURL = pMenu->GetItemCommand(nItemId);
2001 if (aCommandURL.isEmpty())
2003 const SfxSlot *pSlot = SFX_SLOTPOOL().GetSlot(nItemId);
2004 if (pSlot)
2005 aCommandURL = pSlot->GetCommandString();
2008 const OUString aItemText = pMenu->GetItemText(nItemId);
2009 Menu* pPopupSubmenu = pMenu->GetPopupMenu(nItemId);
2011 if (!aItemText.isEmpty())
2012 aItemTree.put("text", aItemText.toUtf8().getStr());
2014 if (pPopupSubmenu)
2016 boost::property_tree::ptree aSubmenu = fillPopupMenu(pPopupSubmenu);
2017 if (aSubmenu.empty())
2018 continue;
2020 aItemTree.put("type", "menu");
2021 if (!aCommandURL.isEmpty())
2022 aItemTree.put("command", aCommandURL.toUtf8().getStr());
2023 aItemTree.push_back(std::make_pair("menu", aSubmenu));
2025 else
2027 // no point in exposing choices that don't have the .uno:
2028 // command
2029 if (aCommandURL.isEmpty())
2030 continue;
2032 aItemTree.put("type", "command");
2033 aItemTree.put("command", aCommandURL.toUtf8().getStr());
2036 aItemTree.put("enabled", pMenu->IsItemEnabled(nItemId));
2038 MenuItemBits aItemBits = pMenu->GetItemBits(nItemId);
2039 bool bHasChecks = true;
2040 if (aItemBits & MenuItemBits::CHECKABLE)
2041 aItemTree.put("checktype", "checkmark");
2042 else if (aItemBits & MenuItemBits::RADIOCHECK)
2043 aItemTree.put("checktype", "radio");
2044 else if (aItemBits & MenuItemBits::AUTOCHECK)
2045 aItemTree.put("checktype", "auto");
2046 else
2047 bHasChecks = false;
2049 if (bHasChecks)
2050 aItemTree.put("checked", pMenu->IsItemChecked(nItemId));
2053 if (!aItemTree.empty())
2055 aTree.push_back(std::make_pair("", aItemTree));
2056 if (aItemType != MenuItemType::SEPARATOR)
2057 bIsLastItemText = true;
2061 return aTree;
2064 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */