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 "Panel.hxx"
27 #include "TitleBar.hxx"
28 #include "SidebarLayouter.hxx"
29 #include "TabBar.hxx"
30 #include "sfxresid.hxx"
31 #include "sfx2/sfxsids.hrc"
32 
33 #include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp>
34 #include <com/sun/star/ui/ContextChangeEventObject.hpp>
35 
36 #include <boost/bind.hpp>
37 #include <comphelper/componentfactory.hxx>
38 #include <comphelper/componentcontext.hxx>
39 #include <comphelper/namedvaluecollection.hxx>
40 
41 
42 using namespace css;
43 using namespace cssu;
44 
45 
46 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
47 
48 namespace sfx2 {
49 
50 
51 class SidebarController::Configuration
52 {
53 public:
54     Deck* mpDeck;
55     ::std::vector<Panel*> maPanels;
56 
57     Configuration (void);
58     void Disable (void);
59     void Activate (void);
60 };
61 
62 
63 
64 
65 SidebarController::SidebarController (
66     Window* pParentWindow,
67     const cssu::Reference<css::frame::XFrame>& rxFrame)
68     : SidebarControllerInterfaceBase(m_aMutex),
69       mpCurrentConfiguration(),
70       mpParentWindow(pParentWindow),
71       mpTabBar(new TabBar(mpParentWindow)),
72       mxFrame(rxFrame)
73 {
74     if (pParentWindow == NULL)
75     {
76         OSL_ASSERT(pParentWindow!=NULL);
77             return;
78     }
79 
80     UpdateConfiguration(Context(A2S("default"), A2S("default")));
81 
82     // Listen for context change events.
83     cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer (
84         css::ui::ContextChangeEventMultiplexer::get(
85             ::comphelper::getProcessComponentContext()));
86     if (xMultiplexer.is())
87         xMultiplexer->addContextChangeEventListener(
88             static_cast<css::ui::XContextChangeEventListener*>(this),
89             NULL);
90 
91     // Listen for window events.
92     mpParentWindow->AddEventListener(LINK(this, SidebarController, WindowEventHandler));
93 }
94 
95 
96 
97 
98 SidebarController::~SidebarController (void)
99 {
100 }
101 
102 
103 
104 
105 void SAL_CALL SidebarController::disposing (void)
106 {
107     cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer (
108         css::ui::ContextChangeEventMultiplexer::get(
109             ::comphelper::getProcessComponentContext()));
110     if (xMultiplexer.is())
111         xMultiplexer->removeAllContextChangeEventListeners(
112             static_cast<css::ui::XContextChangeEventListener*>(this));
113 
114     if (mpParentWindow != NULL)
115     {
116         mpParentWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler));
117         mpParentWindow = NULL;
118     }
119 }
120 
121 
122 
123 
124 void SAL_CALL SidebarController::notifyContextChangeEvent (const css::ui::ContextChangeEventObject& rEvent)
125     throw(cssu::RuntimeException)
126 {
127     UpdateConfiguration(Context(rEvent.ApplicationName, rEvent.ContextName));
128 }
129 
130 
131 
132 
133 void SAL_CALL SidebarController::disposing (const css::lang::EventObject& rEventObject)
134     throw(cssu::RuntimeException)
135 {
136     if (mpCurrentConfiguration)
137     {
138         mpCurrentConfiguration->Disable();
139         mpCurrentConfiguration.reset();
140     }
141     if (mpTabBar != NULL)
142     {
143         mpTabBar->Hide();
144         delete mpTabBar;
145         mpTabBar = NULL;
146     }
147 }
148 
149 
150 
151 
152 void SidebarController::NotifyResize (void)
153 {
154     if (mpCurrentConfiguration != NULL)
155     {
156         SidebarLayouter::LayoutSidebar(mpCurrentConfiguration->mpDeck, mpTabBar);
157         SidebarLayouter::LayoutPanels(mpCurrentConfiguration->mpDeck, mpCurrentConfiguration->maPanels);
158     }
159 }
160 
161 
162 
163 
164 void SidebarController::UpdateConfiguration (const Context& rContext)
165 {
166     ::boost::scoped_ptr<Configuration> pConfiguration(new Configuration());
167 
168     SharedContentPanelManager pContentManager (ContentPanelManager::Instance());
169     pContentManager->CallForBestMatchingDeck (
170         ::boost::bind(&SidebarController::ProcessMatchingDeck, this, _1, ::boost::ref(*pConfiguration)),
171         rContext);
172 
173     if (pConfiguration->mpDeck == NULL)
174         return;
175 
176     pContentManager->CallForMatchingPanels (
177         ::boost::bind(&SidebarController::ProcessMatchingPanel, this, _1, ::boost::ref(*pConfiguration)),
178         rContext,
179         pConfiguration->mpDeck->GetId());
180 
181     MakeConfigurationCurrent(*pConfiguration);
182     mpCurrentConfiguration.swap(pConfiguration);
183 }
184 
185 
186 
187 
188 void SidebarController::ProcessMatchingDeck (
189     const DeckDescriptor& rDeckDescriptor,
190     Configuration& rConfiguration)
191 {
192     if (rConfiguration.mpDeck != NULL)
193     {
194         // When more than one deck matches the context then choose the first.
195         return;
196     }
197 
198     rConfiguration.mpDeck = new Deck(rDeckDescriptor, mpParentWindow);
199 }
200 
201 
202 
203 
204 void SidebarController::ProcessMatchingPanel (
205     const ContentPanelDescriptor& rPanelDescriptor,
206     Configuration& rConfiguration)
207 {
208     // Create the panel which is the parent window of the UIElement
209     // that we are about to create.
210     Panel* pPanel = new Panel(rPanelDescriptor, rConfiguration.mpDeck);
211 
212     Reference<ui::XUIElement> xElement;
213     try
214     {
215         const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory());
216         const Reference<ui::XUIElementFactory> xUIElementFactory (
217             aComponentContext.createComponent("com.sun.star.ui.UIElementFactoryManager"),
218             UNO_QUERY_THROW);
219 
220         ::comphelper::NamedValueCollection aCreationArguments;
221         aCreationArguments.put("Frame", makeAny(mxFrame));
222         aCreationArguments.put("ParentWindow", makeAny(pPanel->GetComponentInterface()));
223 
224         pPanel->SetUIElement(
225             Reference<ui::XUIElement>(
226                 xUIElementFactory->createUIElement(
227                     rPanelDescriptor.msImplementationURL,
228                     aCreationArguments.getPropertyValues()),
229                 UNO_QUERY_THROW));
230     }
231     catch(Exception& rException)
232     {
233         OSL_TRACE("caught exception: %s",
234             OUStringToOString(rException.Message, RTL_TEXTENCODING_ASCII_US).getStr());
235         // For some reason we can not create the actual panel.
236         // Probably because its factory was not properly registered.
237         // TODO: provide feedback to developer to better pinpoint the
238         // source of the error.
239     }
240     rConfiguration.maPanels.push_back(pPanel);
241 }
242 
243 
244 
245 
246 void SidebarController::MakeConfigurationCurrent (Configuration& rConfiguration)
247 {
248     if (rConfiguration.mpDeck == NULL)
249         return;
250 
251     // Deactivate the current deck and panels.
252     if (mpCurrentConfiguration && mpCurrentConfiguration->mpDeck!=NULL)
253         mpCurrentConfiguration->Disable();
254     SidebarLayouter::LayoutSidebar(rConfiguration.mpDeck, mpTabBar);
255     rConfiguration.Activate();
256 }
257 
258 
259 
260 
261 IMPL_LINK(SidebarController, WindowEventHandler, VclWindowEvent*, pEvent)
262 {
263     if (pEvent != NULL)
264     {
265         ::Window* pWindow = pEvent->GetWindow();
266         switch (pEvent->GetId())
267         {
268             case VCLEVENT_WINDOW_GETFOCUS:
269             case VCLEVENT_WINDOW_LOSEFOCUS:
270                 break;
271 
272             case VCLEVENT_WINDOW_SHOW:
273             case VCLEVENT_WINDOW_RESIZE:
274                 NotifyResize();
275                 break;
276 
277             case SFX_HINT_DYING:
278                 dispose();
279                 break;
280 
281             default:
282                 break;
283         }
284     }
285 
286     return sal_True;
287 }
288 
289 
290 
291 
292 //===== SidebarController::Configuration ======================================
293 
294 SidebarController::Configuration::Configuration (void)
295     : mpDeck(NULL),
296       maPanels()
297 {
298 }
299 
300 
301 
302 
303 void SidebarController::Configuration::Disable (void)
304 {
305     // Hide and destroy the panels.
306     for (::std::vector<Panel*>::const_iterator
307              iPanel(maPanels.begin()),
308              iEnd(maPanels.end());
309          iPanel!=iEnd;
310          ++iPanel)
311     {
312         (*iPanel)->Hide();
313         mpDeck->removeWindow(*iPanel, NULL);
314         delete *iPanel;
315     }
316     maPanels.clear();
317 
318     // Hide and destroy the deck window.
319     mpDeck->Hide();
320     mpDeck->GetParent()->removeWindow(mpDeck, NULL);
321     delete mpDeck;
322     mpDeck = NULL;
323 }
324 
325 
326 
327 
328 void SidebarController::Configuration::Activate (void)
329 {
330     SidebarLayouter::LayoutPanels(mpDeck, maPanels);
331 
332     // Show the deck window.
333     mpDeck->GetTitleBar()->Show();
334     mpDeck->Show();
335 
336     // Show the panels.
337     for (::std::vector<Panel*>::const_iterator
338              iPanel(maPanels.begin()),
339              iEnd(maPanels.end());
340          iPanel!=iEnd;
341          ++iPanel)
342     {
343         (*iPanel)->GetTitleBar()->Show();
344         (*iPanel)->Show();
345     }
346 }
347 
348 
349 } // end of namespace sfx2
350