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 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26 
27 #include "FormShellManager.hxx"
28 
29 #include "EventMultiplexer.hxx"
30 #include "ViewShell.hxx"
31 #include "ViewShellBase.hxx"
32 #include "ViewShellManager.hxx"
33 #include "Window.hxx"
34 #include <svx/fmshell.hxx>
35 
36 namespace sd {
37 
38 namespace {
39 
40 /** This factory is responsible for creating and deleting the FmFormShell.
41 */
42 class FormShellManagerFactory
43     : public ::sd::ShellFactory<SfxShell>
44 {
45 public:
46     FormShellManagerFactory (ViewShell& rViewShell, FormShellManager& rManager);
47     virtual FmFormShell* CreateShell (ShellId nId, ::Window* pParentWindow, FrameView* pFrameView);
48     virtual void ReleaseShell (SfxShell* pShell);
49 
50 private:
51     ::sd::ViewShell& mrViewShell;
52     FormShellManager& mrFormShellManager;
53 };
54 
55 } // end of anonymous namespace
56 
57 
58 FormShellManager::FormShellManager (ViewShellBase& rBase)
59     : mrBase(rBase),
60       mpFormShell(NULL),
61       mbFormShellAboveViewShell(false),
62       mpSubShellFactory(),
63       mbIsMainViewChangePending(false),
64       mpMainViewShellWindow(NULL)
65 {
66     // Register at the EventMultiplexer to be informed about changes in the
67     // center pane.
68     Link aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
69     mrBase.GetEventMultiplexer()->AddEventListener(
70         aLink,
71         sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED
72         | sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED
73         | sd::tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED);
74 
75     RegisterAtCenterPane();
76 }
77 
78 
79 
80 
81 FormShellManager::~FormShellManager (void)
82 {
83     SetFormShell(NULL);
84     UnregisterAtCenterPane();
85 
86     // Unregister from the EventMultiplexer.
87     Link aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
88     mrBase.GetEventMultiplexer()->RemoveEventListener(aLink);
89 
90     if (mpSubShellFactory.get() != NULL)
91     {
92         ViewShell* pShell = mrBase.GetMainViewShell().get();
93         if (pShell != NULL)
94             mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell,mpSubShellFactory);
95     }
96 }
97 
98 
99 
100 
101 void FormShellManager::SetFormShell (FmFormShell* pFormShell)
102 {
103     if (mpFormShell != pFormShell)
104     {
105         // Disconnect from the old form shell.
106         if (mpFormShell != NULL)
107         {
108             mpFormShell->SetControlActivationHandler(Link());
109             EndListening(*mpFormShell);
110             mpFormShell->SetView(NULL);
111         }
112 
113         mpFormShell = pFormShell;
114 
115         // Connect to the new form shell.
116         if (mpFormShell != NULL)
117         {
118             mpFormShell->SetControlActivationHandler(
119                 LINK(
120                     this,
121                     FormShellManager,
122                     FormControlActivated));
123             StartListening(*mpFormShell);
124 
125             ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
126             if (pMainViewShell != NULL)
127             {
128                 // Prevent setting the view twice at the FmFormShell.
129                 FmFormView* pFormView = static_cast<FmFormView*>(pMainViewShell->GetView());
130                 if (mpFormShell->GetFormView() != pFormView)
131                     mpFormShell->SetView(pFormView);
132             }
133         }
134 
135         // Tell the ViewShellManager where on the stack to place the form shell.
136         mrBase.GetViewShellManager()->SetFormShell(
137             mrBase.GetMainViewShell().get(),
138             mpFormShell,
139             mbFormShellAboveViewShell);
140     }
141 }
142 
143 
144 
145 
146 FmFormShell* FormShellManager::GetFormShell (void)
147 {
148     return mpFormShell;
149 }
150 
151 
152 
153 
154 void FormShellManager::RegisterAtCenterPane (void)
155 {
156     do
157     {
158         ViewShell* pShell = mrBase.GetMainViewShell().get();
159         if (pShell == NULL)
160             break;
161 
162         // No form shell for the slide sorter.  Besides that it is not
163         // necessary, using both together results in crashes.
164         if (pShell->GetShellType() == ViewShell::ST_SLIDE_SORTER)
165             break;
166 
167         mpMainViewShellWindow = pShell->GetActiveWindow();
168 		if (mpMainViewShellWindow == NULL)
169             break;
170 
171         // Register at the window to get informed when to move the form
172         // shell to the bottom of the shell stack.
173         mpMainViewShellWindow->AddEventListener(
174             LINK(
175                 this,
176                 FormShellManager,
177                 WindowEventHandler));
178 
179         // Create a shell factory and with it activate the form shell.
180         OSL_ASSERT(mpSubShellFactory.get()==NULL);
181         mpSubShellFactory.reset(new FormShellManagerFactory(*pShell, *this));
182         mrBase.GetViewShellManager()->AddSubShellFactory(pShell,mpSubShellFactory);
183         mrBase.GetViewShellManager()->ActivateSubShell(*pShell, RID_FORMLAYER_TOOLBOX);
184     }
185     while (false);
186 }
187 
188 
189 
190 
191 void FormShellManager::UnregisterAtCenterPane (void)
192 {
193     do
194     {
195         if (mpMainViewShellWindow != NULL)
196         {
197             // Unregister from the window.
198             mpMainViewShellWindow->RemoveEventListener(
199                 LINK(
200                     this,
201                     FormShellManager,
202                     WindowEventHandler));
203             mpMainViewShellWindow = NULL;
204         }
205 
206         // Unregister form at the form shell.
207         SetFormShell(NULL);
208 
209         // Deactivate the form shell and destroy the shell factory.
210         ViewShell* pShell = mrBase.GetMainViewShell().get();
211         if (pShell != NULL)
212         {
213             mrBase.GetViewShellManager()->DeactivateSubShell(*pShell,  RID_FORMLAYER_TOOLBOX);
214             mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell, mpSubShellFactory);
215         }
216 
217         mpSubShellFactory.reset();
218     }
219     while (false);
220 }
221 
222 
223 
224 
225 IMPL_LINK(FormShellManager, FormControlActivated, FmFormShell*, EMPTYARG)
226 {
227     // The form shell has been actived.  To give it priority in reacting to
228     // slot calls the form shell is moved to the top of the object bar shell
229     // stack.
230     ViewShell* pShell = mrBase.GetMainViewShell().get();
231     if (pShell!=NULL && !mbFormShellAboveViewShell)
232     {
233         mbFormShellAboveViewShell = true;
234 
235         ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
236         mrBase.GetViewShellManager()->SetFormShell(pShell,mpFormShell,mbFormShellAboveViewShell);
237     }
238 
239     return 0;
240 }
241 
242 
243 
244 
245 IMPL_LINK(FormShellManager, ConfigurationUpdateHandler, sd::tools::EventMultiplexerEvent*, pEvent)
246 {
247     switch (pEvent->meEventId)
248     {
249         case sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED:
250             UnregisterAtCenterPane();
251             break;
252 
253         case sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED:
254             mbIsMainViewChangePending = true;
255             break;
256 
257         case sd::tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED:
258             if (mbIsMainViewChangePending)
259             {
260                 mbIsMainViewChangePending = false;
261                 RegisterAtCenterPane();
262             }
263             break;
264 
265         default:
266             break;
267     }
268 
269     return 0;
270 }
271 
272 
273 
274 
275 IMPL_LINK(FormShellManager, WindowEventHandler, VclWindowEvent*, pEvent)
276 {
277     if (pEvent != NULL)
278     {
279         switch (pEvent->GetId())
280         {
281             case VCLEVENT_WINDOW_GETFOCUS:
282             {
283                 // The window of the center pane got the focus.  Therefore
284                 // the form shell is moved to the bottom of the object bar
285                 // stack.
286                 ViewShell* pShell = mrBase.GetMainViewShell().get();
287                 if (pShell!=NULL && mbFormShellAboveViewShell)
288                 {
289                     mbFormShellAboveViewShell = false;
290                     ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
291                     mrBase.GetViewShellManager()->SetFormShell(
292                         pShell,
293                         mpFormShell,
294                         mbFormShellAboveViewShell);
295                 }
296             }
297             break;
298 
299             case VCLEVENT_WINDOW_LOSEFOCUS:
300                 // We follow the sloppy focus policy.  Losing the focus is
301                 // ignored.  We wait for the focus to be placed either in
302                 // the window or the form shell.  The later, however, is
303                 // notified over the FormControlActivated handler, not this
304                 // one.
305                 break;
306 
307             case VCLEVENT_OBJECT_DYING:
308                 mpMainViewShellWindow = NULL;
309                 break;
310         }
311     }
312 
313     return 0;
314 }
315 
316 
317 
318 
319 void FormShellManager::Notify(SfxBroadcaster&, const SfxHint& rHint)
320 {
321     const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
322     if (pSimpleHint!=NULL && pSimpleHint->GetId()==SFX_HINT_DYING)
323     {
324         // If all goes well this listener is called after the
325         // FormShellManager was notified about the dying form shell by the
326         // FormShellManagerFactory.
327         OSL_ASSERT(mpFormShell==NULL);
328         if (mpFormShell != NULL)
329         {
330             mpFormShell = NULL;
331             mrBase.GetViewShellManager()->SetFormShell(
332                 mrBase.GetMainViewShell().get(),
333                 NULL,
334                 false);
335         }
336     }
337 }
338 
339 
340 
341 
342 
343 //===== FormShellManagerFactory ===============================================
344 
345 namespace {
346 
347 FormShellManagerFactory::FormShellManagerFactory (
348     ::sd::ViewShell& rViewShell,
349     FormShellManager& rManager)
350     : mrViewShell(rViewShell),
351       mrFormShellManager(rManager)
352 {
353 }
354 
355 
356 
357 
358 FmFormShell* FormShellManagerFactory::CreateShell (
359     ::sd::ShellId nId,
360     ::Window*,
361     ::sd::FrameView*)
362 {
363     FmFormShell* pShell = NULL;
364 
365     ::sd::View* pView = mrViewShell.GetView();
366     if (nId == RID_FORMLAYER_TOOLBOX)
367     {
368         pShell = new FmFormShell(&mrViewShell.GetViewShellBase(), pView);
369         mrFormShellManager.SetFormShell(pShell);
370     }
371 
372     return pShell;
373 }
374 
375 
376 
377 
378 void FormShellManagerFactory::ReleaseShell (SfxShell* pShell)
379 {
380     if (pShell != NULL)
381     {
382         mrFormShellManager.SetFormShell(NULL);
383         delete pShell;
384     }
385 }
386 
387 } // end of anonymous namespace
388 
389 } // end of namespace sd
390