Line data Source code
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_features.h>
21 :
22 : #include <algorithm>
23 : #include <deque>
24 : #include <vector>
25 :
26 : #include <stdarg.h>
27 : #include <stdlib.h>
28 :
29 : #include <com/sun/star/beans/XPropertySet.hpp>
30 : #include <com/sun/star/frame/XDispatchRecorderSupplier.hpp>
31 : #include <com/sun/star/frame/XLayoutManager.hpp>
32 :
33 : #include <comphelper/lok.hxx>
34 : #include <rtl/strbuf.hxx>
35 : #include <sfx2/app.hxx>
36 : #include <sfx2/bindings.hxx>
37 : #include <sfx2/childwin.hxx>
38 : #include <sfx2/dispatch.hxx>
39 : #include <sfx2/docfac.hxx>
40 : #include <sfx2/docfile.hxx>
41 : #include <sfx2/hintpost.hxx>
42 : #include <sfx2/ipclient.hxx>
43 : #include <sfx2/mnumgr.hxx>
44 : #include <sfx2/module.hxx>
45 : #include <sfx2/msg.hxx>
46 : #include <sfx2/msgpool.hxx>
47 : #include <sfx2/objface.hxx>
48 : #include <sfx2/request.hxx>
49 : #include <sfx2/sfxhelp.hxx>
50 : #include <sfx2/sfxuno.hxx>
51 : #include <sfx2/viewfrm.hxx>
52 : #include <sfx2/viewsh.hxx>
53 : #include <svl/eitem.hxx>
54 : #include <svl/intitem.hxx>
55 : #include <svl/itemiter.hxx>
56 : #include <svl/itempool.hxx>
57 : #include <svl/undo.hxx>
58 : #include <svl/whiter.hxx>
59 : #include <svtools/helpopt.hxx>
60 : #include <vcl/wrkwin.hxx>
61 : #include <vcl/idle.hxx>
62 :
63 : #include <appdata.hxx>
64 : #include <sfxtypes.hxx>
65 : #include <slotserv.hxx>
66 : #include <workwin.hxx>
67 :
68 : typedef std::vector<SfxShell*> SfxShellStack_Impl;
69 :
70 : typedef std::vector<SfxRequest*> SfxRequestPtrArray;
71 :
72 : struct SfxToDo_Impl
73 : {
74 : SfxShell* pCluster;
75 : bool bPush;
76 : bool bDelete;
77 : bool bDeleted;
78 : bool bUntil;
79 :
80 55486 : SfxToDo_Impl( bool bOpPush, bool bOpDelete, bool bOpUntil, SfxShell& rCluster )
81 : : pCluster(&rCluster)
82 : , bPush(bOpPush)
83 : , bDelete(bOpDelete)
84 : , bDeleted(false)
85 55486 : , bUntil(bOpUntil)
86 55486 : {}
87 : };
88 :
89 : struct SfxObjectBars_Impl
90 : {
91 : sal_uInt32 nResId; // Resource - and ConfigId of the Toolbox
92 : sal_uInt16 nMode; // special visibility flags
93 : SfxInterface* pIFace;
94 :
95 90012 : SfxObjectBars_Impl() : nResId(0), nMode(0), pIFace(NULL) {}
96 : };
97 :
98 3462 : struct SfxDispatcher_Impl
99 : {
100 : //When the dispatched is locked, SfxRequests accumulate in aReqArr for
101 : //later dispatch when unlocked via Post
102 :
103 : //The pointers are typically deleted in Post, only if we never get around
104 : //to posting them do we delete the unposted requests.
105 : SfxRequestPtrArray aReqArr;
106 3366 : ~SfxDispatcher_Impl()
107 3366 : {
108 3366 : for (SfxRequestPtrArray::iterator aI = aReqArr.begin(), aEnd = aReqArr.end(); aI != aEnd; ++aI)
109 0 : delete *aI;
110 3366 : }
111 : const SfxSlotServer* pCachedServ1; // last called message
112 : const SfxSlotServer* pCachedServ2; // penultimate called Message
113 : SfxShellStack_Impl aStack; // active functionality
114 : Idle aIdle; // for Flush
115 : std::deque<SfxToDo_Impl> aToDoStack; // not processed Push/Pop
116 : SfxViewFrame* pFrame; // NULL or associated Frame
117 : SfxDispatcher* pParent; // AppDispatcher, NULL if possible
118 : SfxHintPosterRef xPoster; // Execute asynchronous
119 : bool bFlushing; // sal_True during Flush //?
120 : bool bUpdated; // Update_Impl has run
121 : bool bLocked; // No Execute
122 : bool bInvalidateOnUnlock; // because someone asked
123 : bool bActive; // not to be confused with set!
124 : bool* pInCallAliveFlag; // view the Destructor Stack
125 : SfxObjectBars_Impl aObjBars[SFX_OBJECTBAR_MAX];
126 : SfxObjectBars_Impl aFixedObjBars[SFX_OBJECTBAR_MAX];
127 : std::vector<sal_uInt32> aChildWins;
128 : sal_uInt32 nEventId; // EventId UserEvent
129 : bool bNoUI; // UI only from Parent Dispatcher
130 : bool bReadOnly; // Document is ReadOnly
131 : bool bQuiet; // Only use parent dispatcher
132 : bool bModal; // Only slots from parent dispatcher
133 :
134 : SfxSlotFilterState nFilterEnabling; // 1==filter enabled slots,
135 : // 2==ReadOnlyDoc overturned
136 : sal_uInt16 nFilterCount; // Number of SIDs in pFilterSIDs
137 : const sal_uInt16* pFilterSIDs; // sorted Array of SIDs
138 : sal_uInt32 nDisableFlags;
139 : bool bFlushed;
140 : std::deque< std::deque<SfxToDo_Impl> > aToDoCopyStack;
141 : };
142 :
143 : /** This method checks if the stack of the SfxDispatchers is flushed, or if
144 : push- or pop- commands are pending.
145 : */
146 3595 : bool SfxDispatcher::IsFlushed() const
147 : {
148 3595 : return xImp->bFlushed;
149 : }
150 :
151 : /** This method performs outstanding push- and pop- commands. For <SfxShell>s,
152 : which are new on the stack, the <SfxShell::Activate(bool)> is invoked
153 : with bMDI == sal_True, for SfxShells that are removed from the stack, the
154 : <SfxShell::Deactivate(bool)> is invoked with bMDI == sal_True
155 : */
156 332811 : void SfxDispatcher::Flush()
157 : {
158 332811 : if (!xImp->bFlushed) FlushImpl();
159 332811 : }
160 :
161 : /** With this method, a <SfxShell> pushed on to the SfxDispatcher.
162 : The SfxShell is first marked for push and a timer is set up.
163 : First when the timer has couted down to zero the push
164 : ( <SfxDispatcher::Flush()> ) is actually performed and the
165 : <SfxBindings> is invalidated. While the timer is counting down
166 : the opposing push and pop commands on the same SfxShell are
167 : leveled out.
168 : */
169 26453 : void SfxDispatcher::Push(SfxShell& rShell)
170 :
171 : {
172 26453 : Pop( rShell, SfxDispatcherPopFlags::PUSH );
173 26453 : }
174 :
175 : /** This method checks whether a particular <SfxShell> instance is
176 : on the SfxDispatcher.
177 :
178 : @returns sal_True The SfxShell instance is on the SfxDispatcher.
179 : sal_False The SfxShell instance is not on the SfxDispatcher.
180 : */
181 2763 : bool SfxDispatcher::IsActive(const SfxShell& rShell)
182 :
183 : {
184 2763 : return CheckVirtualStack(rShell, true);
185 : }
186 :
187 : /** With this method it can be determined whether the SfxDispatcher is
188 : locked or unlocked. A locked SfxDispatcher does not perform <SfxRequest>s
189 : and no longer provides any status information. It behaves as if all the
190 : slots are disabled.
191 :
192 : The dispatcher is also marked as blocked, if all Dispatcher are locked
193 : (<SfxApplication::LockDispatcher()>) or the associated top frame is in the
194 : modal-mode and if the specified slot are handled as frame-specific
195 : (ie, not served by the application).
196 : */
197 224417 : bool SfxDispatcher::IsLocked(sal_uInt16) const
198 : {
199 224417 : return xImp->bLocked;
200 : }
201 :
202 : /** With this method it can be determined if the SfxDispacher is the
203 : applications dispatcher.
204 :
205 : @return bool it is the application dispatcher.
206 : */
207 27149 : bool SfxDispatcher::IsAppDispatcher() const
208 : {
209 27149 : return !xImp->pFrame;
210 : }
211 :
212 : /** Helper function to check whether a slot can be executed and
213 : check the execution itself
214 : */
215 529 : void SfxDispatcher::Call_Impl(SfxShell& rShell, const SfxSlot &rSlot, SfxRequest &rReq, bool bRecord)
216 : {
217 : SFX_STACK(SfxDispatcher::Call_Impl);
218 :
219 : // The slot may be called (meaning enabled)
220 529 : if ( rSlot.IsMode(SfxSlotMode::FASTCALL) || rShell.CanExecuteSlot_Impl(rSlot) )
221 : {
222 529 : if ( GetFrame() )
223 : {
224 : // Recording may start
225 : com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xFrame(
226 529 : GetFrame()->GetFrame().GetFrameInterface(),
227 529 : com::sun::star::uno::UNO_QUERY);
228 :
229 : com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > xSet(
230 : xFrame,
231 1058 : com::sun::star::uno::UNO_QUERY);
232 :
233 529 : if ( xSet.is() )
234 : {
235 529 : com::sun::star::uno::Any aProp = xSet->getPropertyValue("DispatchRecorderSupplier");
236 1058 : com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorderSupplier > xSupplier;
237 1058 : com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > xRecorder;
238 529 : aProp >>= xSupplier;
239 529 : if(xSupplier.is())
240 1 : xRecorder = xSupplier->getDispatchRecorder();
241 :
242 529 : if ( bRecord && xRecorder.is() && !rSlot.IsMode(SfxSlotMode::NORECORD) )
243 530 : rReq.Record_Impl( rShell, rSlot, xRecorder, GetFrame() );
244 529 : }
245 : }
246 : // Get all that is needed, because the slot may not have survived the
247 : // Execute if it is a 'pseudo slot' for macros or verbs.
248 529 : bool bAutoUpdate = rSlot.IsMode(SfxSlotMode::AUTOUPDATE);
249 :
250 : // API-call parentheses and document-lock during the calls
251 : {
252 : // 'this' must respond in the Destructor
253 529 : bool bThisDispatcherAlive = true;
254 529 : bool *pOldInCallAliveFlag = xImp->pInCallAliveFlag;
255 529 : xImp->pInCallAliveFlag = &bThisDispatcherAlive;
256 :
257 529 : SfxExecFunc pFunc = rSlot.GetExecFnc();
258 529 : rShell.CallExec( pFunc, rReq );
259 :
260 : // If 'this' is still alive
261 529 : if ( bThisDispatcherAlive )
262 529 : xImp->pInCallAliveFlag = pOldInCallAliveFlag;
263 : else
264 : {
265 0 : if ( pOldInCallAliveFlag )
266 : {
267 : // also protect nested stack frames
268 0 : *pOldInCallAliveFlag = false;
269 : }
270 :
271 : // do nothing after this object is dead
272 529 : return;
273 : }
274 : }
275 :
276 529 : if ( rReq.IsDone() )
277 : {
278 212 : SfxBindings *pBindings = GetBindings();
279 :
280 : // When AutoUpdate update immediately; "Pseudoslots" must not be
281 : // Autoupdate!
282 212 : if ( bAutoUpdate && pBindings )
283 : {
284 10 : const SfxSlot* pSlave = rSlot.GetLinkedSlot();
285 10 : if (pSlave)
286 : {
287 : // When enum slots take any bound slave slot
288 0 : while (!pBindings->IsBound(pSlave->GetSlotId()) && pSlave != &rSlot )
289 0 : pSlave = pSlave->GetLinkedSlot();
290 0 : pBindings->Invalidate(pSlave->GetSlotId());
291 0 : pBindings->Update(pSlave->GetSlotId());
292 : }
293 : else
294 : {
295 10 : pBindings->Invalidate(rSlot.GetSlotId());
296 10 : pBindings->Update(rSlot.GetSlotId());
297 : }
298 : }
299 : }
300 : }
301 : }
302 :
303 3462 : void SfxDispatcher::Construct_Impl( SfxDispatcher* pParent )
304 : {
305 3462 : xImp.reset(new SfxDispatcher_Impl);
306 3462 : xImp->bFlushed = true;
307 :
308 3462 : xImp->pCachedServ1 = 0;
309 3462 : xImp->pCachedServ2 = 0;
310 3462 : xImp->bFlushing = false;
311 3462 : xImp->bUpdated = false;
312 3462 : xImp->bLocked = false;
313 3462 : xImp->bActive = false;
314 3462 : xImp->pParent = NULL;
315 3462 : xImp->bNoUI = false;
316 3462 : xImp->bReadOnly = false;
317 3462 : xImp->bQuiet = false;
318 3462 : xImp->bModal = false;
319 3462 : xImp->pInCallAliveFlag = 0;
320 3462 : xImp->nFilterEnabling = SfxSlotFilterState::DISABLED;
321 3462 : xImp->nFilterCount = 0;
322 3462 : xImp->pFilterSIDs = 0;
323 3462 : xImp->nDisableFlags = 0;
324 :
325 3462 : xImp->pParent = pParent;
326 :
327 3462 : xImp->bInvalidateOnUnlock = false;
328 :
329 48468 : for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++)
330 45006 : xImp->aObjBars[n].nResId = 0;
331 :
332 3462 : GenLink aGenLink( LINK(this, SfxDispatcher, PostMsgHandler) );
333 :
334 3462 : xImp->xPoster = new SfxHintPoster(aGenLink);
335 :
336 3462 : xImp->aIdle.SetPriority(SchedulerPriority::MEDIUM);
337 3462 : xImp->aIdle.SetIdleHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) );
338 3462 : }
339 :
340 208 : SfxDispatcher::SfxDispatcher( SfxDispatcher* pParent )
341 : {
342 208 : Construct_Impl( pParent );
343 208 : xImp->pFrame = 0;
344 208 : }
345 :
346 : /** The constructor of the SfxDispatcher class places a stack of empty
347 : <SfxShell> pointers. It is not initially locked and is considered flushed.
348 : */
349 3254 : SfxDispatcher::SfxDispatcher(SfxViewFrame *pViewFrame)
350 : {
351 3254 : if ( pViewFrame )
352 : {
353 3254 : SfxViewFrame *pFrame = pViewFrame->GetParentViewFrame();
354 3254 : if ( pFrame )
355 0 : Construct_Impl( pFrame->GetDispatcher() );
356 : else
357 3254 : Construct_Impl( 0 );
358 : }
359 : else
360 0 : Construct_Impl( 0 );
361 3254 : xImp->pFrame = pViewFrame;
362 3254 : }
363 :
364 : /** The destructor of the SfxDispatcher class should not be called when the
365 : SfxDispatcher instance is active. It may, however, still be a <SfxShell>
366 : pointer on the stack.
367 : */
368 10098 : SfxDispatcher::~SfxDispatcher()
369 : {
370 : #ifdef DBG_UTIL
371 : OStringBuffer sTemp("Delete Dispatcher ");
372 : sTemp.append(reinterpret_cast<sal_Int64>(this));
373 : OSL_TRACE("%s", sTemp.getStr());
374 : DBG_ASSERT( !xImp->bActive, "deleting active Dispatcher" );
375 : #endif
376 :
377 : // So that no timer by Reschedule in PlugComm strikes the LeaveRegistrations
378 3366 : xImp->aIdle.Stop();
379 3366 : xImp->xPoster->SetEventHdl( Link<>() );
380 :
381 : // Notify the stack varialbles in Call_Impl
382 3366 : if ( xImp->pInCallAliveFlag )
383 0 : *xImp->pInCallAliveFlag = false;
384 :
385 : // Get bindings and application
386 3366 : SfxApplication *pSfxApp = SfxGetpApp();
387 3366 : SfxBindings* pBindings = GetBindings();
388 :
389 : // When not flushed, revive the bindings
390 3366 : if (pBindings && !pSfxApp->IsDowning() && !xImp->bFlushed)
391 3243 : pBindings->DLEAVEREGISTRATIONS();
392 :
393 : // may unregister the bindings
394 9983 : while ( pBindings )
395 : {
396 3251 : if ( pBindings->GetDispatcher_Impl() == this)
397 3247 : pBindings->SetDispatcher(0);
398 3251 : pBindings = pBindings->GetSubBindings_Impl();
399 : }
400 6732 : }
401 :
402 : /** With this method, one or more <SfxShell> are poped from the SfxDispatcher.
403 : The SfxShell is marked for popping and a timer is set up. Only when the
404 : timer has reached the end, the pop is actually performed
405 : ( <SfxDispatcher::Flush()> ) and the <SfxBindings> is invalidated.
406 : While the timer is running the opposing push and pop commands on one
407 : SfxShell cancel each other out.
408 :
409 : @param rShell the stack to take the SfxShell instance.
410 : @param nMode SfxDispatcherPopFlags::POP_UNTIL
411 : Also all 'rShell' of SfxShells are taken from the
412 : stack.
413 :
414 : SfxDispatcherPopFlags::POP_DELETE
415 : All SfxShells actually taken from the stack
416 : will be deleted.
417 :
418 : SfxDispatcherPopFlags::PUSH (InPlace use only)
419 : The Shell is pushed.
420 : */
421 39520 : void SfxDispatcher::Pop(SfxShell& rShell, SfxDispatcherPopFlags nMode)
422 : {
423 : DBG_ASSERT( rShell.GetInterface(),
424 : "pushing SfxShell without previous RegisterInterface()" );
425 :
426 39520 : bool bDelete = bool(nMode & SfxDispatcherPopFlags::POP_DELETE);
427 39520 : bool bUntil = bool(nMode & SfxDispatcherPopFlags::POP_UNTIL);
428 39520 : bool bPush = bool(nMode & SfxDispatcherPopFlags::PUSH);
429 :
430 39520 : SfxApplication *pSfxApp = SfxGetpApp();
431 :
432 : SAL_INFO(
433 : "sfx.control",
434 : "-SfxDispatcher(" << this << (bPush ? ")::Push(" : ")::Pop(")
435 : << (rShell.GetInterface()
436 : ? rShell.GetInterface()->GetClassName() : SAL_STREAM(&rShell))
437 : << (bDelete ? ") with delete" : ")")
438 : << (bUntil ? " (up to)" : ""));
439 :
440 : // same shell as on top of the to-do stack?
441 39520 : if(xImp->aToDoStack.size() && xImp->aToDoStack.front().pCluster == &rShell)
442 : {
443 : // cancel inverse actions
444 23 : if ( xImp->aToDoStack.front().bPush != bPush )
445 23 : xImp->aToDoStack.pop_front();
446 : else
447 : {
448 : DBG_ASSERT( bPush, "SfxInterface pushed more than once" );
449 : DBG_ASSERT( !bPush, "SfxInterface popped more than once" );
450 : }
451 : }
452 : else
453 : {
454 : // Remember Action
455 39497 : xImp->aToDoStack.push_front( SfxToDo_Impl(bPush, bDelete, bUntil, rShell) );
456 39497 : if (xImp->bFlushed)
457 : {
458 : OSL_TRACE("Unflushed dispatcher!");
459 19959 : xImp->bFlushed = false;
460 19959 : xImp->bUpdated = false;
461 :
462 : // Put bindings to sleep
463 19959 : SfxBindings* pBindings = GetBindings();
464 19959 : if ( pBindings )
465 19632 : pBindings->DENTERREGISTRATIONS();
466 : }
467 : }
468 :
469 39520 : if(!pSfxApp->IsDowning() && !xImp->aToDoStack.empty())
470 : {
471 : // No immediate update is requested
472 39520 : xImp->aIdle.SetPriority(SchedulerPriority::MEDIUM);
473 39520 : xImp->aIdle.SetIdleHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) );
474 39520 : xImp->aIdle.Start();
475 : }
476 : else
477 : {
478 : // but to do nothing
479 0 : xImp->aIdle.Stop();
480 :
481 : // Bindings may wake up again
482 0 : if(xImp->aToDoStack.empty())
483 : {
484 0 : SfxBindings* pBindings = GetBindings();
485 0 : if ( pBindings )
486 0 : pBindings->DLEAVEREGISTRATIONS();
487 : }
488 : }
489 39520 : }
490 :
491 :
492 : /** This handler is called after <SfxDispatcher::Invalidate()> or after
493 : changes on the stack (<SfxDispatcher::Push()> and <SfxDispatcher::Pop())
494 :
495 : It flushes the Stack, if it is dirty, thus it actually executes the
496 : pending Push and Pop commands.
497 : */
498 0 : IMPL_LINK_NOARG_TYPED( SfxDispatcher, EventHdl_Impl, Idle *, void )
499 : {
500 0 : Flush();
501 0 : Update_Impl();
502 0 : SfxBindings* pBindings = GetBindings();
503 0 : if ( pBindings )
504 0 : pBindings->StartUpdate_Impl(false);
505 0 : }
506 :
507 : /** With this method it can be tested whether the <SfxShell> rShell is on the
508 : stack, when it was flushed. This way the SfxDispatcher is not actually
509 : flushed.
510 :
511 : This method is intended among other things to make assertions possible
512 : without the side effect of having to flush the SfxDispathcer.
513 : */
514 2763 : bool SfxDispatcher::CheckVirtualStack(const SfxShell& rShell, bool bDeep)
515 : {
516 : SFX_STACK(SfxDispatcher::CheckVirtualStack);
517 :
518 2763 : SfxShellStack_Impl aStack( xImp->aStack );
519 2763 : for(std::deque<SfxToDo_Impl>::reverse_iterator i = xImp->aToDoStack.rbegin(); i != xImp->aToDoStack.rend(); ++i)
520 : {
521 0 : if(i->bPush)
522 0 : aStack.push_back(i->pCluster);
523 : else
524 : {
525 0 : SfxShell* pPopped(NULL);
526 0 : do
527 : {
528 : DBG_ASSERT( !aStack.empty(), "popping from empty stack" );
529 0 : pPopped = aStack.back();
530 0 : aStack.pop_back();
531 : }
532 0 : while(i->bUntil && pPopped != i->pCluster);
533 : DBG_ASSERT(pPopped == i->pCluster, "popping unpushed SfxInterface");
534 : }
535 : }
536 :
537 : bool bReturn;
538 2763 : if ( bDeep )
539 2763 : bReturn = std::find(aStack.begin(), aStack.end(), &rShell) != aStack.end();
540 : else
541 0 : bReturn = aStack.back() == &rShell;
542 2763 : return bReturn;
543 : }
544 :
545 : /** Determines the position of a given SfxShell in the stack of the dispatcher.
546 : If possible this is flushed before.
547 :
548 : [Return value]
549 :
550 : sal_uInt16 == USRT_MAX
551 : The SfxShell is not on this SfxDispatcher.
552 :
553 : < USHRT_MAX
554 : Position of the SfxShell on the Dispatcher
555 : from the top count stating with 0.
556 : */
557 3743 : sal_uInt16 SfxDispatcher::GetShellLevel(const SfxShell& rShell)
558 : {
559 : SFX_STACK(SfxDispatcher::GetShellLevel);
560 3743 : Flush();
561 :
562 12684 : for ( size_t n = 0; n < xImp->aStack.size(); ++n )
563 12684 : if ( *( xImp->aStack.rbegin() + n ) == &rShell )
564 3743 : return n;
565 0 : if ( xImp->pParent )
566 : {
567 0 : sal_uInt16 nRet = xImp->pParent->GetShellLevel(rShell);
568 0 : if ( nRet == USHRT_MAX )
569 0 : return nRet;
570 0 : return nRet + xImp->aStack.size();
571 : }
572 :
573 0 : return USHRT_MAX;
574 : }
575 :
576 : /** Returns a pointer to the <SfxShell> which is at the position nIdx
577 : (from the top, last pushed is 0) on the stack.
578 :
579 : Thus the SfxDispatcher is not flushed.
580 :
581 : Is the stack not deep enough a NULL-Pointer is returned.
582 : */
583 681095 : SfxShell *SfxDispatcher::GetShell(sal_uInt16 nIdx) const
584 : {
585 681095 : sal_uInt16 nShellCount = xImp->aStack.size();
586 681095 : if ( nIdx < nShellCount )
587 681095 : return *(xImp->aStack.rbegin() + nIdx);
588 0 : else if ( xImp->pParent )
589 0 : return xImp->pParent->GetShell( nIdx - nShellCount );
590 0 : return 0;
591 : }
592 :
593 : /** This method returns a pointer to the <SfxBinding> Instance on which the
594 : SfxDispatcher is curretly bound. A SfxDispatcher is only bound to
595 : the SfxBindings when it is <UI-aktiv>. If it is not UI-active,
596 : a NULL-pointer is returned.
597 :
598 : The returned pointer is only valid in the immediate context of the method
599 : call.
600 : */
601 135661 : SfxBindings* SfxDispatcher::GetBindings() const
602 : {
603 135661 : if ( xImp->pFrame )
604 134680 : return &xImp->pFrame->GetBindings();
605 : else
606 981 : return NULL;
607 : }
608 :
609 : /** Returns a pointer to the <SfxViewFrame> instance, which belongs to
610 : this SfxDispatcher. If it is about the application dispatcher,
611 : a NULL-pointer is returned.
612 : */
613 434798 : SfxViewFrame* SfxDispatcher::GetFrame() const
614 : {
615 434798 : return xImp->pFrame;
616 : }
617 :
618 : /** This method controls the activation of a dispatcher.
619 :
620 : Since the application dispatcher is always active, either as a sub
621 : dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
622 : activated as a whole, instead only its individual <SfxShell>s at
623 : <SfxDispatcher::Push(SfxShell&)>.
624 :
625 : When activating a SfxDispatcher all of the SfxShells located on its stack
626 : are called with the handler <SfxShell::Activate(bool)>, starting with
627 : the lowest.
628 : */
629 3356 : void SfxDispatcher::DoActivate_Impl(bool bMDI, SfxViewFrame* /* pOld */)
630 : {
631 : SFX_STACK(SfxDispatcher::DoActivate);
632 3356 : if ( bMDI )
633 : {
634 : #ifdef DBG_UTIL
635 : OStringBuffer sTemp("Activate Dispatcher ");
636 : sTemp.append(reinterpret_cast<sal_Int64>(this));
637 : OSL_TRACE("%s", sTemp.getStr());
638 : DBG_ASSERT( !xImp->bActive, "Activation error" );
639 : #endif
640 3356 : xImp->bActive = true;
641 3356 : xImp->bUpdated = false;
642 3356 : SfxBindings* pBindings = GetBindings();
643 3356 : if ( pBindings )
644 : {
645 3148 : pBindings->SetDispatcher(this);
646 3148 : pBindings->SetActiveFrame( xImp->pFrame->GetFrame().GetFrameInterface() );
647 : }
648 : }
649 : else
650 : {
651 : #ifdef DBG_UTIL
652 : OStringBuffer sTemp("Non-MDI-Activate Dispatcher");
653 : sTemp.append(reinterpret_cast<sal_Int64>(this));
654 : OSL_TRACE("%s", sTemp.getStr());
655 : #endif
656 : }
657 :
658 3356 : if ( IsAppDispatcher() )
659 3564 : return;
660 :
661 20313 : for ( int i = int(xImp->aStack.size()) - 1; i >= 0; --i )
662 17165 : (*(xImp->aStack.rbegin() + i ))->DoActivate_Impl(xImp->pFrame, bMDI);
663 :
664 3148 : if ( bMDI && xImp->pFrame )
665 : {
666 3148 : SfxBindings *pBind = GetBindings();
667 9444 : while ( pBind )
668 : {
669 3148 : pBind->HidePopupCtrls_Impl( false );
670 3148 : pBind = pBind->GetSubBindings_Impl();
671 : }
672 :
673 3148 : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( false, false, 1 );
674 : }
675 :
676 3148 : if(!xImp->aToDoStack.empty())
677 : {
678 : // No immediate update is requested
679 0 : xImp->aIdle.SetPriority(SchedulerPriority::MEDIUM);
680 0 : xImp->aIdle.SetIdleHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) );
681 0 : xImp->aIdle.Start();
682 : }
683 : }
684 :
685 0 : void SfxDispatcher::DoParentActivate_Impl()
686 : {
687 0 : }
688 :
689 : /** This method controls the deactivation of a dispatcher.
690 :
691 : Since the application dispatcher is always active, either as a sub
692 : dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
693 : deactivated as a whole, instead only its individual <SfxShell>s at
694 : <SfxDispatcher::Pop(SfxShell&)>.
695 :
696 : When deactivating a SfxDispatcher all of the SfxShells located on its stack
697 : are called with the handler <SfxShell::Deactivate(bool)>, starting with
698 : the lowest.
699 : */
700 3264 : void SfxDispatcher::DoDeactivate_Impl(bool bMDI, SfxViewFrame* pNew)
701 : {
702 : SFX_STACK(SfxDispatcher::DoDeactivate);
703 :
704 3264 : SfxApplication *pSfxApp = SfxGetpApp();
705 :
706 3264 : if ( bMDI )
707 : {
708 : SAL_INFO("sfx.control", "Deactivate Dispatcher " << this);
709 : DBG_ASSERT( xImp->bActive, "Deactivate error" );
710 3264 : xImp->bActive = false;
711 :
712 3264 : if ( xImp->pFrame && !(xImp->pFrame->GetObjectShell()->IsInPlaceActive() ) )
713 : {
714 3145 : SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
715 3145 : if ( pWorkWin )
716 : {
717 116799 : for (size_t n=0; n<xImp->aChildWins.size();)
718 : {
719 110509 : SfxChildWindow *pWin = pWorkWin->GetChildWindow_Impl( (sal_uInt16) ( xImp->aChildWins[n] & 0xFFFF ) );
720 110509 : if (!pWin || (pWin && pWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT))
721 110466 : xImp->aChildWins.erase(xImp->aChildWins.begin()+n);
722 : else
723 43 : n++;
724 : }
725 : }
726 : }
727 : }
728 : else {
729 : SAL_INFO("sfx.control", "Non-MDI-DeActivate Dispatcher " << this);
730 : }
731 :
732 3264 : if ( IsAppDispatcher() && !pSfxApp->IsDowning() )
733 3264 : return;
734 :
735 27989 : for ( size_t i = 0; i < xImp->aStack.size(); ++i )
736 24725 : (*(xImp->aStack.rbegin() + i))->DoDeactivate_Impl(xImp->pFrame, bMDI);
737 :
738 3264 : bool bHidePopups = bMDI && xImp->pFrame;
739 3264 : if ( pNew && xImp->pFrame )
740 : {
741 : com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xOldFrame(
742 19 : pNew->GetFrame().GetFrameInterface()->getCreator(), com::sun::star::uno::UNO_QUERY );
743 :
744 : com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xMyFrame(
745 38 : GetFrame()->GetFrame().GetFrameInterface(), com::sun::star::uno::UNO_QUERY );
746 :
747 19 : if ( xOldFrame == xMyFrame )
748 19 : bHidePopups = false;
749 : }
750 :
751 3264 : if ( bHidePopups )
752 : {
753 3145 : SfxBindings *pBind = GetBindings();
754 9435 : while ( pBind )
755 : {
756 3145 : pBind->HidePopupCtrls_Impl( true );
757 3145 : pBind = pBind->GetSubBindings_Impl();
758 : }
759 :
760 3145 : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( true, false, 1 );
761 : }
762 :
763 3264 : Flush();
764 : }
765 :
766 0 : void SfxDispatcher::DoParentDeactivate_Impl()
767 : {
768 0 : }
769 :
770 : /** This method searches in SfxDispatcher after <SfxShell> , from the Slot Id
771 : nSlot currently being handled. For this, the dispatcher is first flushed.
772 :
773 : @param nSlot the searchable Slot-Id
774 : @param ppShell the SfxShell, which are currently handled the nSlot
775 : @param ppSlot the SfxSlot, which are currently handled the nSlot
776 :
777 : @return int sal_True
778 : The SfxShell was found, ppShell and ppSlot are valid.
779 :
780 : sal_False
781 : The SfxShell was not found, ppShell and ppSlot are invalid.
782 : */
783 97751 : bool SfxDispatcher::GetShellAndSlot_Impl(sal_uInt16 nSlot, SfxShell** ppShell,
784 : const SfxSlot** ppSlot, bool bOwnShellsOnly, bool bModal, bool bRealSlot)
785 : {
786 : SFX_STACK(SfxDispatcher::GetShellAndSlot_Impl);
787 :
788 97751 : Flush();
789 97751 : SfxSlotServer aSvr;
790 97751 : if ( _FindServer(nSlot, aSvr, bModal) )
791 : {
792 94467 : if ( bOwnShellsOnly && aSvr.GetShellLevel() >= xImp->aStack.size() )
793 0 : return false;
794 :
795 94467 : *ppShell = GetShell(aSvr.GetShellLevel());
796 94467 : *ppSlot = aSvr.GetSlot();
797 94467 : if ( 0 == (*ppSlot)->GetExecFnc() && bRealSlot )
798 1319 : *ppSlot = (*ppShell)->GetInterface()->GetRealSlot(*ppSlot);
799 : // Check only real slots as enum slots don't have an execute function!
800 94467 : if ( bRealSlot && ((0 == *ppSlot) || (0 == (*ppSlot)->GetExecFnc()) ))
801 0 : return false;
802 :
803 94467 : return true;
804 : }
805 :
806 3284 : return false;
807 : }
808 :
809 : /** This method performs a request for a cached <Slot-Server>.
810 :
811 : @param rShell to the calling <SfxShell>
812 : @param rSlot to the calling <SfxSlot>
813 : @param rReq function to be performed (Id and optional parameters)
814 : @param eCallMode Synchronously, asynchronously or as shown in the slot
815 : */
816 857 : void SfxDispatcher::_Execute(SfxShell& rShell, const SfxSlot& rSlot,
817 : SfxRequest& rReq, SfxCallMode eCallMode)
818 : {
819 : DBG_ASSERT( !xImp->bFlushing, "recursive call to dispatcher" );
820 : DBG_ASSERT( xImp->aToDoStack.empty(), "unprepared InPlace _Execute" );
821 :
822 857 : if ( IsLocked( rSlot.GetSlotId() ) )
823 0 : return;
824 :
825 1724 : if ( bool(eCallMode & SfxCallMode::ASYNCHRON) ||
826 206 : ( (eCallMode & SfxCallMode::SYNCHRON) == SfxCallMode::SLOT &&
827 49 : rSlot.IsMode(SfxSlotMode::ASYNCHRON) ) )
828 : {
829 710 : SfxDispatcher *pDispat = this;
830 1420 : while ( pDispat )
831 : {
832 710 : sal_uInt16 nShellCount = pDispat->xImp->aStack.size();
833 765 : for ( sal_uInt16 n=0; n<nShellCount; n++ )
834 : {
835 765 : if ( &rShell == *(pDispat->xImp->aStack.rbegin() + n) )
836 : {
837 710 : if ( bool(eCallMode & SfxCallMode::RECORD) )
838 696 : rReq.AllowRecording( true );
839 710 : pDispat->xImp->xPoster->Post(new SfxRequest(rReq));
840 710 : return;
841 : }
842 : }
843 :
844 0 : pDispat = pDispat->xImp->pParent;
845 : }
846 : }
847 : else
848 147 : Call_Impl( rShell, rSlot, rReq, SfxCallMode::RECORD==(eCallMode&SfxCallMode::RECORD) );
849 : }
850 :
851 : /** Helper function to put from rItem below the Which-ID in the pool of the
852 : Item Sets rSet.
853 : */
854 531 : void MappedPut_Impl(SfxAllItemSet &rSet, const SfxPoolItem &rItem)
855 : {
856 : // Put with mapped Which-Id if possible
857 531 : const SfxItemPool *pPool = rSet.GetPool();
858 531 : sal_uInt16 nWhich = rItem.Which();
859 531 : if ( SfxItemPool::IsSlot(nWhich) )
860 531 : nWhich = pPool->GetWhich(nWhich);
861 531 : rSet.Put( rItem, nWhich );
862 531 : }
863 :
864 4253 : const SfxSlot* SfxDispatcher::GetSlot( const OUString& rCommand )
865 : {
866 : // Count the number of Shells on the linked Dispatcher
867 4253 : Flush();
868 4253 : sal_uInt16 nTotCount = xImp->aStack.size();
869 4253 : if ( xImp->pParent )
870 : {
871 0 : SfxDispatcher *pParent = xImp->pParent;
872 0 : while ( pParent )
873 : {
874 0 : nTotCount = nTotCount + pParent->xImp->aStack.size();
875 0 : pParent = pParent->xImp->pParent;
876 : }
877 : }
878 :
879 4253 : sal_uInt16 nFirstShell = 0;
880 8433 : for ( sal_uInt16 i = nFirstShell; i < nTotCount; ++i )
881 : {
882 4253 : SfxShell *pObjShell = GetShell(i);
883 4253 : SfxInterface *pIFace = pObjShell->GetInterface();
884 4253 : const SfxSlot *pSlot = pIFace->GetSlot( rCommand );
885 4253 : if ( pSlot )
886 73 : return pSlot;
887 : }
888 :
889 4180 : return 0;
890 : }
891 :
892 21 : const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode nCall,
893 : SfxItemSet* pArgs, SfxItemSet* pInternalArgs, sal_uInt16 nModi)
894 : {
895 21 : if ( IsLocked(nSlot) )
896 0 : return 0;
897 :
898 21 : SfxShell *pShell = 0;
899 21 : const SfxSlot *pSlot = 0;
900 21 : if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false,
901 21 : SfxCallMode::MODAL==(nCall&SfxCallMode::MODAL) ) )
902 : {
903 21 : SfxAllItemSet aSet( pShell->GetPool() );
904 21 : if ( pArgs )
905 : {
906 21 : SfxItemIter aIter(*pArgs);
907 42 : for ( const SfxPoolItem *pArg = aIter.FirstItem();
908 : pArg;
909 : pArg = aIter.NextItem() )
910 42 : MappedPut_Impl( aSet, *pArg );
911 : }
912 42 : SfxRequest aReq( nSlot, nCall, aSet );
913 21 : if (pInternalArgs)
914 21 : aReq.SetInternalArgs_Impl( *pInternalArgs );
915 21 : aReq.SetModifier( nModi );
916 :
917 21 : _Execute( *pShell, *pSlot, aReq, nCall );
918 42 : return aReq.GetReturnValue();
919 : }
920 0 : return 0;
921 : }
922 :
923 : /** Method to execute a <SfxSlot>s over the Slot-Id.
924 :
925 : @param nSlot the Id of the executing function
926 : @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
927 : @param pArgs Zero teminated C-Array of Parameters
928 : @param pInternalArgs Zero terminated C-Array of Parameters
929 :
930 : @return const SfxPoolItem* Pointer to the SfxPoolItem valid to the next run
931 : though the Message-Loop, which contains the return
932 : value.
933 :
934 : Or a NULL-Pointer, when the function was not
935 : executed (for example canceled by the user).
936 : */
937 471 : const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
938 : const SfxPoolItem **pArgs, sal_uInt16 nModi, const SfxPoolItem **pInternalArgs)
939 : {
940 471 : if ( IsLocked(nSlot) )
941 0 : return 0;
942 :
943 471 : SfxShell *pShell = 0;
944 471 : const SfxSlot *pSlot = 0;
945 471 : if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false,
946 471 : SfxCallMode::MODAL==(eCall&SfxCallMode::MODAL) ) )
947 : {
948 : SfxRequest* pReq;
949 299 : if ( pArgs && *pArgs )
950 : {
951 0 : SfxAllItemSet aSet( pShell->GetPool() );
952 0 : for ( const SfxPoolItem **pArg = pArgs; *pArg; ++pArg )
953 0 : MappedPut_Impl( aSet, **pArg );
954 0 : pReq = new SfxRequest( nSlot, eCall, aSet );
955 : }
956 : else
957 299 : pReq = new SfxRequest( nSlot, eCall, pShell->GetPool() );
958 299 : pReq->SetModifier( nModi );
959 299 : if( pInternalArgs && *pInternalArgs)
960 : {
961 0 : SfxAllItemSet aSet( SfxGetpApp()->GetPool() );
962 0 : for ( const SfxPoolItem **pArg = pInternalArgs; *pArg; ++pArg )
963 0 : aSet.Put( **pArg );
964 0 : pReq->SetInternalArgs_Impl( aSet );
965 : }
966 299 : _Execute( *pShell, *pSlot, *pReq, eCall );
967 299 : const SfxPoolItem* pRet = pReq->GetReturnValue();
968 299 : delete pReq; return pRet;
969 : }
970 172 : return 0;
971 : }
972 :
973 : /** Method to execute a <SfxSlot>s over the Slot-Id.
974 :
975 : @param nSlot the Id of the executing function
976 : @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
977 : @param rArgs <SfxItemSet> with the parameters
978 :
979 : @return const SfxPoolItem* Pointer to the SfxPoolItem valid to the next run
980 : though the Message-Loop, which contains the return
981 : value.
982 :
983 : Or a NULL-Pointer, when the function was not
984 : executed (for example canceled by the user).
985 : */
986 83 : const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
987 : const SfxItemSet &rArgs)
988 : {
989 83 : return Execute( nSlot, eCall, 0, rArgs );
990 : }
991 :
992 83 : const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
993 : sal_uInt16 nModi, const SfxItemSet &rArgs)
994 : {
995 83 : if ( IsLocked(nSlot) )
996 0 : return 0;
997 :
998 83 : SfxShell *pShell = 0;
999 83 : const SfxSlot *pSlot = 0;
1000 83 : if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false,
1001 83 : SfxCallMode::MODAL==(eCall&SfxCallMode::MODAL) ) )
1002 : {
1003 83 : SfxAllItemSet aSet( pShell->GetPool() );
1004 166 : SfxItemIter aIter(rArgs);
1005 166 : for ( const SfxPoolItem *pArg = aIter.FirstItem();
1006 : pArg;
1007 : pArg = aIter.NextItem() )
1008 83 : MappedPut_Impl( aSet, *pArg );
1009 166 : SfxRequest aReq( nSlot, eCall, aSet );
1010 83 : aReq.SetModifier( nModi );
1011 83 : _Execute( *pShell, *pSlot, aReq, eCall );
1012 166 : return aReq.GetReturnValue();
1013 : }
1014 0 : return 0;
1015 : }
1016 :
1017 : /** Method to execute a <SfxSlot>s over the Slot-Id.
1018 :
1019 : [Note]
1020 :
1021 : The parameters are copied, can therefore be passed on as the address
1022 : of stack objects.
1023 :
1024 : @param nSlot the Id of the executing function
1025 : @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
1026 : @param pArg1 First parameter
1027 : @param ... Zero terminated list of parameters
1028 :
1029 : @return Pointer to the SfxPoolItem valid to the next run
1030 : though the Message-Loop, which contains the return
1031 : value.
1032 :
1033 : Or a NULL-Pointer, when the function was not
1034 : executed (for example canceled by the user).
1035 :
1036 : [Example]
1037 :
1038 : pDispatcher->Execute( SID_OPENDOCUMENT, SfxCallMode::SYNCHRON,
1039 : &SfxStringItem( SID_FILE_NAME, "\\tmp\\temp.sdd" ),
1040 : &SfxStringItem( SID_FILTER_NAME, "StarDraw Presentation" ),
1041 : &SfxBoolItem( SID_DOC_READONLY, sal_False ),
1042 : 0L );
1043 : */
1044 629 : const SfxPoolItem* SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
1045 : const SfxPoolItem* pArg1, ...)
1046 : {
1047 629 : if ( IsLocked(nSlot) )
1048 0 : return 0;
1049 :
1050 629 : SfxShell *pShell = 0;
1051 629 : const SfxSlot *pSlot = 0;
1052 629 : if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false,
1053 629 : SfxCallMode::MODAL==(eCall&SfxCallMode::MODAL) ) )
1054 : {
1055 427 : SfxAllItemSet aSet( pShell->GetPool() );
1056 :
1057 : va_list pVarArgs;
1058 427 : va_start( pVarArgs, pArg1 );
1059 1281 : for ( const SfxPoolItem *pArg = pArg1;
1060 : pArg;
1061 427 : pArg = va_arg( pVarArgs, const SfxPoolItem* ) )
1062 427 : MappedPut_Impl( aSet, *pArg );
1063 427 : va_end(pVarArgs);
1064 :
1065 854 : SfxRequest aReq( nSlot, eCall, aSet );
1066 427 : _Execute( *pShell, *pSlot, aReq, eCall );
1067 854 : return aReq.GetReturnValue();
1068 : }
1069 202 : return 0;
1070 : }
1071 :
1072 : /** Helper method to receive the asynchronously executed <SfxRequest>s.
1073 : */
1074 764 : IMPL_LINK(SfxDispatcher, PostMsgHandler, SfxRequest*, pReq)
1075 : {
1076 : DBG_ASSERT( !xImp->bFlushing, "recursive call to dispatcher" );
1077 : SFX_STACK(SfxDispatcher::PostMsgHandler);
1078 :
1079 : // Has also the Pool not yet died?
1080 382 : if ( !pReq->IsCancelled() )
1081 : {
1082 382 : if ( !IsLocked(pReq->GetSlot()) )
1083 : {
1084 382 : Flush();
1085 382 : SfxSlotServer aSvr;
1086 382 : if ( _FindServer(pReq->GetSlot(), aSvr, true ) ) // HACK(x), whatever that was supposed to mean
1087 : {
1088 382 : const SfxSlot *pSlot = aSvr.GetSlot();
1089 382 : SfxShell *pSh = GetShell(aSvr.GetShellLevel());
1090 :
1091 : // When the pSlot is a "Pseudoslot" for macros or Verbs, it can
1092 : // be destroyed in the Call_Impl, thus do not use it anymore!
1093 382 : pReq->SetSynchronCall( false );
1094 382 : Call_Impl( *pSh, *pSlot, *pReq, pReq->AllowsRecording() ); //! why bRecord?
1095 : }
1096 : }
1097 : else
1098 : {
1099 0 : if ( xImp->bLocked )
1100 0 : xImp->aReqArr.push_back(new SfxRequest(*pReq));
1101 : else
1102 0 : xImp->xPoster->Post(new SfxRequest(*pReq));
1103 : }
1104 : }
1105 :
1106 382 : delete pReq;
1107 382 : return 0;
1108 : }
1109 :
1110 6872 : void SfxDispatcher::SetMenu_Impl()
1111 : {
1112 : #if HAVE_FEATURE_DESKTOP
1113 6872 : if ( xImp->pFrame )
1114 : {
1115 6872 : SfxViewFrame* pTop = xImp->pFrame->GetTopViewFrame();
1116 6872 : if ( pTop && pTop->GetBindings().GetDispatcher() == this )
1117 : {
1118 6872 : SfxFrame& rFrame = pTop->GetFrame();
1119 6872 : if ( rFrame.IsMenuBarOn_Impl() )
1120 : {
1121 6872 : com::sun::star::uno::Reference < com::sun::star::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), com::sun::star::uno::UNO_QUERY );
1122 6872 : if ( xPropSet.is() )
1123 : {
1124 6872 : com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
1125 13744 : com::sun::star::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
1126 6872 : aValue >>= xLayoutManager;
1127 6872 : if ( xLayoutManager.is() )
1128 : {
1129 6872 : OUString aMenuBarURL( "private:resource/menubar/menubar" );
1130 6872 : if ( !xLayoutManager->isElementVisible( aMenuBarURL ) )
1131 3189 : xLayoutManager->createElement( aMenuBarURL );
1132 6872 : }
1133 6872 : }
1134 : }
1135 : }
1136 : }
1137 : #endif
1138 6872 : }
1139 :
1140 10396 : void SfxDispatcher::Update_Impl( bool bForce )
1141 : {
1142 : SFX_STACK(SfxDispatcher::Update_Impl);
1143 :
1144 10396 : Flush();
1145 :
1146 10396 : if ( !xImp->pFrame )
1147 0 : return;
1148 :
1149 10396 : SfxGetpApp(); // -Wall is this required???
1150 10396 : SfxDispatcher *pDisp = this;
1151 10396 : bool bUpdate = bForce;
1152 31188 : while ( pDisp && pDisp->xImp->pFrame )
1153 : {
1154 10396 : SfxWorkWindow *pWork = pDisp->xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1155 10396 : SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1156 10396 : if ( pAct == pDisp || pAct == this )
1157 : {
1158 10396 : if ( !bUpdate )
1159 6758 : bUpdate = !pDisp->xImp->bUpdated;
1160 10396 : pDisp->xImp->bUpdated = true;
1161 : }
1162 : else
1163 : break;
1164 :
1165 10396 : pDisp = pDisp->xImp->pParent;
1166 : }
1167 :
1168 10396 : if ( !bUpdate || xImp->pFrame->GetFrame().IsClosing_Impl() )
1169 3513 : return;
1170 :
1171 6883 : SfxViewFrame* pTop = xImp->pFrame ? xImp->pFrame->GetTopViewFrame() : NULL;
1172 6883 : bool bUIActive = pTop && pTop->GetBindings().GetDispatcher() == this && !comphelper::LibreOfficeKit::isActive();
1173 :
1174 6883 : if ( !bUIActive && pTop && GetBindings() == &pTop->GetBindings() )
1175 : // keep own tools internally for collecting
1176 11 : GetBindings()->GetDispatcher()->xImp->bUpdated = false;
1177 :
1178 6883 : com::sun::star::uno::Reference< com::sun::star::frame::XFrame > xFrame;
1179 6883 : SfxBindings* pBindings = GetBindings();
1180 6883 : if (pBindings)
1181 : {
1182 6883 : pBindings->DENTERREGISTRATIONS();
1183 6883 : xFrame = pBindings->GetActiveFrame();
1184 : }
1185 13766 : com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > xPropSet( xFrame, com::sun::star::uno::UNO_QUERY );
1186 13766 : com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
1187 6883 : if ( xPropSet.is() )
1188 : {
1189 : try
1190 : {
1191 6883 : com::sun::star::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
1192 6883 : aValue >>= xLayoutManager;
1193 : }
1194 0 : catch (const com::sun::star::uno::Exception&)
1195 : {
1196 : }
1197 : }
1198 :
1199 6883 : if ( xLayoutManager.is() )
1200 6883 : xLayoutManager->lock();
1201 :
1202 6883 : bool bIsIPActive = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1203 6883 : SfxInPlaceClient *pClient = xImp->pFrame ? xImp->pFrame->GetViewShell()->GetUIActiveClient() : NULL;
1204 6883 : if ( bUIActive && /* !bIsIPActive && */ ( !pClient || !pClient->IsObjectUIActive() ) )
1205 6872 : SetMenu_Impl();
1206 :
1207 6883 : SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1208 6883 : SfxWorkWindow *pTaskWin = xImp->pFrame->GetTopFrame().GetWorkWindow_Impl();
1209 6883 : pTaskWin->ResetStatusBar_Impl();
1210 :
1211 6883 : SfxDispatcher *pDispat = this;
1212 20649 : while ( pDispat )
1213 : {
1214 6883 : SfxWorkWindow *pWork = pDispat->xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1215 6883 : SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1216 6883 : if ( pAct == pDispat || pAct == this )
1217 : {
1218 6883 : pWork->ResetObjectBars_Impl();
1219 6883 : pWork->ResetChildWindows_Impl();
1220 : }
1221 :
1222 6883 : pDispat = pDispat->xImp->pParent;
1223 : }
1224 :
1225 6883 : bool bIsActive = false;
1226 6883 : SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1227 6883 : pDispat = this;
1228 20649 : while ( pActDispat && !bIsActive )
1229 : {
1230 6883 : if ( pDispat == pActDispat )
1231 6883 : bIsActive = true;
1232 6883 : pActDispat = pActDispat->xImp->pParent;
1233 : }
1234 :
1235 6883 : _Update_Impl( bUIActive, !bIsIPActive, bIsIPActive, pTaskWin );
1236 6883 : if ( (bUIActive || bIsActive) && !comphelper::LibreOfficeKit::isActive() )
1237 6872 : pWorkWin->UpdateObjectBars_Impl();
1238 :
1239 6883 : if ( pBindings )
1240 6883 : pBindings->DLEAVEREGISTRATIONS();
1241 :
1242 6883 : if ( xLayoutManager.is() )
1243 6883 : xLayoutManager->unlock();
1244 :
1245 13766 : return;
1246 : }
1247 :
1248 6883 : void SfxDispatcher::_Update_Impl( bool bUIActive, bool bIsMDIApp, bool bIsIPOwner, SfxWorkWindow *pTaskWin )
1249 : {
1250 6883 : SfxGetpApp();
1251 6883 : SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1252 6883 : bool bIsActive = false;
1253 6883 : SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1254 6883 : SfxDispatcher *pDispat = this;
1255 20649 : while ( pActDispat && !bIsActive )
1256 : {
1257 6883 : if ( pDispat == pActDispat )
1258 6883 : bIsActive = true;
1259 6883 : pActDispat = pActDispat->xImp->pParent;
1260 : }
1261 :
1262 6883 : if ( xImp->pParent && !xImp->bQuiet /* && bUIActive */ )
1263 0 : xImp->pParent->_Update_Impl( bUIActive, bIsMDIApp, bIsIPOwner, pTaskWin );
1264 :
1265 96362 : for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++)
1266 89479 : xImp->aObjBars[n].nResId = 0;
1267 6883 : xImp->aChildWins.clear();
1268 :
1269 : // bQuiet : own shells aren't considered for UI and SlotServer
1270 : // bNoUI: own Shells aren't considered fors UI
1271 6883 : if ( xImp->bQuiet || xImp->bNoUI || (xImp->pFrame && xImp->pFrame->GetObjectShell()->IsPreview()) )
1272 6883 : return;
1273 :
1274 6883 : sal_uInt32 nStatBarId=0;
1275 6883 : SfxShell *pStatusBarShell = NULL;
1276 :
1277 6883 : SfxSlotPool* pSlotPool = &SfxSlotPool::GetSlotPool( GetFrame() );
1278 6883 : sal_uInt16 nTotCount = xImp->aStack.size();
1279 53894 : for ( sal_uInt16 nShell = nTotCount; nShell > 0; --nShell )
1280 : {
1281 47011 : SfxShell *pShell = GetShell( nShell-1 );
1282 47011 : SfxInterface *pIFace = pShell->GetInterface();
1283 :
1284 : // don't consider shells if "Hidden" oder "Quiet"
1285 47011 : bool bReadOnlyShell = IsReadOnlyShell_Impl( nShell-1 );
1286 : sal_uInt16 nNo;
1287 103845 : for ( nNo = 0; pIFace && nNo<pIFace->GetObjectBarCount(); ++nNo )
1288 : {
1289 56834 : sal_uInt16 nPos = pIFace->GetObjectBarPos(nNo);
1290 56834 : if ( bReadOnlyShell && !( nPos & SFX_VISIBILITY_READONLYDOC ) )
1291 36 : continue;
1292 :
1293 : // check whether toolbar needs activation of a special feature
1294 56798 : sal_uInt32 nFeature = pIFace->GetObjectBarFeature(nNo);
1295 56798 : if ( nFeature && !pShell->HasUIFeature( nFeature ) )
1296 12795 : continue;
1297 :
1298 : // check for toolboxes that are exclusively for a viewer
1299 44003 : if ( xImp->pFrame)
1300 : {
1301 44003 : bool bViewerTbx = SFX_VISIBILITY_VIEWER == ( nPos & SFX_VISIBILITY_VIEWER );
1302 44003 : SfxObjectShell* pSh = xImp->pFrame->GetObjectShell();
1303 44003 : SFX_ITEMSET_ARG( pSh->GetMedium()->GetItemSet(), pItem, SfxBoolItem, SID_VIEWONLY, false );
1304 44003 : bool bIsViewer = pItem && pItem->GetValue();
1305 44003 : if ( bIsViewer != bViewerTbx )
1306 6536 : continue;
1307 : }
1308 :
1309 : // always register toolbars, allows to switch them on
1310 37467 : bool bVisible = pIFace->IsObjectBarVisible(nNo);
1311 37467 : if ( !bVisible )
1312 0 : nPos &= SFX_POSITION_MASK;
1313 :
1314 37467 : SfxObjectBars_Impl& rBar = xImp->aObjBars[nPos & SFX_POSITION_MASK];
1315 37467 : rBar.nMode = nPos;
1316 37467 : rBar.nResId = pIFace->GetObjectBarId(nNo);
1317 37467 : rBar.pIFace = pIFace;
1318 :
1319 37467 : if ( bUIActive || bIsActive )
1320 : {
1321 37467 : pWorkWin->SetObjectBar_Impl(nPos, rBar.nResId, rBar.pIFace);
1322 : }
1323 :
1324 37467 : if ( !bVisible )
1325 0 : rBar.nResId = 0;
1326 : }
1327 :
1328 287878 : for ( nNo=0; pIFace && nNo<pIFace->GetChildWindowCount(); nNo++ )
1329 : {
1330 240867 : sal_uInt32 nId = pIFace->GetChildWindowId(nNo);
1331 240867 : const SfxSlot *pSlot = pSlotPool->GetSlot( (sal_uInt16) nId );
1332 : SAL_WARN_IF( !pSlot, "sfx.control", "Childwindow slot missing: " << nId );
1333 240867 : if ( bReadOnlyShell )
1334 : {
1335 : // only show ChildWindows if their slot is allowed for readonly documents
1336 241 : if ( pSlot && !pSlot->IsMode( SfxSlotMode::READONLYDOC ) )
1337 29054 : continue;
1338 : }
1339 :
1340 240767 : sal_uInt32 nFeature = pIFace->GetChildWindowFeature(nNo);
1341 240767 : if ( nFeature && !pShell->HasUIFeature( nFeature ) )
1342 28854 : continue;
1343 :
1344 : // slot decides whether a ChildWindow is shown when document is OLE server or OLE client
1345 211913 : sal_uInt16 nMode = SFX_VISIBILITY_STANDARD;
1346 211913 : if( pSlot )
1347 : {
1348 211232 : if ( pSlot->IsMode(SfxSlotMode::CONTAINER) )
1349 : {
1350 20607 : if ( pWorkWin->IsVisible_Impl( SFX_VISIBILITY_CLIENT ) )
1351 20607 : nMode |= SFX_VISIBILITY_CLIENT;
1352 : }
1353 : else
1354 : {
1355 190625 : if ( pWorkWin->IsVisible_Impl( SFX_VISIBILITY_SERVER ) )
1356 190625 : nMode |= SFX_VISIBILITY_SERVER;
1357 : }
1358 : }
1359 :
1360 211913 : if ( bUIActive || bIsActive )
1361 211913 : pWorkWin->SetChildWindowVisible_Impl( nId, true, nMode );
1362 211913 : if ( bUIActive || bIsActive || !pWorkWin->IsFloating( (sal_uInt16) ( nId & 0xFFFF ) ) )
1363 211913 : xImp->aChildWins.push_back( nId );
1364 : }
1365 :
1366 47011 : if ( bIsMDIApp || bIsIPOwner )
1367 : {
1368 47011 : sal_uInt32 nId = pIFace->GetStatusBarResId().GetId();
1369 47011 : if ( nId )
1370 : {
1371 13766 : nStatBarId = nId;
1372 13766 : pStatusBarShell = pShell;
1373 : }
1374 : }
1375 : }
1376 :
1377 96362 : for ( sal_uInt16 nPos=0; nPos<SFX_OBJECTBAR_MAX; nPos++ )
1378 : {
1379 89479 : SfxObjectBars_Impl& rFixed = xImp->aFixedObjBars[nPos];
1380 89479 : if ( rFixed.nResId )
1381 : {
1382 0 : SfxObjectBars_Impl& rBar = xImp->aObjBars[nPos];
1383 0 : rBar = rFixed;
1384 : pWorkWin->SetObjectBar_Impl(rFixed.nMode,
1385 0 : rFixed.nResId, rFixed.pIFace);
1386 : }
1387 : }
1388 :
1389 6883 : if ( pTaskWin && ( bIsMDIApp || bIsIPOwner ) )
1390 : {
1391 6883 : bool bIsTaskActive = false;
1392 :
1393 6883 : SfxDispatcher *pActDispatcher = pTaskWin->GetBindings().GetDispatcher_Impl();
1394 6883 : SfxDispatcher *pDispatcher = this;
1395 20649 : while ( pActDispatcher && !bIsTaskActive )
1396 : {
1397 6883 : if ( pDispatcher == pActDispatcher )
1398 6883 : bIsTaskActive = true;
1399 6883 : pActDispatcher = pActDispatcher->xImp->pParent;
1400 : }
1401 :
1402 6883 : if ( bIsTaskActive && nStatBarId && xImp->pFrame )
1403 : {
1404 : // internal frames also may control statusbar
1405 6883 : SfxBindings& rBindings = xImp->pFrame->GetBindings();
1406 6883 : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->SetStatusBar_Impl( nStatBarId, pStatusBarShell, rBindings );
1407 : }
1408 : }
1409 : }
1410 :
1411 : /** Helper method to execute the outstanding push and pop commands.
1412 : */
1413 16716 : void SfxDispatcher::FlushImpl()
1414 : {
1415 : SFX_STACK(SfxDispatcher::FlushImpl);
1416 :
1417 : OSL_TRACE("Flushing dispatcher!");
1418 :
1419 16716 : xImp->aIdle.Stop();
1420 :
1421 16716 : if ( xImp->pParent )
1422 0 : xImp->pParent->Flush();
1423 :
1424 16716 : xImp->bFlushing = !xImp->bFlushing;
1425 16716 : if ( !xImp->bFlushing )
1426 : {
1427 0 : xImp->bFlushing = true;
1428 16716 : return;
1429 : }
1430 :
1431 16716 : SfxApplication *pSfxApp = SfxGetpApp();
1432 :
1433 : // Re-build the true stack in the first round
1434 16716 : std::deque<SfxToDo_Impl> aToDoCopy;
1435 16716 : bool bModify = false;
1436 52947 : for(std::deque<SfxToDo_Impl>::reverse_iterator i = xImp->aToDoStack.rbegin(); i != xImp->aToDoStack.rend(); ++i)
1437 : {
1438 36231 : bModify = true;
1439 :
1440 36231 : if(i->bPush)
1441 : {
1442 : // Actually push
1443 : DBG_ASSERT( std::find(xImp->aStack.begin(), xImp->aStack.end(), i->pCluster) == xImp->aStack.end(),
1444 : "pushed SfxShell already on stack" );
1445 26430 : xImp->aStack.push_back(i->pCluster);
1446 26430 : i->pCluster->SetDisableFlags(xImp->nDisableFlags);
1447 :
1448 : // Mark the moved shell
1449 26430 : aToDoCopy.push_front(*i);
1450 : }
1451 : else
1452 : {
1453 : // Actually pop
1454 9801 : SfxShell* pPopped = 0;
1455 9801 : bool bFound = false;
1456 15989 : do
1457 : {
1458 : DBG_ASSERT( !xImp->aStack.empty(), "popping from empty stack" );
1459 15989 : pPopped = xImp->aStack.back();
1460 15989 : xImp->aStack.pop_back();
1461 15989 : pPopped->SetDisableFlags( 0 );
1462 15989 : bFound = (pPopped == i->pCluster);
1463 :
1464 : // Mark the moved Shell
1465 15989 : aToDoCopy.push_front(SfxToDo_Impl(false, i->bDelete, false, *pPopped));
1466 : }
1467 15989 : while(i->bUntil && !bFound);
1468 : DBG_ASSERT( bFound, "wrong SfxShell popped" );
1469 : }
1470 : }
1471 16716 : xImp->aToDoStack.clear();
1472 :
1473 : // Invalidate bindings, if possible
1474 16716 : if ( !pSfxApp->IsDowning() )
1475 : {
1476 16716 : if ( bModify )
1477 : {
1478 16716 : xImp->pCachedServ1 = 0;
1479 16716 : xImp->pCachedServ2 = 0;
1480 : }
1481 :
1482 16716 : InvalidateBindings_Impl( bModify );
1483 : }
1484 :
1485 16716 : xImp->bFlushing = false;
1486 16716 : xImp->bUpdated = false; // not only when bModify, if Doc/Template-Config
1487 16716 : xImp->bFlushed = true;
1488 : OSL_TRACE("Successfully flushed dispatcher!");
1489 :
1490 : //fdo#70703 FlushImpl may call back into itself so use aToDoCopyStack to talk
1491 : //to outer levels of ourself. If DoActivate_Impl/DoDeactivate_Impl deletes
1492 : //an entry, then they will walk back up aToDoCopyStack and set outer
1493 : //levels's entries to bDeleted
1494 16716 : xImp->aToDoCopyStack.push_back(aToDoCopy);
1495 16716 : std::deque<SfxToDo_Impl>& rToDoCopy = xImp->aToDoCopyStack.back();
1496 : // Activate the Shells and possible delete them in the 2nd round
1497 59135 : for(std::deque<SfxToDo_Impl>::reverse_iterator i = rToDoCopy.rbegin(); i != rToDoCopy.rend(); ++i)
1498 : {
1499 42419 : if (i->bDeleted)
1500 0 : continue;
1501 42419 : if (!xImp->bActive)
1502 33890 : continue;
1503 8529 : if (i->bPush)
1504 8281 : i->pCluster->DoActivate_Impl(xImp->pFrame, true);
1505 : else
1506 248 : i->pCluster->DoDeactivate_Impl(xImp->pFrame, true);
1507 : }
1508 :
1509 16716 : aToDoCopy = xImp->aToDoCopyStack.back();
1510 16716 : xImp->aToDoCopyStack.pop_back();
1511 :
1512 59135 : for(std::deque<SfxToDo_Impl>::reverse_iterator i = aToDoCopy.rbegin(); i != aToDoCopy.rend(); ++i)
1513 : {
1514 42419 : if (i->bDelete && !i->bDeleted)
1515 : {
1516 8635 : if (!xImp->aToDoCopyStack.empty())
1517 : {
1518 : //fdo#70703 if there is an outer FlushImpl then inform it that
1519 : //we have deleted this cluster
1520 0 : for (std::deque< std::deque<SfxToDo_Impl> >::iterator aI = xImp->aToDoCopyStack.begin();
1521 0 : aI != xImp->aToDoCopyStack.end(); ++aI)
1522 : {
1523 0 : std::deque<SfxToDo_Impl> &v = *aI;
1524 0 : for(std::deque<SfxToDo_Impl>::iterator aJ = v.begin(); aJ != v.end(); ++aJ)
1525 : {
1526 0 : if (aJ->pCluster == i->pCluster)
1527 0 : aJ->bDeleted = true;
1528 : }
1529 : }
1530 : }
1531 8635 : delete i->pCluster;
1532 : }
1533 : }
1534 16716 : bool bAwakeBindings = !aToDoCopy.empty();
1535 16716 : if( bAwakeBindings )
1536 16716 : aToDoCopy.clear();
1537 :
1538 : // If more changes have occurred on the stach when
1539 : // Activate/Deactivate/Delete:
1540 16716 : if (!xImp->bFlushed)
1541 : // If Push/Pop hs been called by someone, theb also EnterReg was called!
1542 0 : FlushImpl();
1543 :
1544 16716 : if( bAwakeBindings && GetBindings() )
1545 16389 : GetBindings()->DLEAVEREGISTRATIONS();
1546 :
1547 234024 : for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++)
1548 217308 : xImp->aFixedObjBars[n].nResId = 0;
1549 :
1550 16716 : SAL_INFO("sfx.control", "SfxDispatcher(" << this << ")::Flush() done");
1551 : }
1552 :
1553 : /** With this method a filter set, the target slots can be enabled or disabled.
1554 : The passed array must be retained until the destructor or the next
1555 : <SetSlotFilter()>, it is not deleted from the dispatcher, so it can thus be
1556 : static.
1557 :
1558 : In read-only documents the quasi ReadOnlyDoc Flag of slots can be
1559 : overturned by the use of 'bEnable == 2', so this will be displayed again.
1560 : On the other slots it has no effect.
1561 :
1562 : // HACK(hier muss mal ein enum rein) ???
1563 : @param nEnable 1==true: only enable specified slots, disable all other
1564 : 0==false: disable specified slots, first enable all other
1565 : @param nCount Number of SIDs in the following Array
1566 : @param pSIDs sorted Array of 'nCount' SIDs
1567 :
1568 : [Example]
1569 :
1570 : Targeted disabling of Slots 1, 2 and 3:
1571 :
1572 : static sal_uInt16 const pSIDs[] = { 1, 2, 3 };
1573 : pDisp->SetSlotFilter( sal_False, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );
1574 :
1575 : only permit Slots 5, 6 and 7:
1576 :
1577 : static sal_uInt16 const pSIDs[] = { 5, 6, 7 };
1578 : pDisp->SetSlotFilter( sal_True, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );
1579 :
1580 : Turn-off Filter:
1581 :
1582 : pDisp->SetSlotFilter();
1583 : */
1584 120 : void SfxDispatcher::SetSlotFilter(SfxSlotFilterState nEnable,
1585 : sal_uInt16 nCount, const sal_uInt16* pSIDs)
1586 : {
1587 : #ifdef DBG_UTIL
1588 : // Check Array
1589 : for ( sal_uInt16 n = 1; n < nCount; ++n )
1590 : DBG_ASSERT( pSIDs[n] > pSIDs[n-1], "SetSlotFilter: SIDs not sorted" );
1591 : #endif
1592 :
1593 120 : if ( xImp->pFilterSIDs )
1594 0 : xImp->pFilterSIDs = 0;
1595 :
1596 120 : xImp->nFilterEnabling = nEnable;
1597 120 : xImp->nFilterCount = nCount;
1598 120 : xImp->pFilterSIDs = pSIDs;
1599 :
1600 120 : GetBindings()->InvalidateAll(true);
1601 120 : }
1602 :
1603 0 : extern "C" int SAL_CALL SfxCompareSIDs_Impl(const void* pSmaller, const void* pBigger)
1604 : {
1605 0 : return ( (long) *static_cast<sal_uInt16 const *>(pSmaller) ) - ( (long) *static_cast<sal_uInt16 const *>(pBigger) );
1606 : }
1607 :
1608 : /** Searches for 'nSID' in the Filter set by <SetSlotFilter()> and
1609 : returns sal_True, if the SIDis allowed, or sal_False, if it is
1610 : disabled by the Filter.
1611 :
1612 : @return 0 => disabled
1613 : 1 => enabled
1614 : 2 => enabled even if ReadOnlyDoc
1615 : */
1616 177278 : SfxSlotFilterState SfxDispatcher::IsSlotEnabledByFilter_Impl( sal_uInt16 nSID ) const
1617 : {
1618 : // no filter?
1619 177278 : if ( 0 == xImp->nFilterCount )
1620 : // => all SIDs allowed
1621 177278 : return SfxSlotFilterState::ENABLED;
1622 :
1623 : // search
1624 0 : bool bFound = 0 != bsearch( &nSID, xImp->pFilterSIDs, xImp->nFilterCount,
1625 0 : sizeof(sal_uInt16), SfxCompareSIDs_Impl );
1626 :
1627 : // even if ReadOnlyDoc
1628 0 : if ( SfxSlotFilterState::ENABLED_READONLY == xImp->nFilterEnabling )
1629 0 : return bFound ? SfxSlotFilterState::ENABLED_READONLY : SfxSlotFilterState::ENABLED;
1630 : // Otherwise after Negative/Positive Filter
1631 0 : else if ( SfxSlotFilterState::ENABLED == xImp->nFilterEnabling )
1632 0 : return bFound ? SfxSlotFilterState::ENABLED : SfxSlotFilterState::DISABLED;
1633 : else
1634 0 : return bFound ? SfxSlotFilterState::DISABLED : SfxSlotFilterState::ENABLED;
1635 : }
1636 :
1637 : /** This helper method searches for the <Slot-Server> which currently serves
1638 : the nSlot. As the result, rServe is filled accordingly.
1639 :
1640 : If known the SfxInterface which is currently served by nSlot can be
1641 : passed along.
1642 :
1643 : The SfxDispatcher is flushed while searching for nSlot.
1644 :
1645 : @param nSlot Slot-Id to search for
1646 : @param rServer <SfxSlotServer>-Instance to fill
1647 : @param bModal Despite ModalMode
1648 :
1649 : @return true
1650 : The Slot was found, rServer is valid.
1651 :
1652 : false
1653 : The Slot is currently not served, rServer is invalid.
1654 : */
1655 177361 : bool SfxDispatcher::_FindServer(sal_uInt16 nSlot, SfxSlotServer& rServer, bool bModal)
1656 : {
1657 : SFX_STACK(SfxDispatcher::_FindServer);
1658 :
1659 : // Dispatcher locked? (nevertheless let SID_HELP_PI through)
1660 177361 : if ( IsLocked(nSlot) )
1661 : {
1662 16 : xImp->bInvalidateOnUnlock = true;
1663 16 : return false;
1664 : }
1665 :
1666 : // Count the number of Shells in the linked dispatchers.
1667 177345 : Flush();
1668 177345 : sal_uInt16 nTotCount = xImp->aStack.size();
1669 177345 : if ( xImp->pParent )
1670 : {
1671 0 : SfxDispatcher *pParent = xImp->pParent;
1672 0 : while ( pParent )
1673 : {
1674 0 : nTotCount = nTotCount + pParent->xImp->aStack.size();
1675 0 : pParent = pParent->xImp->pParent;
1676 : }
1677 : }
1678 :
1679 : // Verb-Slot?
1680 177345 : if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END)
1681 : {
1682 0 : for ( sal_uInt16 nShell = 0;; ++nShell )
1683 : {
1684 0 : SfxShell *pSh = GetShell(nShell);
1685 0 : if ( pSh == NULL )
1686 0 : return false;
1687 0 : if ( pSh->ISA(SfxViewShell) )
1688 : {
1689 0 : const SfxSlot* pSlot = pSh->GetVerbSlot_Impl(nSlot);
1690 0 : if ( pSlot )
1691 : {
1692 0 : rServer.SetShellLevel(nShell);
1693 0 : rServer.SetSlot( pSlot );
1694 0 : return true;
1695 : }
1696 : }
1697 0 : }
1698 : }
1699 :
1700 : // SID check against set filter
1701 177345 : SfxSlotFilterState nSlotEnableMode = SfxSlotFilterState::DISABLED;
1702 177345 : if ( xImp->pFrame )
1703 : {
1704 177278 : nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot );
1705 177278 : if ( SfxSlotFilterState::DISABLED == nSlotEnableMode )
1706 0 : return false;
1707 : }
1708 :
1709 : // In Quiet-Mode only Parent-Dispatcher
1710 177345 : if ( xImp->bQuiet )
1711 : {
1712 0 : if ( xImp->pParent )
1713 : {
1714 0 : bool bRet = xImp->pParent->_FindServer( nSlot, rServer, bModal );
1715 : rServer.SetShellLevel
1716 0 : ( rServer.GetShellLevel() + xImp->aStack.size() );
1717 0 : return bRet;
1718 : }
1719 : else
1720 0 : return false;
1721 : }
1722 :
1723 177345 : bool bReadOnly = ( SfxSlotFilterState::ENABLED_READONLY != nSlotEnableMode && xImp->bReadOnly );
1724 :
1725 : // search through all the shells of the chained dispatchers
1726 : // from top to bottom
1727 177345 : sal_uInt16 nFirstShell = xImp->bModal && !bModal ? xImp->aStack.size() : 0;
1728 430671 : for ( sal_uInt16 i = nFirstShell; i < nTotCount; ++i )
1729 : {
1730 425312 : SfxShell *pObjShell = GetShell(i);
1731 425312 : SfxInterface *pIFace = pObjShell->GetInterface();
1732 425312 : const SfxSlot *pSlot = pIFace->GetSlot(nSlot);
1733 :
1734 425312 : if ( pSlot && pSlot->nDisableFlags && ( pSlot->nDisableFlags & pObjShell->GetDisableFlags() ) != 0 )
1735 0 : return false;
1736 :
1737 425312 : if ( pSlot && !( pSlot->nFlags & SfxSlotMode::READONLYDOC ) && bReadOnly )
1738 112 : return false;
1739 :
1740 425200 : if ( pSlot )
1741 : {
1742 : // Slot belongs to Container?
1743 171874 : bool bIsContainerSlot = pSlot->IsMode(SfxSlotMode::CONTAINER);
1744 171874 : bool bIsInPlace = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1745 :
1746 : // Shell belongs to Server?
1747 : // AppDispatcher or IPFrame-Dispatcher
1748 171874 : bool bIsServerShell = !xImp->pFrame || bIsInPlace;
1749 :
1750 : // Of course ShellServer-Slots are also executable even when it is
1751 : // executed on a container dispatcher without a IPClient.
1752 171874 : if ( !bIsServerShell )
1753 : {
1754 171807 : SfxViewShell *pViewSh = xImp->pFrame->GetViewShell();
1755 171807 : bIsServerShell = !pViewSh || !pViewSh->GetUIActiveClient();
1756 : }
1757 :
1758 : // Shell belongs to Container?
1759 : // AppDispatcher or no IPFrameDispatcher
1760 171874 : bool bIsContainerShell = !xImp->pFrame || !bIsInPlace;
1761 : // Shell and Slot match
1762 171874 : if ( !( ( bIsContainerSlot && bIsContainerShell ) ||
1763 159291 : ( !bIsContainerSlot && bIsServerShell ) ) )
1764 0 : pSlot = 0;
1765 : }
1766 :
1767 425200 : if ( pSlot )
1768 : {
1769 171874 : rServer.SetSlot(pSlot);
1770 171874 : rServer.SetShellLevel(i);
1771 171874 : return true;
1772 : }
1773 : }
1774 :
1775 5359 : return false;
1776 : }
1777 :
1778 : /** Helper method to obtain the status of the <Slot-Server>s rSvr.
1779 : The required slots IDs (partly converted to Which-IDs of the pool)
1780 : must be present in rstate.
1781 :
1782 : The SfxDispatcher is flushed before the query.
1783 :
1784 : @param rSvr Slot-Server to query
1785 : @param rState SfxItemSet to be filled
1786 : @param pRealSlot The actual Slot if possible
1787 : */
1788 23916 : bool SfxDispatcher::_FillState(const SfxSlotServer& rSvr, SfxItemSet& rState,
1789 : const SfxSlot* pRealSlot)
1790 : {
1791 : SFX_STACK(SfxDispatcher::_FillState);
1792 :
1793 23916 : const SfxSlot *pSlot = rSvr.GetSlot();
1794 23916 : if ( pSlot && IsLocked( pSlot->GetSlotId() ) )
1795 : {
1796 0 : xImp->bInvalidateOnUnlock = true;
1797 0 : return false;
1798 : }
1799 :
1800 23916 : if ( pSlot )
1801 : {
1802 : DBG_ASSERT(xImp->bFlushed,
1803 : "Dispatcher not flushed after retrieving slot servers!");
1804 23916 : if (!xImp->bFlushed)
1805 0 : return false;
1806 :
1807 : // Determine the object and call the Message of this object
1808 23916 : SfxShell *pSh = GetShell(rSvr.GetShellLevel());
1809 : DBG_ASSERT(pSh, "ObjectShell not found");
1810 :
1811 : SfxStateFunc pFunc;
1812 :
1813 23916 : if (pRealSlot)
1814 23916 : pFunc = pRealSlot->GetStateFnc();
1815 : else
1816 0 : pFunc = pSlot->GetStateFnc();
1817 :
1818 23916 : pSh->CallState( pFunc, rState );
1819 : #ifdef DBG_UTIL
1820 : // To examine the conformity of IDL (SlotMap) and current Items
1821 : if ( rState.Count() )
1822 : {
1823 : SfxInterface *pIF = pSh->GetInterface();
1824 : SfxItemIter aIter( rState );
1825 : for ( const SfxPoolItem *pItem = aIter.FirstItem();
1826 : pItem;
1827 : pItem = aIter.NextItem() )
1828 : {
1829 : if ( !IsInvalidItem(pItem) && !pItem->ISA(SfxVoidItem) )
1830 : {
1831 : sal_uInt16 nSlotId = rState.GetPool()->GetSlotId(pItem->Which());
1832 : SAL_INFO_IF(
1833 : !pItem->IsA(pIF->GetSlot(nSlotId)->GetType()->Type()),
1834 : "sfx.control",
1835 : "item-type unequal to IDL (=> no BASIC) with SID: "
1836 : << nSlotId << " in " << pIF->GetClassName());
1837 : }
1838 : }
1839 : }
1840 : #endif
1841 :
1842 23916 : return true;
1843 : }
1844 :
1845 0 : return false;
1846 : }
1847 :
1848 0 : SfxPopupMenuManager* SfxDispatcher::Popup( sal_uInt16 nConfigId, vcl::Window *pWin, const Point *pPos )
1849 : {
1850 0 : SfxDispatcher &rDisp = *SfxGetpApp()->GetDispatcher_Impl();
1851 0 : sal_uInt16 nShLevel = 0;
1852 : SfxShell *pSh;
1853 :
1854 0 : if ( rDisp.xImp->bQuiet )
1855 : {
1856 0 : nConfigId = 0;
1857 0 : nShLevel = rDisp.xImp->aStack.size();
1858 : }
1859 :
1860 0 : vcl::Window *pWindow = pWin ? pWin : rDisp.xImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
1861 0 : for ( pSh = rDisp.GetShell(nShLevel); pSh; ++nShLevel, pSh = rDisp.GetShell(nShLevel) )
1862 : {
1863 0 : const ResId& rResId = pSh->GetInterface()->GetPopupMenuResId();
1864 0 : if ( ( nConfigId == 0 && rResId.GetId() ) || ( nConfigId != 0 && rResId.GetId() == nConfigId ) )
1865 : {
1866 0 : return SfxPopupMenuManager::Popup( rResId, rDisp.GetFrame(), pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow );
1867 : }
1868 : }
1869 0 : return 0;
1870 : }
1871 :
1872 0 : void SfxDispatcher::ExecutePopup( sal_uInt16 nConfigId, vcl::Window *pWin, const Point *pPos )
1873 : {
1874 0 : SfxDispatcher &rDisp = *SfxGetpApp()->GetDispatcher_Impl();
1875 0 : sal_uInt16 nShLevel = 0;
1876 : SfxShell *pSh;
1877 :
1878 0 : if ( rDisp.xImp->bQuiet )
1879 : {
1880 0 : nConfigId = 0;
1881 0 : nShLevel = rDisp.xImp->aStack.size();
1882 : }
1883 :
1884 0 : vcl::Window *pWindow = pWin ? pWin : rDisp.xImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
1885 0 : for ( pSh = rDisp.GetShell(nShLevel); pSh; ++nShLevel, pSh = rDisp.GetShell(nShLevel) )
1886 : {
1887 0 : const ResId& rResId = pSh->GetInterface()->GetPopupMenuResId();
1888 0 : if ( ( nConfigId == 0 && rResId.GetId() ) || ( nConfigId != 0 && rResId.GetId() == nConfigId ) )
1889 : {
1890 0 : SfxPopupMenuManager::ExecutePopup( rResId, rDisp.GetFrame(), pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow );
1891 0 : return;
1892 : }
1893 : }
1894 : }
1895 :
1896 0 : void SfxDispatcher::ExecutePopup( const ResId &rId, vcl::Window *pWin, const Point *pPos )
1897 : {
1898 0 : vcl::Window *pWindow = pWin ? pWin : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
1899 0 : SfxPopupMenuManager::ExecutePopup( rId, GetFrame(), pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow );
1900 0 : }
1901 :
1902 : /** With this method the SfxDispatcher can be locked and released. A locked
1903 : SfxDispatcher does not perform <SfxRequest>s and does no longer provide
1904 : status information. It behaves as if all the slots were disabled.
1905 : */
1906 12438 : void SfxDispatcher::Lock( bool bLock )
1907 : {
1908 12438 : SfxBindings* pBindings = GetBindings();
1909 12438 : if ( !bLock && xImp->bLocked && xImp->bInvalidateOnUnlock )
1910 : {
1911 1 : if ( pBindings )
1912 1 : pBindings->InvalidateAll(true);
1913 1 : xImp->bInvalidateOnUnlock = false;
1914 : }
1915 12437 : else if ( pBindings )
1916 12437 : pBindings->InvalidateAll(false);
1917 12438 : xImp->bLocked = bLock;
1918 12438 : if ( !bLock )
1919 : {
1920 6229 : for(size_t i = 0; i < xImp->aReqArr.size(); ++i)
1921 0 : xImp->xPoster->Post(xImp->aReqArr[i]);
1922 6229 : xImp->aReqArr.clear();
1923 : }
1924 12438 : }
1925 :
1926 24 : sal_uInt32 SfxDispatcher::GetObjectBarId( sal_uInt16 nPos ) const
1927 : {
1928 24 : return xImp->aObjBars[nPos].nResId;
1929 : }
1930 :
1931 3163 : void SfxDispatcher::HideUI( bool bHide )
1932 : {
1933 3163 : bool bWasHidden = xImp->bNoUI;
1934 3163 : xImp->bNoUI = bHide;
1935 3163 : if ( xImp->pFrame )
1936 : {
1937 3163 : SfxViewFrame* pTop = xImp->pFrame->GetTopViewFrame();
1938 3163 : if ( pTop && pTop->GetBindings().GetDispatcher() == this )
1939 : {
1940 3163 : SfxFrame& rFrame = pTop->GetFrame();
1941 3163 : if ( rFrame.IsMenuBarOn_Impl() )
1942 : {
1943 3163 : com::sun::star::uno::Reference < com::sun::star::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), com::sun::star::uno::UNO_QUERY );
1944 3163 : if ( xPropSet.is() )
1945 : {
1946 3163 : com::sun::star::uno::Reference< ::com::sun::star::frame::XLayoutManager > xLayoutManager;
1947 6326 : com::sun::star::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
1948 3163 : aValue >>= xLayoutManager;
1949 3163 : if ( xLayoutManager.is() )
1950 6326 : xLayoutManager->setVisible( !bHide );
1951 3163 : }
1952 : }
1953 : }
1954 : }
1955 :
1956 3163 : if ( bHide != bWasHidden )
1957 0 : Update_Impl( true );
1958 3163 : }
1959 :
1960 3250 : void SfxDispatcher::SetReadOnly_Impl( bool bOn )
1961 : {
1962 3250 : xImp->bReadOnly = bOn;
1963 3250 : }
1964 :
1965 38 : bool SfxDispatcher::GetReadOnly_Impl() const
1966 : {
1967 38 : return xImp->bReadOnly;
1968 : }
1969 :
1970 : /** With 'bOn' the Dispatcher is quasi dead and transfers everything to the
1971 : Parent-Dispatcher.
1972 : */
1973 0 : void SfxDispatcher::SetQuietMode_Impl( bool bOn )
1974 : {
1975 0 : xImp->bQuiet = bOn;
1976 0 : SfxBindings* pBindings = GetBindings();
1977 0 : if ( pBindings )
1978 0 : pBindings->InvalidateAll(true);
1979 0 : }
1980 :
1981 5126 : SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSlot, const SfxPoolItem* &rpState )
1982 : {
1983 5126 : SfxShell *pShell = 0;
1984 5126 : const SfxSlot *pSlot = 0;
1985 5126 : if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, false ) )
1986 : {
1987 5109 : rpState = pShell->GetSlotState(nSlot);
1988 5109 : if ( !rpState )
1989 1 : return SfxItemState::DISABLED;
1990 : else
1991 5108 : return SfxItemState::DEFAULT;
1992 : }
1993 :
1994 17 : return SfxItemState::DISABLED;
1995 : }
1996 :
1997 91373 : SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSID, ::com::sun::star::uno::Any& rAny )
1998 : {
1999 91373 : SfxShell *pShell = 0;
2000 91373 : const SfxSlot *pSlot = 0;
2001 91373 : if ( GetShellAndSlot_Impl( nSID, &pShell, &pSlot, false, false ) )
2002 : {
2003 88480 : const SfxPoolItem* pItem( 0 );
2004 :
2005 88480 : pItem = pShell->GetSlotState( nSID );
2006 88480 : if ( !pItem )
2007 7686 : return SfxItemState::DISABLED;
2008 : else
2009 : {
2010 80794 : ::com::sun::star::uno::Any aState;
2011 80794 : if ( !pItem->ISA(SfxVoidItem) )
2012 : {
2013 51421 : sal_uInt16 nSubId( 0 );
2014 51421 : SfxItemPool& rPool = pShell->GetPool();
2015 51421 : sal_uInt16 nWhich = rPool.GetWhich( nSID );
2016 51421 : if ( rPool.GetMetric( nWhich ) == SFX_MAPUNIT_TWIP )
2017 40288 : nSubId |= CONVERT_TWIPS;
2018 51421 : pItem->QueryValue( aState, (sal_uInt8)nSubId );
2019 : }
2020 80794 : rAny = aState;
2021 :
2022 80794 : return SfxItemState::DEFAULT;
2023 : }
2024 : }
2025 :
2026 2893 : return SfxItemState::DISABLED;
2027 : }
2028 :
2029 47011 : bool SfxDispatcher::IsReadOnlyShell_Impl( sal_uInt16 nShell ) const
2030 : {
2031 47011 : sal_uInt16 nShellCount = xImp->aStack.size();
2032 47011 : if ( nShell < nShellCount )
2033 : {
2034 47011 : SfxShell* pShell = *( xImp->aStack.rbegin() + nShell );
2035 47011 : if( pShell->ISA( SfxModule ) || pShell->ISA( SfxApplication ) || pShell->ISA( SfxViewFrame ) )
2036 20649 : return false;
2037 : else
2038 26362 : return xImp->bReadOnly;
2039 : }
2040 0 : else if ( xImp->pParent )
2041 0 : return xImp->pParent->IsReadOnlyShell_Impl( nShell - nShellCount );
2042 0 : return true;
2043 : }
2044 :
2045 3813 : void SfxDispatcher::RemoveShell_Impl( SfxShell& rShell )
2046 : {
2047 3813 : Flush();
2048 :
2049 3813 : sal_uInt16 nCount = xImp->aStack.size();
2050 10694 : for ( sal_uInt16 n=0; n<nCount; ++n )
2051 : {
2052 10694 : if ( xImp->aStack[n] == &rShell )
2053 : {
2054 3813 : xImp->aStack.erase( xImp->aStack.begin() + n );
2055 3813 : rShell.SetDisableFlags( 0 );
2056 3813 : rShell.DoDeactivate_Impl(xImp->pFrame, true);
2057 3813 : break;
2058 : }
2059 : }
2060 :
2061 3813 : if ( !SfxGetpApp()->IsDowning() )
2062 : {
2063 3813 : xImp->bUpdated = false;
2064 3813 : xImp->pCachedServ1 = 0;
2065 3813 : xImp->pCachedServ2 = 0;
2066 3813 : InvalidateBindings_Impl(true);
2067 : }
2068 3813 : }
2069 :
2070 20529 : void SfxDispatcher::InvalidateBindings_Impl( bool bModify )
2071 : {
2072 : // App-Dispatcher?
2073 20529 : if ( IsAppDispatcher() )
2074 : {
2075 327 : for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst();
2076 : pFrame;
2077 : pFrame = SfxViewFrame::GetNext( *pFrame ) )
2078 0 : pFrame->GetBindings().InvalidateAll(bModify);
2079 : }
2080 : else
2081 : {
2082 20202 : SfxDispatcher *pDisp = GetBindings()->GetDispatcher_Impl();
2083 40404 : while ( pDisp )
2084 : {
2085 20202 : if ( pDisp == this )
2086 : {
2087 20202 : GetBindings()->InvalidateAll( bModify );
2088 20202 : break;
2089 : }
2090 :
2091 0 : pDisp = pDisp->xImp->pParent;
2092 : }
2093 : }
2094 20529 : }
2095 :
2096 0 : bool SfxDispatcher::IsUpdated_Impl() const
2097 : {
2098 0 : return xImp->bUpdated;
2099 : }
2100 :
2101 6520 : void SfxDispatcher::SetDisableFlags( sal_uInt32 nFlags )
2102 : {
2103 6520 : xImp->nDisableFlags = nFlags;
2104 26132 : for ( SfxShellStack_Impl::reverse_iterator it = xImp->aStack.rbegin(); it != xImp->aStack.rend(); ++it )
2105 19612 : (*it)->SetDisableFlags( nFlags );
2106 6520 : }
2107 :
2108 24332 : sal_uInt32 SfxDispatcher::GetDisableFlags() const
2109 : {
2110 24332 : return xImp->nDisableFlags;
2111 : }
2112 :
2113 0 : SfxModule* SfxDispatcher::GetModule() const
2114 : {
2115 0 : for ( sal_uInt16 nShell = 0;; ++nShell )
2116 : {
2117 0 : SfxShell *pSh = GetShell(nShell);
2118 0 : if ( pSh == NULL )
2119 0 : return 0;
2120 0 : if ( pSh->ISA(SfxModule) )
2121 0 : return static_cast<SfxModule*>(pSh);
2122 0 : }
2123 648 : }
2124 :
2125 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|