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