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_sd.hxx" 30 31 #include "ViewTabBar.hxx" 32 33 #define USE_TAB_CONTROL 34 35 #include "ViewShell.hxx" 36 #include "ViewShellBase.hxx" 37 #include "DrawViewShell.hxx" 38 #include "FrameView.hxx" 39 #include "EventMultiplexer.hxx" 40 #include "framework/FrameworkHelper.hxx" 41 #include "framework/Pane.hxx" 42 #include "DrawController.hxx" 43 44 #include "sdresid.hxx" 45 #include "strings.hrc" 46 #include "helpids.h" 47 #include "Client.hxx" 48 #include <vcl/svapp.hxx> 49 #include <vcl/tabpage.hxx> 50 #include <vos/mutex.hxx> 51 #include <sfx2/viewfrm.hxx> 52 #include <com/sun/star/drawing/framework/ResourceId.hpp> 53 #include <com/sun/star/drawing/framework/XControllerManager.hpp> 54 #include <com/sun/star/lang/XUnoTunnel.hpp> 55 #include <com/sun/star/lang/DisposedException.hpp> 56 #include <comphelper/processfactory.hxx> 57 #include <tools/diagnose_ex.h> 58 59 using namespace ::com::sun::star; 60 using namespace ::com::sun::star::uno; 61 using namespace ::com::sun::star::drawing::framework; 62 using ::sd::framework::FrameworkHelper; 63 using ::sd::tools::EventMultiplexerEvent; 64 using ::rtl::OUString; 65 66 namespace sd { 67 68 namespace { 69 bool IsEqual (const TabBarButton& rButton1, const TabBarButton& rButton2) 70 { 71 return ( 72 (rButton1.ResourceId.is() 73 && rButton2.ResourceId.is() 74 && rButton1.ResourceId->compareTo(rButton2.ResourceId)==0) 75 || rButton1.ButtonLabel == rButton2.ButtonLabel); 76 } 77 78 class TabBarControl : public ::TabControl 79 { 80 public: 81 TabBarControl ( 82 ::Window* pParentWindow, 83 const ::rtl::Reference<ViewTabBar>& rpViewTabBar); 84 virtual void Paint (const Rectangle& rRect); 85 virtual void ActivatePage (void); 86 private: 87 ::rtl::Reference<ViewTabBar> mpViewTabBar; 88 }; 89 90 } // end of anonymous namespace 91 92 93 94 95 96 class ViewTabPage : public TabPage 97 { 98 public: 99 ViewTabPage (Window* pParent) : TabPage(pParent) {} 100 virtual void Resize (void) 101 { SetPosSizePixel(Point(0,0),GetParent()->GetOutputSizePixel()); } 102 }; 103 104 105 106 107 //===== ViewTabBar ============================================================ 108 109 ViewTabBar::ViewTabBar ( 110 const Reference<XResourceId>& rxViewTabBarId, 111 const Reference<frame::XController>& rxController) 112 : ViewTabBarInterfaceBase(maMutex), 113 mpTabControl(new TabBarControl(GetAnchorWindow(rxViewTabBarId,rxController), this)), 114 mxController(rxController), 115 maTabBarButtons(), 116 mpTabPage(NULL), 117 mxViewTabBarId(rxViewTabBarId), 118 mpViewShellBase(NULL) 119 { 120 // Set one new tab page for all tab entries. We need it only to 121 // determine the height of the tab bar. 122 mpTabPage.reset(new TabPage (mpTabControl.get())); 123 mpTabPage->Hide(); 124 125 // add some space before the tabitems 126 mpTabControl->SetItemsOffset(Point(5, 3)); 127 128 // Tunnel through the controller and use the ViewShellBase to obtain the 129 // view frame. 130 try 131 { 132 Reference<lang::XUnoTunnel> xTunnel (mxController, UNO_QUERY_THROW); 133 DrawController* pController = reinterpret_cast<DrawController*>( 134 xTunnel->getSomething(DrawController::getUnoTunnelId())); 135 mpViewShellBase = pController->GetViewShellBase(); 136 } 137 catch(RuntimeException&) 138 {} 139 140 // Register as listener at XConfigurationController. 141 Reference<XControllerManager> xControllerManager (mxController, UNO_QUERY); 142 if (xControllerManager.is()) 143 { 144 mxConfigurationController = xControllerManager->getConfigurationController(); 145 if (mxConfigurationController.is()) 146 { 147 mxConfigurationController->addConfigurationChangeListener( 148 this, 149 FrameworkHelper::msResourceActivationEvent, 150 Any()); 151 } 152 } 153 154 mpTabControl->Show(); 155 156 if (mpViewShellBase != NULL 157 && rxViewTabBarId->isBoundToURL( 158 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) 159 { 160 mpViewShellBase->SetViewTabBar(this); 161 } 162 } 163 164 165 166 167 ViewTabBar::~ViewTabBar (void) 168 { 169 } 170 171 172 173 174 void ViewTabBar::disposing (void) 175 { 176 if (mpViewShellBase != NULL 177 && mxViewTabBarId->isBoundToURL( 178 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) 179 { 180 mpViewShellBase->SetViewTabBar(NULL); 181 } 182 183 if (mxConfigurationController.is()) 184 { 185 // Unregister listener from XConfigurationController. 186 try 187 { 188 mxConfigurationController->removeConfigurationChangeListener(this); 189 } 190 catch (lang::DisposedException e) 191 { 192 // Receiving a disposed exception is the normal case. Is there 193 // a way to avoid it? 194 } 195 mxConfigurationController = NULL; 196 } 197 198 { 199 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 200 // Set all references to the one tab page to NULL and delete the page. 201 for (sal_uInt16 nIndex=0; nIndex<mpTabControl->GetPageCount(); ++nIndex) 202 mpTabControl->SetTabPage(nIndex, NULL); 203 mpTabPage.reset(); 204 mpTabControl.reset(); 205 } 206 207 mxController = NULL; 208 } 209 210 211 212 213 ::boost::shared_ptr< ::TabControl> ViewTabBar::GetTabControl (void) const 214 { 215 return mpTabControl; 216 } 217 218 219 220 221 ::Window* ViewTabBar::GetAnchorWindow( 222 const Reference<XResourceId>& rxViewTabBarId, 223 const Reference<frame::XController>& rxController) 224 { 225 ::Window* pWindow = NULL; 226 ViewShellBase* pBase = NULL; 227 228 // Tunnel through the controller and use the ViewShellBase to obtain the 229 // view frame. 230 try 231 { 232 Reference<lang::XUnoTunnel> xTunnel (rxController, UNO_QUERY_THROW); 233 DrawController* pController = reinterpret_cast<DrawController*>( 234 xTunnel->getSomething(DrawController::getUnoTunnelId())); 235 pBase = pController->GetViewShellBase(); 236 } 237 catch(RuntimeException&) 238 {} 239 240 // The ViewTabBar supports at the moment only the center pane. 241 if (rxViewTabBarId.is() 242 && rxViewTabBarId->isBoundToURL( 243 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) 244 { 245 if (pBase != NULL && pBase->GetViewFrame() != NULL) 246 pWindow = &pBase->GetViewFrame()->GetWindow(); 247 } 248 249 // The rest is (at the moment) just for the emergency case. 250 if (pWindow == NULL) 251 { 252 Reference<XPane> xPane; 253 try 254 { 255 Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY_THROW); 256 Reference<XConfigurationController> xCC ( 257 xControllerManager->getConfigurationController()); 258 if (xCC.is()) 259 xPane = Reference<XPane>(xCC->getResource(rxViewTabBarId->getAnchor()), UNO_QUERY); 260 } 261 catch (RuntimeException&) 262 {} 263 264 // Tunnel through the XWindow to the VCL side. 265 try 266 { 267 Reference<lang::XUnoTunnel> xTunnel (xPane, UNO_QUERY_THROW); 268 framework::Pane* pPane = reinterpret_cast<framework::Pane*>( 269 xTunnel->getSomething(framework::Pane::getUnoTunnelId())); 270 if (pPane != NULL) 271 pWindow = pPane->GetWindow()->GetParent(); 272 } 273 catch (RuntimeException&) 274 {} 275 } 276 277 return pWindow; 278 } 279 280 281 282 283 //----- XConfigurationChangeListener ------------------------------------------ 284 285 void SAL_CALL ViewTabBar::notifyConfigurationChange ( 286 const ConfigurationChangeEvent& rEvent) 287 throw (RuntimeException) 288 { 289 if (rEvent.Type.equals(FrameworkHelper::msResourceActivationEvent) 290 && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix) 291 && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT)) 292 { 293 UpdateActiveButton(); 294 } 295 } 296 297 298 299 300 //----- XEventListener -------------------------------------------------------- 301 302 void SAL_CALL ViewTabBar::disposing( 303 const lang::EventObject& rEvent) 304 throw (RuntimeException) 305 { 306 if (rEvent.Source == mxConfigurationController) 307 { 308 mxConfigurationController = NULL; 309 mxController = NULL; 310 } 311 } 312 313 314 315 316 //----- XTabBar --------------------------------------------------------------- 317 318 void SAL_CALL ViewTabBar::addTabBarButtonAfter ( 319 const TabBarButton& rButton, 320 const TabBarButton& rAnchor) 321 throw (::com::sun::star::uno::RuntimeException) 322 { 323 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 324 AddTabBarButton(rButton, rAnchor); 325 } 326 327 328 329 330 void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton) 331 throw (::com::sun::star::uno::RuntimeException) 332 { 333 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 334 AddTabBarButton(rButton); 335 } 336 337 338 339 void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton) 340 throw (::com::sun::star::uno::RuntimeException) 341 { 342 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 343 RemoveTabBarButton(rButton); 344 } 345 346 347 348 349 sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton) 350 throw (::com::sun::star::uno::RuntimeException) 351 { 352 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 353 return HasTabBarButton(rButton); 354 } 355 356 357 358 359 Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons (void) 360 throw (::com::sun::star::uno::RuntimeException) 361 { 362 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 363 return GetTabBarButtons(); 364 } 365 366 367 368 369 //----- XResource ------------------------------------------------------------- 370 371 Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId (void) 372 throw (RuntimeException) 373 { 374 return mxViewTabBarId; 375 } 376 377 378 379 380 sal_Bool SAL_CALL ViewTabBar::isAnchorOnly (void) 381 throw (RuntimeException) 382 { 383 return false; 384 } 385 386 387 388 389 //----- XUnoTunnel ------------------------------------------------------------ 390 391 const Sequence<sal_Int8>& ViewTabBar::getUnoTunnelId (void) 392 { 393 static Sequence<sal_Int8>* pSequence = NULL; 394 if (pSequence == NULL) 395 { 396 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 397 if (pSequence == NULL) 398 { 399 static ::com::sun::star::uno::Sequence<sal_Int8> aSequence (16); 400 rtl_createUuid((sal_uInt8*)aSequence.getArray(), 0, sal_True); 401 pSequence = &aSequence; 402 } 403 } 404 return *pSequence; 405 } 406 407 408 409 410 sal_Int64 SAL_CALL ViewTabBar::getSomething (const Sequence<sal_Int8>& rId) 411 throw (RuntimeException) 412 { 413 sal_Int64 nResult = 0; 414 415 if (rId.getLength() == 16 416 && rtl_compareMemory(getUnoTunnelId().getConstArray(), rId.getConstArray(), 16) == 0) 417 { 418 nResult = reinterpret_cast<sal_Int64>(this); 419 } 420 421 return nResult; 422 } 423 424 425 426 427 //----------------------------------------------------------------------------- 428 429 bool ViewTabBar::ActivatePage (void) 430 { 431 try 432 { 433 Reference<XControllerManager> xControllerManager (mxController,UNO_QUERY_THROW); 434 Reference<XConfigurationController> xConfigurationController ( 435 xControllerManager->getConfigurationController()); 436 if ( ! xConfigurationController.is()) 437 throw RuntimeException(); 438 Reference<XView> xView; 439 try 440 { 441 xView = Reference<XView>(xConfigurationController->getResource( 442 ResourceId::create( 443 ::comphelper::getProcessComponentContext(), 444 FrameworkHelper::msCenterPaneURL)), 445 UNO_QUERY); 446 } 447 catch (DeploymentException) 448 { 449 } 450 451 Client* pIPClient = NULL; 452 if (mpViewShellBase != NULL) 453 pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient()); 454 if (pIPClient==NULL || ! pIPClient->IsObjectInPlaceActive()) 455 { 456 sal_uInt16 nIndex (mpTabControl->GetCurPageId() - 1); 457 if (nIndex < maTabBarButtons.size()) 458 { 459 xConfigurationController->requestResourceActivation( 460 maTabBarButtons[nIndex].ResourceId, 461 ResourceActivationMode_REPLACE); 462 } 463 464 return true; 465 } 466 else 467 { 468 // When we run into this else branch then we have an active OLE 469 // object. We ignore the request to switch views. Additionally 470 // we put the active tab back to the one for the current view. 471 UpdateActiveButton(); 472 } 473 } 474 catch (RuntimeException&) 475 { 476 DBG_UNHANDLED_EXCEPTION(); 477 } 478 479 return false; 480 } 481 482 483 484 485 int ViewTabBar::GetHeight (void) 486 { 487 int nHeight (0); 488 489 if (!maTabBarButtons.empty()) 490 { 491 TabPage* pActivePage (mpTabControl->GetTabPage( 492 mpTabControl->GetCurPageId())); 493 if (pActivePage!=NULL && mpTabControl->IsReallyVisible()) 494 nHeight = pActivePage->GetPosPixel().Y(); 495 496 if (nHeight <= 0) 497 // Using a default when the real height can not be determined. 498 // To get correct height this method should be called when the 499 // control is visible. 500 nHeight = 21; 501 } 502 503 return nHeight; 504 } 505 506 507 508 509 void ViewTabBar::AddTabBarButton ( 510 const ::com::sun::star::drawing::framework::TabBarButton& rButton, 511 const ::com::sun::star::drawing::framework::TabBarButton& rAnchor) 512 { 513 sal_uInt32 nIndex; 514 515 if ( ! rAnchor.ResourceId.is() 516 || (rAnchor.ResourceId->getResourceURL().getLength() == 0 517 && rAnchor.ButtonLabel.getLength() == 0)) 518 { 519 nIndex = 0; 520 } 521 else 522 { 523 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 524 { 525 if (IsEqual(maTabBarButtons[nIndex], rAnchor)) 526 { 527 ++nIndex; 528 break; 529 } 530 } 531 } 532 533 AddTabBarButton(rButton,nIndex); 534 } 535 536 537 538 539 void ViewTabBar::AddTabBarButton ( 540 const ::com::sun::star::drawing::framework::TabBarButton& rButton) 541 { 542 AddTabBarButton(rButton, maTabBarButtons.size()); 543 } 544 545 546 547 548 void ViewTabBar::AddTabBarButton ( 549 const ::com::sun::star::drawing::framework::TabBarButton& rButton, 550 sal_Int32 nPosition) 551 { 552 if (nPosition>=0 553 && nPosition<=mpTabControl->GetPageCount()) 554 { 555 sal_uInt16 nIndex ((sal_uInt16)nPosition); 556 557 // Insert the button into our local array. 558 maTabBarButtons.insert(maTabBarButtons.begin()+nIndex, rButton); 559 UpdateTabBarButtons(); 560 UpdateActiveButton(); 561 } 562 } 563 564 565 566 567 void ViewTabBar::RemoveTabBarButton ( 568 const ::com::sun::star::drawing::framework::TabBarButton& rButton) 569 { 570 sal_uInt16 nIndex; 571 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 572 { 573 if (IsEqual(maTabBarButtons[nIndex], rButton)) 574 { 575 maTabBarButtons.erase(maTabBarButtons.begin()+nIndex); 576 UpdateTabBarButtons(); 577 UpdateActiveButton(); 578 break; 579 } 580 } 581 } 582 583 584 585 586 bool ViewTabBar::HasTabBarButton ( 587 const ::com::sun::star::drawing::framework::TabBarButton& rButton) 588 { 589 bool bResult (false); 590 591 for (sal_uInt32 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 592 { 593 if (IsEqual(maTabBarButtons[nIndex], rButton)) 594 { 595 bResult = true; 596 break; 597 } 598 } 599 600 return bResult; 601 } 602 603 604 605 606 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton> 607 ViewTabBar::GetTabBarButtons (void) 608 { 609 sal_uInt32 nCount (maTabBarButtons.size()); 610 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton> 611 aList (nCount); 612 613 for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex) 614 aList[nIndex] = maTabBarButtons[nIndex]; 615 616 return aList; 617 } 618 619 620 621 622 void ViewTabBar::UpdateActiveButton (void) 623 { 624 Reference<XView> xView; 625 if (mpViewShellBase != NULL) 626 xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView( 627 mxViewTabBarId->getAnchor()); 628 if (xView.is()) 629 { 630 Reference<XResourceId> xViewId (xView->getResourceId()); 631 for (sal_uInt16 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 632 { 633 if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0) 634 { 635 mpTabControl->SetCurPageId(nIndex+1); 636 mpTabControl->::TabControl::ActivatePage(); 637 break; 638 } 639 } 640 } 641 } 642 643 644 645 646 void ViewTabBar::UpdateTabBarButtons (void) 647 { 648 TabBarButtonList::const_iterator iTab; 649 sal_uInt16 nPageCount (mpTabControl->GetPageCount()); 650 sal_uInt16 nIndex; 651 for (iTab=maTabBarButtons.begin(),nIndex=1; iTab!=maTabBarButtons.end(); ++iTab,++nIndex) 652 { 653 // Create a new tab when there are not enough. 654 if (nPageCount < nIndex) 655 mpTabControl->InsertPage(nIndex, iTab->ButtonLabel); 656 657 // Update the tab. 658 mpTabControl->SetPageText(nIndex, iTab->ButtonLabel); 659 mpTabControl->SetHelpText(nIndex, iTab->HelpText); 660 mpTabControl->SetTabPage(nIndex, mpTabPage.get()); 661 } 662 663 // Delete tabs that are no longer used. 664 for (; nIndex<=nPageCount; ++nIndex) 665 mpTabControl->RemovePage(nIndex); 666 667 mpTabPage->Hide(); 668 } 669 670 671 672 673 //===== TabBarControl ========================================================= 674 675 TabBarControl::TabBarControl ( 676 ::Window* pParentWindow, 677 const ::rtl::Reference<ViewTabBar>& rpViewTabBar) 678 : ::TabControl(pParentWindow), 679 mpViewTabBar(rpViewTabBar) 680 { 681 } 682 683 684 685 686 void TabBarControl::Paint (const Rectangle& rRect) 687 { 688 Color aOriginalFillColor (GetFillColor()); 689 Color aOriginalLineColor (GetLineColor()); 690 691 // Because the actual window background is transparent--to avoid 692 // flickering due to multiple background paintings by this and by child 693 // windows--we have to paint the background for this control explicitly: 694 // the actual control is not painted over its whole bounding box. 695 SetFillColor (GetSettings().GetStyleSettings().GetDialogColor()); 696 SetLineColor (); 697 DrawRect (rRect); 698 ::TabControl::Paint (rRect); 699 700 SetFillColor (aOriginalFillColor); 701 SetLineColor (aOriginalLineColor); 702 } 703 704 705 706 707 void TabBarControl::ActivatePage (void) 708 { 709 if (mpViewTabBar->ActivatePage()) 710 { 711 // Call the parent so that the correct tab is highlighted. 712 this->::TabControl::ActivatePage(); 713 } 714 } 715 716 } // end of namespace sd 717