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 #include "precompiled_sfx2.hxx" 23 24 #include "SidebarController.hxx" 25 #include "Deck.hxx" 26 #include "DeckTitleBar.hxx" 27 #include "Panel.hxx" 28 #include "SidebarPanel.hxx" 29 #include "SidebarResource.hxx" 30 #include "TabBar.hxx" 31 #include "sfx2/sidebar/Theme.hxx" 32 #include "SidebarDockingWindow.hxx" 33 #include "Context.hxx" 34 #include "Tools.hxx" 35 36 #include "sfxresid.hxx" 37 #include "sfx2/sfxsids.hrc" 38 #include "sfx2/titledockwin.hxx" 39 #include "sfxlocal.hrc" 40 #include <vcl/floatwin.hxx> 41 #include "splitwin.hxx" 42 #include <svl/smplhint.hxx> 43 #include <tools/link.hxx> 44 #include <toolkit/helper/vclunohelper.hxx> 45 46 #include <comphelper/componentfactory.hxx> 47 #include <comphelper/processfactory.hxx> 48 #include <comphelper/componentcontext.hxx> 49 #include <comphelper/namedvaluecollection.hxx> 50 51 #include <com/sun/star/frame/XDispatchProvider.hpp> 52 #include <com/sun/star/lang/XInitialization.hpp> 53 #include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp> 54 #include <com/sun/star/ui/ContextChangeEventObject.hpp> 55 #include <com/sun/star/ui/XUIElementFactory.hpp> 56 #include <com/sun/star/util/XURLTransformer.hpp> 57 #include <com/sun/star/util/URL.hpp> 58 #include <com/sun/star/rendering/XSpriteCanvas.hpp> 59 60 #include <boost/bind.hpp> 61 #include <boost/function.hpp> 62 #include <boost/scoped_array.hpp> 63 64 65 using namespace css; 66 using namespace cssu; 67 using ::rtl::OUString; 68 69 70 #undef VERBOSE 71 72 namespace sfx2 { namespace sidebar { 73 74 namespace { 75 enum MenuId 76 { 77 MID_UNLOCK_TASK_PANEL = 1, 78 MID_LOCK_TASK_PANEL, 79 MID_CUSTOMIZATION, 80 MID_RESTORE_DEFAULT, 81 MID_FIRST_PANEL, 82 MID_FIRST_HIDE = 1000 83 }; 84 } 85 86 87 SidebarController::SidebarController ( 88 SidebarDockingWindow* pParentWindow, 89 const cssu::Reference<css::frame::XFrame>& rxFrame) 90 : SidebarControllerInterfaceBase(m_aMutex), 91 mpCurrentDeck(), 92 mpParentWindow(pParentWindow), 93 mpTabBar(new TabBar( 94 mpParentWindow, 95 rxFrame, 96 ::boost::bind(&SidebarController::SwitchToDeck, this, _1), 97 ::boost::bind(&SidebarController::ShowPopupMenu, this, _1,_2,_3))), 98 mxFrame(rxFrame), 99 maCurrentContext(OUString(), OUString()), 100 msCurrentDeckId(A2S("PropertyDeck")), 101 maPropertyChangeForwarder(::boost::bind(&SidebarController::BroadcastPropertyChange, this)), 102 maContextChangeUpdate(::boost::bind(&SidebarController::UpdateConfigurations, this)), 103 mbIsDeckClosed(false), 104 mnSavedSidebarWidth(pParentWindow->GetSizePixel().Width()) 105 { 106 if (pParentWindow == NULL) 107 { 108 OSL_ASSERT(pParentWindow!=NULL); 109 return; 110 } 111 112 // Listen for context change events. 113 cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( 114 css::ui::ContextChangeEventMultiplexer::get( 115 ::comphelper::getProcessComponentContext())); 116 if (xMultiplexer.is()) 117 xMultiplexer->addContextChangeEventListener( 118 static_cast<css::ui::XContextChangeEventListener*>(this), 119 mxFrame->getController()); 120 121 // Listen for window events. 122 mpParentWindow->AddEventListener(LINK(this, SidebarController, WindowEventHandler)); 123 124 // Listen for theme property changes. 125 Theme::GetPropertySet()->addPropertyChangeListener( 126 A2S(""), 127 static_cast<css::beans::XPropertyChangeListener*>(this)); 128 129 SwitchToDeck(A2S("default")); 130 } 131 132 133 134 135 SidebarController::~SidebarController (void) 136 { 137 } 138 139 140 141 142 void SAL_CALL SidebarController::disposing (void) 143 { 144 maFocusManager.Clear(); 145 146 cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( 147 css::ui::ContextChangeEventMultiplexer::get( 148 ::comphelper::getProcessComponentContext())); 149 if (xMultiplexer.is()) 150 xMultiplexer->removeAllContextChangeEventListeners( 151 static_cast<css::ui::XContextChangeEventListener*>(this)); 152 153 if (mpParentWindow != NULL) 154 { 155 mpParentWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler)); 156 mpParentWindow = NULL; 157 } 158 159 if (mpCurrentDeck) 160 { 161 mpCurrentDeck->Dispose(); 162 mpCurrentDeck->PrintWindowTree(); 163 mpCurrentDeck.reset(); 164 } 165 166 mpTabBar.reset(); 167 168 Theme::GetPropertySet()->removePropertyChangeListener( 169 A2S(""), 170 static_cast<css::beans::XPropertyChangeListener*>(this)); 171 } 172 173 174 175 176 void SAL_CALL SidebarController::notifyContextChangeEvent (const css::ui::ContextChangeEventObject& rEvent) 177 throw(cssu::RuntimeException) 178 { 179 // Update to the requested new context asynchronously to avoid 180 // subtle errors caused by SFX2 which in rare cases can not 181 // properly handle a synchronous update. 182 maRequestedContext = Context( 183 rEvent.ApplicationName, 184 rEvent.ContextName); 185 if (maRequestedContext != maCurrentContext) 186 maContextChangeUpdate.RequestCall(); 187 } 188 189 190 191 192 void SAL_CALL SidebarController::disposing (const css::lang::EventObject& rEventObject) 193 throw(cssu::RuntimeException) 194 { 195 (void)rEventObject; 196 197 dispose(); 198 } 199 200 201 202 203 void SAL_CALL SidebarController::propertyChange (const css::beans::PropertyChangeEvent& rEvent) 204 throw(cssu::RuntimeException) 205 { 206 (void)rEvent; 207 208 maPropertyChangeForwarder.RequestCall(); 209 } 210 211 212 213 214 void SAL_CALL SidebarController::requestLayout (void) 215 throw(cssu::RuntimeException) 216 { 217 if (mpCurrentDeck) 218 mpCurrentDeck->RequestLayout(); 219 RestrictWidth(); 220 } 221 222 223 224 225 void SidebarController::BroadcastPropertyChange (void) 226 { 227 DataChangedEvent aEvent (DATACHANGED_USER); 228 mpParentWindow->NotifyAllChilds(aEvent); 229 mpParentWindow->Invalidate(INVALIDATE_CHILDREN); 230 } 231 232 233 234 235 void SidebarController::NotifyResize (void) 236 { 237 if (mpTabBar == NULL) 238 { 239 OSL_ASSERT(mpTabBar!=NULL); 240 return; 241 } 242 243 Window* pParentWindow = mpTabBar->GetParent(); 244 245 const sal_Int32 nWidth (pParentWindow->GetSizePixel().Width()); 246 const sal_Int32 nHeight (pParentWindow->GetSizePixel().Height()); 247 248 // Place the deck. 249 if (mpCurrentDeck) 250 { 251 mpCurrentDeck->SetPosSizePixel(0,0, nWidth-TabBar::GetDefaultWidth(), nHeight); 252 mpCurrentDeck->Show(); 253 mpCurrentDeck->RequestLayout(); 254 } 255 256 // Place the tab bar. 257 mpTabBar->SetPosSizePixel(nWidth-TabBar::GetDefaultWidth(),0,TabBar::GetDefaultWidth(),nHeight); 258 mpTabBar->Show(); 259 260 // Determine if the closer of the deck can be shown. 261 if (mpCurrentDeck) 262 { 263 DeckTitleBar* pTitleBar = mpCurrentDeck->GetTitleBar(); 264 if (pTitleBar != NULL && pTitleBar->IsVisible()) 265 pTitleBar->SetCloserVisible(CanModifyChildWindowWidth()); 266 } 267 268 if (nWidth > TabBar::GetDefaultWidth()) 269 mnSavedSidebarWidth = nWidth; 270 271 RestrictWidth(); 272 #ifdef VERBOSE 273 if (mpCurrentDeck) 274 { 275 mpCurrentDeck->PrintWindowTree(); 276 sal_Int32 nPanelIndex (0); 277 for (SharedPanelContainer::const_iterator 278 iPanel(mpCurrentDeck->GetPanels().begin()), 279 iEnd(mpCurrentDeck->GetPanels().end()); 280 iPanel!=iEnd; 281 ++iPanel,++nPanelIndex) 282 { 283 OSL_TRACE("panel %d:", nPanelIndex); 284 (*iPanel)->PrintWindowTree(); 285 } 286 } 287 #endif 288 } 289 290 291 292 293 void SidebarController::UpdateConfigurations (void) 294 { 295 if (maCurrentContext != maRequestedContext) 296 { 297 maCurrentContext = maRequestedContext; 298 299 // Notify the tab bar about the updated set of decks. 300 ResourceManager::IdContainer aDeckIds; 301 ResourceManager::Instance().GetMatchingDecks ( 302 aDeckIds, 303 maCurrentContext, 304 mxFrame); 305 mpTabBar->SetDecks(aDeckIds); 306 307 // Check if the current deck is among the matching decks. 308 bool bCurrentDeckMatches (false); 309 for (ResourceManager::IdContainer::const_iterator 310 iDeck(aDeckIds.begin()), 311 iEnd(aDeckIds.end()); 312 iDeck!=iEnd; 313 ++iDeck) 314 { 315 if (iDeck->equals(msCurrentDeckId)) 316 { 317 bCurrentDeckMatches = true; 318 break; 319 } 320 } 321 322 DeckDescriptor const* pDeckDescriptor = NULL; 323 if ( ! bCurrentDeckMatches) 324 pDeckDescriptor = ResourceManager::Instance().GetBestMatchingDeck(maCurrentContext, mxFrame); 325 else 326 pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(msCurrentDeckId); 327 if (pDeckDescriptor != NULL) 328 { 329 msCurrentDeckId = pDeckDescriptor->msId; 330 SwitchToDeck(*pDeckDescriptor, maCurrentContext); 331 332 // Tell the tab bar to highlight the button associated 333 // with the deck. 334 mpTabBar->HighlightDeck(msCurrentDeckId); 335 } 336 337 #ifdef DEBUG 338 // Show the context name in the deck title bar. 339 if (mpCurrentDeck) 340 { 341 DeckTitleBar* pTitleBar = mpCurrentDeck->GetTitleBar(); 342 if (pTitleBar != NULL) 343 pTitleBar->SetTitle(msCurrentDeckTitle+A2S(" (")+maCurrentContext.msContext+A2S(")")); 344 } 345 #endif 346 } 347 } 348 349 350 351 352 void SidebarController::SwitchToDeck ( 353 const ::rtl::OUString& rsDeckId) 354 { 355 if ( ! msCurrentDeckId.equals(rsDeckId) || mbIsDeckClosed) 356 { 357 const DeckDescriptor* pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(rsDeckId); 358 if (pDeckDescriptor != NULL) 359 SwitchToDeck(*pDeckDescriptor, maCurrentContext); 360 } 361 } 362 363 364 365 366 void SidebarController::SwitchToDeck ( 367 const DeckDescriptor& rDeckDescriptor, 368 const Context& rContext) 369 { 370 maFocusManager.Clear(); 371 372 if ( ! msCurrentDeckId.equals(rDeckDescriptor.msId)) 373 { 374 // When the deck changes then destroy the deck and all panels 375 // and create everything new. 376 if (mpCurrentDeck) 377 { 378 mpCurrentDeck->Dispose(); 379 mpCurrentDeck.reset(); 380 } 381 382 msCurrentDeckId = rDeckDescriptor.msId; 383 } 384 385 // Reopen the deck when necessary. 386 OpenDeck(); 387 388 // Determine the panels to display in the deck. 389 ResourceManager::PanelContextDescriptorContainer aPanelContextDescriptors; 390 ResourceManager::Instance().GetMatchingPanels( 391 aPanelContextDescriptors, 392 rContext, 393 rDeckDescriptor.msId, 394 mxFrame); 395 396 if (aPanelContextDescriptors.empty()) 397 { 398 // There are no panels to be displayed in the current context. 399 if (EnumContext::GetContextEnum(rContext.msContext) != EnumContext::Context_Empty) 400 { 401 // Switch to the "empty" context and try again. 402 SwitchToDeck( 403 rDeckDescriptor, 404 Context( 405 rContext.msApplication, 406 EnumContext::GetContextName(EnumContext::Context_Empty))); 407 return; 408 } 409 else 410 { 411 // This is already the "empty" context. Looks like we have 412 // to live with an empty deck. 413 } 414 } 415 416 if (mpCurrentDeck 417 && ArePanelSetsEqual(mpCurrentDeck->GetPanels(), aPanelContextDescriptors)) 418 { 419 // Requested set of panels is identical to the current set of 420 // panels => Nothing to do. 421 return; 422 } 423 424 // Provide a configuration and Deck object. 425 if ( ! mpCurrentDeck) 426 { 427 mpCurrentDeck.reset( 428 new Deck( 429 rDeckDescriptor, 430 mpParentWindow, 431 ::boost::bind(&SidebarController::CloseDeck, this))); 432 msCurrentDeckTitle = rDeckDescriptor.msTitle; 433 } 434 if ( ! mpCurrentDeck) 435 return; 436 437 // Update the panel list. 438 const sal_Int32 nNewPanelCount (aPanelContextDescriptors.size()); 439 SharedPanelContainer aNewPanels; 440 const SharedPanelContainer& rCurrentPanels (mpCurrentDeck->GetPanels()); 441 aNewPanels.resize(nNewPanelCount); 442 sal_Int32 nWriteIndex (0); 443 bool bHasPanelSetChanged (false); 444 for (sal_Int32 nReadIndex=0; nReadIndex<nNewPanelCount; ++nReadIndex) 445 { 446 const ResourceManager::PanelContextDescriptor& rPanelContexDescriptor ( 447 aPanelContextDescriptors[nReadIndex]); 448 449 // Find the corresponding panel among the currently active 450 // panels. 451 SharedPanelContainer::const_iterator iPanel (::std::find_if( 452 rCurrentPanels.begin(), 453 rCurrentPanels.end(), 454 ::boost::bind(&Panel::HasIdPredicate, _1, ::boost::cref(rPanelContexDescriptor.msId)))); 455 if (iPanel != rCurrentPanels.end()) 456 { 457 // Panel already exists in current deck. Reuse it. 458 aNewPanels[nWriteIndex] = *iPanel; 459 } 460 else 461 { 462 // Panel does not yet exist. Create it. 463 aNewPanels[nWriteIndex] = CreatePanel( 464 rPanelContexDescriptor.msId, 465 mpCurrentDeck->GetPanelParentWindow()); 466 bHasPanelSetChanged = true; 467 } 468 if (aNewPanels[nWriteIndex] != NULL) 469 { 470 // Depending on the context we have to collapse the panel. 471 aNewPanels[nWriteIndex]->SetExpanded(rPanelContexDescriptor.mbIsInitiallyVisible); 472 // Depending on the context we have to apply the show menu functor. 473 aNewPanels[nWriteIndex]->SetShowMenuFunctor( 474 rPanelContexDescriptor.msMenuCommand.getLength()>0 475 ? ::boost::bind(&SidebarController::ShowDetailMenu,this,rPanelContexDescriptor.msMenuCommand) 476 : ::boost::function<void(void)>() ); 477 478 ++nWriteIndex; 479 } 480 481 } 482 aNewPanels.resize(nWriteIndex); 483 484 // Activate the deck and the new set of panels. 485 mpCurrentDeck->SetPosSizePixel( 486 0, 487 0, 488 mpParentWindow->GetSizePixel().Width()-TabBar::GetDefaultWidth(), 489 mpParentWindow->GetSizePixel().Height()); 490 mpCurrentDeck->SetPanels(aNewPanels); 491 mpCurrentDeck->Show(); 492 493 mpParentWindow->SetText(rDeckDescriptor.msTitle); 494 495 if (bHasPanelSetChanged) 496 NotifyResize(); 497 498 // Tell the focus manager about the new panels and tab bar 499 // buttons. 500 maFocusManager.SetPanels(aNewPanels); 501 mpTabBar->UpdateFocusManager(maFocusManager); 502 UpdateTitleBarIcons(); 503 } 504 505 506 507 508 bool SidebarController::ArePanelSetsEqual ( 509 const SharedPanelContainer& rCurrentPanels, 510 const ResourceManager::PanelContextDescriptorContainer& rRequestedPanels) 511 { 512 #ifdef VERBOSE 513 OSL_TRACE("current panel list:"); 514 for (SharedPanelContainer::const_iterator 515 iPanel(rCurrentPanels.begin()), 516 iEnd(rCurrentPanels.end()); 517 iPanel!=iEnd; 518 ++iPanel) 519 { 520 OSL_TRACE(" panel %s", S2A((*iPanel)->GetId())); 521 } 522 523 OSL_TRACE("requested panels: "); 524 for (ResourceManager::PanelContextDescriptorContainer::const_iterator 525 iId(rRequestedPanels.begin()), 526 iEnd(rRequestedPanels.end()); 527 iId!=iEnd; 528 ++iId) 529 { 530 OSL_TRACE(" panel %s", S2A(iId->msId)); 531 } 532 #endif 533 534 if (rCurrentPanels.size() != rRequestedPanels.size()) 535 return false; 536 for (sal_Int32 nIndex=0,nCount=rCurrentPanels.size(); nIndex<nCount; ++nIndex) 537 { 538 if (rCurrentPanels[nIndex] == NULL) 539 return false; 540 if ( ! rCurrentPanels[nIndex]->GetId().equals(rRequestedPanels[nIndex].msId)) 541 return false; 542 } 543 return true; 544 } 545 546 547 548 549 SharedPanel SidebarController::CreatePanel ( 550 const OUString& rsPanelId, 551 ::Window* pParentWindow ) 552 { 553 const PanelDescriptor* pPanelDescriptor = ResourceManager::Instance().GetPanelDescriptor(rsPanelId); 554 if (pPanelDescriptor == NULL) 555 return SharedPanel(); 556 557 // Create the panel which is the parent window of the UIElement. 558 SharedPanel pPanel (new Panel( 559 *pPanelDescriptor, 560 pParentWindow, 561 ::boost::bind(&Deck::RequestLayout, mpCurrentDeck.get()) ) ); 562 563 // Create the XUIElement. 564 Reference<ui::XUIElement> xUIElement (CreateUIElement( 565 pPanel->GetComponentInterface(), 566 pPanelDescriptor->msImplementationURL, 567 pPanelDescriptor->mbWantsCanvas)); 568 if (xUIElement.is()) 569 { 570 // Initialize the panel and add it to the active deck. 571 pPanel->SetUIElement(xUIElement); 572 } 573 else 574 { 575 pPanel.reset(); 576 } 577 578 return pPanel; 579 } 580 581 582 583 584 Reference<ui::XUIElement> SidebarController::CreateUIElement ( 585 const Reference<awt::XWindowPeer>& rxWindow, 586 const ::rtl::OUString& rsImplementationURL, 587 const bool bWantsCanvas) 588 { 589 try 590 { 591 const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory()); 592 const Reference<ui::XUIElementFactory> xUIElementFactory ( 593 aComponentContext.createComponent("com.sun.star.ui.UIElementFactoryManager"), 594 UNO_QUERY_THROW); 595 596 // Create the XUIElement. 597 ::comphelper::NamedValueCollection aCreationArguments; 598 aCreationArguments.put("Frame", makeAny(mxFrame)); 599 aCreationArguments.put("ParentWindow", makeAny(rxWindow)); 600 SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(mpParentWindow); 601 if (pSfxDockingWindow != NULL) 602 aCreationArguments.put("SfxBindings", makeAny(sal_uInt64(&pSfxDockingWindow->GetBindings()))); 603 aCreationArguments.put("Theme", Theme::GetPropertySet()); 604 aCreationArguments.put("Sidebar", makeAny(Reference<ui::XSidebar>(static_cast<ui::XSidebar*>(this)))); 605 if (bWantsCanvas) 606 { 607 Reference<rendering::XSpriteCanvas> xCanvas (VCLUnoHelper::GetWindow(rxWindow)->GetSpriteCanvas()); 608 aCreationArguments.put("Canvas", makeAny(xCanvas)); 609 } 610 611 Reference<ui::XUIElement> xUIElement( 612 xUIElementFactory->createUIElement( 613 rsImplementationURL, 614 Sequence<beans::PropertyValue>(aCreationArguments.getPropertyValues())), 615 UNO_QUERY_THROW); 616 617 return xUIElement; 618 } 619 catch(Exception& rException) 620 { 621 OSL_TRACE("caught exception: %s", 622 OUStringToOString(rException.Message, RTL_TEXTENCODING_ASCII_US).getStr()); 623 // For some reason we can not create the actual panel. 624 // Probably because its factory was not properly registered. 625 // TODO: provide feedback to developer to better pinpoint the 626 // source of the error. 627 628 return NULL; 629 } 630 } 631 632 633 634 635 IMPL_LINK(SidebarController, WindowEventHandler, VclWindowEvent*, pEvent) 636 { 637 if (pEvent != NULL) 638 { 639 switch (pEvent->GetId()) 640 { 641 case VCLEVENT_WINDOW_GETFOCUS: 642 case VCLEVENT_WINDOW_LOSEFOCUS: 643 break; 644 645 case VCLEVENT_WINDOW_SHOW: 646 case VCLEVENT_WINDOW_RESIZE: 647 NotifyResize(); 648 break; 649 650 case VCLEVENT_WINDOW_DATACHANGED: 651 // Force an update of deck and tab bar to reflect 652 // changes in theme (high contrast mode). 653 Theme::HandleDataChange(); 654 UpdateTitleBarIcons(); 655 mpParentWindow->Invalidate(); 656 break; 657 658 case SFX_HINT_DYING: 659 dispose(); 660 break; 661 662 default: 663 break; 664 } 665 } 666 667 return sal_True; 668 } 669 670 671 672 673 void SidebarController::ShowPopupMenu ( 674 const Rectangle& rButtonBox, 675 const ::std::vector<TabBar::DeckMenuData>& rDeckSelectionData, 676 const ::std::vector<TabBar::DeckMenuData>& rDeckShowData) const 677 { 678 ::boost::shared_ptr<PopupMenu> pMenu = CreatePopupMenu(rDeckSelectionData, rDeckShowData); 679 pMenu->SetSelectHdl(LINK(this, SidebarController, OnMenuItemSelected)); 680 681 // pass toolbox button rect so the menu can stay open on button up 682 Rectangle aBox (rButtonBox); 683 aBox.Move(mpTabBar->GetPosPixel().X(), 0); 684 pMenu->Execute(mpParentWindow, aBox, POPUPMENU_EXECUTE_DOWN); 685 } 686 687 688 689 690 void SidebarController::ShowDetailMenu (const ::rtl::OUString& rsMenuCommand) const 691 { 692 try 693 { 694 util::URL aURL; 695 aURL.Complete = rsMenuCommand; 696 697 const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory()); 698 const Reference<util::XURLTransformer> xParser ( 699 aComponentContext.createComponent("com.sun.star.util.URLTransformer"), 700 UNO_QUERY_THROW); 701 xParser->parseStrict(aURL); 702 Reference<frame::XDispatchProvider> xProvider (mxFrame, UNO_QUERY_THROW); 703 Reference<frame::XDispatch> xDispatch (xProvider->queryDispatch(aURL, OUString(), 0)); 704 if (xDispatch.is()) 705 xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>()); 706 } 707 catch(Exception& rException) 708 { 709 OSL_TRACE("caught exception: %s", 710 OUStringToOString(rException.Message, RTL_TEXTENCODING_ASCII_US).getStr()); 711 } 712 } 713 714 715 716 717 ::boost::shared_ptr<PopupMenu> SidebarController::CreatePopupMenu ( 718 const ::std::vector<TabBar::DeckMenuData>& rDeckSelectionData, 719 const ::std::vector<TabBar::DeckMenuData>& rDeckShowData) const 720 { 721 ::boost::shared_ptr<PopupMenu> pMenu (new PopupMenu()); 722 FloatingWindow* pMenuWindow = dynamic_cast<FloatingWindow*>(pMenu->GetWindow()); 723 if (pMenuWindow != NULL) 724 { 725 pMenuWindow->SetPopupModeFlags(pMenuWindow->GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE); 726 } 727 728 SidebarResource aLocalResource; 729 730 // Add one entry for every tool panel element to individually make 731 // them visible or hide them. 732 { 733 sal_Int32 nIndex (MID_FIRST_PANEL); 734 for(::std::vector<TabBar::DeckMenuData>::const_iterator 735 iItem(rDeckSelectionData.begin()), 736 iEnd(rDeckSelectionData.end()); 737 iItem!=iEnd; 738 ++iItem) 739 { 740 pMenu->InsertItem(nIndex, iItem->get<0>(), MIB_RADIOCHECK); 741 pMenu->CheckItem(nIndex, iItem->get<2>()); 742 ++nIndex; 743 } 744 } 745 746 pMenu->InsertSeparator(); 747 748 // Add entry for docking or un-docking the tool panel. 749 if (mpParentWindow->IsFloatingMode()) 750 pMenu->InsertItem(MID_LOCK_TASK_PANEL, String(SfxResId(STR_SFX_DOCK))); 751 else 752 pMenu->InsertItem(MID_UNLOCK_TASK_PANEL, String(SfxResId(STR_SFX_UNDOCK))); 753 754 // Add sub menu for customization (hiding of deck tabs.) 755 PopupMenu* pCustomizationMenu = new PopupMenu(); 756 { 757 sal_Int32 nIndex (MID_FIRST_HIDE); 758 for(::std::vector<TabBar::DeckMenuData>::const_iterator 759 iItem(rDeckShowData.begin()), 760 iEnd(rDeckShowData.end()); 761 iItem!=iEnd; 762 ++iItem) 763 { 764 pCustomizationMenu->InsertItem(nIndex, iItem->get<0>(), MIB_CHECKABLE); 765 pCustomizationMenu->CheckItem(nIndex, iItem->get<2>()); 766 ++nIndex; 767 } 768 } 769 770 pCustomizationMenu->InsertSeparator(); 771 pCustomizationMenu->InsertItem(MID_RESTORE_DEFAULT, String(SfxResId(STRING_RESTORE))); 772 773 pMenu->InsertItem(MID_CUSTOMIZATION, String(SfxResId(STRING_CUSTOMIZATION))); 774 pMenu->SetPopupMenu(MID_CUSTOMIZATION, pCustomizationMenu); 775 776 pMenu->RemoveDisabledEntries(sal_False, sal_False); 777 778 return pMenu; 779 } 780 781 782 783 784 IMPL_LINK(SidebarController, OnMenuItemSelected, Menu*, pMenu) 785 { 786 if (pMenu == NULL) 787 { 788 OSL_ENSURE(pMenu!=NULL, "sfx2::sidebar::SidebarController::OnMenuItemSelected: illegal menu!"); 789 return 0; 790 } 791 792 pMenu->Deactivate(); 793 const sal_Int32 nIndex (pMenu->GetCurItemId()); 794 switch (nIndex) 795 { 796 case MID_UNLOCK_TASK_PANEL: 797 mpParentWindow->SetFloatingMode(sal_True); 798 break; 799 800 case MID_LOCK_TASK_PANEL: 801 mpParentWindow->SetFloatingMode(sal_False); 802 break; 803 804 case MID_RESTORE_DEFAULT: 805 mpTabBar->RestoreHideFlags(); 806 break; 807 808 default: 809 { 810 try 811 { 812 if (nIndex >= MID_FIRST_PANEL && nIndex<MID_FIRST_HIDE) 813 SwitchToDeck(mpTabBar->GetDeckIdForIndex(nIndex - MID_FIRST_PANEL)); 814 else if (nIndex >=MID_FIRST_HIDE) 815 mpTabBar->ToggleHideFlag(nIndex-MID_FIRST_HIDE); 816 } 817 catch (RuntimeException&) 818 { 819 } 820 } 821 break; 822 } 823 824 return 1; 825 } 826 827 828 829 830 void SidebarController::CloseDeck (void) 831 { 832 if ( ! mbIsDeckClosed) 833 { 834 mbIsDeckClosed = true; 835 if ( ! mpParentWindow->IsFloatingMode()) 836 mnSavedSidebarWidth = SetChildWindowWidth(TabBar::GetDefaultWidth()); 837 mpParentWindow->SetStyle(mpParentWindow->GetStyle() & ~WB_SIZEABLE); 838 839 if (mpCurrentDeck) 840 mpCurrentDeck->Hide(); 841 842 NotifyResize(); 843 } 844 } 845 846 847 848 849 void SidebarController::OpenDeck (void) 850 { 851 if (mbIsDeckClosed) 852 { 853 mbIsDeckClosed = false; 854 SetChildWindowWidth(mnSavedSidebarWidth); 855 856 if (mpCurrentDeck) 857 mpCurrentDeck->Show(); 858 859 NotifyResize(); 860 } 861 } 862 863 864 865 866 FocusManager& SidebarController::GetFocusManager (void) 867 { 868 return maFocusManager; 869 } 870 871 872 873 874 bool SidebarController::CanModifyChildWindowWidth (void) const 875 { 876 SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); 877 if (pSplitWindow == NULL) 878 { 879 return 0; 880 } 881 882 sal_uInt16 nRow (0xffff); 883 sal_uInt16 nColumn (0xffff); 884 pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow); 885 886 sal_uInt16 nRowCount (pSplitWindow->GetWindowCount(nColumn)); 887 888 return nRowCount == 1; 889 } 890 891 892 893 894 sal_Int32 SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth) 895 { 896 SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); 897 if (pSplitWindow == NULL) 898 return 0; 899 900 sal_uInt16 nRow (0xffff); 901 sal_uInt16 nColumn (0xffff); 902 pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow); 903 const long nColumnWidth (pSplitWindow->GetLineSize(nColumn)); 904 905 Window* pWindow = mpParentWindow; 906 const Point aWindowPosition (pWindow->GetPosPixel()); 907 const Size aWindowSize (pWindow->GetSizePixel()); 908 909 pSplitWindow->MoveWindow( 910 mpParentWindow, 911 Size(nNewWidth, aWindowSize.Height()), 912 nColumn, 913 nRow); 914 915 return static_cast<sal_Int32>(nColumnWidth); 916 } 917 918 919 920 921 void SidebarController::RestrictWidth (void) 922 { 923 SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); 924 if (pSplitWindow != NULL) 925 { 926 const sal_uInt16 nId (pSplitWindow->GetItemId(mpParentWindow)); 927 const sal_uInt16 nSetId (pSplitWindow->GetSet(nId)); 928 // Minimum width is always that of the tabbar. 929 const sal_Int32 nMinimumWidth (TabBar::GetDefaultWidth()); 930 // Maximum width depends on whether the deck is open or closed. 931 const sal_Int32 nMaximumWidth ( 932 mbIsDeckClosed 933 ? TabBar::GetDefaultWidth() 934 : 400); 935 pSplitWindow->SetItemSizeRange( 936 nSetId, 937 Range(nMinimumWidth, nMaximumWidth)); 938 if (nMinimumWidth == nMaximumWidth) 939 pSplitWindow->SetItemSize(nSetId, nMinimumWidth); 940 } 941 } 942 943 944 945 946 void SidebarController::UpdateTitleBarIcons (void) 947 { 948 if ( ! mpCurrentDeck) 949 return; 950 951 const bool bIsHighContrastModeActive (Theme::IsHighContrastMode()); 952 const ResourceManager& rResourceManager (ResourceManager::Instance()); 953 954 // Update the deck icon. 955 const DeckDescriptor* pDeckDescriptor = rResourceManager.GetDeckDescriptor(mpCurrentDeck->GetId()); 956 if (pDeckDescriptor != NULL && mpCurrentDeck->GetTitleBar()) 957 { 958 const OUString sIconURL( 959 bIsHighContrastModeActive 960 ? pDeckDescriptor->msHighContrastTitleBarIconURL 961 : pDeckDescriptor->msTitleBarIconURL); 962 mpCurrentDeck->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL, mxFrame)); 963 } 964 965 // Update the panel icons. 966 const SharedPanelContainer& rPanels (mpCurrentDeck->GetPanels()); 967 for (SharedPanelContainer::const_iterator 968 iPanel(rPanels.begin()), iEnd(rPanels.end()); 969 iPanel!=iEnd; 970 ++iPanel) 971 { 972 if ( ! *iPanel) 973 continue; 974 if ((*iPanel)->GetTitleBar() == NULL) 975 continue; 976 const PanelDescriptor* pPanelDescriptor = rResourceManager.GetPanelDescriptor((*iPanel)->GetId()); 977 if (pPanelDescriptor == NULL) 978 continue; 979 const OUString sIconURL ( 980 bIsHighContrastModeActive 981 ? pPanelDescriptor->msHighContrastTitleBarIconURL 982 : pPanelDescriptor->msTitleBarIconURL); 983 (*iPanel)->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL, mxFrame)); 984 } 985 } 986 987 988 } } // end of namespace sfx2::sidebar 989