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 #ifndef SFX_SIDEBAR_CONTROLLER_HXX
23 #define SFX_SIDEBAR_CONTROLLER_HXX
24 
25 #include "AsynchronousCall.hxx"
26 #include "Context.hxx"
27 #include "FocusManager.hxx"
28 #include "Panel.hxx"
29 #include "ResourceManager.hxx"
30 #include "TabBar.hxx"
31 
32 #include <vcl/menu.hxx>
33 
34 #include <com/sun/star/awt/XWindowPeer.hpp>
35 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
36 #include <com/sun/star/frame/XDispatch.hpp>
37 #include <com/sun/star/ui/XContextChangeEventListener.hpp>
38 #include <com/sun/star/ui/XUIElement.hpp>
39 #include <com/sun/star/ui/XSidebar.hpp>
40 
41 #include <boost/noncopyable.hpp>
42 #include <boost/optional.hpp>
43 #include <cppuhelper/compbase4.hxx>
44 #include <cppuhelper/basemutex.hxx>
45 #include <cppuhelper/weakref.hxx>
46 #include <comphelper/stl_types.hxx>
47 
48 
49 namespace css = ::com::sun::star;
50 namespace cssu = ::com::sun::star::uno;
51 
52 
53 namespace
54 {
55     typedef ::cppu::WeakComponentImplHelper4 <
56         css::ui::XContextChangeEventListener,
57         css::beans::XPropertyChangeListener,
58         css::ui::XSidebar,
59         css::frame::XStatusListener
60         > SidebarControllerInterfaceBase;
61 }
62 
63 class SfxSplitWindow;
64 class FixedBitmap;
65 
66 namespace sfx2 { namespace sidebar {
67 
68 class ContentPanelDescriptor;
69 class Deck;
70 class DeckDescriptor;
71 class SidebarDockingWindow;
72 class TabBar;
73 class TabBarConfiguration;
74 
75 class SidebarController
76     : private ::boost::noncopyable,
77       private ::cppu::BaseMutex,
78       public SidebarControllerInterfaceBase
79 {
80 public:
81     SidebarController(
82         SidebarDockingWindow* pParentWindow,
83         const cssu::Reference<css::frame::XFrame>& rxFrame);
84     virtual ~SidebarController (void);
85 
86     /** Return the SidebarController object that is associated with
87         the given XFrame.
88         @return
89             When there is no SidebarController object for the given
90             XFrame then <NULL/> is returned.
91     */
92     static SidebarController* GetSidebarControllerForFrame (
93         const cssu::Reference<css::frame::XFrame>& rxFrame);
94 
95     // ui::XContextChangeEventListener
96     virtual void SAL_CALL notifyContextChangeEvent (const css::ui::ContextChangeEventObject& rEvent)
97         throw(cssu::RuntimeException);
98 
99     // XEventListener
100     virtual void SAL_CALL disposing (const css::lang::EventObject& rEventObject)
101         throw(cssu::RuntimeException);
102 
103     // beans::XPropertyChangeListener
104     virtual void SAL_CALL propertyChange (const css::beans::PropertyChangeEvent& rEvent)
105         throw(cssu::RuntimeException);
106 
107     // frame::XStatusListener
108     virtual void SAL_CALL statusChanged (const css::frame::FeatureStateEvent& rEvent)
109         throw(cssu::RuntimeException);
110 
111     // ui::XSidebar
112     virtual void SAL_CALL requestLayout (void)
113         throw(cssu::RuntimeException);
114 
115     void NotifyResize (void);
116 
117     /** In some situations it is necessary to force an update of the
118         current deck and its panels.  One reason is a change of the
119         view scale.  Some panels can handle this only when
120         constructed.  In this case we have to a context change and
121         also force that all panels are destroyed and created new.
122     */
123     const static sal_Int32 SwitchFlag_NoForce = 0x00;
124     const static sal_Int32 SwitchFlag_ForceSwitch = 0x01;
125     const static sal_Int32 SwitchFlag_ForceNewDeck = 0x02;
126     const static sal_Int32 SwitchFlag_ForceNewPanels = 0x02;
127 
128     void RequestSwitchToDeck (
129         const ::rtl::OUString& rsDeckId);
130     void OpenThenSwitchToDeck (
131         const ::rtl::OUString& rsDeckId);
132 
133     /** Show only the tab bar, not the deck.
134     */
135     void RequestCloseDeck (void);
136 
137     /** Open the deck area and restore the parent window to its old width.
138     */
139     void RequestOpenDeck (void);
140 
141     FocusManager& GetFocusManager (void);
142 
143 private:
144     typedef ::std::map<
145         const cssu::Reference<css::frame::XFrame>,
146         cssu::WeakReference<SidebarController>
147     > SidebarControllerContainer;
148     static SidebarControllerContainer maSidebarControllerContainer;
149 
150     ::boost::scoped_ptr<Deck> mpCurrentDeck;
151     SidebarDockingWindow* mpParentWindow;
152     ::boost::scoped_ptr<TabBar> mpTabBar;
153     cssu::Reference<css::frame::XFrame> mxFrame;
154     Context maCurrentContext;
155     Context maRequestedContext;
156     /// Use a combination of SwitchFlag_* as value.
157     sal_Int32 mnRequestedForceFlags;
158     ::rtl::OUString msCurrentDeckId;
159     ::rtl::OUString msCurrentDeckTitle;
160     AsynchronousCall maPropertyChangeForwarder;
161     AsynchronousCall maContextChangeUpdate;
162     AsynchronousCall maAsynchronousDeckSwitch;
163 
164     /** Two flags control whether the deck is displayed or if only the
165         tab bar remains visible.
166         The mbIsDeckOpen flag stores the current state while
167         mbIsDeckRequestedOpen stores how this state should be.  User
168         actions like clicking on the deck closer affect the
169         mbIsDeckRequestedOpen.  Normally both flags have the same
170         value.  A document being read-only can prevent the deck from opening.
171     */
172     ::boost::optional<bool> mbIsDeckRequestedOpen;
173     ::boost::optional<bool> mbIsDeckOpen;
174     bool mbCanDeckBeOpened;
175 
176     /** Before the deck is closed the sidebar width is saved into this variable,
177         so that it can be restored when the deck is reopended.
178     */
179     sal_Int32 mnSavedSidebarWidth;
180     FocusManager maFocusManager;
181     cssu::Reference<css::frame::XDispatch> mxReadOnlyModeDispatch;
182     bool mbIsDocumentReadOnly;
183     SfxSplitWindow* mpSplitWindow;
184     /** When the user moves the splitter then we remember the
185         width at that time.
186     */
187     sal_Int32 mnWidthOnSplitterButtonDown;
188     /** Control that is temporarily used as replacement for the deck
189         to indicate that when the current mouse drag operation ends, the
190         sidebar will only show the tab bar.
191     */
192     ::boost::scoped_ptr<Window> mpCloseIndicator;
193 
194     DECL_LINK(WindowEventHandler, VclWindowEvent*);
195     /** Make maRequestedContext the current context.
196     */
197     void UpdateConfigurations (void);
198 
199     cssu::Reference<css::ui::XUIElement> CreateUIElement (
200         const cssu::Reference<css::awt::XWindowPeer>& rxWindow,
201         const ::rtl::OUString& rsImplementationURL,
202         const bool bWantsCanvas,
203         const Context& rContext);
204     SharedPanel CreatePanel (
205         const ::rtl::OUString& rsPanelId,
206         ::Window* pParentWindow,
207         const bool bIsInitiallyExpanded,
208         const Context& rContext);
209     void SwitchToDeck (
210         const ::rtl::OUString& rsDeckId);
211     void SwitchToDeck (
212         const DeckDescriptor& rDeckDescriptor,
213         const Context& rContext);
214     void ShowPopupMenu (
215         const Rectangle& rButtonBox,
216         const ::std::vector<TabBar::DeckMenuData>& rMenuData) const;
217     void ShowDetailMenu (const ::rtl::OUString& rsMenuCommand) const;
218     ::boost::shared_ptr<PopupMenu> CreatePopupMenu (
219         const ::std::vector<TabBar::DeckMenuData>& rMenuData) const;
220     DECL_LINK(OnMenuItemSelected, Menu*);
221     void BroadcastPropertyChange (void);
222 
223     /** The close of the deck changes the width of the child window.
224         That is only possible if there is no other docking window docked above or below the sidebar.
225         Return whether the width of the child window can be modified.
226     */
227     bool CanModifyChildWindowWidth (void);
228 
229     /** Set the child window container to a new width.
230         Return the old width.
231     */
232     sal_Int32 SetChildWindowWidth (const sal_Int32 nNewWidth);
233 
234     /** Update the icons displayed in the title bars of the deck and
235         the panels.  This is called once when a deck is created and
236         every time when a data change event is processed.
237     */
238     void UpdateTitleBarIcons (void);
239 
240     void UpdateDeckOpenState (void);
241     void RestrictWidth (void);
242     SfxSplitWindow* GetSplitWindow (void);
243     void ProcessNewWidth (const sal_Int32 nNewWidth);
244     void UpdateCloseIndicator (const bool bIsIndicatorVisible);
245 
246     /** Typically called when a panel is focused via keyboard.
247         Tries to scroll the deck up or down to make the given panel
248         completely visible.
249     */
250     void ShowPanel (const Panel& rPanel);
251 
252     Context GetCurrentContext (void) const;
253 
254     virtual void SAL_CALL disposing (void);
255 };
256 
257 
258 } } // end of namespace sfx2::sidebar
259 
260 #endif
261