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 [Querverweise] 765 StarView SystemWindow::Activate(sal_Bool) 766 */ 767 768 { 769 BroadcastContextForActivation(true); 770 } 771 772 //-------------------------------------------------------------------- 773 774 void SfxShell::Deactivate 775 ( 776 sal_Bool /*bMDI*/ /* TRUE 777 der <SfxDispatcher>, auf dem die SfxShell sich 778 befindet, ist inaktiv geworden oder die SfxShell 779 Instanz wurde auf einen aktiven SfxDispatcher 780 gepoppt. (vergl. SystemWindow::IsMDIActivate()) 781 782 FALSE 783 das zum <SfxViewFrame>, auf dessen SfxDispatcher 784 sich die SfxShell Instanz befindet, wurde 785 deaktiviert. (z.B. durch einen Dialog) */ 786 787 ) 788 789 /* [Beschreibung] 790 791 Virtuelle Methode, die beim Deaktivieren der SfxShell Instanz gerufen 792 wird, um den Subclasses die Gelegenheit zu geben, auf das Deaktivieren 793 zu reagieren. 794 795 [Querverweise] 796 StarView SystemWindow::Dectivate(sal_Bool) 797 */ 798 799 { 800 BroadcastContextForActivation(false); 801 } 802 803 804 void SfxShell::ParentActivate 805 ( 806 ) 807 808 /* [Beschreibung] 809 810 Ein Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet, 811 ist aktiv geworden, oder die SfxShell Instanz wurde auf einen 812 <SfxDispatcher> gepusht, dessen parent aktiv ist. 813 814 Die Basisimplementation ist leer und braucht nicht gerufen zu werden. 815 816 [Querverweise] 817 SfxShell::Activate() 818 */ 819 { 820 } 821 822 //-------------------------------------------------------------------- 823 824 void SfxShell::ParentDeactivate 825 ( 826 ) 827 828 /* [Beschreibung] 829 830 Der aktive Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet, 831 ist deaktiviert worden. 832 833 Die Basisimplementation ist leer und braucht nicht gerufen zu werden. 834 835 [Querverweise] 836 SfxShell::Deactivate() 837 */ 838 { 839 } 840 841 //-------------------------------------------------------------------- 842 843 ResMgr* SfxShell::GetResMgr() const 844 845 /* [Beschreibung] 846 847 Diese Methode liefert den ResMgr der <Resource-DLL>, die von der 848 SfxShell-Instanz verwendet wird. Ist dies ein 0-Pointer, so 849 ist der aktuelle Resource-Manager zu verwenden. 850 */ 851 852 { 853 return GetInterface()->GetResMgr(); 854 } 855 856 //-------------------------------------------------------------------- 857 858 bool SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot ) 859 860 /* [Beschreibung] 861 862 Diese Methode stellt durch Aufruf der Statusfunktion fest, 863 ob 'rSlot' aktuell ausgef"uhrt werden kann. 864 */ 865 { 866 // Slot-Status holen 867 SfxItemPool &rPool = GetPool(); 868 const sal_uInt16 nId = rSlot.GetWhich( rPool ); 869 SfxItemSet aSet(rPool, nId, nId); 870 SfxStateFunc pFunc = rSlot.GetStateFnc(); 871 CallState( pFunc, aSet ); 872 return aSet.GetItemState(nId) != SFX_ITEM_DISABLED; 873 } 874 875 //-------------------------------------------------------------------- 876 877 long ShellCall_Impl( void* pObj, void* pArg ) 878 { 879 ((SfxShell* )pObj)->ExecuteSlot( *(SfxRequest*)pArg, (SfxInterface*)0L ); 880 return 0; 881 } 882 883 /* [Beschreibung] 884 Asynchrones ExecuteSlot fuer das RELOAD 885 */ 886 887 //-------------------------------------------------------------------- 888 const SfxPoolItem* SfxShell::ExecuteSlot( SfxRequest& rReq, sal_Bool bAsync ) 889 { 890 if( !bAsync ) 891 return ExecuteSlot( rReq, (SfxInterface*)0L ); 892 else 893 { 894 if( !pImp->pExecuter ) 895 pImp->pExecuter = new svtools::AsynchronLink( 896 Link( this, ShellCall_Impl ) ); 897 pImp->pExecuter->Call( new SfxRequest( rReq ) ); 898 return 0; 899 } 900 } 901 902 const SfxPoolItem* SfxShell::ExecuteSlot 903 ( 904 SfxRequest &rReq, // der weiterzuleitende <SfxRequest> 905 const SfxInterface* pIF // default = 0 bedeutet virtuell besorgen 906 ) 907 908 /* [Beschreibung] 909 910 Diese Methode erm"oglicht das Weiterleiten eines <SfxRequest> an 911 die angegebene Basis-<SfxShell>. 912 913 914 [Beispiel] 915 916 In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT 917 abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken 918 eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden. 919 920 Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die 921 Execute-Methode enth"alt dann skizziert: 922 923 void SubViewShell::Exec( SfxRequest &rReq ) 924 { 925 if ( rReq.GetSlot() == SID_PRINTDOCDIRECT ) 926 { 927 'dialog' 928 if ( 'condition' ) 929 ExecuteSlot( rReq, SfxViewShell::GetInterface() ); 930 } 931 } 932 933 Es braucht i.d.R. kein rReq.Done() gerufen zu werden, da das bereits 934 die Implementierung der SfxViewShell erledigt bzw. abgebrochen wurde. 935 936 937 [Querverweise] 938 939 <SfxShell::GetSlotState(sal_uInt16,const SfxInterface*,SfxItemSet*)> 940 */ 941 942 { 943 if ( !pIF ) 944 pIF = GetInterface(); 945 946 sal_uInt16 nSlot = rReq.GetSlot(); 947 const SfxSlot* pSlot = NULL; 948 if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END ) 949 pSlot = GetVerbSlot_Impl(nSlot); 950 if ( !pSlot ) 951 pSlot = pIF->GetSlot(nSlot); 952 DBG_ASSERT( pSlot, "slot not supported" ); 953 954 SfxExecFunc pFunc = pSlot->GetExecFnc(); 955 if ( pFunc ) 956 CallExec( pFunc, rReq ); 957 958 return rReq.GetReturnValue(); 959 } 960 961 //-------------------------------------------------------------------- 962 963 const SfxPoolItem* SfxShell::GetSlotState 964 ( 965 sal_uInt16 nSlotId, // Slot-Id des zu befragenden Slots 966 const SfxInterface* pIF, // default = 0 bedeutet virtuell besorgen 967 SfxItemSet* pStateSet // SfxItemSet der Slot-State-Methode 968 ) 969 970 /* [Beschreibung] 971 972 Diese Methode liefert den Status des Slots mit der angegebenen Slot-Id 973 "uber das angegebene Interface. 974 975 Ist der Slot disabled oder in dieser SfxShell (und deren Parent-Shells) 976 nicht bekannt, wird ein 0-Pointer zur"uckgeliefert. 977 978 Hat der Slot keinen Status, wird ein SfxVoidItem zur"uckgeliefert. 979 980 Der Status wird bei pStateSet != 0 gleich in diesem Set gesetzt, so 981 da\s <SfxShell>-Subklassen Slots-"uberladen und auch bei der 982 Status-Methode die Basis-Implementierung rufen k"onnen. 983 984 985 [Beispiel] 986 987 In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT 988 abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken 989 eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden. 990 991 Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die 992 Status-Methode enth"alt dann skizziert: 993 994 void SubViewShell::PrintState( SfxItemSet &rState ) 995 { 996 if ( rState.GetItemState( SID_PRINTDOCDIRECT ) != SFX_ITEM_UNKNOWN ) 997 GetSlotState( SID_PRINTDOCDIRECT, SfxViewShell::GetInterface(), 998 &rState ); 999 ... 1000 } 1001 1002 1003 [Querverweise] 1004 1005 <SfxShell::ExecuteSlot(SfxRequest&)> 1006 */ 1007 1008 { 1009 // Slot am angegebenen Interface besorgen 1010 if ( !pIF ) 1011 pIF = GetInterface(); 1012 SfxItemState eState; 1013 SfxItemPool &rPool = GetPool(); 1014 1015 const SfxSlot* pSlot = NULL; 1016 if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END ) 1017 pSlot = GetVerbSlot_Impl(nSlotId); 1018 if ( !pSlot ) 1019 pSlot = pIF->GetSlot(nSlotId); 1020 if ( pSlot ) 1021 // ggf. auf Which-Id mappen 1022 nSlotId = pSlot->GetWhich( rPool ); 1023 1024 // Item und Item-Status besorgen 1025 const SfxPoolItem *pItem = NULL; 1026 SfxItemSet aSet( rPool, nSlotId, nSlotId ); // pItem stirbt sonst zu fr"uh 1027 if ( pSlot ) 1028 { 1029 // Status-Methode rufen 1030 SfxStateFunc pFunc = pSlot->GetStateFnc(); 1031 if ( pFunc ) 1032 CallState( pFunc, aSet ); 1033 eState = aSet.GetItemState( nSlotId, sal_True, &pItem ); 1034 1035 // ggf. Default-Item besorgen 1036 if ( eState == SFX_ITEM_DEFAULT ) 1037 { 1038 if ( SfxItemPool::IsWhich(nSlotId) ) 1039 pItem = &rPool.GetDefaultItem(nSlotId); 1040 else 1041 eState = SFX_ITEM_DONTCARE; 1042 } 1043 } 1044 else 1045 eState = SFX_ITEM_UNKNOWN; 1046 1047 // Item und Item-Status auswerten und ggf. in pStateSet mitpflegen 1048 SfxPoolItem *pRetItem = 0; 1049 if ( eState <= SFX_ITEM_DISABLED ) 1050 { 1051 if ( pStateSet ) 1052 pStateSet->DisableItem(nSlotId); 1053 return 0; 1054 } 1055 else if ( eState == SFX_ITEM_DONTCARE ) 1056 { 1057 if ( pStateSet ) 1058 pStateSet->ClearItem(nSlotId); 1059 pRetItem = new SfxVoidItem(0); 1060 } 1061 else 1062 { 1063 if ( pStateSet && pStateSet->Put( *pItem ) ) 1064 return &pStateSet->Get( pItem->Which() ); 1065 pRetItem = pItem->Clone(); 1066 } 1067 DeleteItemOnIdle(pRetItem); 1068 1069 return pRetItem; 1070 } 1071 1072 //-------------------------------------------------------------------- 1073 1074 SFX_EXEC_STUB(SfxShell, VerbExec) 1075 SFX_STATE_STUB(SfxShell, VerbState) 1076 1077 void SfxShell::SetVerbs(const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& aVerbs) 1078 { 1079 SfxViewShell *pViewSh = PTR_CAST ( SfxViewShell, this); 1080 1081 DBG_ASSERT(pViewSh, "SetVerbs nur an der ViewShell aufrufen!"); 1082 if ( !pViewSh ) 1083 return; 1084 1085 // Zun"achst alle Statecaches dirty machen, damit keiner mehr versucht, 1086 // die Slots zu benutzen 1087 { 1088 SfxBindings *pBindings = 1089 pViewSh->GetViewFrame()->GetDispatcher()->GetBindings(); 1090 sal_uInt16 nCount = pImp->aSlotArr.Count(); 1091 for (sal_uInt16 n1=0; n1<nCount ; n1++) 1092 { 1093 sal_uInt16 nId = SID_VERB_START + n1; 1094 pBindings->Invalidate(nId, sal_False, sal_True); 1095 } 1096 } 1097 1098 sal_uInt16 nr=0; 1099 for (sal_Int32 n=0; n<aVerbs.getLength(); n++) 1100 { 1101 sal_uInt16 nSlotId = SID_VERB_START + nr++; 1102 DBG_ASSERT(nSlotId <= SID_VERB_END, "Zuviele Verben!"); 1103 if (nSlotId > SID_VERB_END) 1104 break; 1105 1106 SfxSlot *pNewSlot = new SfxSlot; 1107 pNewSlot->nSlotId = nSlotId; 1108 pNewSlot->nGroupId = 0; 1109 1110 // Verb-Slots m"ussen asynchron ausgef"uhrt werden, da sie w"ahrend 1111 // des Ausf"uhrens zerst"ort werden k"onnten 1112 pNewSlot->nFlags = SFX_SLOT_ASYNCHRON | SFX_SLOT_CONTAINER; 1113 pNewSlot->nMasterSlotId = 0; 1114 pNewSlot->nValue = 0; 1115 pNewSlot->fnExec = SFX_STUB_PTR(SfxShell,VerbExec); 1116 pNewSlot->fnState = SFX_STUB_PTR(SfxShell,VerbState); 1117 pNewSlot->pType = 0; HACK(SFX_TYPE(SfxVoidItem)) 1118 pNewSlot->pName = U2S(aVerbs[n].VerbName); 1119 pNewSlot->pLinkedSlot = 0; 1120 pNewSlot->nArgDefCount = 0; 1121 pNewSlot->pFirstArgDef = 0; 1122 pNewSlot->pUnoName = 0; 1123 1124 if (pImp->aSlotArr.Count()) 1125 { 1126 SfxSlot *pSlot = (pImp->aSlotArr)[0]; 1127 pNewSlot->pNextSlot = pSlot->pNextSlot; 1128 pSlot->pNextSlot = pNewSlot; 1129 } 1130 else 1131 pNewSlot->pNextSlot = pNewSlot; 1132 1133 pImp->aSlotArr.Insert(pNewSlot, (sal_uInt16) n); 1134 } 1135 1136 pImp->aVerbList = aVerbs; 1137 1138 if (pViewSh) 1139 { 1140 // Der Status von SID_OBJECT wird im Controller direkt an der Shell 1141 // abgeholt, es reicht also, ein neues StatusUpdate anzuregen 1142 SfxBindings *pBindings = pViewSh->GetViewFrame()->GetDispatcher()-> 1143 GetBindings(); 1144 pBindings->Invalidate( SID_OBJECT, sal_True, sal_True ); 1145 } 1146 } 1147 1148 //-------------------------------------------------------------------- 1149 1150 const com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor >& SfxShell::GetVerbs() const 1151 { 1152 return pImp->aVerbList; 1153 } 1154 1155 //-------------------------------------------------------------------- 1156 1157 void SfxShell::VerbExec(SfxRequest& rReq) 1158 { 1159 sal_uInt16 nId = rReq.GetSlot(); 1160 SfxViewShell *pViewShell = GetViewShell(); 1161 if ( pViewShell ) 1162 { 1163 sal_Bool bReadOnly = pViewShell->GetObjectShell()->IsReadOnly(); 1164 com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > aList = pViewShell->GetVerbs(); 1165 for (sal_Int32 n=0, nVerb=0; n<aList.getLength(); n++) 1166 { 1167 // check for ReadOnly verbs 1168 if ( bReadOnly && !(aList[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) ) 1169 continue; 1170 1171 // check for verbs that shouldn't appear in the menu 1172 if ( !(aList[n].VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) ) 1173 continue; 1174 1175 if (nId == SID_VERB_START + nVerb++) 1176 { 1177 pViewShell->DoVerb(aList[n].VerbID); 1178 rReq.Done(); 1179 return; 1180 } 1181 } 1182 } 1183 } 1184 1185 //-------------------------------------------------------------------- 1186 1187 void SfxShell::VerbState(SfxItemSet& ) 1188 { 1189 } 1190 1191 //-------------------------------------------------------------------- 1192 1193 const SfxSlot* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId) const 1194 { 1195 com::sun::star::uno::Sequence < com::sun::star::embed::VerbDescriptor > rList = pImp->aVerbList; 1196 1197 DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Falsche VerbId!"); 1198 sal_uInt16 nIndex = nId - SID_VERB_START; 1199 DBG_ASSERT(nIndex < rList.getLength(),"Falsche VerbId!"); 1200 1201 if (nIndex < rList.getLength()) 1202 return pImp->aSlotArr[nIndex]; 1203 else 1204 return 0; 1205 } 1206 1207 //-------------------------------------------------------------------- 1208 1209 void SfxShell::SetHelpId(sal_uIntPtr nId) 1210 { 1211 pImp->nHelpId = nId; 1212 } 1213 1214 //-------------------------------------------------------------------- 1215 1216 sal_uIntPtr SfxShell::GetHelpId() const 1217 { 1218 return pImp->nHelpId; 1219 } 1220 1221 //-------------------------------------------------------------------- 1222 1223 SfxObjectShell* SfxShell::GetObjectShell() 1224 { 1225 if ( GetViewShell() ) 1226 return GetViewShell()->GetViewFrame()->GetObjectShell(); 1227 else 1228 return NULL; 1229 } 1230 1231 //-------------------------------------------------------------------- 1232 1233 sal_Bool SfxShell::HasUIFeature( sal_uInt32 ) 1234 { 1235 return sal_False; 1236 } 1237 1238 long DispatcherUpdate_Impl( void*, void* pArg ) 1239 { 1240 ((SfxDispatcher*) pArg)->Update_Impl( sal_True ); 1241 ((SfxDispatcher*) pArg)->GetBindings()->InvalidateAll(sal_False); 1242 return 0; 1243 } 1244 1245 void SfxShell::UIFeatureChanged() 1246 { 1247 SfxViewFrame *pFrame = GetFrame(); 1248 if ( pFrame && pFrame->IsVisible() ) 1249 { 1250 // Auch dann Update erzwingen, wenn Dispatcher schon geupdated ist, 1251 // sonst bleibt evtl. irgendwas in den gebunkerten Tools stecken. 1252 // Asynchron aufrufen, um Rekursionen zu vermeiden 1253 if ( !pImp->pUpdater ) 1254 pImp->pUpdater = new svtools::AsynchronLink( Link( this, DispatcherUpdate_Impl ) ); 1255 1256 // Mehrfachaufrufe gestattet 1257 pImp->pUpdater->Call( pFrame->GetDispatcher(), sal_True ); 1258 } 1259 } 1260 1261 void SfxShell::SetDisableFlags( sal_uIntPtr nFlags ) 1262 { 1263 pImp->nDisableFlags = nFlags; 1264 } 1265 1266 sal_uIntPtr SfxShell::GetDisableFlags() const 1267 { 1268 return pImp->nDisableFlags; 1269 } 1270 1271 SfxItemSet* SfxShell::CreateItemSet( sal_uInt16 ) 1272 { 1273 return NULL; 1274 } 1275 1276 void SfxShell::ApplyItemSet( sal_uInt16, const SfxItemSet& ) 1277 { 1278 } 1279 1280 void SfxShell::SetContextName (const ::rtl::OUString& rsContextName) 1281 { 1282 pImp->maContextChangeBroadcaster.Initialize(rsContextName); 1283 } 1284 1285 void SfxShell::SetViewShell_Impl( SfxViewShell* pView ) 1286 { 1287 pImp->pViewSh = pView; 1288 } 1289 1290 1291 1292 1293 void SfxShell::BroadcastContextForActivation (const bool bIsActivated) 1294 { 1295 SfxViewFrame* pViewFrame = GetFrame(); 1296 if (pViewFrame != NULL) 1297 if (bIsActivated) 1298 pImp->maContextChangeBroadcaster.Activate(pViewFrame->GetFrame().GetFrameInterface()); 1299 else 1300 pImp->maContextChangeBroadcaster.Deactivate(pViewFrame->GetFrame().GetFrameInterface()); 1301 } 1302 1303 1304 1305 1306 bool SfxShell::SetContextBroadcasterEnabled (const bool bIsEnabled) 1307 { 1308 return pImp->maContextChangeBroadcaster.SetBroadcasterEnabled(bIsEnabled); 1309 } 1310