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 { 284 if (rEvent.Type.equals(FrameworkHelper::msResourceActivationEvent) 285 && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix) 286 && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT)) 287 { 288 UpdateActiveButton(); 289 } 290 } 291 292 293 294 295 //----- XEventListener -------------------------------------------------------- 296 297 void SAL_CALL ViewTabBar::disposing( 298 const lang::EventObject& rEvent) 299 { 300 if (rEvent.Source == mxConfigurationController) 301 { 302 mxConfigurationController = NULL; 303 mxController = NULL; 304 } 305 } 306 307 308 309 310 //----- XTabBar --------------------------------------------------------------- 311 312 void SAL_CALL ViewTabBar::addTabBarButtonAfter ( 313 const TabBarButton& rButton, 314 const TabBarButton& rAnchor) 315 { 316 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 317 AddTabBarButton(rButton, rAnchor); 318 } 319 320 321 322 323 void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton) 324 { 325 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 326 AddTabBarButton(rButton); 327 } 328 329 330 331 void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton) 332 { 333 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 334 RemoveTabBarButton(rButton); 335 } 336 337 338 339 340 sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton) 341 { 342 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 343 return HasTabBarButton(rButton); 344 } 345 346 347 348 349 Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons (void) 350 { 351 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 352 return GetTabBarButtons(); 353 } 354 355 356 357 358 //----- XResource ------------------------------------------------------------- 359 360 Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId (void) 361 { 362 return mxViewTabBarId; 363 } 364 365 366 367 368 sal_Bool SAL_CALL ViewTabBar::isAnchorOnly (void) 369 { 370 return false; 371 } 372 373 374 375 376 //----- XUnoTunnel ------------------------------------------------------------ 377 378 const Sequence<sal_Int8>& ViewTabBar::getUnoTunnelId (void) 379 { 380 static Sequence<sal_Int8>* pSequence = NULL; 381 if (pSequence == NULL) 382 { 383 const ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); 384 if (pSequence == NULL) 385 { 386 static ::com::sun::star::uno::Sequence<sal_Int8> aSequence (16); 387 rtl_createUuid((sal_uInt8*)aSequence.getArray(), 0, sal_True); 388 pSequence = &aSequence; 389 } 390 } 391 return *pSequence; 392 } 393 394 395 396 397 sal_Int64 SAL_CALL ViewTabBar::getSomething (const Sequence<sal_Int8>& rId) 398 { 399 sal_Int64 nResult = 0; 400 401 if (rId.getLength() == 16 402 && rtl_compareMemory(getUnoTunnelId().getConstArray(), rId.getConstArray(), 16) == 0) 403 { 404 nResult = reinterpret_cast<sal_Int64>(this); 405 } 406 407 return nResult; 408 } 409 410 411 412 413 //----------------------------------------------------------------------------- 414 415 bool ViewTabBar::ActivatePage (void) 416 { 417 try 418 { 419 Reference<XControllerManager> xControllerManager (mxController,UNO_QUERY_THROW); 420 Reference<XConfigurationController> xConfigurationController ( 421 xControllerManager->getConfigurationController()); 422 if ( ! xConfigurationController.is()) 423 throw RuntimeException(); 424 Reference<XView> xView; 425 try 426 { 427 xView = Reference<XView>(xConfigurationController->getResource( 428 ResourceId::create( 429 ::comphelper::getProcessComponentContext(), 430 FrameworkHelper::msCenterPaneURL)), 431 UNO_QUERY); 432 } 433 catch (DeploymentException) 434 { 435 } 436 437 Client* pIPClient = NULL; 438 if (mpViewShellBase != NULL) 439 pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient()); 440 if (pIPClient==NULL || ! pIPClient->IsObjectInPlaceActive()) 441 { 442 sal_uInt16 nIndex (mpTabControl->GetCurPageId() - 1); 443 if (nIndex < maTabBarButtons.size()) 444 { 445 xConfigurationController->requestResourceActivation( 446 maTabBarButtons[nIndex].ResourceId, 447 ResourceActivationMode_REPLACE); 448 } 449 450 return true; 451 } 452 else 453 { 454 // When we run into this else branch then we have an active OLE 455 // object. We ignore the request to switch views. Additionally 456 // we put the active tab back to the one for the current view. 457 UpdateActiveButton(); 458 } 459 } 460 catch (RuntimeException&) 461 { 462 DBG_UNHANDLED_EXCEPTION(); 463 } 464 465 return false; 466 } 467 468 469 470 471 int ViewTabBar::GetHeight (void) 472 { 473 int nHeight (0); 474 475 if (!maTabBarButtons.empty()) 476 { 477 TabPage* pActivePage (mpTabControl->GetTabPage( 478 mpTabControl->GetCurPageId())); 479 if (pActivePage!=NULL && mpTabControl->IsReallyVisible()) 480 nHeight = pActivePage->GetPosPixel().Y(); 481 482 if (nHeight <= 0) 483 // Using a default when the real height can not be determined. 484 // To get correct height this method should be called when the 485 // control is visible. 486 nHeight = 21; 487 } 488 489 return nHeight; 490 } 491 492 493 494 495 void ViewTabBar::AddTabBarButton ( 496 const ::com::sun::star::drawing::framework::TabBarButton& rButton, 497 const ::com::sun::star::drawing::framework::TabBarButton& rAnchor) 498 { 499 sal_uInt32 nIndex; 500 501 if ( ! rAnchor.ResourceId.is() 502 || (rAnchor.ResourceId->getResourceURL().getLength() == 0 503 && rAnchor.ButtonLabel.getLength() == 0)) 504 { 505 nIndex = 0; 506 } 507 else 508 { 509 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 510 { 511 if (IsEqual(maTabBarButtons[nIndex], rAnchor)) 512 { 513 ++nIndex; 514 break; 515 } 516 } 517 } 518 519 AddTabBarButton(rButton,nIndex); 520 } 521 522 523 524 525 void ViewTabBar::AddTabBarButton ( 526 const ::com::sun::star::drawing::framework::TabBarButton& rButton) 527 { 528 AddTabBarButton(rButton, maTabBarButtons.size()); 529 } 530 531 532 533 534 void ViewTabBar::AddTabBarButton ( 535 const ::com::sun::star::drawing::framework::TabBarButton& rButton, 536 sal_Int32 nPosition) 537 { 538 if (nPosition>=0 539 && nPosition<=mpTabControl->GetPageCount()) 540 { 541 sal_uInt16 nIndex ((sal_uInt16)nPosition); 542 543 // Insert the button into our local array. 544 maTabBarButtons.insert(maTabBarButtons.begin()+nIndex, rButton); 545 UpdateTabBarButtons(); 546 UpdateActiveButton(); 547 } 548 } 549 550 551 552 553 void ViewTabBar::RemoveTabBarButton ( 554 const ::com::sun::star::drawing::framework::TabBarButton& rButton) 555 { 556 sal_uInt16 nIndex; 557 for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 558 { 559 if (IsEqual(maTabBarButtons[nIndex], rButton)) 560 { 561 maTabBarButtons.erase(maTabBarButtons.begin()+nIndex); 562 UpdateTabBarButtons(); 563 UpdateActiveButton(); 564 break; 565 } 566 } 567 } 568 569 570 571 572 bool ViewTabBar::HasTabBarButton ( 573 const ::com::sun::star::drawing::framework::TabBarButton& rButton) 574 { 575 bool bResult (false); 576 577 for (sal_uInt32 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 578 { 579 if (IsEqual(maTabBarButtons[nIndex], rButton)) 580 { 581 bResult = true; 582 break; 583 } 584 } 585 586 return bResult; 587 } 588 589 590 591 592 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton> 593 ViewTabBar::GetTabBarButtons (void) 594 { 595 sal_uInt32 nCount (maTabBarButtons.size()); 596 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton> 597 aList (nCount); 598 599 for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex) 600 aList[nIndex] = maTabBarButtons[nIndex]; 601 602 return aList; 603 } 604 605 606 607 608 void ViewTabBar::UpdateActiveButton (void) 609 { 610 Reference<XView> xView; 611 if (mpViewShellBase != NULL) 612 xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView( 613 mxViewTabBarId->getAnchor()); 614 if (xView.is()) 615 { 616 Reference<XResourceId> xViewId (xView->getResourceId()); 617 for (sal_uInt16 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) 618 { 619 if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0) 620 { 621 mpTabControl->SetCurPageId(nIndex+1); 622 mpTabControl->::TabControl::ActivatePage(); 623 break; 624 } 625 } 626 } 627 } 628 629 630 631 632 void ViewTabBar::UpdateTabBarButtons (void) 633 { 634 TabBarButtonList::const_iterator iTab; 635 sal_uInt16 nPageCount (mpTabControl->GetPageCount()); 636 sal_uInt16 nIndex; 637 for (iTab=maTabBarButtons.begin(),nIndex=1; iTab!=maTabBarButtons.end(); ++iTab,++nIndex) 638 { 639 // Create a new tab when there are not enough. 640 if (nPageCount < nIndex) 641 mpTabControl->InsertPage(nIndex, iTab->ButtonLabel); 642 643 // Update the tab. 644 mpTabControl->SetPageText(nIndex, iTab->ButtonLabel); 645 mpTabControl->SetHelpText(nIndex, iTab->HelpText); 646 mpTabControl->SetTabPage(nIndex, mpTabPage.get()); 647 } 648 649 // Delete tabs that are no longer used. 650 for (; nIndex<=nPageCount; ++nIndex) 651 mpTabControl->RemovePage(nIndex); 652 653 mpTabPage->Hide(); 654 } 655 656 657 658 659 //===== TabBarControl ========================================================= 660 661 TabBarControl::TabBarControl ( 662 ::Window* pParentWindow, 663 const ::rtl::Reference<ViewTabBar>& rpViewTabBar) 664 : ::TabControl(pParentWindow), 665 mpViewTabBar(rpViewTabBar) 666 { 667 } 668 669 670 671 672 void TabBarControl::Paint (const Rectangle& rRect) 673 { 674 Color aOriginalFillColor (GetFillColor()); 675 Color aOriginalLineColor (GetLineColor()); 676 677 // Because the actual window background is transparent--to avoid 678 // flickering due to multiple background paintings by this and by child 679 // windows--we have to paint the background for this control explicitly: 680 // the actual control is not painted over its whole bounding box. 681 SetFillColor (GetSettings().GetStyleSettings().GetDialogColor()); 682 SetLineColor (); 683 DrawRect (rRect); 684 ::TabControl::Paint (rRect); 685 686 SetFillColor (aOriginalFillColor); 687 SetLineColor (aOriginalLineColor); 688 } 689 690 691 692 693 void TabBarControl::ActivatePage (void) 694 { 695 if (mpViewTabBar->ActivatePage()) 696 { 697 // Call the parent so that the correct tab is highlighted. 698 this->::TabControl::ActivatePage(); 699 } 700 } 701 702 } // end of namespace sd 703