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