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