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