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