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