xref: /trunk/main/sfx2/source/control/shell.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 #include <com/sun/star/embed/VerbDescriptor.hpp>
31 #include <com/sun/star/embed/VerbAttributes.hpp>
32 #include <basic/sbstar.hxx>
33 #include <svl/itempool.hxx>
34 #include <svl/undo.hxx>
35 #include <svtools/itemdel.hxx>
36 #include <svtools/asynclink.hxx>
37 #include <basic/sbx.hxx>
38 
39 #include <unotools/undoopt.hxx>
40 
41 #ifndef GCC
42 #endif
43 
44 #include <sfx2/app.hxx>
45 #include <sfx2/shell.hxx>
46 #include <sfx2/bindings.hxx>
47 #include <sfx2/dispatch.hxx>
48 #include <sfx2/viewfrm.hxx>
49 #include <sfx2/objface.hxx>
50 #include <sfx2/objsh.hxx>
51 #include <sfx2/viewsh.hxx>
52 #include <sfx2/dispatch.hxx>
53 #include "sfxtypes.hxx"
54 #include <sfx2/request.hxx>
55 #include <sfx2/mnumgr.hxx>
56 #include "statcach.hxx"
57 #include <sfx2/msgpool.hxx>
58 
59 //====================================================================
60 
61 DBG_NAME(SfxShell)
62 
63 //====================================================================
64 
65 TYPEINIT0(SfxShell);
66 
67 //====================================================================
68 typedef SfxSlot* SfxSlotPtr;
69 SV_DECL_PTRARR_DEL( SfxVerbSlotArr_Impl, SfxSlotPtr, 4, 4)
70 SV_IMPL_PTRARR( SfxVerbSlotArr_Impl, SfxSlotPtr);
71 
72 using namespace com::sun::star;
73 
74 //=========================================================================
75 // SfxShell_Impl
76 //=========================================================================
77 struct SfxShell_Impl: public SfxBroadcaster
78 {
79     String                      aObjectName;// Name des Sbx-Objects
80     SfxItemArray_Impl           aItems;     // Datenaustausch auf Item-Basis
81     SfxViewShell*               pViewSh;    // SfxViewShell falls Shell ViewFrame/ViewShell/SubShell ist
82     SfxViewFrame*               pFrame;     // Frame, falls <UI-aktiv>
83     SfxRepeatTarget*            pRepeatTarget;
84 //    SbxObjectRef                xParent;
85     sal_Bool                        bInAppBASIC;
86     sal_Bool                        bActive;
87     sal_uIntPtr                     nDisableFlags;
88     sal_uIntPtr                       nHelpId;
89     svtools::AsynchronLink*     pExecuter;
90     svtools::AsynchronLink*     pUpdater;
91     SfxVerbSlotArr_Impl         aSlotArr;
92     com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > aVerbList;
93     SfxShell_Impl()  : pExecuter( 0 ), pUpdater( 0 ) {}
94     ~SfxShell_Impl() { delete pExecuter; delete pUpdater;}
95 };
96 
97 //====================================================================
98 #ifdef DBG_UTIL
99 
100 String SfxShellIdent_Impl( const SfxShell *pSh )
101 
102 /*  [Beschreibung]
103 
104     Interne Hilfesfunktion. Liefert einen die SfxShell 'pSh' beschreibenden
105     String zur"uck. Z.B.: SfxApplication[StarWriter]
106 */
107 
108 {
109     String aIdent( pSh->ISA(SfxApplication) ? DEFINE_CONST_UNICODE("SfxApplication") :
110                    pSh->ISA(SfxViewFrame) ? DEFINE_CONST_UNICODE("SfxViewFrame") :
111                    pSh->ISA(SfxViewShell) ? DEFINE_CONST_UNICODE("SfxViewShell") :
112                    pSh->ISA(SfxObjectShell) ? DEFINE_CONST_UNICODE("SfxObjectShell") : DEFINE_CONST_UNICODE("SfxShell") );
113     aIdent += '[';
114     aIdent += pSh->GetName();
115     aIdent += ']';
116     return aIdent;
117 }
118 
119 #endif
120 //====================================================================
121 
122 //=========================================================================
123 // SfxShell
124 //=========================================================================
125 
126 void __EXPORT SfxShell::EmptyExecStub(SfxShell *, SfxRequest &)
127 {
128 }
129 
130 void __EXPORT SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &)
131 {
132 }
133 
134 SfxShell::SfxShell()
135 
136 /*  [Beschreibung]
137 
138     Der Konstruktor der Klasse SfxShell initialisierung nur einfache
139     Typen, das dazugeh"orige SbxObject wird erst on-demand erzeugt.
140     Daher ist das Anlegen einer SfxShell Instanz sehr billig.
141 */
142 
143 :   pImp(0),
144     pPool(0),
145     pUndoMgr(0)
146 {
147     DBG_CTOR(SfxShell, 0);
148     pImp = new SfxShell_Impl;
149     pImp->pViewSh = 0;
150     pImp->pFrame = 0;
151     pImp->pRepeatTarget = 0;
152     pImp->bInAppBASIC = sal_False;
153     pImp->nHelpId = 0L;
154     pImp->bActive = sal_False;
155     pImp->nDisableFlags = 0;
156 }
157 
158 //-------------------------------------------------------------------------
159 
160 SfxShell::SfxShell( SfxViewShell *pViewSh )
161 
162 /*  [Beschreibung]
163 
164     Der Konstruktor der Klasse SfxShell initialisierung nur einfache
165     Typen, das dazugeh"orige SbxObject wird erst on-demand erzeugt.
166     Daher ist das Anlegen einer SfxShell Instanz sehr billig.
167 */
168 
169 :   pImp(0),
170     pPool(0),
171     pUndoMgr(0)
172 {
173     DBG_CTOR(SfxShell, 0);
174     pImp = new SfxShell_Impl;
175     pImp->pViewSh = pViewSh;
176     pImp->pFrame = 0;
177     pImp->pRepeatTarget = 0;
178     pImp->bInAppBASIC = sal_False;
179     pImp->nHelpId = 0L;
180     pImp->bActive = sal_False;
181 }
182 
183 //--------------------------------------------------------------------
184 
185 SfxShell::~SfxShell()
186 
187 /*  [Beschreibung]
188 
189     Die Verbindungs zu einem ggf. zugeh"origen SbxObject wird gel"ost.
190     Das SbxObject existiert ggf. weiter, kann aber keine Funktionen
191     mehr ausf"uhren und keine Properties mehr bereitstellen.
192 */
193 
194 {
195     DBG_DTOR(SfxShell, 0);
196     delete pImp;
197 }
198 
199 //--------------------------------------------------------------------
200 
201 void SfxShell::SetName( const String &rName )
202 
203 /*  [Beschreibung]
204 
205     Setzt den Namen des Shell-Objekts. Mit diesem Namen kann die
206     SfxShell-Instanz vom BASIC aus angesprochen werden.
207 */
208 
209 {
210     pImp->aObjectName = rName;
211 }
212 
213 //--------------------------------------------------------------------
214 
215 const String& SfxShell::GetName() const
216 
217 /*  [Beschreibung]
218 
219     Liefert den Namen des Shell-Objekts. Mit diesem Namen kann die
220     SfxShell-Instanz vom BASIC aus angesprochen werden.
221 */
222 
223 {
224     return pImp->aObjectName;
225 }
226 
227 //--------------------------------------------------------------------
228 
229 SvGlobalName SfxShell::GetGlobalName() const
230 
231 /*  [Beschreibung]
232 
233     Liefert den Global Unique Identifier des Shell-Objekts. Mit diesem
234     Namen kann die SfxShell-Instanz z.B. via OLE Automation angesprochen
235     werden, bzw. in der Registration-Database gefunden werden.
236 */
237 
238 {
239     return SvGlobalName();
240 }
241 
242 //--------------------------------------------------------------------
243 
244 SfxDispatcher* SfxShell::GetDispatcher() const
245 
246 /*  [Beschreibung]
247 
248     Diese Methode liefert einen Pointer auf den <SfxDispatcher>, in
249     dem die SfxShell gerade <UI-aktiv> ist bzw. einen 0-Pointer, wenn
250     sie gerade nicht UI-aktiv ist.
251 
252     Der zur"uckgegebene Pointer ist nur im unmittelbaren Kontext des
253     Methodenaufrufs g"ultig.
254 */
255 
256 {
257     return pImp->pFrame ? pImp->pFrame->GetDispatcher() : 0;
258 }
259 
260 //--------------------------------------------------------------------
261 
262 SfxViewShell* SfxShell::GetViewShell() const
263 
264 /*  [Beschreibung]
265 
266     Liefert bei SubShells die SfxViewShell, in der sie liegen. Sonst und
267     falls nicht vom App-Entwickler angegeben liefert diese Methode 0.
268 */
269 
270 {
271     return pImp->pViewSh;
272 }
273 
274 //--------------------------------------------------------------------
275 
276 SfxViewFrame* SfxShell::GetFrame() const
277 
278 /*  [Beschreibung]
279 
280     Diese Methode liefert einen Pointer auf den <SfxViewFrame>, dem diese
281     SfxShell-Instanz zugeordnet ist oder in dem sie zur Zeit <UI-aktiv> ist.
282     Ein 0-Pointer wird geliefert, wenn diese SfxShell-OInstanz gerade nicht
283     UI-aktiv ist und auch keinem SfxViewFrame fest zugeordnet ist.
284 
285     Der zur"uckgegebene Pointer ist nur im unmittelbaren Kontext des
286     Methodenaufrufs g"ultig.
287 
288 
289     [Anmerkung]
290 
291     Nur Instanzen von Subklasse von SfxApplication und SfxObjectShell sollten
292     hier einen 0-Pointer liefern. Ansonsten liegt ein Fehler im Anwendungs-
293     programm vor (falscher Ctor von SfxShell gerufen).
294 
295 
296     [Querverweise]
297 
298     <SfxViewShell::GetViewFrame()const>
299 */
300 
301 {
302     if ( pImp->pFrame )
303         return pImp->pFrame;
304     if ( pImp->pViewSh )
305         return pImp->pViewSh->GetViewFrame();
306     return 0;
307 }
308 
309 //--------------------------------------------------------------------
310 
311 const SfxPoolItem* SfxShell::GetItem
312 (
313     sal_uInt16  nSlotId         // Slot-Id des zu erfragenden <SfxPoolItem>s
314 )   const
315 
316 /*  [Beschreibung]
317 
318     Mit dieser Methode kann auf beliebige Objekte von Subklassen von
319     <SfxPoolItem> zugegriffen werden. Diese Austauschtechnik wird ben"otigt,
320     wenn z.B. spezielle <SfxToolBoxControl> Subklassen Zugriff auf
321     bestimmte Daten z.B. der <SfxObjectShell> ben"otigen.
322 
323     Die zur"uckgelieferte Instanz geh"ort der jeweilige SfxShell und
324     darf nur im unmittelbaren Kontext des Methodenaufrufs verwendet werden.
325 
326 
327     [Querverweise]
328 
329     <SfxShell::PutItem(const SfxPoolItem&)>
330     <SfxShell::RemoveItem(sal_uInt16)>
331 */
332 
333 {
334     for ( sal_uInt16 nPos = 0; nPos < pImp->aItems.Count(); ++nPos )
335         if ( pImp->aItems.GetObject(nPos)->Which() == nSlotId )
336             return pImp->aItems.GetObject(nPos);
337     return 0;
338 }
339 
340 //--------------------------------------------------------------------
341 
342 void SfxShell::RemoveItem
343 (
344     sal_uInt16  nSlotId         // Slot-Id des zu l"oschenden <SfxPoolItem>s
345 )
346 
347 /*  [Beschreibung]
348 
349     Mit dieser Methode k"onnen die allgemein zur Verf"ugung gestellten
350     Instanzen von Subklassen von <SfxPoolItem> aus der SfxShell entfernt
351     werden.
352 
353     Die gespeicherte Instanz wird gel"oscht.
354 
355 
356     [Querverweise]
357 
358     <SfxShell::PutItem(const SfxPoolItem&)>
359     <SfxShell::GetItem(sal_uInt16)>
360 */
361 
362 {
363     for ( sal_uInt16 nPos = 0; nPos < pImp->aItems.Count(); ++nPos )
364         if ( pImp->aItems.GetObject(nPos)->Which() == nSlotId )
365         {
366             // Item entfernen und l"oschen
367             SfxPoolItem *pItem = pImp->aItems.GetObject(nPos);
368             delete pItem;
369             pImp->aItems.Remove(nPos);
370 
371             // falls aktiv Bindings benachrichtigen
372             SfxDispatcher *pDispat = GetDispatcher();
373             if ( pDispat )
374             {
375                 SfxVoidItem aVoid( nSlotId );
376                 pDispat->GetBindings()->Broadcast( SfxPoolItemHint( &aVoid ) );
377             }
378         }
379 }
380 
381 //--------------------------------------------------------------------
382 
383 void SfxShell::PutItem
384 (
385     const SfxPoolItem&  rItem   /*  Instanz, von der eine Kopie erstellt wird,
386                                     die in der SfxShell in einer Liste
387                                     gespeichert wird. */
388 )
389 
390 /*  [Beschreibung]
391 
392     Mit dieser Methode k"onnen beliebige Objekte von Subklassen von
393     <SfxPoolItem> zur Verf"ugung gestellt werden. Diese Austauschtechnik
394     wird ben"otigt, wenn z.B. spezielle <SfxToolBoxControl> Subklassen
395     Zugriff auf bestimmte Daten z.B. der <SfxObjectShell> ben"otigen.
396 
397     Falls ein SfxPoolItem mit derselben Slot-Id exisitert, wird dieses
398     automatisch gel"oscht.
399 
400 
401     [Querverweise]
402 
403     <SfxShell::RemoveItem(sal_uInt16)>
404     <SfxShell::GetItem(sal_uInt16)>
405 */
406 
407 {
408     DBG_ASSERT( !rItem.ISA(SfxSetItem), "SetItems aren't allowed here" );
409     DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
410                 "items with Which-Ids aren't allowed here" );
411 
412     // MSC auf WNT/W95 machte hier Mist, Vorsicht bei Umstellungen
413     const SfxPoolItem *pItem = rItem.Clone();
414     SfxPoolItemHint aItemHint( (SfxPoolItem*) pItem );
415     const sal_uInt16 nWhich = rItem.Which();
416     SfxPoolItem **ppLoopItem = (SfxPoolItem**) pImp->aItems.GetData();
417     sal_uInt16 nPos;
418     for ( nPos = 0; nPos < pImp->aItems.Count(); ++nPos, ++ppLoopItem )
419     {
420         if ( (*ppLoopItem)->Which() == nWhich )
421         {
422             // Item austauschen
423             delete *ppLoopItem;
424             pImp->aItems.Remove(nPos);
425             pImp->aItems.Insert( (SfxPoolItemPtr) pItem, nPos );
426 
427             // falls aktiv Bindings benachrichtigen
428             SfxDispatcher *pDispat = GetDispatcher();
429             if ( pDispat )
430             {
431                 SfxBindings* pBindings = pDispat->GetBindings();
432                 pBindings->Broadcast( aItemHint );
433                 sal_uInt16 nSlotId = nWhich; //pItem->GetSlotId();
434                 SfxStateCache* pCache = pBindings->GetStateCache( nSlotId );
435                 if ( pCache )
436                 {
437                     pCache->SetState( SFX_ITEM_AVAILABLE, pItem->Clone(), sal_True );
438                     pCache->SetCachedState( sal_True );
439                 }
440             }
441             return;
442         }
443     }
444 
445     Broadcast( aItemHint );
446     pImp->aItems.Insert((SfxPoolItemPtr)pItem, nPos );
447 }
448 
449 //--------------------------------------------------------------------
450 
451 SfxInterface* SfxShell::GetInterface() const
452 
453 /*  [Beschreibung]
454 
455     Mit dieser virtuellen Methode, die durch das Makro <SFX_DECL_INTERFACE>
456     von jeder Subclass mit eigenen Slots automatisch "uberladen wird, kann
457     auf die zu der Subklasse geh"orende <SfxInterface>-Instanz zugegriffen
458     werden.
459 
460     Die Klasse SfxShell selbst hat noch kein eigenes SfxInterface
461     (keine Slots), daher wird ein 0-Pointer zur"uckgeliefert.
462 */
463 
464 {
465     return GetStaticInterface();
466 }
467 
468 //--------------------------------------------------------------------
469 
470 SfxBroadcaster* SfxShell::GetBroadcaster()
471 
472 /*  [Beschreibung]
473 
474     Liefert einen SfxBroadcaster f"ur diese SfxShell-Instanz bis die
475     Klasse SfxShell von SfxBroadcaster abgeleitet ist.
476 */
477 
478 {
479     return pImp;
480 }
481 
482 //--------------------------------------------------------------------
483 
484 ::svl::IUndoManager* SfxShell::GetUndoManager()
485 
486 /*  [Beschreibung]
487 
488     Jede Subclass von SfxShell kann "uber einen <SfxUndoManager> verf"ugen.
489     Dieser kann in den abgeleiteten Klasse mit <SfxShell:SetUndoManager()>
490     gesetzt werden.
491 
492     Die Klasse SfxShell selbst hat noch keinen SfxUndoManager, es wird
493     daher ein 0-Pointer zur"uckgeliefert.
494 */
495 
496 {
497     return pUndoMgr;
498 }
499 
500 //--------------------------------------------------------------------
501 
502 void SfxShell::SetUndoManager( ::svl::IUndoManager *pNewUndoMgr )
503 
504 /*  [Beschreibung]
505 
506     Setzt einen <SfxUndoManager> f"ur diese <SfxShell> Instanz. F"ur das
507     Undo wird immer nur der Undo-Manager an der jeweils oben auf dem
508     Stack des <SfxDispatcher> liegenden SfxShell verwendet.
509 
510     Am "ubergebenen <SfxUndoManager> wird automatisch die aktuelle
511     Max-Undo-Action-Count Einstellung aus den Optionen gesetzt.
512 
513     'pNewUndoMgr' mu\s bis zum Dtor dieser SfxShell-Instanz oder bis
514     zum n"achsten 'SetUndoManager()' existieren.
515 */
516 
517 {
518     OSL_ENSURE( ( pUndoMgr == NULL ) || ( pNewUndoMgr == NULL ) || ( pUndoMgr == pNewUndoMgr ),
519         "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" );
520     // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which
521     // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really
522     // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances.
523 
524     pUndoMgr = pNewUndoMgr;
525     if ( pUndoMgr )
526         pUndoMgr->SetMaxUndoActionCount( (sal_uInt16) SvtUndoOptions().GetUndoCount() );
527 }
528 
529 //--------------------------------------------------------------------
530 
531 SfxRepeatTarget* SfxShell::GetRepeatTarget() const
532 
533 /*  [Beschreibung]
534 
535     Liefert einen Pointer auf die <SfxRepeatTarget>-Instanz, die
536     als RepeatTarget bei SID_REPEAT verwendet wird, wenn der
537     von dieser SfxShell gelieferte <SfxUndoManager> angesprochen wird.
538     Der R"uckgabewert kann 0 sein.
539 
540 
541     [Anmerkung]
542 
543     Eine Ableitung von <SfxShell> oder einer ihrer Subklassen von
544     <SfxRepeatTarget> ist nicht zu empfehlen, da Compiler-Fehler
545     provoziert werden (wegen Call-to-Pointer-to-Member-Function to
546     subclass).
547 */
548 
549 {
550     return pImp->pRepeatTarget;
551 }
552 
553 //--------------------------------------------------------------------
554 
555 void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget )
556 
557 /*  [Beschreibung]
558 
559     Setzt den die <SfxRepeatTarget>-Instanz, die bei SID_REPEAT als
560     RepeatTarget verwendet wird, wenn der von dieser SfxShell gelieferte
561     <SfxUndoManager> angesprochen wird. Durch 'pTarget==0' wird SID_REPEAT
562     f"ur diese SfxShell disabled. Die Instanz '*pTarget' mu\s so lange
563     leben, wie sie angemeldet ist.
564 
565 
566     [Anmerkung]
567 
568     Eine Ableitung von <SfxShell> oder einer ihrer Subklassen von
569     <SfxRepeatTarget> ist nicht zu empfehlen, da Compiler-Fehler
570     provoziert werden (wegen Call-to-Pointer-to-Member-Function to
571     subclass).
572 */
573 
574 {
575     pImp->pRepeatTarget = pTarget;
576 }
577 
578 //--------------------------------------------------------------------
579 
580 void SfxShell::Invalidate
581 (
582     sal_uInt16          nId     /* Zu invalidierende Slot-Id oder Which-Id.
583                                Falls diese 0 ist (default), werden
584                                alle z.Zt. von dieser Shell bedienten
585                                Slot-Ids invalidiert. */
586 )
587 
588 /*  [Beschreibung]
589 
590     Mit dieser Methode k"onnen Slots der Subclasses "uber die Slot-Id
591     oder alternativ "uber die Which-Id invalidiert werden. Slot-Ids,
592     die von der Subclass ererbt sind, werden ebenfalls invalidert.
593 
594     [Querverweise]
595     <SfxBindings::Invalidate(sal_uInt16)>
596     <SfxBindings::InvalidateAll(sal_Bool)>
597 */
598 
599 {
600     if ( !GetViewShell() )
601     {
602         DBG_ERROR( "wrong Invalidate method called!" );
603         return;
604     }
605 
606     Invalidate_Impl( GetViewShell()->GetViewFrame()->GetBindings(), nId );
607 }
608 
609 void SfxShell::Invalidate_Impl( SfxBindings& rBindings, sal_uInt16 nId )
610 {
611     if ( nId == 0 )
612     {
613         rBindings.InvalidateShell( *this, sal_False );
614     }
615     else
616     {
617         const SfxInterface *pIF = GetInterface();
618         do
619         {
620             const SfxSlot *pSlot = pIF->GetSlot(nId);
621             if ( pSlot )
622             {
623                 // bei Enum-Slots ist der Master-Slot zu invalidieren
624                 if ( SFX_KIND_ENUM == pSlot->GetKind() )
625                     pSlot = pSlot->GetLinkedSlot();
626 
627                 // den Slot selbst und ggf. auch alle Slave-Slots invalidieren
628                 rBindings.Invalidate( pSlot->GetSlotId() );
629                 for ( const SfxSlot *pSlave = pSlot->GetLinkedSlot();
630                       pSlave && pIF->ContainsSlot_Impl( pSlave ) &&
631                         pSlave->GetLinkedSlot() == pSlot;
632                       ++pSlave )
633                     rBindings.Invalidate( pSlave->GetSlotId() );
634 
635                 return;
636             }
637 
638             pIF = pIF->GetGenoType();
639         }
640 
641         while ( pIF );
642 
643         DBG_WARNING( "W3: invalidating slot-id unknown in shell" );
644     }
645 }
646 
647 //--------------------------------------------------------------------
648 
649 void SfxShell::DoActivate_Impl( SfxViewFrame *pFrame, sal_Bool bMDI )
650 
651 /*  [Beschreibung]
652 
653     Diese Methode steuert die Aktivierung der SfxShell-Instanz. Zun"achst
654     wird durch Aufruf der virtuellen Methode <SfxShell::Activate(sal_Bool)>
655     der Subclass die M"oglichkeit gegeben, auf das Event zu reagieren.
656 
657     Bei bMDI == TRUE wird das zugeh"orige SbxObject 'scharfgeschaltet',
658     so da\s Methoden des Objekts unqualifiziert (ohne den Namen des Objekts)
659     vom BASIC gefunden werden.
660 */
661 
662 {
663 #ifdef DBG_UTIL
664     const SfxInterface *p_IF = GetInterface();
665     if ( !p_IF )
666         return;
667 #endif
668 #ifdef DBG_UTIL_VB
669         String aMsg("SfxShell::DoActivate() ");
670         aMsg += (long)this;
671         aMsg += "  ";
672         aMsg += GetInterface()->GetName();
673         aMsg += " bMDI ";
674         if ( bMDI ) aMsg += "MDI";
675         DbgTrace( aMsg.GetBuffer() );
676 #endif
677 
678     if ( bMDI )
679     {
680         // Frame merken, in dem aktiviert wird
681         pImp->pFrame = pFrame;
682         pImp->bActive = sal_True;
683     }
684 
685     // Subklasse benachrichtigen
686     Activate(bMDI);
687 }
688 
689 //--------------------------------------------------------------------
690 
691 void SfxShell::DoDeactivate_Impl( SfxViewFrame *pFrame, sal_Bool bMDI )
692 
693 /*  [Beschreibung]
694 
695     Diese Methode steuert die Deaktivierung der SfxShell-Instanz. Bei
696     bMDI == TRUE wird zun"achst das SbxObject in einen Status versetzt,
697     so da\s Methoden vom BASIC aus nur noch qualifiziert gerufen werden
698     k"onnen.
699 
700     Dann erh"alt in jedem Fall die Subclass durch Aufruf der virtuellen
701     Methode <SfxShell::Deactivate(sal_Bool)> die M"oglichkeit auf das Event
702     zu reagieren.
703 */
704 
705 {
706 #ifdef DBG_UTIL
707     const SfxInterface *p_IF = GetInterface();
708     if ( !p_IF )
709         return;
710 #endif
711 #ifdef DBG_UTIL_VB
712         String aMsg("SfxShell::DoDeactivate()");
713         aMsg += (long)this;
714         aMsg += "  ";
715         aMsg += GetInterface()->GetName();
716         aMsg += " bMDI ";
717         if ( bMDI ) aMsg += "MDI";
718         DbgTrace( aMsg.GetBuffer() );
719 #endif
720 
721     // nur wenn er vom Frame kommt (nicht z.B. pop der BASIC-IDE vom AppDisp)
722     if ( bMDI && pImp->pFrame == pFrame )
723     {
724         // austragen
725         pImp->pFrame = 0;
726         pImp->bActive = sal_False;
727     }
728 
729     // Subklasse benachrichtigen
730     Deactivate(bMDI);
731 }
732 
733 //--------------------------------------------------------------------
734 
735 sal_Bool SfxShell::IsActive() const
736 {
737     return pImp->bActive;
738 }
739 
740 //--------------------------------------------------------------------
741 
742 void SfxShell::Activate
743 (
744     sal_Bool    /*bMDI*/        /*  TRUE
745                             der <SfxDispatcher>, auf dem die SfxShell sich
746                             befindet, ist aktiv geworden oder die SfxShell
747                             Instanz wurde auf einen aktiven SfxDispatcher
748                             gepusht. (vergl. SystemWindow::IsMDIActivate())
749 
750                             FALSE
751                             das zum <SfxViewFrame>, auf dessen SfxDispatcher
752                             sich die SfxShell Instanz befindet, wurde
753                             aktiviert.
754                             (z.B. durch einen geschlossenen Dialog) */
755 )
756 
757 /*  [Beschreibung]
758 
759     Virtuelle Methode, die beim Aktivieren der SfxShell Instanz gerufen
760     wird, um den Subclasses die Gelegenheit zu geben, auf das Aktivieren
761     zu reagieren.
762 
763     Die Basisimplementation ist leer und braucht nicht gerufen zu werden.
764 
765 
766     [Querverweise]
767     StarView SystemWindow::Activate(sal_Bool)
768 */
769 
770 {
771 }
772 
773 //--------------------------------------------------------------------
774 
775 void SfxShell::Deactivate
776 (
777     sal_Bool    /*bMDI*/        /*  TRUE
778                             der <SfxDispatcher>, auf dem die SfxShell sich
779                             befindet, ist inaktiv geworden oder die SfxShell
780                             Instanz wurde auf einen aktiven SfxDispatcher
781                             gepoppt. (vergl. SystemWindow::IsMDIActivate())
782 
783                             FALSE
784                             das zum <SfxViewFrame>, auf dessen SfxDispatcher
785                             sich die SfxShell Instanz befindet, wurde
786                             deaktiviert. (z.B. durch einen Dialog) */
787 
788 )
789 
790 /*  [Beschreibung]
791 
792     Virtuelle Methode, die beim Deaktivieren der SfxShell Instanz gerufen
793     wird, um den Subclasses die Gelegenheit zu geben, auf das Deaktivieren
794     zu reagieren.
795 
796     Die Basisimplementation ist leer und braucht nicht gerufen zu werden.
797 
798 
799     [Querverweise]
800     StarView SystemWindow::Dectivate(sal_Bool)
801 */
802 
803 {
804 }
805 
806 void SfxShell::ParentActivate
807 (
808 )
809 
810 /*  [Beschreibung]
811 
812     Ein Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet,
813     ist aktiv geworden, oder die SfxShell Instanz wurde auf einen
814     <SfxDispatcher> gepusht, dessen parent aktiv ist.
815 
816     Die Basisimplementation ist leer und braucht nicht gerufen zu werden.
817 
818     [Querverweise]
819     SfxShell::Activate()
820 */
821 {
822 }
823 
824 //--------------------------------------------------------------------
825 
826 void SfxShell::ParentDeactivate
827 (
828 )
829 
830 /*  [Beschreibung]
831 
832     Der aktive Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet,
833     ist deaktiviert worden.
834 
835     Die Basisimplementation ist leer und braucht nicht gerufen zu werden.
836 
837     [Querverweise]
838     SfxShell::Deactivate()
839 */
840 {
841 }
842 
843 //--------------------------------------------------------------------
844 
845 ResMgr* SfxShell::GetResMgr() const
846 
847 /*  [Beschreibung]
848 
849     Diese Methode liefert den ResMgr der <Resource-DLL>, die von der
850     SfxShell-Instanz verwendet wird. Ist dies ein 0-Pointer, so
851     ist der aktuelle Resource-Manager zu verwenden.
852 */
853 
854 {
855     return GetInterface()->GetResMgr();
856 }
857 
858 //--------------------------------------------------------------------
859 
860 bool SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot )
861 
862 /*  [Beschreibung]
863 
864     Diese Methode stellt durch Aufruf der Statusfunktion fest,
865     ob 'rSlot' aktuell ausgef"uhrt werden kann.
866 */
867 {
868     // Slot-Status holen
869     SfxItemPool &rPool = GetPool();
870     const sal_uInt16 nId = rSlot.GetWhich( rPool );
871     SfxItemSet aSet(rPool, nId, nId);
872     SfxStateFunc pFunc = rSlot.GetStateFnc();
873     CallState( pFunc, aSet );
874     return aSet.GetItemState(nId) != SFX_ITEM_DISABLED;
875 }
876 
877 //--------------------------------------------------------------------
878 
879 long ShellCall_Impl( void* pObj, void* pArg )
880 {
881     ((SfxShell* )pObj)->ExecuteSlot( *(SfxRequest*)pArg, (SfxInterface*)0L );
882     return 0;
883 }
884 
885 /*  [Beschreibung]
886     Asynchrones ExecuteSlot fuer das RELOAD
887  */
888 
889 //--------------------------------------------------------------------
890 const SfxPoolItem* SfxShell::ExecuteSlot( SfxRequest& rReq, sal_Bool bAsync )
891 {
892     if( !bAsync )
893         return ExecuteSlot( rReq, (SfxInterface*)0L );
894     else
895     {
896         if( !pImp->pExecuter )
897             pImp->pExecuter = new svtools::AsynchronLink(
898                 Link( this, ShellCall_Impl ) );
899         pImp->pExecuter->Call( new SfxRequest( rReq ) );
900         return 0;
901     }
902 }
903 
904 const SfxPoolItem* SfxShell::ExecuteSlot
905 (
906     SfxRequest &rReq,           // der weiterzuleitende <SfxRequest>
907     const SfxInterface* pIF     // default = 0 bedeutet virtuell besorgen
908 )
909 
910 /*  [Beschreibung]
911 
912     Diese Methode erm"oglicht das Weiterleiten eines <SfxRequest> an
913     die angegebene Basis-<SfxShell>.
914 
915 
916     [Beispiel]
917 
918     In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT
919     abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken
920     eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden.
921 
922     Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die
923     Execute-Methode enth"alt dann skizziert:
924 
925     void SubViewShell::Exec( SfxRequest &rReq )
926     {
927         if ( rReq.GetSlot() == SID_PRINTDOCDIRECT )
928         {
929             'dialog'
930             if ( 'condition' )
931                 ExecuteSlot( rReq, SfxViewShell::GetInterface() );
932         }
933     }
934 
935     Es braucht i.d.R. kein rReq.Done() gerufen zu werden, da das bereits
936     die Implementierung der SfxViewShell erledigt bzw. abgebrochen wurde.
937 
938 
939     [Querverweise]
940 
941     <SfxShell::GetSlotState(sal_uInt16,const SfxInterface*,SfxItemSet*)>
942 */
943 
944 {
945     if ( !pIF )
946         pIF = GetInterface();
947 
948     sal_uInt16 nSlot = rReq.GetSlot();
949     const SfxSlot* pSlot = NULL;
950     if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END )
951         pSlot = GetVerbSlot_Impl(nSlot);
952     if ( !pSlot )
953         pSlot = pIF->GetSlot(nSlot);
954     DBG_ASSERT( pSlot, "slot not supported" );
955 
956     SfxExecFunc pFunc = pSlot->GetExecFnc();
957     if ( pFunc )
958         CallExec( pFunc, rReq );
959 
960     return rReq.GetReturnValue();
961 }
962 
963 //--------------------------------------------------------------------
964 
965 const SfxPoolItem* SfxShell::GetSlotState
966 (
967     sal_uInt16              nSlotId,    // Slot-Id des zu befragenden Slots
968     const SfxInterface* pIF,        // default = 0 bedeutet virtuell besorgen
969     SfxItemSet*         pStateSet   // SfxItemSet der Slot-State-Methode
970 )
971 
972 /*  [Beschreibung]
973 
974     Diese Methode liefert den Status des Slots mit der angegebenen Slot-Id
975     "uber das angegebene Interface.
976 
977     Ist der Slot disabled oder in dieser SfxShell (und deren Parent-Shells)
978     nicht bekannt, wird ein 0-Pointer zur"uckgeliefert.
979 
980     Hat der Slot keinen Status, wird ein SfxVoidItem zur"uckgeliefert.
981 
982     Der Status wird bei pStateSet != 0 gleich in diesem Set gesetzt, so
983     da\s <SfxShell>-Subklassen Slots-"uberladen und auch bei der
984     Status-Methode die Basis-Implementierung rufen k"onnen.
985 
986 
987     [Beispiel]
988 
989     In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT
990     abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken
991     eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden.
992 
993     Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die
994     Status-Methode enth"alt dann skizziert:
995 
996     void SubViewShell::PrintState( SfxItemSet &rState )
997     {
998         if ( rState.GetItemState( SID_PRINTDOCDIRECT ) != SFX_ITEM_UNKNOWN )
999             GetSlotState( SID_PRINTDOCDIRECT, SfxViewShell::GetInterface(),
1000                     &rState );
1001         ...
1002     }
1003 
1004 
1005     [Querverweise]
1006 
1007     <SfxShell::ExecuteSlot(SfxRequest&)>
1008 */
1009 
1010 {
1011     // Slot am angegebenen Interface besorgen
1012     if ( !pIF )
1013         pIF = GetInterface();
1014     SfxItemState eState;
1015     SfxItemPool &rPool = GetPool();
1016 
1017     const SfxSlot* pSlot = NULL;
1018     if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END )
1019         pSlot = GetVerbSlot_Impl(nSlotId);
1020     if ( !pSlot )
1021         pSlot = pIF->GetSlot(nSlotId);
1022     if ( pSlot )
1023         // ggf. auf Which-Id mappen
1024         nSlotId = pSlot->GetWhich( rPool );
1025 
1026     // Item und Item-Status besorgen
1027     const SfxPoolItem *pItem = NULL;
1028     SfxItemSet aSet( rPool, nSlotId, nSlotId ); // pItem stirbt sonst zu fr"uh
1029     if ( pSlot )
1030     {
1031         // Status-Methode rufen
1032         SfxStateFunc pFunc = pSlot->GetStateFnc();
1033         if ( pFunc )
1034             CallState( pFunc, aSet );
1035         eState = aSet.GetItemState( nSlotId, sal_True, &pItem );
1036 
1037         // ggf. Default-Item besorgen
1038         if ( eState == SFX_ITEM_DEFAULT )
1039         {
1040             if ( SfxItemPool::IsWhich(nSlotId) )
1041                 pItem = &rPool.GetDefaultItem(nSlotId);
1042             else
1043                 eState = SFX_ITEM_DONTCARE;
1044         }
1045     }
1046     else
1047         eState = SFX_ITEM_UNKNOWN;
1048 
1049     // Item und Item-Status auswerten und ggf. in pStateSet mitpflegen
1050     SfxPoolItem *pRetItem = 0;
1051     if ( eState <= SFX_ITEM_DISABLED )
1052     {
1053         if ( pStateSet )
1054             pStateSet->DisableItem(nSlotId);
1055         return 0;
1056     }
1057     else if ( eState == SFX_ITEM_DONTCARE )
1058     {
1059         if ( pStateSet )
1060             pStateSet->ClearItem(nSlotId);
1061         pRetItem = new SfxVoidItem(0);
1062     }
1063     else
1064     {
1065         if ( pStateSet && pStateSet->Put( *pItem ) )
1066             return &pStateSet->Get( pItem->Which() );
1067         pRetItem = pItem->Clone();
1068     }
1069     DeleteItemOnIdle(pRetItem);
1070 
1071     return pRetItem;
1072 }
1073 
1074 //--------------------------------------------------------------------
1075 
1076 SFX_EXEC_STUB(SfxShell, VerbExec)
1077 SFX_STATE_STUB(SfxShell, VerbState)
1078 
1079 void SfxShell::SetVerbs(const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& aVerbs)
1080 {
1081     SfxViewShell *pViewSh = PTR_CAST ( SfxViewShell, this);
1082 
1083     DBG_ASSERT(pViewSh, "SetVerbs nur an der ViewShell aufrufen!");
1084     if ( !pViewSh )
1085         return;
1086 
1087     // Zun"achst alle Statecaches dirty machen, damit keiner mehr versucht,
1088     // die Slots zu benutzen
1089     {
1090         SfxBindings *pBindings =
1091             pViewSh->GetViewFrame()->GetDispatcher()->GetBindings();
1092         sal_uInt16 nCount = pImp->aSlotArr.Count();
1093         for (sal_uInt16 n1=0; n1<nCount ; n1++)
1094         {
1095             sal_uInt16 nId = SID_VERB_START + n1;
1096             pBindings->Invalidate(nId, sal_False, sal_True);
1097         }
1098     }
1099 
1100     sal_uInt16 nr=0;
1101     for (sal_Int32 n=0; n<aVerbs.getLength(); n++)
1102     {
1103         sal_uInt16 nSlotId = SID_VERB_START + nr++;
1104         DBG_ASSERT(nSlotId <= SID_VERB_END, "Zuviele Verben!");
1105         if (nSlotId > SID_VERB_END)
1106             break;
1107 
1108         SfxSlot *pNewSlot = new SfxSlot;
1109         pNewSlot->nSlotId = nSlotId;
1110         pNewSlot->nGroupId = 0;
1111 
1112         // Verb-Slots m"ussen asynchron ausgef"uhrt werden, da sie w"ahrend
1113         // des Ausf"uhrens zerst"ort werden k"onnten
1114         pNewSlot->nFlags = SFX_SLOT_ASYNCHRON | SFX_SLOT_CONTAINER;
1115         pNewSlot->nMasterSlotId = 0;
1116         pNewSlot->nValue = 0;
1117         pNewSlot->fnExec = SFX_STUB_PTR(SfxShell,VerbExec);
1118         pNewSlot->fnState = SFX_STUB_PTR(SfxShell,VerbState);
1119         pNewSlot->pType = 0; HACK(SFX_TYPE(SfxVoidItem))
1120         pNewSlot->pName = U2S(aVerbs[n].VerbName);
1121         pNewSlot->pLinkedSlot = 0;
1122         pNewSlot->nArgDefCount = 0;
1123         pNewSlot->pFirstArgDef = 0;
1124         pNewSlot->pUnoName = 0;
1125 
1126         if (pImp->aSlotArr.Count())
1127         {
1128             SfxSlot *pSlot = (pImp->aSlotArr)[0];
1129             pNewSlot->pNextSlot = pSlot->pNextSlot;
1130             pSlot->pNextSlot = pNewSlot;
1131         }
1132         else
1133             pNewSlot->pNextSlot = pNewSlot;
1134 
1135         pImp->aSlotArr.Insert(pNewSlot, (sal_uInt16) n);
1136     }
1137 
1138     pImp->aVerbList = aVerbs;
1139 
1140     if (pViewSh)
1141     {
1142         // Der Status von SID_OBJECT wird im Controller direkt an der Shell
1143         // abgeholt, es reicht also, ein neues StatusUpdate anzuregen
1144         SfxBindings *pBindings = pViewSh->GetViewFrame()->GetDispatcher()->
1145                 GetBindings();
1146         pBindings->Invalidate( SID_OBJECT, sal_True, sal_True );
1147     }
1148 }
1149 
1150 //--------------------------------------------------------------------
1151 
1152 const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& SfxShell::GetVerbs() const
1153 {
1154     return pImp->aVerbList;
1155 }
1156 
1157 //--------------------------------------------------------------------
1158 
1159 void SfxShell::VerbExec(SfxRequest& rReq)
1160 {
1161     sal_uInt16 nId = rReq.GetSlot();
1162     SfxViewShell *pViewShell = GetViewShell();
1163     if ( pViewShell )
1164     {
1165         sal_Bool bReadOnly = pViewShell->GetObjectShell()->IsReadOnly();
1166         com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > aList = pViewShell->GetVerbs();
1167         for (sal_Int32 n=0, nVerb=0; n<aList.getLength(); n++)
1168         {
1169             // check for ReadOnly verbs
1170             if ( bReadOnly && !(aList[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) )
1171                 continue;
1172 
1173             // check for verbs that shouldn't appear in the menu
1174             if ( !(aList[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) )
1175                 continue;
1176 
1177             if (nId == SID_VERB_START + nVerb++)
1178             {
1179                 pViewShell->DoVerb(aList[n].VerbID);
1180                 rReq.Done();
1181                 return;
1182             }
1183         }
1184     }
1185 }
1186 
1187 //--------------------------------------------------------------------
1188 
1189 void SfxShell::VerbState(SfxItemSet& )
1190 {
1191 }
1192 
1193 //--------------------------------------------------------------------
1194 
1195 const SfxSlot* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId) const
1196 {
1197     com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > rList = pImp->aVerbList;
1198 
1199     DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Falsche VerbId!");
1200     sal_uInt16 nIndex = nId - SID_VERB_START;
1201     DBG_ASSERT(nIndex < rList.getLength(),"Falsche VerbId!");
1202 
1203     if (nIndex < rList.getLength())
1204         return pImp->aSlotArr[nIndex];
1205     else
1206         return 0;
1207 }
1208 
1209 //--------------------------------------------------------------------
1210 
1211 void SfxShell::SetHelpId(sal_uIntPtr nId)
1212 {
1213     pImp->nHelpId = nId;
1214 }
1215 
1216 //--------------------------------------------------------------------
1217 
1218 sal_uIntPtr SfxShell::GetHelpId() const
1219 {
1220     return pImp->nHelpId;
1221 }
1222 
1223 //--------------------------------------------------------------------
1224 
1225 SfxObjectShell* SfxShell::GetObjectShell()
1226 {
1227     if ( GetViewShell() )
1228         return GetViewShell()->GetViewFrame()->GetObjectShell();
1229     else
1230         return NULL;
1231 }
1232 
1233 //--------------------------------------------------------------------
1234 
1235 sal_Bool SfxShell::HasUIFeature( sal_uInt32 )
1236 {
1237     return sal_False;
1238 }
1239 
1240 long DispatcherUpdate_Impl( void*, void* pArg )
1241 {
1242     ((SfxDispatcher*) pArg)->Update_Impl( sal_True );
1243     ((SfxDispatcher*) pArg)->GetBindings()->InvalidateAll(sal_False);
1244     return 0;
1245 }
1246 
1247 void SfxShell::UIFeatureChanged()
1248 {
1249     SfxViewFrame *pFrame = GetFrame();
1250     if ( pFrame && pFrame->IsVisible() )
1251     {
1252         // Auch dann Update erzwingen, wenn Dispatcher schon geupdated ist,
1253         // sonst bleibt evtl. irgendwas in den gebunkerten Tools stecken.
1254         // Asynchron aufrufen, um Rekursionen zu vermeiden
1255         if ( !pImp->pUpdater )
1256             pImp->pUpdater = new svtools::AsynchronLink( Link( this, DispatcherUpdate_Impl ) );
1257 
1258         // Mehrfachaufrufe gestattet
1259         pImp->pUpdater->Call( pFrame->GetDispatcher(), sal_True );
1260     }
1261 }
1262 
1263 void SfxShell::SetDisableFlags( sal_uIntPtr nFlags )
1264 {
1265     pImp->nDisableFlags = nFlags;
1266 }
1267 
1268 sal_uIntPtr SfxShell::GetDisableFlags() const
1269 {
1270     return pImp->nDisableFlags;
1271 }
1272 
1273 SfxItemSet* SfxShell::CreateItemSet( sal_uInt16 )
1274 {
1275     return NULL;
1276 }
1277 
1278 void SfxShell::ApplyItemSet( sal_uInt16, const SfxItemSet& )
1279 {
1280 }
1281 
1282 void SfxShell::SetViewShell_Impl( SfxViewShell* pView )
1283 {
1284     pImp->pViewSh = pView;
1285 }
1286 
1287 
1288 
1289