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