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