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