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