2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 #include "SidebarController.hxx"
20 #include "DeckTitleBar.hxx"
22 #include "PanelTitleBar.hxx"
23 #include "SidebarPanel.hxx"
24 #include "SidebarResource.hxx"
26 #include "sfx2/sidebar/Theme.hxx"
27 #include "sfx2/sidebar/SidebarChildWindow.hxx"
28 #include "sfx2/sidebar/Tools.hxx"
29 #include "SidebarDockingWindow.hxx"
30 #include "Context.hxx"
32 #include "sfxresid.hxx"
33 #include "sfx2/sfxsids.hrc"
34 #include "sfx2/titledockwin.hxx"
35 #include "sfxlocal.hrc"
36 #include <vcl/floatwin.hxx>
37 #include <vcl/fixed.hxx>
38 #include "splitwin.hxx"
39 #include <svl/smplhint.hxx>
40 #include <tools/link.hxx>
41 #include <toolkit/helper/vclunohelper.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <comphelper/componentcontext.hxx>
44 #include <comphelper/namedvaluecollection.hxx>
46 #include <com/sun/star/frame/XDispatchProvider.hpp>
47 #include <com/sun/star/lang/XInitialization.hpp>
48 #include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp>
49 #include <com/sun/star/ui/ContextChangeEventObject.hpp>
50 #include <com/sun/star/ui/XUIElementFactory.hpp>
51 #include <com/sun/star/util/XURLTransformer.hpp>
52 #include <com/sun/star/util/URL.hpp>
53 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
55 #include <boost/bind.hpp>
56 #include <boost/function.hpp>
57 #include <boost/scoped_array.hpp>
62 using ::rtl::OUString
;
69 const static char gsReadOnlyCommandName
[] = ".uno:EditDoc";
70 const static sal_Int32
gnMaximumSidebarWidth (400);
71 const static sal_Int32
gnWidthCloseThreshold (70);
72 const static sal_Int32
gnWidthOpenThreshold (40);
76 namespace sfx2
{ namespace sidebar
{
81 MID_UNLOCK_TASK_PANEL
= 1,
89 /** When in doubt, show this deck.
91 static const char gsDefaultDeckId
[] = "PropertyDeck";
95 SidebarController::SidebarController (
96 SidebarDockingWindow
* pParentWindow
,
97 const cssu::Reference
<css::frame::XFrame
>& rxFrame
)
98 : SidebarControllerInterfaceBase(m_aMutex
),
100 mpParentWindow(pParentWindow
),
104 ::boost::bind(&SidebarController::OpenThenSwitchToDeck
, this, _1
),
105 ::boost::bind(&SidebarController::ShowPopupMenu
, this, _1
,_2
))),
107 maCurrentContext(OUString(), OUString()),
108 maRequestedContext(),
109 mnRequestedForceFlags(SwitchFlag_NoForce
),
110 msCurrentDeckId(gsDefaultDeckId
),
111 msCurrentDeckTitle(),
112 maPropertyChangeForwarder(::boost::bind(&SidebarController::BroadcastPropertyChange
, this)),
113 maContextChangeUpdate(::boost::bind(&SidebarController::UpdateConfigurations
, this)),
114 mbIsDeckRequestedOpen(),
116 mbCanDeckBeOpened(true),
117 mnSavedSidebarWidth(pParentWindow
->GetSizePixel().Width()),
118 maFocusManager(::boost::bind(&SidebarController::ShowPanel
, this, _1
)),
119 mxReadOnlyModeDispatch(),
120 mbIsDocumentReadOnly(false),
122 mnWidthOnSplitterButtonDown(0),
125 if (pParentWindow
== NULL
)
127 OSL_ASSERT(pParentWindow
!=NULL
);
131 // Listen for context change events.
132 cssu::Reference
<css::ui::XContextChangeEventMultiplexer
> xMultiplexer (
133 css::ui::ContextChangeEventMultiplexer::get(
134 ::comphelper::getProcessComponentContext()));
135 if (xMultiplexer
.is())
136 xMultiplexer
->addContextChangeEventListener(
137 static_cast<css::ui::XContextChangeEventListener
*>(this),
138 mxFrame
->getController());
140 // Listen for window events.
141 mpParentWindow
->AddEventListener(LINK(this, SidebarController
, WindowEventHandler
));
143 // Listen for theme property changes.
144 Theme::GetPropertySet()->addPropertyChangeListener(
146 static_cast<css::beans::XPropertyChangeListener
*>(this));
148 // Get the dispatch object as preparation to listen for changes of
149 // the read-only state.
150 const util::URL
aURL (Tools::GetURL(gsReadOnlyCommandName
));
151 mxReadOnlyModeDispatch
= Tools::GetDispatch(mxFrame
, aURL
);
152 if (mxReadOnlyModeDispatch
.is())
153 mxReadOnlyModeDispatch
->addStatusListener(this, aURL
);
155 SwitchToDeck(A2S("default"));
161 SidebarController::~SidebarController (void)
168 void SAL_CALL
SidebarController::disposing (void)
170 maFocusManager
.Clear();
172 cssu::Reference
<css::ui::XContextChangeEventMultiplexer
> xMultiplexer (
173 css::ui::ContextChangeEventMultiplexer::get(
174 ::comphelper::getProcessComponentContext()));
175 if (xMultiplexer
.is())
176 xMultiplexer
->removeAllContextChangeEventListeners(
177 static_cast<css::ui::XContextChangeEventListener
*>(this));
179 if (mxReadOnlyModeDispatch
.is())
180 mxReadOnlyModeDispatch
->removeStatusListener(this, Tools::GetURL(gsReadOnlyCommandName
));
181 if (mpSplitWindow
!= NULL
)
183 mpSplitWindow
->RemoveEventListener(LINK(this, SidebarController
, WindowEventHandler
));
184 mpSplitWindow
= NULL
;
187 if (mpParentWindow
!= NULL
)
189 mpParentWindow
->RemoveEventListener(LINK(this, SidebarController
, WindowEventHandler
));
190 mpParentWindow
= NULL
;
195 mpCurrentDeck
->Dispose();
196 mpCurrentDeck
->PrintWindowTree();
197 mpCurrentDeck
.reset();
202 Theme::GetPropertySet()->removePropertyChangeListener(
204 static_cast<css::beans::XPropertyChangeListener
*>(this));
206 maContextChangeUpdate
.CancelRequest();
212 void SAL_CALL
SidebarController::notifyContextChangeEvent (const css::ui::ContextChangeEventObject
& rEvent
)
213 throw(cssu::RuntimeException
)
215 // Update to the requested new context asynchronously to avoid
216 // subtle errors caused by SFX2 which in rare cases can not
217 // properly handle a synchronous update.
218 maRequestedContext
= Context(
219 rEvent
.ApplicationName
,
221 if (maRequestedContext
!= maCurrentContext
)
222 maContextChangeUpdate
.RequestCall();
228 void SAL_CALL
SidebarController::disposing (const css::lang::EventObject
& rEventObject
)
229 throw(cssu::RuntimeException
)
239 void SAL_CALL
SidebarController::propertyChange (const css::beans::PropertyChangeEvent
& rEvent
)
240 throw(cssu::RuntimeException
)
244 maPropertyChangeForwarder
.RequestCall();
250 void SAL_CALL
SidebarController::statusChanged (const css::frame::FeatureStateEvent
& rEvent
)
251 throw(cssu::RuntimeException
)
253 bool bIsReadWrite (true);
254 if (rEvent
.IsEnabled
)
255 rEvent
.State
>>= bIsReadWrite
;
257 if (mbIsDocumentReadOnly
!= !bIsReadWrite
)
259 mbIsDocumentReadOnly
= !bIsReadWrite
;
261 // Force the current deck to update its panel list.
262 if ( ! mbIsDocumentReadOnly
)
263 msCurrentDeckId
= gsDefaultDeckId
;
264 mnRequestedForceFlags
|= SwitchFlag_ForceSwitch
;
265 maContextChangeUpdate
.RequestCall();
272 void SAL_CALL
SidebarController::requestLayout (void)
273 throw(cssu::RuntimeException
)
275 sal_Int32 nMinimalWidth
= 0;
278 mpCurrentDeck
->RequestLayout();
279 nMinimalWidth
= mpCurrentDeck
->GetMinimalWidth();
281 RestrictWidth(nMinimalWidth
);
287 void SidebarController::BroadcastPropertyChange (void)
289 DataChangedEvent
aEvent (DATACHANGED_USER
);
290 mpParentWindow
->NotifyAllChildren(aEvent
);
291 mpParentWindow
->Invalidate(INVALIDATE_CHILDREN
);
297 void SidebarController::NotifyResize (void)
299 if (mpTabBar
== NULL
)
301 OSL_ASSERT(mpTabBar
!=NULL
);
305 Window
* pParentWindow
= mpTabBar
->GetParent();
307 const sal_Int32
nWidth (pParentWindow
->GetSizePixel().Width());
308 const sal_Int32
nHeight (pParentWindow
->GetSizePixel().Height());
310 mbIsDeckOpen
= (nWidth
> TabBar::GetDefaultWidth());
312 if (mnSavedSidebarWidth
<= 0)
313 mnSavedSidebarWidth
= nWidth
;
316 if (mbCanDeckBeOpened
)
318 const bool bIsOpening (nWidth
> mnWidthOnSplitterButtonDown
);
320 bIsDeckVisible
= nWidth
>= TabBar::GetDefaultWidth() + gnWidthOpenThreshold
;
322 bIsDeckVisible
= nWidth
>= TabBar::GetDefaultWidth() + gnWidthCloseThreshold
;
323 mbIsDeckRequestedOpen
= bIsDeckVisible
;
324 UpdateCloseIndicator(!bIsDeckVisible
);
327 bIsDeckVisible
= false;
334 mpCurrentDeck
->setPosSizePixel(0,0, nWidth
-TabBar::GetDefaultWidth(), nHeight
);
335 mpCurrentDeck
->Show();
336 mpCurrentDeck
->RequestLayout();
339 mpCurrentDeck
->Hide();
342 // Place the tab bar.
343 mpTabBar
->setPosSizePixel(nWidth
-TabBar::GetDefaultWidth(),0,TabBar::GetDefaultWidth(),nHeight
);
346 // Determine if the closer of the deck can be shown.
347 sal_Int32 nMinimalWidth
= 0;
350 DeckTitleBar
* pTitleBar
= mpCurrentDeck
->GetTitleBar();
351 if (pTitleBar
!= NULL
&& pTitleBar
->IsVisible())
352 pTitleBar
->SetCloserVisible(CanModifyChildWindowWidth());
353 nMinimalWidth
= mpCurrentDeck
->GetMinimalWidth();
356 RestrictWidth(nMinimalWidth
);
362 void SidebarController::ProcessNewWidth (const sal_Int32 nNewWidth
)
364 if ( ! mbIsDeckRequestedOpen
)
367 if (mbIsDeckRequestedOpen
.get())
369 // Deck became large enough to be shown. Show it.
370 mnSavedSidebarWidth
= nNewWidth
;
375 // Deck became too small. Close it completely.
376 // If window is wider than the tab bar then mark the deck as being visible, even when it its not.
377 // This is to trigger an adjustment of the width to the width of the tab bar.
381 if (mnWidthOnSplitterButtonDown
> TabBar::GetDefaultWidth())
382 mnSavedSidebarWidth
= mnWidthOnSplitterButtonDown
;
389 void SidebarController::UpdateConfigurations (void)
391 if (maCurrentContext
!= maRequestedContext
392 || mnRequestedForceFlags
!=SwitchFlag_NoForce
)
394 maCurrentContext
= maRequestedContext
;
396 // Find the set of decks that could be displayed for the new context.
397 ResourceManager::DeckContextDescriptorContainer aDecks
;
398 ResourceManager::Instance().GetMatchingDecks (
401 mbIsDocumentReadOnly
,
404 // Notify the tab bar about the updated set of decks.
405 mpTabBar
->SetDecks(aDecks
);
407 // Find the new deck. By default that is the same as the old
408 // one. If that is not set or not enabled, then choose the
409 // first enabled deck.
411 for (ResourceManager::DeckContextDescriptorContainer::const_iterator
412 iDeck(aDecks
.begin()),
417 if (iDeck
->mbIsEnabled
)
419 if (iDeck
->msId
.equals(msCurrentDeckId
))
421 sNewDeckId
= msCurrentDeckId
;
424 else if (sNewDeckId
.getLength() == 0)
425 sNewDeckId
= iDeck
->msId
;
429 if (sNewDeckId
.getLength() == 0)
431 // We did not find a valid deck.
436 // Tell the tab bar to highlight the button associated
438 mpTabBar
->HighlightDeck(sNewDeckId
);
441 *ResourceManager::Instance().GetDeckDescriptor(sNewDeckId
),
445 // Show the context name in the deck title bar.
448 DeckTitleBar
* pTitleBar
= mpCurrentDeck
->GetTitleBar();
449 if (pTitleBar
!= NULL
)
450 pTitleBar
->SetTitle(msCurrentDeckTitle
+A2S(" (")+maCurrentContext
.msContext
+A2S(")"));
459 void SidebarController::OpenThenSwitchToDeck (
460 const ::rtl::OUString
& rsDeckId
)
463 SwitchToDeck(rsDeckId
);
469 void SidebarController::SwitchToDeck (
470 const ::rtl::OUString
& rsDeckId
)
472 if ( ! msCurrentDeckId
.equals(rsDeckId
)
474 || mnRequestedForceFlags
!=SwitchFlag_NoForce
)
476 const DeckDescriptor
* pDeckDescriptor
= ResourceManager::Instance().GetDeckDescriptor(rsDeckId
);
477 if (pDeckDescriptor
!= NULL
)
478 SwitchToDeck(*pDeckDescriptor
, maCurrentContext
);
485 void SidebarController::SwitchToDeck (
486 const DeckDescriptor
& rDeckDescriptor
,
487 const Context
& rContext
)
489 maFocusManager
.Clear();
491 const bool bForceNewDeck ((mnRequestedForceFlags
&SwitchFlag_ForceNewDeck
)!=0);
492 const bool bForceNewPanels ((mnRequestedForceFlags
&SwitchFlag_ForceNewPanels
)!=0);
493 mnRequestedForceFlags
= SwitchFlag_NoForce
;
495 if ( ! msCurrentDeckId
.equals(rDeckDescriptor
.msId
)
498 // When the deck changes then destroy the deck and all panels
499 // and create everything new.
502 mpCurrentDeck
->Dispose();
503 mpCurrentDeck
.reset();
506 msCurrentDeckId
= rDeckDescriptor
.msId
;
508 mpTabBar
->HighlightDeck(msCurrentDeckId
);
510 // Determine the panels to display in the deck.
511 ResourceManager::PanelContextDescriptorContainer aPanelContextDescriptors
;
512 ResourceManager::Instance().GetMatchingPanels(
513 aPanelContextDescriptors
,
515 rDeckDescriptor
.msId
,
518 if (aPanelContextDescriptors
.empty())
520 // There are no panels to be displayed in the current context.
521 if (EnumContext::GetContextEnum(rContext
.msContext
) != EnumContext::Context_Empty
)
523 // Switch to the "empty" context and try again.
527 rContext
.msApplication
,
528 EnumContext::GetContextName(EnumContext::Context_Empty
)));
533 // This is already the "empty" context. Looks like we have
534 // to live with an empty deck.
538 // Provide a configuration and Deck object.
539 if ( ! mpCurrentDeck
)
545 ::boost::bind(&SidebarController::RequestCloseDeck
, this)));
546 msCurrentDeckTitle
= rDeckDescriptor
.msTitle
;
548 if ( ! mpCurrentDeck
)
551 // Update the panel list.
552 const sal_Int32
nNewPanelCount (aPanelContextDescriptors
.size());
553 SharedPanelContainer aNewPanels
;
554 const SharedPanelContainer
& rCurrentPanels (mpCurrentDeck
->GetPanels());
555 aNewPanels
.resize(nNewPanelCount
);
556 sal_Int32
nWriteIndex (0);
557 bool bHasPanelSetChanged (false);
558 for (sal_Int32 nReadIndex
=0; nReadIndex
<nNewPanelCount
; ++nReadIndex
)
560 const ResourceManager::PanelContextDescriptor
& rPanelContexDescriptor (
561 aPanelContextDescriptors
[nReadIndex
]);
563 // Determine if the panel can be displayed.
564 const bool bIsPanelVisible (!mbIsDocumentReadOnly
|| rPanelContexDescriptor
.mbShowForReadOnlyDocuments
);
565 if ( ! bIsPanelVisible
)
568 // Find the corresponding panel among the currently active
570 SharedPanelContainer::const_iterator iPanel
;
573 // All panels have to be created in any case. There is no
574 // point in searching already existing panels.
575 iPanel
= rCurrentPanels
.end();
579 iPanel
= ::std::find_if(
580 rCurrentPanels
.begin(),
581 rCurrentPanels
.end(),
582 ::boost::bind(&Panel::HasIdPredicate
, _1
, ::boost::cref(rPanelContexDescriptor
.msId
)));
584 if (iPanel
!= rCurrentPanels
.end())
586 // Panel already exists in current deck. Reuse it.
587 aNewPanels
[nWriteIndex
] = *iPanel
;
588 aNewPanels
[nWriteIndex
]->SetExpanded(rPanelContexDescriptor
.mbIsInitiallyVisible
);
592 // Panel does not yet exist or creation of new panels is forced.
594 aNewPanels
[nWriteIndex
] = CreatePanel(
595 rPanelContexDescriptor
.msId
,
596 mpCurrentDeck
->GetPanelParentWindow(),
597 rPanelContexDescriptor
.mbIsInitiallyVisible
,
599 bHasPanelSetChanged
= true;
601 if (aNewPanels
[nWriteIndex
] != NULL
)
603 // Depending on the context we have to change the command
604 // for the "more options" dialog.
605 PanelTitleBar
* pTitleBar
= aNewPanels
[nWriteIndex
]->GetTitleBar();
606 if (pTitleBar
!= NULL
)
608 pTitleBar
->SetMoreOptionsCommand(
609 rPanelContexDescriptor
.msMenuCommand
,
617 aNewPanels
.resize(nWriteIndex
);
619 // Activate the deck and the new set of panels.
620 mpCurrentDeck
->setPosSizePixel(
623 mpParentWindow
->GetSizePixel().Width()-TabBar::GetDefaultWidth(),
624 mpParentWindow
->GetSizePixel().Height());
625 mpCurrentDeck
->SetPanels(aNewPanels
);
626 mpCurrentDeck
->Show();
628 mpParentWindow
->SetText(rDeckDescriptor
.msTitle
);
630 if (bHasPanelSetChanged
)
633 // Tell the focus manager about the new panels and tab bar
635 maFocusManager
.SetDeckTitle(mpCurrentDeck
->GetTitleBar());
636 maFocusManager
.SetPanels(aNewPanels
);
637 mpTabBar
->UpdateFocusManager(maFocusManager
);
638 UpdateTitleBarIcons();
644 SharedPanel
SidebarController::CreatePanel (
645 const OUString
& rsPanelId
,
646 ::Window
* pParentWindow
,
647 const bool bIsInitiallyExpanded
,
648 const Context
& rContext
)
650 const PanelDescriptor
* pPanelDescriptor
= ResourceManager::Instance().GetPanelDescriptor(rsPanelId
);
651 if (pPanelDescriptor
== NULL
)
652 return SharedPanel();
654 // Create the panel which is the parent window of the UIElement.
655 SharedPanel
pPanel (new Panel(
658 bIsInitiallyExpanded
,
659 ::boost::bind(&Deck::RequestLayout
, mpCurrentDeck
.get()),
660 ::boost::bind(&SidebarController::GetCurrentContext
, this)));
662 // Create the XUIElement.
663 Reference
<ui::XUIElement
> xUIElement (CreateUIElement(
664 pPanel
->GetComponentInterface(),
665 pPanelDescriptor
->msImplementationURL
,
666 pPanelDescriptor
->mbWantsCanvas
,
670 // Initialize the panel and add it to the active deck.
671 pPanel
->SetUIElement(xUIElement
);
684 Reference
<ui::XUIElement
> SidebarController::CreateUIElement (
685 const Reference
<awt::XWindowPeer
>& rxWindow
,
686 const ::rtl::OUString
& rsImplementationURL
,
687 const bool bWantsCanvas
,
688 const Context
& rContext
)
692 const ::comphelper::ComponentContext
aComponentContext (::comphelper::getProcessServiceFactory());
693 const Reference
<ui::XUIElementFactory
> xUIElementFactory (
694 aComponentContext
.createComponent("com.sun.star.ui.UIElementFactoryManager"),
697 // Create the XUIElement.
698 ::comphelper::NamedValueCollection aCreationArguments
;
699 aCreationArguments
.put("Frame", makeAny(mxFrame
));
700 aCreationArguments
.put("ParentWindow", makeAny(rxWindow
));
701 SfxDockingWindow
* pSfxDockingWindow
= dynamic_cast<SfxDockingWindow
*>(mpParentWindow
);
702 if (pSfxDockingWindow
!= NULL
)
703 aCreationArguments
.put("SfxBindings", makeAny(sal_uInt64(&pSfxDockingWindow
->GetBindings())));
704 aCreationArguments
.put("Theme", Theme::GetPropertySet());
705 aCreationArguments
.put("Sidebar", makeAny(Reference
<ui::XSidebar
>(static_cast<ui::XSidebar
*>(this))));
708 Reference
<rendering::XSpriteCanvas
> xCanvas (VCLUnoHelper::GetWindow(rxWindow
)->GetSpriteCanvas());
709 aCreationArguments
.put("Canvas", makeAny(xCanvas
));
711 aCreationArguments
.put("ApplicationName", makeAny(rContext
.msApplication
));
712 aCreationArguments
.put("ContextName", makeAny(rContext
.msContext
));
714 Reference
<ui::XUIElement
> xUIElement(
715 xUIElementFactory
->createUIElement(
717 Sequence
<beans::PropertyValue
>(aCreationArguments
.getPropertyValues())),
722 catch(Exception
& rException
)
724 OSL_TRACE("caught exception: %s",
725 OUStringToOString(rException
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr());
726 // For some reason we can not create the actual panel.
727 // Probably because its factory was not properly registered.
728 // TODO: provide feedback to developer to better pinpoint the
729 // source of the error.
738 IMPL_LINK(SidebarController
, WindowEventHandler
, VclWindowEvent
*, pEvent
)
743 if (pEvent
->GetWindow() == mpParentWindow
)
745 switch (pEvent
->GetId())
747 case VCLEVENT_WINDOW_SHOW
:
748 case VCLEVENT_WINDOW_RESIZE
:
752 case VCLEVENT_WINDOW_DATACHANGED
:
753 // Force an update of deck and tab bar to reflect
754 // changes in theme (high contrast mode).
755 Theme::HandleDataChange();
756 UpdateTitleBarIcons();
757 mpParentWindow
->Invalidate();
758 mnRequestedForceFlags
|= SwitchFlag_ForceNewDeck
| SwitchFlag_ForceNewPanels
;
759 maContextChangeUpdate
.RequestCall();
766 case VCLEVENT_WINDOW_PAINT
:
774 else if (pEvent
->GetWindow()==mpSplitWindow
&& mpSplitWindow
!=NULL
)
776 switch (pEvent
->GetId())
778 case VCLEVENT_WINDOW_MOUSEBUTTONDOWN
:
779 mnWidthOnSplitterButtonDown
= mpParentWindow
->GetSizePixel().Width();
782 case VCLEVENT_WINDOW_MOUSEBUTTONUP
:
784 ProcessNewWidth(mpParentWindow
->GetSizePixel().Width());
785 mnWidthOnSplitterButtonDown
= 0;
801 void SidebarController::ShowPopupMenu (
802 const Rectangle
& rButtonBox
,
803 const ::std::vector
<TabBar::DeckMenuData
>& rMenuData
) const
805 ::boost::shared_ptr
<PopupMenu
> pMenu
= CreatePopupMenu(rMenuData
);
806 pMenu
->SetSelectHdl(LINK(this, SidebarController
, OnMenuItemSelected
));
808 // pass toolbox button rect so the menu can stay open on button up
809 Rectangle
aBox (rButtonBox
);
810 aBox
.Move(mpTabBar
->GetPosPixel().X(), 0);
811 pMenu
->Execute(mpParentWindow
, aBox
, POPUPMENU_EXECUTE_DOWN
);
817 void SidebarController::ShowDetailMenu (const ::rtl::OUString
& rsMenuCommand
) const
821 const util::URL
aURL (Tools::GetURL(rsMenuCommand
));
822 Reference
<frame::XDispatch
> xDispatch (Tools::GetDispatch(mxFrame
, aURL
));
824 xDispatch
->dispatch(aURL
, Sequence
<beans::PropertyValue
>());
826 catch(Exception
& rException
)
828 OSL_TRACE("caught exception: %s",
829 OUStringToOString(rException
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr());
836 ::boost::shared_ptr
<PopupMenu
> SidebarController::CreatePopupMenu (
837 const ::std::vector
<TabBar::DeckMenuData
>& rMenuData
) const
839 // Create the top level popup menu.
840 ::boost::shared_ptr
<PopupMenu
> pMenu (new PopupMenu());
841 FloatingWindow
* pMenuWindow
= dynamic_cast<FloatingWindow
*>(pMenu
->GetWindow());
842 if (pMenuWindow
!= NULL
)
844 pMenuWindow
->SetPopupModeFlags(pMenuWindow
->GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE
);
847 // Create sub menu for customization (hiding of deck tabs.)
848 PopupMenu
* pCustomizationMenu
= new PopupMenu();
850 SidebarResource aLocalResource
;
852 // Add one entry for every tool panel element to individually make
853 // them visible or hide them.
854 sal_Int32
nIndex (0);
855 for(::std::vector
<TabBar::DeckMenuData
>::const_iterator
856 iItem(rMenuData
.begin()),
857 iEnd(rMenuData
.end());
861 const sal_Int32
nMenuIndex (nIndex
+MID_FIRST_PANEL
);
862 pMenu
->InsertItem(nMenuIndex
, iItem
->msDisplayName
, MIB_RADIOCHECK
);
863 pMenu
->CheckItem(nMenuIndex
, iItem
->mbIsCurrentDeck
? sal_True
: sal_False
);
864 pMenu
->EnableItem(nMenuIndex
, (iItem
->mbIsEnabled
&&iItem
->mbIsActive
) ? sal_True
: sal_False
);
866 const sal_Int32
nSubMenuIndex (nIndex
+MID_FIRST_HIDE
);
867 if (iItem
->mbIsCurrentDeck
)
869 // Don't allow the currently visible deck to be disabled.
870 pCustomizationMenu
->InsertItem(nSubMenuIndex
, iItem
->msDisplayName
, MIB_RADIOCHECK
);
871 pCustomizationMenu
->CheckItem(nSubMenuIndex
, sal_True
);
875 pCustomizationMenu
->InsertItem(nSubMenuIndex
, iItem
->msDisplayName
, MIB_CHECKABLE
);
876 pCustomizationMenu
->CheckItem(nSubMenuIndex
, iItem
->mbIsActive
? sal_True
: sal_False
);
880 pMenu
->InsertSeparator();
882 // Add entry for docking or un-docking the tool panel.
883 if (mpParentWindow
->IsFloatingMode())
884 pMenu
->InsertItem(MID_LOCK_TASK_PANEL
, String(SfxResId(STR_SFX_DOCK
)));
886 pMenu
->InsertItem(MID_UNLOCK_TASK_PANEL
, String(SfxResId(STR_SFX_UNDOCK
)));
888 pCustomizationMenu
->InsertSeparator();
889 pCustomizationMenu
->InsertItem(MID_RESTORE_DEFAULT
, String(SfxResId(STRING_RESTORE
)));
891 pMenu
->InsertItem(MID_CUSTOMIZATION
, String(SfxResId(STRING_CUSTOMIZATION
)));
892 pMenu
->SetPopupMenu(MID_CUSTOMIZATION
, pCustomizationMenu
);
894 pMenu
->RemoveDisabledEntries(sal_False
, sal_False
);
902 IMPL_LINK(SidebarController
, OnMenuItemSelected
, Menu
*, pMenu
)
906 OSL_ENSURE(pMenu
!=NULL
, "sfx2::sidebar::SidebarController::OnMenuItemSelected: illegal menu!");
911 const sal_Int32
nIndex (pMenu
->GetCurItemId());
914 case MID_UNLOCK_TASK_PANEL
:
915 mpParentWindow
->SetFloatingMode(sal_True
);
918 case MID_LOCK_TASK_PANEL
:
919 mpParentWindow
->SetFloatingMode(sal_False
);
922 case MID_RESTORE_DEFAULT
:
923 mpTabBar
->RestoreHideFlags();
930 if (nIndex
>= MID_FIRST_PANEL
&& nIndex
<MID_FIRST_HIDE
)
931 SwitchToDeck(mpTabBar
->GetDeckIdForIndex(nIndex
- MID_FIRST_PANEL
));
932 else if (nIndex
>=MID_FIRST_HIDE
)
933 if (pMenu
->GetItemBits(nIndex
) == MIB_CHECKABLE
)
934 mpTabBar
->ToggleHideFlag(nIndex
-MID_FIRST_HIDE
);
936 catch (RuntimeException
&)
949 void SidebarController::RequestCloseDeck (void)
951 mbIsDeckRequestedOpen
= false;
952 UpdateDeckOpenState();
958 void SidebarController::RequestOpenDeck (void)
960 mbIsDeckRequestedOpen
= true;
961 UpdateDeckOpenState();
967 void SidebarController::UpdateDeckOpenState (void)
969 if ( ! mbIsDeckRequestedOpen
)
970 // No state requested.
973 // Update (change) the open state when it either has not yet been initialized
974 // or when its value differs from the requested state.
976 || mbIsDeckOpen
.get() != mbIsDeckRequestedOpen
.get())
978 if (mbIsDeckRequestedOpen
.get())
980 if (mnSavedSidebarWidth
<= TabBar::GetDefaultWidth())
981 SetChildWindowWidth(SidebarChildWindow::GetDefaultWidth(mpParentWindow
));
983 SetChildWindowWidth(mnSavedSidebarWidth
);
987 if ( ! mpParentWindow
->IsFloatingMode())
988 mnSavedSidebarWidth
= SetChildWindowWidth(TabBar::GetDefaultWidth());
989 if (mnWidthOnSplitterButtonDown
> TabBar::GetDefaultWidth())
990 mnSavedSidebarWidth
= mnWidthOnSplitterButtonDown
;
991 mpParentWindow
->SetStyle(mpParentWindow
->GetStyle() & ~WB_SIZEABLE
);
994 mbIsDeckOpen
= mbIsDeckRequestedOpen
.get();
995 if (mbIsDeckOpen
.get() && mpCurrentDeck
)
996 mpCurrentDeck
->Show(mbIsDeckOpen
.get());
1004 FocusManager
& SidebarController::GetFocusManager (void)
1006 return maFocusManager
;
1012 bool SidebarController::CanModifyChildWindowWidth (void)
1014 SfxSplitWindow
* pSplitWindow
= GetSplitWindow();
1015 if (pSplitWindow
== NULL
)
1018 sal_uInt16
nRow (0xffff);
1019 sal_uInt16
nColumn (0xffff);
1020 if (pSplitWindow
->GetWindowPos(mpParentWindow
, nColumn
, nRow
))
1022 sal_uInt16
nRowCount (pSplitWindow
->GetWindowCount(nColumn
));
1023 return nRowCount
==1;
1032 sal_Int32
SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth
)
1034 SfxSplitWindow
* pSplitWindow
= GetSplitWindow();
1035 if (pSplitWindow
== NULL
)
1038 sal_uInt16
nRow (0xffff);
1039 sal_uInt16
nColumn (0xffff);
1040 pSplitWindow
->GetWindowPos(mpParentWindow
, nColumn
, nRow
);
1041 const long nColumnWidth (pSplitWindow
->GetLineSize(nColumn
));
1043 Window
* pWindow
= mpParentWindow
;
1044 const Size
aWindowSize (pWindow
->GetSizePixel());
1046 pSplitWindow
->MoveWindow(
1048 Size(nNewWidth
, aWindowSize
.Height()),
1051 static_cast<SplitWindow
*>(pSplitWindow
)->Split();
1053 return static_cast<sal_Int32
>(nColumnWidth
);
1059 void SidebarController::RestrictWidth (sal_Int32 nWidth
)
1061 SfxSplitWindow
* pSplitWindow
= GetSplitWindow();
1062 if (pSplitWindow
!= NULL
)
1064 const sal_uInt16
nId (pSplitWindow
->GetItemId(mpParentWindow
));
1065 const sal_uInt16
nSetId (pSplitWindow
->GetSet(nId
));
1066 pSplitWindow
->SetItemSizeRange(
1068 Range(TabBar::GetDefaultWidth() + nWidth
, gnMaximumSidebarWidth
));
1075 SfxSplitWindow
* SidebarController::GetSplitWindow (void)
1077 if (mpParentWindow
!= NULL
)
1079 SfxSplitWindow
* pSplitWindow
= dynamic_cast<SfxSplitWindow
*>(mpParentWindow
->GetParent());
1080 if (pSplitWindow
!= mpSplitWindow
)
1082 if (mpSplitWindow
!= NULL
)
1083 mpSplitWindow
->RemoveEventListener(LINK(this, SidebarController
, WindowEventHandler
));
1085 mpSplitWindow
= pSplitWindow
;
1087 if (mpSplitWindow
!= NULL
)
1088 mpSplitWindow
->AddEventListener(LINK(this, SidebarController
, WindowEventHandler
));
1090 return mpSplitWindow
;
1099 void SidebarController::UpdateCloseIndicator (const bool bCloseAfterDrag
)
1101 if (mpParentWindow
== NULL
)
1104 if (bCloseAfterDrag
)
1106 // Make sure that the indicator exists.
1107 if ( ! mpCloseIndicator
)
1109 mpCloseIndicator
.reset(new FixedImage(mpParentWindow
));
1110 FixedImage
* pFixedImage
= static_cast<FixedImage
*>(mpCloseIndicator
.get());
1111 const Image
aImage (Theme::GetImage(Theme::Image_CloseIndicator
));
1112 pFixedImage
->SetImage(aImage
);
1113 pFixedImage
->SetSizePixel(aImage
.GetSizePixel());
1114 pFixedImage
->SetBackground(Theme::GetWallpaper(Theme::Paint_DeckBackground
));
1117 // Place and show the indicator.
1118 const Size
aWindowSize (mpParentWindow
->GetSizePixel());
1119 const Size
aImageSize (mpCloseIndicator
->GetSizePixel());
1120 mpCloseIndicator
->SetPosPixel(
1122 aWindowSize
.Width() - TabBar::GetDefaultWidth() - aImageSize
.Width(),
1123 (aWindowSize
.Height() - aImageSize
.Height())/2));
1124 mpCloseIndicator
->Show();
1128 // Hide but don't delete the indicator.
1129 if (mpCloseIndicator
)
1130 mpCloseIndicator
->Hide();
1137 void SidebarController::UpdateTitleBarIcons (void)
1139 if ( ! mpCurrentDeck
)
1142 const bool bIsHighContrastModeActive (Theme::IsHighContrastMode());
1143 const ResourceManager
& rResourceManager (ResourceManager::Instance());
1145 // Update the deck icon.
1146 const DeckDescriptor
* pDeckDescriptor
= rResourceManager
.GetDeckDescriptor(mpCurrentDeck
->GetId());
1147 if (pDeckDescriptor
!= NULL
&& mpCurrentDeck
->GetTitleBar())
1149 const OUString
sIconURL(
1150 bIsHighContrastModeActive
1151 ? pDeckDescriptor
->msHighContrastTitleBarIconURL
1152 : pDeckDescriptor
->msTitleBarIconURL
);
1153 mpCurrentDeck
->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL
, mxFrame
));
1156 // Update the panel icons.
1157 const SharedPanelContainer
& rPanels (mpCurrentDeck
->GetPanels());
1158 for (SharedPanelContainer::const_iterator
1159 iPanel(rPanels
.begin()), iEnd(rPanels
.end());
1165 if ((*iPanel
)->GetTitleBar() == NULL
)
1167 const PanelDescriptor
* pPanelDescriptor
= rResourceManager
.GetPanelDescriptor((*iPanel
)->GetId());
1168 if (pPanelDescriptor
== NULL
)
1170 const OUString
sIconURL (
1171 bIsHighContrastModeActive
1172 ? pPanelDescriptor
->msHighContrastTitleBarIconURL
1173 : pPanelDescriptor
->msTitleBarIconURL
);
1174 (*iPanel
)->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL
, mxFrame
));
1181 void SidebarController::ShowPanel (const Panel
& rPanel
)
1184 mpCurrentDeck
->ShowPanel(rPanel
);
1190 Context
SidebarController::GetCurrentContext (void) const
1192 return maCurrentContext
;
1196 } } // end of namespace sfx2::sidebar