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