Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "FormShellManager.hxx"
21 :
22 : #include "EventMultiplexer.hxx"
23 : #include "ViewShell.hxx"
24 : #include "ViewShellBase.hxx"
25 : #include "ViewShellManager.hxx"
26 : #include "Window.hxx"
27 : #include <svx/fmshell.hxx>
28 :
29 : namespace sd {
30 :
31 : namespace {
32 :
33 : /** This factory is responsible for creating and deleting the FmFormShell.
34 : */
35 266 : class FormShellManagerFactory
36 : : public ::sd::ShellFactory<SfxShell>
37 : {
38 : public:
39 : FormShellManagerFactory (ViewShell& rViewShell, FormShellManager& rManager);
40 : virtual FmFormShell* CreateShell (ShellId nId, vcl::Window* pParentWindow, FrameView* pFrameView) SAL_OVERRIDE;
41 : virtual void ReleaseShell (SfxShell* pShell) SAL_OVERRIDE;
42 :
43 : private:
44 : ::sd::ViewShell& mrViewShell;
45 : FormShellManager& mrFormShellManager;
46 : };
47 :
48 : } // end of anonymous namespace
49 :
50 127 : FormShellManager::FormShellManager (ViewShellBase& rBase)
51 : : mrBase(rBase),
52 : mpFormShell(NULL),
53 : mbFormShellAboveViewShell(false),
54 : mpSubShellFactory(),
55 : mbIsMainViewChangePending(false),
56 127 : mpMainViewShellWindow(NULL)
57 : {
58 : // Register at the EventMultiplexer to be informed about changes in the
59 : // center pane.
60 127 : Link<> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
61 : mrBase.GetEventMultiplexer()->AddEventListener(
62 : aLink,
63 : sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED
64 : | sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED
65 127 : | sd::tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED);
66 :
67 127 : RegisterAtCenterPane();
68 127 : }
69 :
70 381 : FormShellManager::~FormShellManager()
71 : {
72 127 : SetFormShell(NULL);
73 127 : UnregisterAtCenterPane();
74 :
75 : // Unregister from the EventMultiplexer.
76 127 : Link<> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
77 127 : mrBase.GetEventMultiplexer()->RemoveEventListener(aLink);
78 :
79 127 : if (mpSubShellFactory.get() != NULL)
80 : {
81 0 : ViewShell* pShell = mrBase.GetMainViewShell().get();
82 0 : if (pShell != NULL)
83 0 : mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell,mpSubShellFactory);
84 : }
85 254 : }
86 :
87 653 : void FormShellManager::SetFormShell (FmFormShell* pFormShell)
88 : {
89 653 : if (mpFormShell != pFormShell)
90 : {
91 : // Disconnect from the old form shell.
92 266 : if (mpFormShell != NULL)
93 : {
94 133 : mpFormShell->SetControlActivationHandler(Link<>());
95 133 : EndListening(*mpFormShell);
96 133 : mpFormShell->SetView(NULL);
97 : }
98 :
99 266 : mpFormShell = pFormShell;
100 :
101 : // Connect to the new form shell.
102 266 : if (mpFormShell != NULL)
103 : {
104 : mpFormShell->SetControlActivationHandler(
105 : LINK(
106 : this,
107 : FormShellManager,
108 133 : FormControlActivated));
109 133 : StartListening(*mpFormShell);
110 :
111 133 : ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
112 133 : if (pMainViewShell != NULL)
113 : {
114 : // Prevent setting the view twice at the FmFormShell.
115 133 : FmFormView* pFormView = static_cast<FmFormView*>(pMainViewShell->GetView());
116 133 : if (mpFormShell->GetFormView() != pFormView)
117 0 : mpFormShell->SetView(pFormView);
118 : }
119 : }
120 :
121 : // Tell the ViewShellManager where on the stack to place the form shell.
122 : mrBase.GetViewShellManager()->SetFormShell(
123 532 : mrBase.GetMainViewShell().get(),
124 : mpFormShell,
125 532 : mbFormShellAboveViewShell);
126 : }
127 653 : }
128 :
129 260 : void FormShellManager::RegisterAtCenterPane()
130 : {
131 260 : ViewShell* pShell = mrBase.GetMainViewShell().get();
132 260 : if (pShell == NULL)
133 127 : return;
134 :
135 : // No form shell for the slide sorter. Besides that it is not
136 : // necessary, using both together results in crashes.
137 133 : if (pShell->GetShellType() == ViewShell::ST_SLIDE_SORTER)
138 0 : return;
139 :
140 133 : mpMainViewShellWindow = pShell->GetActiveWindow();
141 133 : if (mpMainViewShellWindow == nullptr)
142 0 : return;
143 :
144 : // Register at the window to get informed when to move the form
145 : // shell to the bottom of the shell stack.
146 : mpMainViewShellWindow->AddEventListener(
147 : LINK(
148 : this,
149 : FormShellManager,
150 133 : WindowEventHandler));
151 :
152 : // Create a shell factory and with it activate the form shell.
153 : OSL_ASSERT(mpSubShellFactory.get()==NULL);
154 133 : mpSubShellFactory.reset(new FormShellManagerFactory(*pShell, *this));
155 133 : mrBase.GetViewShellManager()->AddSubShellFactory(pShell,mpSubShellFactory);
156 133 : mrBase.GetViewShellManager()->ActivateSubShell(*pShell, RID_FORMLAYER_TOOLBOX);
157 : }
158 :
159 260 : void FormShellManager::UnregisterAtCenterPane()
160 : {
161 260 : if (mpMainViewShellWindow != nullptr)
162 : {
163 : // Unregister from the window.
164 : mpMainViewShellWindow->RemoveEventListener(
165 : LINK(
166 : this,
167 : FormShellManager,
168 133 : WindowEventHandler));
169 133 : mpMainViewShellWindow = NULL;
170 : }
171 :
172 : // Unregister form at the form shell.
173 260 : SetFormShell(NULL);
174 :
175 : // Deactivate the form shell and destroy the shell factory.
176 260 : ViewShell* pShell = mrBase.GetMainViewShell().get();
177 260 : if (pShell != NULL)
178 : {
179 0 : mrBase.GetViewShellManager()->DeactivateSubShell(*pShell, RID_FORMLAYER_TOOLBOX);
180 0 : mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell, mpSubShellFactory);
181 : }
182 :
183 260 : mpSubShellFactory.reset();
184 260 : }
185 :
186 0 : IMPL_LINK_NOARG(FormShellManager, FormControlActivated)
187 : {
188 : // The form shell has been activated. To give it priority in reacting to
189 : // slot calls the form shell is moved to the top of the object bar shell
190 : // stack.
191 0 : ViewShell* pShell = mrBase.GetMainViewShell().get();
192 0 : if (pShell!=NULL && !mbFormShellAboveViewShell)
193 : {
194 0 : mbFormShellAboveViewShell = true;
195 :
196 0 : ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
197 0 : mrBase.GetViewShellManager()->SetFormShell(pShell,mpFormShell,mbFormShellAboveViewShell);
198 : }
199 :
200 0 : return 0;
201 : }
202 :
203 14500 : IMPL_LINK(FormShellManager, ConfigurationUpdateHandler, sd::tools::EventMultiplexerEvent*, pEvent)
204 : {
205 7250 : switch (pEvent->meEventId)
206 : {
207 : case sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED:
208 133 : UnregisterAtCenterPane();
209 133 : break;
210 :
211 : case sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED:
212 133 : mbIsMainViewChangePending = true;
213 133 : break;
214 :
215 : case sd::tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED:
216 355 : if (mbIsMainViewChangePending)
217 : {
218 133 : mbIsMainViewChangePending = false;
219 133 : RegisterAtCenterPane();
220 : }
221 355 : break;
222 :
223 : default:
224 6629 : break;
225 : }
226 :
227 7250 : return 0;
228 : }
229 :
230 1736 : IMPL_LINK(FormShellManager, WindowEventHandler, VclWindowEvent*, pEvent)
231 : {
232 868 : if (pEvent != NULL)
233 : {
234 868 : switch (pEvent->GetId())
235 : {
236 : case VCLEVENT_WINDOW_GETFOCUS:
237 : {
238 : // The window of the center pane got the focus. Therefore
239 : // the form shell is moved to the bottom of the object bar
240 : // stack.
241 83 : ViewShell* pShell = mrBase.GetMainViewShell().get();
242 83 : if (pShell!=NULL && mbFormShellAboveViewShell)
243 : {
244 0 : mbFormShellAboveViewShell = false;
245 0 : ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
246 : mrBase.GetViewShellManager()->SetFormShell(
247 : pShell,
248 : mpFormShell,
249 0 : mbFormShellAboveViewShell);
250 : }
251 : }
252 83 : break;
253 :
254 : case VCLEVENT_WINDOW_LOSEFOCUS:
255 : // We follow the sloppy focus policy. Losing the focus is
256 : // ignored. We wait for the focus to be placed either in
257 : // the window or the form shell. The later, however, is
258 : // notified over the FormControlActivated handler, not this
259 : // one.
260 0 : break;
261 :
262 : case VCLEVENT_OBJECT_DYING:
263 0 : mpMainViewShellWindow = NULL;
264 0 : break;
265 : }
266 : }
267 :
268 868 : return 0;
269 : }
270 :
271 16 : void FormShellManager::Notify(SfxBroadcaster&, const SfxHint& rHint)
272 : {
273 16 : const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
274 16 : if (pSimpleHint!=NULL && pSimpleHint->GetId()==SFX_HINT_DYING)
275 : {
276 : // If all goes well this listener is called after the
277 : // FormShellManager was notified about the dying form shell by the
278 : // FormShellManagerFactory.
279 : OSL_ASSERT(mpFormShell==NULL);
280 0 : if (mpFormShell != NULL)
281 : {
282 0 : mpFormShell = NULL;
283 : mrBase.GetViewShellManager()->SetFormShell(
284 0 : mrBase.GetMainViewShell().get(),
285 : NULL,
286 0 : false);
287 : }
288 : }
289 16 : }
290 :
291 : //===== FormShellManagerFactory ===============================================
292 :
293 : namespace {
294 :
295 133 : FormShellManagerFactory::FormShellManagerFactory (
296 : ::sd::ViewShell& rViewShell,
297 : FormShellManager& rManager)
298 : : mrViewShell(rViewShell),
299 133 : mrFormShellManager(rManager)
300 : {
301 133 : }
302 :
303 136 : FmFormShell* FormShellManagerFactory::CreateShell (
304 : ::sd::ShellId nId,
305 : vcl::Window*,
306 : ::sd::FrameView*)
307 : {
308 136 : FmFormShell* pShell = NULL;
309 :
310 136 : ::sd::View* pView = mrViewShell.GetView();
311 136 : if (nId == RID_FORMLAYER_TOOLBOX)
312 : {
313 133 : pShell = new FmFormShell(&mrViewShell.GetViewShellBase(), pView);
314 133 : mrFormShellManager.SetFormShell(pShell);
315 : }
316 :
317 136 : return pShell;
318 : }
319 :
320 133 : void FormShellManagerFactory::ReleaseShell (SfxShell* pShell)
321 : {
322 133 : if (pShell != NULL)
323 : {
324 133 : mrFormShellManager.SetFormShell(NULL);
325 133 : delete pShell;
326 : }
327 133 : }
328 :
329 : } // end of anonymous namespace
330 :
331 66 : } // end of namespace sd
332 :
333 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|