cid#1607171 Data race condition
[LibreOffice.git] / sd / source / ui / view / FormShellManager.cxx
blobd2cb6ebfee21071d2ff4e16c80e19b550a73fa39
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <FormShellManager.hxx>
22 #include <EventMultiplexer.hxx>
23 #include <ViewShell.hxx>
24 #include <ViewShellBase.hxx>
25 #include <ViewShellManager.hxx>
26 #include <Window.hxx>
27 #include <vcl/vclevent.hxx>
28 #include <svx/fmshell.hxx>
29 #include <osl/diagnose.h>
31 namespace sd {
33 namespace {
35 /** This factory is responsible for creating and deleting the FmFormShell.
37 class FormShellManagerFactory
38 : public ::sd::ShellFactory<SfxShell>
40 public:
41 FormShellManagerFactory (ViewShell& rViewShell, FormShellManager& rManager);
42 virtual FmFormShell* CreateShell (ShellId nId) override;
43 virtual void ReleaseShell (SfxShell* pShell) override;
45 private:
46 ::sd::ViewShell& mrViewShell;
47 FormShellManager& mrFormShellManager;
50 } // end of anonymous namespace
52 FormShellManager::FormShellManager (ViewShellBase& rBase)
53 : mrBase(rBase),
54 mpFormShell(nullptr),
55 mbFormShellAboveViewShell(false),
56 mbIsMainViewChangePending(false),
57 mpMainViewShellWindow(nullptr)
59 // Register at the EventMultiplexer to be informed about changes in the
60 // center pane.
61 Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
62 mrBase.GetEventMultiplexer()->AddEventListener(aLink);
64 RegisterAtCenterPane();
67 void FormShellManager::ImplDestroy()
69 SetFormShell(nullptr);
70 UnregisterAtCenterPane();
72 // Unregister from the EventMultiplexer.
73 Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler));
74 mrBase.GetEventMultiplexer()->RemoveEventListener(aLink);
76 if (mpSubShellFactory)
78 ViewShell* pShell = mrBase.GetMainViewShell().get();
79 if (pShell != nullptr)
80 mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell,mpSubShellFactory);
84 FormShellManager::~FormShellManager()
86 suppress_fun_call_w_exception(ImplDestroy());
89 void FormShellManager::SetFormShell (FmFormShell* pFormShell)
91 if (mpFormShell == pFormShell)
92 return;
94 // Disconnect from the old form shell.
95 if (mpFormShell != nullptr)
97 mpFormShell->SetControlActivationHandler(Link<LinkParamNone*,void>());
98 EndListening(*mpFormShell);
99 mpFormShell->SetView(nullptr);
102 mpFormShell = pFormShell;
104 // Connect to the new form shell.
105 if (mpFormShell != nullptr)
107 mpFormShell->SetControlActivationHandler(
108 LINK(
109 this,
110 FormShellManager,
111 FormControlActivated));
112 StartListening(*mpFormShell);
114 ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
115 if (pMainViewShell != nullptr)
117 // Prevent setting the view twice at the FmFormShell.
118 FmFormView* pFormView = pMainViewShell->GetView();
119 if (mpFormShell->GetFormView() != pFormView)
120 mpFormShell->SetView(pFormView);
124 // Tell the ViewShellManager where on the stack to place the form shell.
125 mrBase.GetViewShellManager()->SetFormShell(
126 mrBase.GetMainViewShell().get(),
127 mpFormShell,
128 mbFormShellAboveViewShell);
131 void FormShellManager::RegisterAtCenterPane()
133 ViewShell* pShell = mrBase.GetMainViewShell().get();
134 if (pShell == nullptr)
135 return;
137 // No form shell for the slide sorter. Besides that it is not
138 // necessary, using both together results in crashes.
139 if (pShell->GetShellType() == ViewShell::ST_SLIDE_SORTER)
140 return;
142 mpMainViewShellWindow = pShell->GetActiveWindow();
143 if (mpMainViewShellWindow == nullptr)
144 return;
146 // Register at the window to get informed when to move the form
147 // shell to the bottom of the shell stack.
148 mpMainViewShellWindow->AddEventListener(
149 LINK(
150 this,
151 FormShellManager,
152 WindowEventHandler));
154 // Create a shell factory and with it activate the form shell.
155 OSL_ASSERT(!mpSubShellFactory);
156 mpSubShellFactory = std::make_shared<FormShellManagerFactory>(*pShell, *this);
157 mrBase.GetViewShellManager()->AddSubShellFactory(pShell,mpSubShellFactory);
158 mrBase.GetViewShellManager()->ActivateSubShell(*pShell, ToolbarId::FormLayer_Toolbox);
161 void FormShellManager::UnregisterAtCenterPane()
163 if (mpMainViewShellWindow != nullptr)
165 // Unregister from the window.
166 mpMainViewShellWindow->RemoveEventListener(
167 LINK(
168 this,
169 FormShellManager,
170 WindowEventHandler));
171 mpMainViewShellWindow = nullptr;
174 // Unregister form at the form shell.
175 SetFormShell(nullptr);
177 // Deactivate the form shell and destroy the shell factory.
178 ViewShell* pShell = mrBase.GetMainViewShell().get();
179 if (pShell != nullptr)
181 mrBase.GetViewShellManager()->DeactivateSubShell(*pShell, ToolbarId::FormLayer_Toolbox);
182 mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell, mpSubShellFactory);
185 mpSubShellFactory.reset();
188 IMPL_LINK_NOARG(FormShellManager, FormControlActivated, LinkParamNone*, void)
190 // The form shell has been activated. To give it priority in reacting to
191 // slot calls the form shell is moved to the top of the object bar shell
192 // stack.
193 ViewShell* pShell = mrBase.GetMainViewShell().get();
194 if (pShell!=nullptr && !mbFormShellAboveViewShell)
196 mbFormShellAboveViewShell = true;
198 ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
199 mrBase.GetViewShellManager()->SetFormShell(pShell,mpFormShell,mbFormShellAboveViewShell);
203 IMPL_LINK(FormShellManager, ConfigurationUpdateHandler, sd::tools::EventMultiplexerEvent&, rEvent, void)
205 switch (rEvent.meEventId)
207 case EventMultiplexerEventId::MainViewRemoved:
208 UnregisterAtCenterPane();
209 break;
211 case EventMultiplexerEventId::MainViewAdded:
212 mbIsMainViewChangePending = true;
213 break;
215 case EventMultiplexerEventId::ConfigurationUpdated:
216 if (mbIsMainViewChangePending)
218 mbIsMainViewChangePending = false;
219 RegisterAtCenterPane();
221 break;
223 default:
224 break;
228 IMPL_LINK(FormShellManager, WindowEventHandler, VclWindowEvent&, rEvent, void)
230 switch (rEvent.GetId())
232 case VclEventId::WindowGetFocus:
234 // The window of the center pane got the focus. Therefore
235 // the form shell is moved to the bottom of the object bar
236 // stack.
237 ViewShell* pShell = mrBase.GetMainViewShell().get();
238 if (pShell!=nullptr && mbFormShellAboveViewShell)
240 mbFormShellAboveViewShell = false;
241 ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager());
242 mrBase.GetViewShellManager()->SetFormShell(
243 pShell,
244 mpFormShell,
245 mbFormShellAboveViewShell);
248 break;
250 case VclEventId::WindowLoseFocus:
251 // We follow the sloppy focus policy. Losing the focus is
252 // ignored. We wait for the focus to be placed either in
253 // the window or the form shell. The later, however, is
254 // notified over the FormControlActivated handler, not this
255 // one.
256 break;
258 case VclEventId::ObjectDying:
259 mpMainViewShellWindow = nullptr;
260 break;
262 default: break;
266 void FormShellManager::Notify(SfxBroadcaster&, const SfxHint& rHint)
268 if (rHint.GetId()!=SfxHintId::Dying)
269 return;
271 // If all goes well this listener is called after the
272 // FormShellManager was notified about the dying form shell by the
273 // FormShellManagerFactory.
274 OSL_ASSERT(mpFormShell==nullptr);
275 if (mpFormShell != nullptr)
277 mpFormShell = nullptr;
278 mrBase.GetViewShellManager()->SetFormShell(
279 mrBase.GetMainViewShell().get(),
280 nullptr,
281 false);
285 //===== FormShellManagerFactory ===============================================
287 namespace {
289 FormShellManagerFactory::FormShellManagerFactory (
290 ::sd::ViewShell& rViewShell,
291 FormShellManager& rManager)
292 : mrViewShell(rViewShell),
293 mrFormShellManager(rManager)
297 FmFormShell* FormShellManagerFactory::CreateShell( ::sd::ShellId nId )
299 FmFormShell* pShell = nullptr;
301 ::sd::View* pView = mrViewShell.GetView();
302 if (nId == ToolbarId::FormLayer_Toolbox)
304 pShell = new FmFormShell(&mrViewShell.GetViewShellBase(), pView);
305 mrFormShellManager.SetFormShell(pShell);
308 return pShell;
311 void FormShellManagerFactory::ReleaseShell (SfxShell* pShell)
313 if (pShell != nullptr)
315 mrFormShellManager.SetFormShell(nullptr);
316 delete pShell;
320 } // end of anonymous namespace
322 } // end of namespace sd
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */