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