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
FormShellManager(ViewShellBase & rBase)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
~FormShellManager(void)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
SetFormShell(FmFormShell * pFormShell)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
GetFormShell(void)146 FmFormShell* FormShellManager::GetFormShell (void)
147 {
148 return mpFormShell;
149 }
150
151
152
153
RegisterAtCenterPane(void)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
UnregisterAtCenterPane(void)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
IMPL_LINK(FormShellManager,FormControlActivated,FmFormShell *,EMPTYARG)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
IMPL_LINK(FormShellManager,ConfigurationUpdateHandler,sd::tools::EventMultiplexerEvent *,pEvent)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
IMPL_LINK(FormShellManager,WindowEventHandler,VclWindowEvent *,pEvent)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
Notify(SfxBroadcaster &,const SfxHint & rHint)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
FormShellManagerFactory(::sd::ViewShell & rViewShell,FormShellManager & rManager)347 FormShellManagerFactory::FormShellManagerFactory (
348 ::sd::ViewShell& rViewShell,
349 FormShellManager& rManager)
350 : mrViewShell(rViewShell),
351 mrFormShellManager(rManager)
352 {
353 }
354
355
356
357
CreateShell(::sd::ShellId nId,::Window *,::sd::FrameView *)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
ReleaseShell(SfxShell * pShell)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