File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 113, column 13 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | #include <sfx2/sidebar/SidebarController.hxx> | ||||||
20 | #include <sfx2/sidebar/Deck.hxx> | ||||||
21 | #include <sidebar/DeckDescriptor.hxx> | ||||||
22 | #include <sidebar/DeckTitleBar.hxx> | ||||||
23 | #include <sfx2/sidebar/Panel.hxx> | ||||||
24 | #include <sidebar/PanelDescriptor.hxx> | ||||||
25 | #include <sidebar/PanelTitleBar.hxx> | ||||||
26 | #include <sfx2/sidebar/TabBar.hxx> | ||||||
27 | #include <sfx2/sidebar/Theme.hxx> | ||||||
28 | #include <sfx2/sidebar/SidebarChildWindow.hxx> | ||||||
29 | #include <sidebar/Tools.hxx> | ||||||
30 | #include <sfx2/sidebar/SidebarDockingWindow.hxx> | ||||||
31 | #include <sfx2/sidebar/Context.hxx> | ||||||
32 | |||||||
33 | |||||||
34 | #include <sfx2/lokhelper.hxx> | ||||||
35 | #include <sfx2/sfxresid.hxx> | ||||||
36 | #include <sfx2/strings.hrc> | ||||||
37 | #include <framework/ContextChangeEventMultiplexerTunnel.hxx> | ||||||
38 | #include <vcl/floatwin.hxx> | ||||||
39 | #include <vcl/fixed.hxx> | ||||||
40 | #include <vcl/uitest/logger.hxx> | ||||||
41 | #include <vcl/uitest/eventdescription.hxx> | ||||||
42 | #include <vcl/svapp.hxx> | ||||||
43 | #include <splitwin.hxx> | ||||||
44 | #include <tools/diagnose_ex.h> | ||||||
45 | #include <tools/link.hxx> | ||||||
46 | #include <toolkit/helper/vclunohelper.hxx> | ||||||
47 | #include <comphelper/processfactory.hxx> | ||||||
48 | #include <comphelper/namedvaluecollection.hxx> | ||||||
49 | #include <comphelper/lok.hxx> | ||||||
50 | #include <sal/log.hxx> | ||||||
51 | #include <officecfg/Office/UI/Sidebar.hxx> | ||||||
52 | #include <LibreOfficeKit/LibreOfficeKitEnums.h> | ||||||
53 | #include <boost/property_tree/ptree.hpp> | ||||||
54 | #include <boost/property_tree/json_parser.hpp> | ||||||
55 | |||||||
56 | #include <com/sun/star/awt/XWindowPeer.hpp> | ||||||
57 | #include <com/sun/star/frame/XDispatch.hpp> | ||||||
58 | #include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp> | ||||||
59 | #include <com/sun/star/ui/ContextChangeEventObject.hpp> | ||||||
60 | #include <com/sun/star/ui/theUIElementFactoryManager.hpp> | ||||||
61 | #include <com/sun/star/util/URL.hpp> | ||||||
62 | #include <com/sun/star/rendering/XSpriteCanvas.hpp> | ||||||
63 | |||||||
64 | |||||||
65 | using namespace css; | ||||||
66 | using namespace css::uno; | ||||||
67 | |||||||
68 | namespace | ||||||
69 | { | ||||||
70 | const char gsReadOnlyCommandName[] = ".uno:EditDoc"; | ||||||
71 | const sal_Int32 gnWidthCloseThreshold (70); | ||||||
72 | const sal_Int32 gnWidthOpenThreshold (40); | ||||||
73 | |||||||
74 | std::string UnoNameFromDeckId(const OUString& rsDeckId, bool isImpress = false) | ||||||
75 | { | ||||||
76 | if (rsDeckId == "SdCustomAnimationDeck") | ||||||
77 | return ".uno:CustomAnimation"; | ||||||
78 | |||||||
79 | if (rsDeckId == "PropertyDeck") | ||||||
80 | return isImpress ? ".uno:ModifyPage" : ".uno:Sidebar"; | ||||||
81 | |||||||
82 | if (rsDeckId == "SdLayoutsDeck") | ||||||
83 | return ".uno:ModifyPage"; | ||||||
84 | |||||||
85 | if (rsDeckId == "SdSlideTransitionDeck") | ||||||
86 | return ".uno:SlideChangeWindow"; | ||||||
87 | |||||||
88 | if (rsDeckId == "SdAllMasterPagesDeck") | ||||||
89 | return ".uno:MasterSlidesPanel"; | ||||||
90 | |||||||
91 | if (rsDeckId == "SdMasterPagesDeck") | ||||||
92 | return ".uno:MasterSlidesPanel"; | ||||||
93 | |||||||
94 | if (rsDeckId == "GalleryDeck") | ||||||
95 | return ".uno:Gallery"; | ||||||
96 | |||||||
97 | return ""; | ||||||
98 | } | ||||||
99 | } | ||||||
100 | |||||||
101 | namespace sfx2::sidebar { | ||||||
102 | |||||||
103 | namespace { | ||||||
104 | enum MenuId | ||||||
105 | { | ||||||
106 | MID_UNLOCK_TASK_PANEL = 1, | ||||||
107 | MID_LOCK_TASK_PANEL, | ||||||
108 | MID_HIDE_SIDEBAR, | ||||||
109 | MID_CUSTOMIZATION, | ||||||
110 | MID_RESTORE_DEFAULT, | ||||||
111 | MID_FIRST_PANEL, | ||||||
112 | MID_FIRST_HIDE = 1000 | ||||||
113 | }; | ||||||
114 | |||||||
115 | /** When in doubt, show this deck. | ||||||
116 | */ | ||||||
117 | const char gsDefaultDeckId[] = "PropertyDeck"; | ||||||
118 | } | ||||||
119 | |||||||
120 | SidebarController::SidebarController ( | ||||||
121 | SidebarDockingWindow* pParentWindow, | ||||||
122 | const SfxViewFrame* pViewFrame) | ||||||
123 | : SidebarControllerInterfaceBase(m_aMutex), | ||||||
124 | mpCurrentDeck(), | ||||||
125 | mpParentWindow(pParentWindow), | ||||||
126 | mpViewFrame(pViewFrame), | ||||||
127 | mxFrame(pViewFrame->GetFrame().GetFrameInterface()), | ||||||
128 | mpTabBar(VclPtr<TabBar>::Create( | ||||||
129 | mpParentWindow, | ||||||
130 | mxFrame, | ||||||
131 | [this](const OUString& rsDeckId) { return this->OpenThenToggleDeck(rsDeckId); }, | ||||||
132 | [this](const tools::Rectangle& rButtonBox,const ::std::vector<TabBar::DeckMenuData>& rMenuData) { return this->ShowPopupMenu(rButtonBox,rMenuData); }, | ||||||
133 | this)), | ||||||
134 | maCurrentContext(OUString(), OUString()), | ||||||
135 | maRequestedContext(), | ||||||
136 | mnRequestedForceFlags(SwitchFlag_NoForce), | ||||||
137 | mnMaximumSidebarWidth(officecfg::Office::UI::Sidebar::General::MaximumWidth::get()), | ||||||
138 | msCurrentDeckId(gsDefaultDeckId), | ||||||
139 | maPropertyChangeForwarder([this](){ return this->BroadcastPropertyChange(); }), | ||||||
140 | maContextChangeUpdate([this](){ return this->UpdateConfigurations(); }), | ||||||
141 | mbIsDeckRequestedOpen(), | ||||||
142 | mbIsDeckOpen(), | ||||||
143 | mbFloatingDeckClosed(!pParentWindow->IsFloatingMode()), | ||||||
144 | mnSavedSidebarWidth(pParentWindow->GetSizePixel().Width()), | ||||||
145 | maFocusManager([this](const Panel& rPanel){ return this->ShowPanel(rPanel); }, | ||||||
146 | [this](const sal_Int32 nIndex){ return this->IsDeckOpen(nIndex); }), | ||||||
147 | mxReadOnlyModeDispatch(), | ||||||
148 | mbIsDocumentReadOnly(false), | ||||||
149 | mpSplitWindow(nullptr), | ||||||
150 | mnWidthOnSplitterButtonDown(0), | ||||||
151 | mpResourceManager() | ||||||
152 | { | ||||||
153 | // Decks and panel collections for this sidebar | ||||||
154 | mpResourceManager = std::make_unique<ResourceManager>(); | ||||||
155 | } | ||||||
156 | |||||||
157 | rtl::Reference<SidebarController> SidebarController::create(SidebarDockingWindow* pParentWindow, | ||||||
158 | const SfxViewFrame* pViewFrame) | ||||||
159 | { | ||||||
160 | rtl::Reference<SidebarController> instance(new SidebarController(pParentWindow, pViewFrame)); | ||||||
161 | |||||||
162 | const css::uno::Reference<css::frame::XFrame>& rxFrame = pViewFrame->GetFrame().GetFrameInterface(); | ||||||
163 | registerSidebarForFrame(instance.get(), rxFrame->getController()); | ||||||
164 | rxFrame->addFrameActionListener(instance.get()); | ||||||
165 | // Listen for window events. | ||||||
166 | instance->mpParentWindow->AddEventListener(LINK(instance.get(), SidebarController, WindowEventHandler)::tools::detail::makeLink( ::tools::detail::castTo<SidebarController *>(instance.get()), &SidebarController::LinkStubWindowEventHandler )); | ||||||
167 | |||||||
168 | // Listen for theme property changes. | ||||||
169 | Theme::GetPropertySet()->addPropertyChangeListener( | ||||||
170 | "", | ||||||
171 | static_cast<css::beans::XPropertyChangeListener*>(instance.get())); | ||||||
172 | |||||||
173 | // Get the dispatch object as preparation to listen for changes of | ||||||
174 | // the read-only state. | ||||||
175 | const util::URL aURL (Tools::GetURL(gsReadOnlyCommandName)); | ||||||
176 | instance->mxReadOnlyModeDispatch = Tools::GetDispatch(rxFrame, aURL); | ||||||
177 | if (instance->mxReadOnlyModeDispatch.is()) | ||||||
178 | instance->mxReadOnlyModeDispatch->addStatusListener(instance.get(), aURL); | ||||||
179 | |||||||
180 | //first UpdateConfigurations call will SwitchToDeck | ||||||
181 | |||||||
182 | return instance; | ||||||
183 | } | ||||||
184 | |||||||
185 | SidebarController::~SidebarController() | ||||||
186 | { | ||||||
187 | } | ||||||
188 | |||||||
189 | SidebarController* SidebarController::GetSidebarControllerForFrame ( | ||||||
190 | const css::uno::Reference<css::frame::XFrame>& rxFrame) | ||||||
191 | { | ||||||
192 | uno::Reference<frame::XController> const xController(rxFrame->getController()); | ||||||
193 | if (!xController.is()) // this may happen during dispose of Draw controller but perhaps it's a bug | ||||||
194 | { | ||||||
195 | SAL_WARN("sfx.sidebar", "GetSidebarControllerForFrame: frame has no XController")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sfx.sidebar")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "GetSidebarControllerForFrame: frame has no XController" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx.sidebar" ), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "195" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GetSidebarControllerForFrame: frame has no XController" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetSidebarControllerForFrame: frame has no XController" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx.sidebar" ), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "195" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetSidebarControllerForFrame: frame has no XController" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx.sidebar" ), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "195" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GetSidebarControllerForFrame: frame has no XController" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetSidebarControllerForFrame: frame has no XController" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx.sidebar" ), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "195" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||||
196 | return nullptr; | ||||||
197 | } | ||||||
198 | uno::Reference<ui::XContextChangeEventListener> const xListener( | ||||||
199 | framework::GetFirstListenerWith(xController, | ||||||
200 | [] (uno::Reference<uno::XInterface> const& xRef) | ||||||
201 | { return nullptr != dynamic_cast<SidebarController*>(xRef.get()); } | ||||||
202 | )); | ||||||
203 | |||||||
204 | return dynamic_cast<SidebarController*>(xListener.get()); | ||||||
205 | } | ||||||
206 | |||||||
207 | void SidebarController::registerSidebarForFrame(SidebarController* pController, const css::uno::Reference<css::frame::XController>& xController) | ||||||
208 | { | ||||||
209 | // Listen for context change events. | ||||||
210 | css::uno::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( | ||||||
211 | css::ui::ContextChangeEventMultiplexer::get( | ||||||
212 | ::comphelper::getProcessComponentContext())); | ||||||
213 | xMultiplexer->addContextChangeEventListener( | ||||||
214 | static_cast<css::ui::XContextChangeEventListener*>(pController), | ||||||
215 | xController); | ||||||
216 | } | ||||||
217 | |||||||
218 | void SidebarController::unregisterSidebarForFrame(SidebarController* pController, const css::uno::Reference<css::frame::XController>& xController) | ||||||
219 | { | ||||||
220 | pController->saveDeckState(); | ||||||
221 | pController->disposeDecks(); | ||||||
222 | |||||||
223 | css::uno::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( | ||||||
224 | css::ui::ContextChangeEventMultiplexer::get( | ||||||
225 | ::comphelper::getProcessComponentContext())); | ||||||
226 | xMultiplexer->removeContextChangeEventListener( | ||||||
227 | static_cast<css::ui::XContextChangeEventListener*>(pController), | ||||||
228 | xController); | ||||||
229 | } | ||||||
230 | |||||||
231 | void SidebarController::disposeDecks() | ||||||
232 | { | ||||||
233 | SolarMutexGuard aSolarMutexGuard; | ||||||
234 | |||||||
235 | if (comphelper::LibreOfficeKit::isActive()) | ||||||
236 | { | ||||||
237 | if (const SfxViewShell* pViewShell = mpViewFrame->GetViewShell()) | ||||||
238 | { | ||||||
239 | const std::string hide = UnoNameFromDeckId(msCurrentDeckId, vcl::EnumContext::Application::Impress == vcl::EnumContext::GetApplicationEnum(GetCurrentContext().msApplication)); | ||||||
240 | if (!hide.empty()) | ||||||
241 | pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, | ||||||
242 | (hide + "=false").c_str()); | ||||||
243 | } | ||||||
244 | |||||||
245 | mpParentWindow->ReleaseLOKNotifier(); | ||||||
246 | } | ||||||
247 | |||||||
248 | mpCurrentDeck.clear(); | ||||||
249 | maFocusManager.Clear(); | ||||||
250 | mpResourceManager->disposeDecks(); | ||||||
251 | } | ||||||
252 | |||||||
253 | void SAL_CALL SidebarController::disposing() | ||||||
254 | { | ||||||
255 | mpCloseIndicator.disposeAndClear(); | ||||||
256 | |||||||
257 | maFocusManager.Clear(); | ||||||
258 | mpTabBar.disposeAndClear(); | ||||||
259 | |||||||
260 | saveDeckState(); | ||||||
261 | |||||||
262 | // clear decks | ||||||
263 | ResourceManager::DeckContextDescriptorContainer aDecks; | ||||||
264 | |||||||
265 | mpResourceManager->GetMatchingDecks ( | ||||||
266 | aDecks, | ||||||
267 | GetCurrentContext(), | ||||||
268 | IsDocumentReadOnly(), | ||||||
269 | mxFrame->getController()); | ||||||
270 | |||||||
271 | for (const auto& rDeck : aDecks) | ||||||
272 | { | ||||||
273 | std::shared_ptr<DeckDescriptor> deckDesc = mpResourceManager->GetDeckDescriptor(rDeck.msId); | ||||||
274 | |||||||
275 | VclPtr<Deck> aDeck = deckDesc->mpDeck; | ||||||
276 | if (aDeck) | ||||||
277 | aDeck.disposeAndClear(); | ||||||
278 | } | ||||||
279 | |||||||
280 | uno::Reference<css::frame::XController> xController = mxFrame->getController(); | ||||||
281 | if (!xController.is()) | ||||||
282 | xController = mxCurrentController; | ||||||
283 | |||||||
284 | mxFrame->removeFrameActionListener(this); | ||||||
285 | unregisterSidebarForFrame(this, xController); | ||||||
286 | |||||||
287 | if (mxReadOnlyModeDispatch.is()) | ||||||
288 | mxReadOnlyModeDispatch->removeStatusListener(this, Tools::GetURL(gsReadOnlyCommandName)); | ||||||
289 | if (mpSplitWindow != nullptr) | ||||||
290 | { | ||||||
291 | mpSplitWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler)::tools::detail::makeLink( ::tools::detail::castTo<SidebarController *>(this), &SidebarController::LinkStubWindowEventHandler )); | ||||||
292 | mpSplitWindow = nullptr; | ||||||
293 | } | ||||||
294 | |||||||
295 | if (mpParentWindow != nullptr) | ||||||
296 | { | ||||||
297 | mpParentWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler)::tools::detail::makeLink( ::tools::detail::castTo<SidebarController *>(this), &SidebarController::LinkStubWindowEventHandler )); | ||||||
298 | mpParentWindow = nullptr; | ||||||
299 | } | ||||||
300 | |||||||
301 | Theme::GetPropertySet()->removePropertyChangeListener( | ||||||
302 | "", | ||||||
303 | static_cast<css::beans::XPropertyChangeListener*>(this)); | ||||||
304 | |||||||
305 | maContextChangeUpdate.CancelRequest(); | ||||||
306 | } | ||||||
307 | |||||||
308 | void SAL_CALL SidebarController::notifyContextChangeEvent (const css::ui::ContextChangeEventObject& rEvent) | ||||||
309 | { | ||||||
310 | // Update to the requested new context asynchronously to avoid | ||||||
311 | // subtle errors caused by SFX2 which in rare cases can not | ||||||
312 | // properly handle a synchronous update. | ||||||
313 | |||||||
314 | maRequestedContext = Context( | ||||||
315 | rEvent.ApplicationName, | ||||||
316 | rEvent.ContextName); | ||||||
317 | |||||||
318 | if (maRequestedContext != maCurrentContext) | ||||||
319 | { | ||||||
320 | mxCurrentController.set(rEvent.Source, css::uno::UNO_QUERY); | ||||||
321 | maContextChangeUpdate.RequestCall(); | ||||||
322 | // TODO: this call is redundant but mandatory for unit test to update context on document loading | ||||||
323 | UpdateConfigurations(); | ||||||
324 | } | ||||||
325 | } | ||||||
326 | |||||||
327 | void SAL_CALL SidebarController::disposing (const css::lang::EventObject& ) | ||||||
328 | { | ||||||
329 | dispose(); | ||||||
330 | } | ||||||
331 | |||||||
332 | void SAL_CALL SidebarController::propertyChange (const css::beans::PropertyChangeEvent& ) | ||||||
333 | { | ||||||
334 | maPropertyChangeForwarder.RequestCall(); | ||||||
335 | } | ||||||
336 | |||||||
337 | void SAL_CALL SidebarController::statusChanged (const css::frame::FeatureStateEvent& rEvent) | ||||||
338 | { | ||||||
339 | bool bIsReadWrite (true); | ||||||
340 | if (rEvent.IsEnabled) | ||||||
341 | rEvent.State >>= bIsReadWrite; | ||||||
342 | |||||||
343 | if (mbIsDocumentReadOnly != !bIsReadWrite) | ||||||
344 | { | ||||||
345 | mbIsDocumentReadOnly = !bIsReadWrite; | ||||||
346 | |||||||
347 | // Force the current deck to update its panel list. | ||||||
348 | if ( ! mbIsDocumentReadOnly) | ||||||
349 | SwitchToDefaultDeck(); | ||||||
350 | |||||||
351 | mnRequestedForceFlags |= SwitchFlag_ForceSwitch; | ||||||
352 | maContextChangeUpdate.RequestCall(); | ||||||
353 | } | ||||||
354 | } | ||||||
355 | |||||||
356 | void SAL_CALL SidebarController::requestLayout() | ||||||
357 | { | ||||||
358 | sal_Int32 nMinimalWidth = 0; | ||||||
359 | if (mpCurrentDeck && !mpCurrentDeck->isDisposed()) | ||||||
360 | { | ||||||
361 | mpCurrentDeck->RequestLayout(); | ||||||
362 | nMinimalWidth = mpCurrentDeck->GetMinimalWidth(); | ||||||
363 | } | ||||||
364 | RestrictWidth(nMinimalWidth); | ||||||
365 | } | ||||||
366 | |||||||
367 | void SidebarController::BroadcastPropertyChange() | ||||||
368 | { | ||||||
369 | mpParentWindow->Invalidate(InvalidateFlags::Children); | ||||||
370 | } | ||||||
371 | |||||||
372 | void SidebarController::NotifyResize() | ||||||
373 | { | ||||||
374 | if (!mpTabBar) | ||||||
375 | { | ||||||
376 | OSL_ASSERT(mpTabBar!=nullptr)do { if (true && (!(mpTabBar!=nullptr))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "376" ": "), "OSL_ASSERT: %s", "mpTabBar!=nullptr"); } } while (false); | ||||||
377 | return; | ||||||
378 | } | ||||||
379 | |||||||
380 | vcl::Window* pParentWindow = mpTabBar->GetParent(); | ||||||
381 | const sal_Int32 nTabBarDefaultWidth = TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor(); | ||||||
382 | |||||||
383 | const sal_Int32 nWidth (pParentWindow->GetSizePixel().Width()); | ||||||
384 | const sal_Int32 nHeight (pParentWindow->GetSizePixel().Height()); | ||||||
385 | |||||||
386 | mbIsDeckOpen = (nWidth > nTabBarDefaultWidth); | ||||||
387 | |||||||
388 | if (mnSavedSidebarWidth <= 0) | ||||||
389 | mnSavedSidebarWidth = nWidth; | ||||||
390 | |||||||
391 | bool bIsDeckVisible; | ||||||
392 | const bool bIsOpening (nWidth > mnWidthOnSplitterButtonDown); | ||||||
393 | if (bIsOpening) | ||||||
394 | bIsDeckVisible = nWidth >= nTabBarDefaultWidth + gnWidthOpenThreshold; | ||||||
395 | else | ||||||
396 | bIsDeckVisible = nWidth >= nTabBarDefaultWidth + gnWidthCloseThreshold; | ||||||
397 | mbIsDeckRequestedOpen = bIsDeckVisible; | ||||||
398 | UpdateCloseIndicator(!bIsDeckVisible); | ||||||
399 | |||||||
400 | if (mpCurrentDeck && !mpCurrentDeck->isDisposed()) | ||||||
401 | { | ||||||
402 | SfxSplitWindow* pSplitWindow = GetSplitWindow(); | ||||||
403 | WindowAlign eAlign = pSplitWindow ? pSplitWindow->GetAlign() : WindowAlign::Right; | ||||||
404 | long nDeckX, nTabX; | ||||||
405 | if (eAlign == WindowAlign::Left) // attach the Sidebar towards the left-side of screen | ||||||
406 | { | ||||||
407 | nDeckX = nTabBarDefaultWidth; | ||||||
408 | nTabX = 0; | ||||||
409 | } | ||||||
410 | else // attach the Sidebar towards the right-side of screen | ||||||
411 | { | ||||||
412 | nDeckX = 0; | ||||||
413 | nTabX = nWidth - nTabBarDefaultWidth; | ||||||
414 | } | ||||||
415 | |||||||
416 | // Place the deck first. | ||||||
417 | if (bIsDeckVisible) | ||||||
418 | { | ||||||
419 | if (comphelper::LibreOfficeKit::isActive()) | ||||||
420 | { | ||||||
421 | // We want to let the layouter use up as much of the | ||||||
422 | // height as necessary to make sure no scrollbar is | ||||||
423 | // visible. This only works when there are no greedy | ||||||
424 | // panes that fill up all available area. So we only | ||||||
425 | // use this for the PropertyDeck, which has no such | ||||||
426 | // panes, while most other do. This is fine, since | ||||||
427 | // it's the PropertyDeck that really has many panes | ||||||
428 | // that can collapse or expand. For others, limit | ||||||
429 | // the height to something sensible. | ||||||
430 | // tdf#130348: Add special case for ChartDeck, too. | ||||||
431 | const sal_Int32 nExtHeight = (msCurrentDeckId == "PropertyDeck" ? 2000 : | ||||||
432 | (msCurrentDeckId == "ChartDeck" ? 1200 : 600)); | ||||||
433 | // No TabBar in LOK (use nWidth in full). | ||||||
434 | mpCurrentDeck->setPosSizePixel(nDeckX, 0, nWidth, nExtHeight); | ||||||
435 | } | ||||||
436 | else | ||||||
437 | mpCurrentDeck->setPosSizePixel(nDeckX, 0, nWidth - nTabBarDefaultWidth, nHeight); | ||||||
438 | mpCurrentDeck->Show(); | ||||||
439 | mpCurrentDeck->RequestLayout(); | ||||||
440 | } | ||||||
441 | else | ||||||
442 | mpCurrentDeck->Hide(); | ||||||
443 | |||||||
444 | // Now place the tab bar. | ||||||
445 | mpTabBar->setPosSizePixel(nTabX, 0, nTabBarDefaultWidth, nHeight); | ||||||
446 | if (!comphelper::LibreOfficeKit::isActive()) | ||||||
447 | mpTabBar->Show(); // Don't show TabBar in LOK. | ||||||
448 | } | ||||||
449 | |||||||
450 | // Determine if the closer of the deck can be shown. | ||||||
451 | sal_Int32 nMinimalWidth = 0; | ||||||
452 | if (mpCurrentDeck && !mpCurrentDeck->isDisposed()) | ||||||
453 | { | ||||||
454 | VclPtr<DeckTitleBar> pTitleBar = mpCurrentDeck->GetTitleBar(); | ||||||
455 | if (pTitleBar && pTitleBar->IsVisible()) | ||||||
456 | pTitleBar->SetCloserVisible(CanModifyChildWindowWidth()); | ||||||
457 | nMinimalWidth = mpCurrentDeck->GetMinimalWidth(); | ||||||
458 | } | ||||||
459 | |||||||
460 | RestrictWidth(nMinimalWidth); | ||||||
461 | |||||||
462 | mpParentWindow->NotifyResize(); | ||||||
463 | } | ||||||
464 | |||||||
465 | void SidebarController::ProcessNewWidth (const sal_Int32 nNewWidth) | ||||||
466 | { | ||||||
467 | if ( ! mbIsDeckRequestedOpen) | ||||||
468 | return; | ||||||
469 | |||||||
470 | if (*mbIsDeckRequestedOpen) | ||||||
471 | { | ||||||
472 | // Deck became large enough to be shown. Show it. | ||||||
473 | mnSavedSidebarWidth = nNewWidth; | ||||||
474 | if (!*mbIsDeckOpen) | ||||||
475 | RequestOpenDeck(); | ||||||
476 | } | ||||||
477 | else | ||||||
478 | { | ||||||
479 | // Deck became too small. Close it completely. | ||||||
480 | // If window is wider than the tab bar then mark the deck as being visible, even when it is not. | ||||||
481 | // This is to trigger an adjustment of the width to the width of the tab bar. | ||||||
482 | mbIsDeckOpen = true; | ||||||
483 | RequestCloseDeck(); | ||||||
484 | |||||||
485 | if (mnWidthOnSplitterButtonDown > TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor()) | ||||||
486 | mnSavedSidebarWidth = mnWidthOnSplitterButtonDown; | ||||||
487 | } | ||||||
488 | } | ||||||
489 | |||||||
490 | void SidebarController::SyncUpdate() | ||||||
491 | { | ||||||
492 | maPropertyChangeForwarder.Sync(); | ||||||
493 | maContextChangeUpdate.Sync(); | ||||||
494 | } | ||||||
495 | |||||||
496 | void SidebarController::UpdateConfigurations() | ||||||
497 | { | ||||||
498 | if (maCurrentContext == maRequestedContext | ||||||
499 | && mnRequestedForceFlags == SwitchFlag_NoForce) | ||||||
500 | return; | ||||||
501 | |||||||
502 | if ((maCurrentContext.msApplication != "none") && | ||||||
503 | !maCurrentContext.msApplication.isEmpty()) | ||||||
504 | { | ||||||
505 | mpResourceManager->SaveDecksSettings(maCurrentContext); | ||||||
506 | mpResourceManager->SetLastActiveDeck(maCurrentContext, msCurrentDeckId); | ||||||
507 | } | ||||||
508 | |||||||
509 | // get last active deck for this application on first update | ||||||
510 | if (!maRequestedContext.msApplication.isEmpty() && | ||||||
511 | (maCurrentContext.msApplication != maRequestedContext.msApplication)) | ||||||
512 | { | ||||||
513 | OUString sLastActiveDeck = mpResourceManager->GetLastActiveDeck( maRequestedContext ); | ||||||
514 | if (!sLastActiveDeck.isEmpty()) | ||||||
515 | msCurrentDeckId = sLastActiveDeck; | ||||||
516 | } | ||||||
517 | |||||||
518 | maCurrentContext = maRequestedContext; | ||||||
519 | |||||||
520 | mpResourceManager->InitDeckContext(GetCurrentContext()); | ||||||
521 | |||||||
522 | // Find the set of decks that could be displayed for the new context. | ||||||
523 | ResourceManager::DeckContextDescriptorContainer aDecks; | ||||||
524 | |||||||
525 | css::uno::Reference<css::frame::XController> xController = mxCurrentController.is() ? mxCurrentController : mxFrame->getController(); | ||||||
526 | |||||||
527 | mpResourceManager->GetMatchingDecks ( | ||||||
528 | aDecks, | ||||||
529 | maCurrentContext, | ||||||
530 | mbIsDocumentReadOnly, | ||||||
531 | xController); | ||||||
532 | |||||||
533 | // Notify the tab bar about the updated set of decks. | ||||||
534 | mpTabBar->SetDecks(aDecks); | ||||||
535 | |||||||
536 | // Find the new deck. By default that is the same as the old | ||||||
537 | // one. If that is not set or not enabled, then choose the | ||||||
538 | // first enabled deck (which is PropertyDeck). | ||||||
539 | OUString sNewDeckId; | ||||||
540 | for (const auto& rDeck : aDecks) | ||||||
541 | { | ||||||
542 | if (rDeck.mbIsEnabled) | ||||||
543 | { | ||||||
544 | if (rDeck.msId == msCurrentDeckId) | ||||||
545 | { | ||||||
546 | sNewDeckId = msCurrentDeckId; | ||||||
547 | break; | ||||||
548 | } | ||||||
549 | else if (sNewDeckId.getLength() == 0) | ||||||
550 | sNewDeckId = rDeck.msId; | ||||||
551 | } | ||||||
552 | } | ||||||
553 | |||||||
554 | if (sNewDeckId.getLength() == 0) | ||||||
555 | { | ||||||
556 | // We did not find a valid deck. | ||||||
557 | RequestCloseDeck(); | ||||||
558 | return; | ||||||
559 | } | ||||||
560 | |||||||
561 | // Tell the tab bar to highlight the button associated | ||||||
562 | // with the deck. | ||||||
563 | mpTabBar->HighlightDeck(sNewDeckId); | ||||||
564 | |||||||
565 | std::shared_ptr<DeckDescriptor> xDescriptor = mpResourceManager->GetDeckDescriptor(sNewDeckId); | ||||||
566 | |||||||
567 | if (xDescriptor) | ||||||
568 | { | ||||||
569 | SwitchToDeck(*xDescriptor, maCurrentContext); | ||||||
570 | } | ||||||
571 | } | ||||||
572 | |||||||
573 | namespace { | ||||||
574 | |||||||
575 | void collectUIInformation(const OUString& rDeckId) | ||||||
576 | { | ||||||
577 | EventDescription aDescription; | ||||||
578 | aDescription.aAction = "SIDEBAR"; | ||||||
579 | aDescription.aParent = "MainWindow"; | ||||||
580 | aDescription.aParameters = {{"PANEL", rDeckId}}; | ||||||
581 | aDescription.aKeyWord = "CurrentApp"; | ||||||
582 | |||||||
583 | UITestLogger::getInstance().logEvent(aDescription); | ||||||
584 | } | ||||||
585 | |||||||
586 | } | ||||||
587 | |||||||
588 | void SidebarController::OpenThenToggleDeck ( | ||||||
589 | const OUString& rsDeckId) | ||||||
590 | { | ||||||
591 | SfxSplitWindow* pSplitWindow = GetSplitWindow(); | ||||||
592 | if ( pSplitWindow && !pSplitWindow->IsFadeIn() ) | ||||||
593 | // tdf#83546 Collapsed sidebar should expand first | ||||||
594 | pSplitWindow->FadeIn(); | ||||||
595 | else if ( IsDeckVisible( rsDeckId ) ) | ||||||
596 | { | ||||||
597 | if( !WasFloatingDeckClosed() ) | ||||||
598 | { | ||||||
599 | // tdf#88241 Summoning an undocked sidebar a second time should close sidebar | ||||||
600 | mpParentWindow->Close(); | ||||||
601 | return; | ||||||
602 | } | ||||||
603 | else | ||||||
604 | { | ||||||
605 | // tdf#67627 Clicking a second time on a Deck icon will close the Deck | ||||||
606 | RequestCloseDeck(); | ||||||
607 | return; | ||||||
608 | } | ||||||
609 | } | ||||||
610 | RequestOpenDeck(); | ||||||
611 | SwitchToDeck(rsDeckId); | ||||||
612 | |||||||
613 | // Make sure the sidebar is wide enough to fit the requested content | ||||||
614 | sal_Int32 nRequestedWidth = (mpCurrentDeck->GetMinimalWidth() + TabBar::GetDefaultWidth()) | ||||||
615 | * mpTabBar->GetDPIScaleFactor(); | ||||||
616 | if (mnSavedSidebarWidth < nRequestedWidth) | ||||||
617 | SetChildWindowWidth(nRequestedWidth); | ||||||
618 | |||||||
619 | collectUIInformation(rsDeckId); | ||||||
620 | } | ||||||
621 | |||||||
622 | void SidebarController::OpenThenSwitchToDeck ( | ||||||
623 | const OUString& rsDeckId) | ||||||
624 | { | ||||||
625 | RequestOpenDeck(); | ||||||
626 | SwitchToDeck(rsDeckId); | ||||||
627 | |||||||
628 | } | ||||||
629 | |||||||
630 | void SidebarController::SwitchToDefaultDeck() | ||||||
631 | { | ||||||
632 | SwitchToDeck(gsDefaultDeckId); | ||||||
633 | } | ||||||
634 | |||||||
635 | void SidebarController::SwitchToDeck ( | ||||||
636 | const OUString& rsDeckId) | ||||||
637 | { | ||||||
638 | if ( msCurrentDeckId != rsDeckId | ||||||
639 | || ! mbIsDeckOpen | ||||||
640 | || mnRequestedForceFlags!=SwitchFlag_NoForce) | ||||||
641 | { | ||||||
642 | std::shared_ptr<DeckDescriptor> xDeckDescriptor = mpResourceManager->GetDeckDescriptor(rsDeckId); | ||||||
643 | |||||||
644 | if (xDeckDescriptor) | ||||||
645 | SwitchToDeck(*xDeckDescriptor, maCurrentContext); | ||||||
646 | } | ||||||
647 | } | ||||||
648 | |||||||
649 | void SidebarController::CreateDeck(const OUString& rDeckId) { | ||||||
650 | CreateDeck(rDeckId, maCurrentContext); | ||||||
| |||||||
651 | } | ||||||
652 | |||||||
653 | void SidebarController::CreateDeck(const OUString& rDeckId, const Context& rContext, bool bForceCreate) | ||||||
654 | { | ||||||
655 | std::shared_ptr<DeckDescriptor> xDeckDescriptor = mpResourceManager->GetDeckDescriptor(rDeckId); | ||||||
656 | |||||||
657 | if (!xDeckDescriptor) | ||||||
658 | return; | ||||||
659 | |||||||
660 | VclPtr<Deck> aDeck = xDeckDescriptor->mpDeck; | ||||||
661 | if (!aDeck || bForceCreate
| ||||||
662 | { | ||||||
663 | if (aDeck) | ||||||
664 | aDeck.disposeAndClear(); | ||||||
665 | |||||||
666 | aDeck = VclPtr<Deck>::Create( | ||||||
667 | *xDeckDescriptor, | ||||||
668 | mpParentWindow, | ||||||
669 | [this]() { return this->RequestCloseDeck(); }); | ||||||
670 | } | ||||||
671 | xDeckDescriptor->mpDeck = aDeck; | ||||||
672 | CreatePanels(rDeckId, rContext); | ||||||
673 | } | ||||||
674 | |||||||
675 | void SidebarController::CreatePanels(const OUString& rDeckId, const Context& rContext) | ||||||
676 | { | ||||||
677 | std::shared_ptr<DeckDescriptor> xDeckDescriptor = mpResourceManager->GetDeckDescriptor(rDeckId); | ||||||
678 | |||||||
679 | // init panels bounded to that deck, do not wait them being displayed as may be accessed through API | ||||||
680 | |||||||
681 | VclPtr<Deck> pDeck = xDeckDescriptor->mpDeck; | ||||||
682 | |||||||
683 | ResourceManager::PanelContextDescriptorContainer aPanelContextDescriptors; | ||||||
684 | |||||||
685 | css::uno::Reference<css::frame::XController> xController = mxCurrentController.is() ? mxCurrentController : mxFrame->getController(); | ||||||
686 | |||||||
687 | mpResourceManager->GetMatchingPanels( | ||||||
688 | aPanelContextDescriptors, | ||||||
689 | rContext, | ||||||
690 | rDeckId, | ||||||
691 | xController); | ||||||
692 | |||||||
693 | // Update the panel list. | ||||||
694 | const sal_Int32 nNewPanelCount (aPanelContextDescriptors.size()); | ||||||
695 | SharedPanelContainer aNewPanels; | ||||||
696 | sal_Int32 nWriteIndex (0); | ||||||
697 | |||||||
698 | aNewPanels.resize(nNewPanelCount); | ||||||
699 | |||||||
700 | for (sal_Int32 nReadIndex=0; nReadIndex<nNewPanelCount; ++nReadIndex) | ||||||
701 | { | ||||||
702 | const ResourceManager::PanelContextDescriptor& rPanelContexDescriptor ( | ||||||
703 | aPanelContextDescriptors[nReadIndex]); | ||||||
704 | |||||||
705 | // Determine if the panel can be displayed. | ||||||
706 | const bool bIsPanelVisible (!mbIsDocumentReadOnly || rPanelContexDescriptor.mbShowForReadOnlyDocuments); | ||||||
707 | if ( ! bIsPanelVisible) | ||||||
708 | continue; | ||||||
709 | |||||||
710 | Panel *const pPanel(pDeck->GetPanel(rPanelContexDescriptor.msId)); | ||||||
711 | if (pPanel != nullptr) | ||||||
712 | { | ||||||
713 | pPanel->SetLurkMode(false); | ||||||
714 | aNewPanels[nWriteIndex] = pPanel; | ||||||
715 | pPanel->SetExpanded( rPanelContexDescriptor.mbIsInitiallyVisible ); | ||||||
716 | ++nWriteIndex; | ||||||
717 | } | ||||||
718 | else | ||||||
719 | { | ||||||
720 | VclPtr<Panel> aPanel = CreatePanel( | ||||||
721 | rPanelContexDescriptor.msId, | ||||||
722 | pDeck->GetPanelParentWindow(), | ||||||
723 | rPanelContexDescriptor.mbIsInitiallyVisible, | ||||||
724 | rContext, | ||||||
725 | pDeck); | ||||||
726 | if (aPanel ) | ||||||
727 | { | ||||||
728 | aNewPanels[nWriteIndex] = aPanel; | ||||||
729 | |||||||
730 | // Depending on the context we have to change the command | ||||||
731 | // for the "more options" dialog. | ||||||
732 | VclPtr<PanelTitleBar> pTitleBar = aNewPanels[nWriteIndex]->GetTitleBar(); | ||||||
733 | if (pTitleBar) | ||||||
734 | { | ||||||
735 | pTitleBar->SetMoreOptionsCommand( | ||||||
736 | rPanelContexDescriptor.msMenuCommand, | ||||||
737 | mxFrame, xController); | ||||||
738 | } | ||||||
739 | ++nWriteIndex; | ||||||
740 | } | ||||||
741 | } | ||||||
742 | } | ||||||
743 | |||||||
744 | // mpCurrentPanels - may miss stuff (?) | ||||||
745 | aNewPanels.resize(nWriteIndex); | ||||||
746 | pDeck->ResetPanels(aNewPanels); | ||||||
747 | } | ||||||
748 | |||||||
749 | void SidebarController::SwitchToDeck ( | ||||||
750 | const DeckDescriptor& rDeckDescriptor, | ||||||
751 | const Context& rContext) | ||||||
752 | { | ||||||
753 | if (comphelper::LibreOfficeKit::isActive()) | ||||||
754 | { | ||||||
755 | if (const SfxViewShell* pViewShell = mpViewFrame->GetViewShell()) | ||||||
756 | { | ||||||
757 | if (msCurrentDeckId != rDeckDescriptor.msId) | ||||||
758 | { | ||||||
759 | const std::string hide = UnoNameFromDeckId(msCurrentDeckId, vcl::EnumContext::Application::Impress == vcl::EnumContext::GetApplicationEnum(GetCurrentContext().msApplication)); | ||||||
760 | if (!hide.empty()) | ||||||
761 | pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, | ||||||
762 | (hide + "=false").c_str()); | ||||||
763 | } | ||||||
764 | |||||||
765 | const std::string show = UnoNameFromDeckId(rDeckDescriptor.msId, vcl::EnumContext::Application::Impress == vcl::EnumContext::GetApplicationEnum(GetCurrentContext().msApplication)); | ||||||
766 | if (!show.empty()) | ||||||
767 | pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, | ||||||
768 | (show + "=true").c_str()); | ||||||
769 | } | ||||||
770 | } | ||||||
771 | |||||||
772 | maFocusManager.Clear(); | ||||||
773 | |||||||
774 | const bool bForceNewDeck ((mnRequestedForceFlags&SwitchFlag_ForceNewDeck)!=0); | ||||||
775 | const bool bForceNewPanels ((mnRequestedForceFlags&SwitchFlag_ForceNewPanels)!=0); | ||||||
776 | mnRequestedForceFlags = SwitchFlag_NoForce; | ||||||
777 | |||||||
778 | if ( msCurrentDeckId != rDeckDescriptor.msId | ||||||
779 | || bForceNewDeck) | ||||||
780 | { | ||||||
781 | if (mpCurrentDeck) | ||||||
782 | mpCurrentDeck->Hide(); | ||||||
783 | |||||||
784 | msCurrentDeckId = rDeckDescriptor.msId; | ||||||
785 | } | ||||||
786 | mpTabBar->Invalidate(); | ||||||
787 | mpTabBar->HighlightDeck(msCurrentDeckId); | ||||||
788 | |||||||
789 | // Determine the panels to display in the deck. | ||||||
790 | ResourceManager::PanelContextDescriptorContainer aPanelContextDescriptors; | ||||||
791 | |||||||
792 | css::uno::Reference<css::frame::XController> xController = mxCurrentController.is() ? mxCurrentController : mxFrame->getController(); | ||||||
793 | |||||||
794 | mpResourceManager->GetMatchingPanels( | ||||||
795 | aPanelContextDescriptors, | ||||||
796 | rContext, | ||||||
797 | rDeckDescriptor.msId, | ||||||
798 | xController); | ||||||
799 | |||||||
800 | if (aPanelContextDescriptors.empty()) | ||||||
801 | { | ||||||
802 | // There are no panels to be displayed in the current context. | ||||||
803 | if (vcl::EnumContext::GetContextEnum(rContext.msContext) != vcl::EnumContext::Context::Empty) | ||||||
804 | { | ||||||
805 | // Switch to the "empty" context and try again. | ||||||
806 | SwitchToDeck( | ||||||
807 | rDeckDescriptor, | ||||||
808 | Context( | ||||||
809 | rContext.msApplication, | ||||||
810 | vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Empty))); | ||||||
811 | return; | ||||||
812 | } | ||||||
813 | else | ||||||
814 | { | ||||||
815 | // This is already the "empty" context. Looks like we have | ||||||
816 | // to live with an empty deck. | ||||||
817 | } | ||||||
818 | } | ||||||
819 | |||||||
820 | // Provide a configuration and Deck object. | ||||||
821 | |||||||
822 | CreateDeck(rDeckDescriptor.msId, rContext, bForceNewDeck); | ||||||
823 | |||||||
824 | if (bForceNewPanels && !bForceNewDeck) // already forced if bForceNewDeck | ||||||
825 | CreatePanels(rDeckDescriptor.msId, rContext); | ||||||
826 | |||||||
827 | if (mpCurrentDeck && mpCurrentDeck != rDeckDescriptor.mpDeck) | ||||||
828 | mpCurrentDeck->Hide(); | ||||||
829 | mpCurrentDeck.reset(rDeckDescriptor.mpDeck); | ||||||
830 | |||||||
831 | if ( ! mpCurrentDeck) | ||||||
832 | return; | ||||||
833 | |||||||
834 | #ifdef DEBUG | ||||||
835 | // Show the context name in the deck title bar. | ||||||
836 | VclPtr<DeckTitleBar> pDebugTitleBar = mpCurrentDeck->GetTitleBar(); | ||||||
837 | if (pDebugTitleBar) | ||||||
838 | pDebugTitleBar->SetTitle(rDeckDescriptor.msTitle + " (" + maCurrentContext.msContext + ")"); | ||||||
839 | #endif | ||||||
840 | |||||||
841 | SfxSplitWindow* pSplitWindow = GetSplitWindow(); | ||||||
842 | sal_Int32 nTabBarDefaultWidth = TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor(); | ||||||
843 | WindowAlign eAlign = pSplitWindow ? pSplitWindow->GetAlign() : WindowAlign::Right; | ||||||
844 | long nDeckX; | ||||||
845 | if (eAlign == WindowAlign::Left) // attach the Sidebar towards the left-side of screen | ||||||
846 | { | ||||||
847 | nDeckX = nTabBarDefaultWidth; | ||||||
848 | } | ||||||
849 | else // attach the Sidebar towards the right-side of screen | ||||||
850 | { | ||||||
851 | nDeckX = 0; | ||||||
852 | } | ||||||
853 | |||||||
854 | // Activate the deck and the new set of panels. | ||||||
855 | mpCurrentDeck->setPosSizePixel( | ||||||
856 | nDeckX, | ||||||
857 | 0, | ||||||
858 | mpParentWindow->GetSizePixel().Width() - nTabBarDefaultWidth, | ||||||
859 | mpParentWindow->GetSizePixel().Height()); | ||||||
860 | |||||||
861 | mpCurrentDeck->Show(); | ||||||
862 | |||||||
863 | mpParentWindow->SetText(rDeckDescriptor.msTitle); | ||||||
864 | |||||||
865 | NotifyResize(); | ||||||
866 | |||||||
867 | // Tell the focus manager about the new panels and tab bar | ||||||
868 | // buttons. | ||||||
869 | maFocusManager.SetDeckTitle(mpCurrentDeck->GetTitleBar()); | ||||||
870 | maFocusManager.SetPanels(mpCurrentDeck->GetPanels()); | ||||||
871 | |||||||
872 | mpTabBar->UpdateFocusManager(maFocusManager); | ||||||
873 | UpdateTitleBarIcons(); | ||||||
874 | } | ||||||
875 | |||||||
876 | void SidebarController::notifyDeckTitle(const OUString& targetDeckId) | ||||||
877 | { | ||||||
878 | if (msCurrentDeckId == targetDeckId) | ||||||
879 | { | ||||||
880 | maFocusManager.SetDeckTitle(mpCurrentDeck->GetTitleBar()); | ||||||
881 | mpTabBar->UpdateFocusManager(maFocusManager); | ||||||
882 | UpdateTitleBarIcons(); | ||||||
883 | } | ||||||
884 | } | ||||||
885 | |||||||
886 | VclPtr<Panel> SidebarController::CreatePanel ( | ||||||
887 | const OUString& rsPanelId, | ||||||
888 | vcl::Window* pParentWindow, | ||||||
889 | const bool bIsInitiallyExpanded, | ||||||
890 | const Context& rContext, | ||||||
891 | const VclPtr<Deck>& pDeck) | ||||||
892 | { | ||||||
893 | std::shared_ptr<PanelDescriptor> xPanelDescriptor = mpResourceManager->GetPanelDescriptor(rsPanelId); | ||||||
894 | |||||||
895 | if (!xPanelDescriptor) | ||||||
896 | return nullptr; | ||||||
897 | |||||||
898 | // Create the panel which is the parent window of the UIElement. | ||||||
899 | VclPtr<Panel> pPanel = VclPtr<Panel>::Create( | ||||||
900 | *xPanelDescriptor, | ||||||
901 | pParentWindow, | ||||||
902 | bIsInitiallyExpanded, | ||||||
903 | [pDeck]() { return pDeck->RequestLayout(); }, | ||||||
904 | [this]() { return this->GetCurrentContext(); }, | ||||||
905 | mxFrame); | ||||||
906 | |||||||
907 | // Create the XUIElement. | ||||||
908 | Reference<ui::XUIElement> xUIElement (CreateUIElement( | ||||||
909 | pPanel->GetComponentInterface(), | ||||||
910 | xPanelDescriptor->msImplementationURL, | ||||||
911 | xPanelDescriptor->mbWantsCanvas, | ||||||
912 | rContext)); | ||||||
913 | if (xUIElement.is()) | ||||||
914 | { | ||||||
915 | // Initialize the panel and add it to the active deck. | ||||||
916 | pPanel->SetUIElement(xUIElement); | ||||||
917 | } | ||||||
918 | else | ||||||
919 | { | ||||||
920 | pPanel.disposeAndClear(); | ||||||
921 | } | ||||||
922 | |||||||
923 | return pPanel; | ||||||
924 | } | ||||||
925 | |||||||
926 | Reference<ui::XUIElement> SidebarController::CreateUIElement ( | ||||||
927 | const Reference<awt::XWindowPeer>& rxWindow, | ||||||
928 | const OUString& rsImplementationURL, | ||||||
929 | const bool bWantsCanvas, | ||||||
930 | const Context& rContext) | ||||||
931 | { | ||||||
932 | try | ||||||
933 | { | ||||||
934 | const Reference<XComponentContext> xComponentContext (::comphelper::getProcessComponentContext() ); | ||||||
935 | const Reference<ui::XUIElementFactory> xUIElementFactory = | ||||||
936 | ui::theUIElementFactoryManager::get( xComponentContext ); | ||||||
937 | |||||||
938 | // Create the XUIElement. | ||||||
939 | ::comphelper::NamedValueCollection aCreationArguments; | ||||||
940 | aCreationArguments.put("Frame", makeAny(mxFrame)); | ||||||
941 | aCreationArguments.put("ParentWindow", makeAny(rxWindow)); | ||||||
942 | SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(mpParentWindow.get()); | ||||||
943 | if (pSfxDockingWindow != nullptr) | ||||||
944 | aCreationArguments.put("SfxBindings", makeAny(reinterpret_cast<sal_uInt64>(&pSfxDockingWindow->GetBindings()))); | ||||||
945 | aCreationArguments.put("Theme", Theme::GetPropertySet()); | ||||||
946 | aCreationArguments.put("Sidebar", makeAny(Reference<ui::XSidebar>(static_cast<ui::XSidebar*>(this)))); | ||||||
947 | if (bWantsCanvas) | ||||||
948 | { | ||||||
949 | Reference<rendering::XSpriteCanvas> xCanvas (VCLUnoHelper::GetWindow(rxWindow)->GetSpriteCanvas()); | ||||||
950 | aCreationArguments.put("Canvas", makeAny(xCanvas)); | ||||||
951 | } | ||||||
952 | |||||||
953 | if (mxCurrentController.is()) | ||||||
954 | { | ||||||
955 | OUString aModule = Tools::GetModuleName(mxCurrentController); | ||||||
956 | if (!aModule.isEmpty()) | ||||||
957 | { | ||||||
958 | aCreationArguments.put("Module", makeAny(aModule)); | ||||||
959 | } | ||||||
960 | aCreationArguments.put("Controller", makeAny(mxCurrentController)); | ||||||
961 | } | ||||||
962 | |||||||
963 | aCreationArguments.put("ApplicationName", makeAny(rContext.msApplication)); | ||||||
964 | aCreationArguments.put("ContextName", makeAny(rContext.msContext)); | ||||||
965 | |||||||
966 | Reference<ui::XUIElement> xUIElement( | ||||||
967 | xUIElementFactory->createUIElement( | ||||||
968 | rsImplementationURL, | ||||||
969 | aCreationArguments.getPropertyValues()), | ||||||
970 | UNO_SET_THROW); | ||||||
971 | |||||||
972 | return xUIElement; | ||||||
973 | } | ||||||
974 | catch(const Exception&) | ||||||
975 | { | ||||||
976 | TOOLS_WARN_EXCEPTION("sfx.sidebar", "Cannot create panel " << rsImplementationURL)do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sfx.sidebar")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Cannot create panel " << rsImplementationURL << " " << exceptionToString (tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sfx.sidebar"), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "976" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Cannot create panel " << rsImplementationURL << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Cannot create panel " << rsImplementationURL << " " << exceptionToString(tools_warn_exception ); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx.sidebar" ), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "976" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Cannot create panel " << rsImplementationURL << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "sfx.sidebar"), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "976" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Cannot create panel " << rsImplementationURL << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Cannot create panel " << rsImplementationURL << " " << exceptionToString(tools_warn_exception ); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx.sidebar" ), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "976" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | ||||||
977 | return nullptr; | ||||||
978 | } | ||||||
979 | } | ||||||
980 | |||||||
981 | IMPL_LINK(SidebarController, WindowEventHandler, VclWindowEvent&, rEvent, void)void SidebarController::LinkStubWindowEventHandler(void * instance , VclWindowEvent& data) { return static_cast<SidebarController *>(instance)->WindowEventHandler(data); } void SidebarController ::WindowEventHandler(VclWindowEvent& rEvent) | ||||||
982 | { | ||||||
983 | if (rEvent.GetWindow() == mpParentWindow) | ||||||
984 | { | ||||||
985 | switch (rEvent.GetId()) | ||||||
986 | { | ||||||
987 | case VclEventId::WindowShow: | ||||||
988 | case VclEventId::WindowResize: | ||||||
989 | NotifyResize(); | ||||||
990 | break; | ||||||
991 | |||||||
992 | case VclEventId::WindowDataChanged: | ||||||
993 | // Force an update of deck and tab bar to reflect | ||||||
994 | // changes in theme (high contrast mode). | ||||||
995 | Theme::HandleDataChange(); | ||||||
996 | UpdateTitleBarIcons(); | ||||||
997 | mpParentWindow->Invalidate(); | ||||||
998 | mnRequestedForceFlags |= SwitchFlag_ForceNewDeck | SwitchFlag_ForceNewPanels; | ||||||
999 | maContextChangeUpdate.RequestCall(); | ||||||
1000 | break; | ||||||
1001 | |||||||
1002 | case VclEventId::ObjectDying: | ||||||
1003 | dispose(); | ||||||
1004 | break; | ||||||
1005 | |||||||
1006 | case VclEventId::WindowPaint: | ||||||
1007 | SAL_INFO("sfx.sidebar", "Paint")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "sfx.sidebar")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Paint") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sfx.sidebar"), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "1007" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Paint"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Paint"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sfx.sidebar") , ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "1007" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Paint") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("sfx.sidebar"), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "1007" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Paint"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Paint"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sfx.sidebar") , ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "1007" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||||
1008 | break; | ||||||
1009 | |||||||
1010 | default: | ||||||
1011 | break; | ||||||
1012 | } | ||||||
1013 | } | ||||||
1014 | else if (rEvent.GetWindow()==mpSplitWindow && mpSplitWindow!=nullptr) | ||||||
1015 | { | ||||||
1016 | switch (rEvent.GetId()) | ||||||
1017 | { | ||||||
1018 | case VclEventId::WindowMouseButtonDown: | ||||||
1019 | mnWidthOnSplitterButtonDown = mpParentWindow->GetSizePixel().Width(); | ||||||
1020 | break; | ||||||
1021 | |||||||
1022 | case VclEventId::WindowMouseButtonUp: | ||||||
1023 | { | ||||||
1024 | ProcessNewWidth(mpParentWindow->GetSizePixel().Width()); | ||||||
1025 | mnWidthOnSplitterButtonDown = 0; | ||||||
1026 | break; | ||||||
1027 | } | ||||||
1028 | |||||||
1029 | case VclEventId::ObjectDying: | ||||||
1030 | dispose(); | ||||||
1031 | break; | ||||||
1032 | |||||||
1033 | default: break; | ||||||
1034 | } | ||||||
1035 | } | ||||||
1036 | } | ||||||
1037 | |||||||
1038 | void SidebarController::ShowPopupMenu ( | ||||||
1039 | const tools::Rectangle& rButtonBox, | ||||||
1040 | const ::std::vector<TabBar::DeckMenuData>& rMenuData) const | ||||||
1041 | { | ||||||
1042 | VclPtr<PopupMenu> pMenu = CreatePopupMenu(rMenuData); | ||||||
1043 | pMenu->SetSelectHdl(LINK(const_cast<SidebarController*>(this), SidebarController, OnMenuItemSelected)::tools::detail::makeLink( ::tools::detail::castTo<SidebarController *>(const_cast<SidebarController*>(this)), &SidebarController ::LinkStubOnMenuItemSelected)); | ||||||
1044 | |||||||
1045 | // pass toolbox button rect so the menu can stay open on button up | ||||||
1046 | tools::Rectangle aBox (rButtonBox); | ||||||
1047 | aBox.Move(mpTabBar->GetPosPixel().X(), 0); | ||||||
1048 | const PopupMenuFlags aMenuDirection | ||||||
1049 | = (comphelper::LibreOfficeKit::isActive() ? PopupMenuFlags::ExecuteLeft | ||||||
1050 | : PopupMenuFlags::ExecuteDown); | ||||||
1051 | pMenu->Execute(mpParentWindow, aBox, aMenuDirection); | ||||||
1052 | pMenu.disposeAndClear(); | ||||||
1053 | } | ||||||
1054 | |||||||
1055 | VclPtr<PopupMenu> | ||||||
1056 | SidebarController::CreatePopupMenu(const ::std::vector<TabBar::DeckMenuData>& rMenuData) const | ||||||
1057 | { | ||||||
1058 | // Create the top level popup menu. | ||||||
1059 | auto pMenu = VclPtr<PopupMenu>::Create(); | ||||||
1060 | FloatingWindow* pMenuWindow = dynamic_cast<FloatingWindow*>(pMenu->GetWindow()); | ||||||
1061 | if (pMenuWindow != nullptr) | ||||||
1062 | { | ||||||
1063 | pMenuWindow->SetPopupModeFlags(pMenuWindow->GetPopupModeFlags() | ||||||
1064 | | FloatWinPopupFlags::NoMouseUpClose); | ||||||
1065 | } | ||||||
1066 | |||||||
1067 | // Create sub menu for customization (hiding of deck tabs), only on desktop. | ||||||
1068 | VclPtr<PopupMenu> pCustomizationMenu | ||||||
1069 | = (comphelper::LibreOfficeKit::isActive() ? nullptr : VclPtr<PopupMenu>::Create()); | ||||||
1070 | |||||||
1071 | // Add one entry for every tool panel element to individually make | ||||||
1072 | // them visible or hide them. | ||||||
1073 | sal_Int32 nIndex (0); | ||||||
1074 | for (const auto& rItem : rMenuData) | ||||||
1075 | { | ||||||
1076 | const sal_Int32 nMenuIndex (nIndex+MID_FIRST_PANEL); | ||||||
1077 | pMenu->InsertItem(nMenuIndex, rItem.msDisplayName, MenuItemBits::RADIOCHECK); | ||||||
1078 | pMenu->CheckItem(nMenuIndex, rItem.mbIsCurrentDeck); | ||||||
1079 | pMenu->EnableItem(nMenuIndex, rItem.mbIsEnabled && rItem.mbIsActive); | ||||||
1080 | |||||||
1081 | if (!comphelper::LibreOfficeKit::isActive()) | ||||||
1082 | { | ||||||
1083 | const sal_Int32 nSubMenuIndex(nIndex + MID_FIRST_HIDE); | ||||||
1084 | if (rItem.mbIsCurrentDeck) | ||||||
1085 | { | ||||||
1086 | // Don't allow the currently visible deck to be disabled. | ||||||
1087 | pCustomizationMenu->InsertItem(nSubMenuIndex, rItem.msDisplayName, | ||||||
1088 | MenuItemBits::RADIOCHECK); | ||||||
1089 | pCustomizationMenu->CheckItem(nSubMenuIndex); | ||||||
1090 | } | ||||||
1091 | else | ||||||
1092 | { | ||||||
1093 | pCustomizationMenu->InsertItem(nSubMenuIndex, rItem.msDisplayName, | ||||||
1094 | MenuItemBits::CHECKABLE); | ||||||
1095 | pCustomizationMenu->CheckItem(nSubMenuIndex, rItem.mbIsEnabled && rItem.mbIsActive); | ||||||
1096 | } | ||||||
1097 | } | ||||||
1098 | |||||||
1099 | ++nIndex; | ||||||
1100 | } | ||||||
1101 | |||||||
1102 | pMenu->InsertSeparator(); | ||||||
1103 | |||||||
1104 | // LOK doesn't support docked/undocked; Sidebar is floating but rendered docked in browser. | ||||||
1105 | if (!comphelper::LibreOfficeKit::isActive()) | ||||||
1106 | { | ||||||
1107 | // Add entry for docking or un-docking the tool panel. | ||||||
1108 | if (mpParentWindow->IsFloatingMode()) | ||||||
1109 | { | ||||||
1110 | pMenu->InsertItem(MID_LOCK_TASK_PANEL, SfxResId(STR_SFX_DOCKreinterpret_cast<char const *>("STR_SFX_DOCK" "\004" u8"Dock" ))); | ||||||
1111 | pMenu->SetAccelKey(MID_LOCK_TASK_PANEL, vcl::KeyCode(KEY_F10, true, true, false, false)); | ||||||
1112 | } | ||||||
1113 | else | ||||||
1114 | { | ||||||
1115 | pMenu->InsertItem(MID_UNLOCK_TASK_PANEL, SfxResId(STR_SFX_UNDOCKreinterpret_cast<char const *>("STR_SFX_UNDOCK" "\004" u8"Undock" ))); | ||||||
1116 | pMenu->SetAccelKey(MID_UNLOCK_TASK_PANEL, vcl::KeyCode(KEY_F10, true, true, false, false)); | ||||||
1117 | } | ||||||
1118 | } | ||||||
1119 | |||||||
1120 | pMenu->InsertItem(MID_HIDE_SIDEBAR, SfxResId(SFX_STR_SIDEBAR_HIDE_SIDEBARreinterpret_cast<char const *>("SFX_STR_SIDEBAR_HIDE_SIDEBAR" "\004" u8"Close Sidebar"))); | ||||||
1121 | |||||||
1122 | // No Restore or Customize options for LoKit. | ||||||
1123 | if (!comphelper::LibreOfficeKit::isActive()) | ||||||
1124 | { | ||||||
1125 | pCustomizationMenu->InsertSeparator(); | ||||||
1126 | pCustomizationMenu->InsertItem(MID_RESTORE_DEFAULT, SfxResId(SFX_STR_SIDEBAR_RESTOREreinterpret_cast<char const *>("SFX_STR_SIDEBAR_RESTORE" "\004" u8"Restore Default"))); | ||||||
1127 | |||||||
1128 | pMenu->InsertItem(MID_CUSTOMIZATION, SfxResId(SFX_STR_SIDEBAR_CUSTOMIZATIONreinterpret_cast<char const *>("SFX_STR_SIDEBAR_CUSTOMIZATION" "\004" u8"Customization"))); | ||||||
1129 | pMenu->SetPopupMenu(MID_CUSTOMIZATION, pCustomizationMenu); | ||||||
1130 | } | ||||||
1131 | |||||||
1132 | pMenu->RemoveDisabledEntries(false); | ||||||
1133 | |||||||
1134 | return pMenu; | ||||||
1135 | } | ||||||
1136 | |||||||
1137 | IMPL_LINK(SidebarController, OnMenuItemSelected, Menu*, pMenu, bool)bool SidebarController::LinkStubOnMenuItemSelected(void * instance , Menu* data) { return static_cast<SidebarController *> (instance)->OnMenuItemSelected(data); } bool SidebarController ::OnMenuItemSelected(Menu* pMenu) | ||||||
1138 | { | ||||||
1139 | if (pMenu == nullptr) | ||||||
1140 | { | ||||||
1141 | OSL_ENSURE(pMenu!=nullptr, "sfx2::sidebar::SidebarController::OnMenuItemSelected: illegal menu!")do { if (true && (!(pMenu!=nullptr))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx" ":" "1141" ": "), "%s", "sfx2::sidebar::SidebarController::OnMenuItemSelected: illegal menu!" ); } } while (false); | ||||||
1142 | return false; | ||||||
1143 | } | ||||||
1144 | |||||||
1145 | pMenu->Deactivate(); | ||||||
1146 | const sal_Int32 nIndex (pMenu->GetCurItemId()); | ||||||
1147 | switch (nIndex) | ||||||
1148 | { | ||||||
1149 | case MID_UNLOCK_TASK_PANEL: | ||||||
1150 | mpParentWindow->SetFloatingMode(true); | ||||||
1151 | if (mpParentWindow->IsFloatingMode()) | ||||||
1152 | mpParentWindow->ToTop(ToTopFlags::GrabFocusOnly); | ||||||
1153 | break; | ||||||
1154 | |||||||
1155 | case MID_LOCK_TASK_PANEL: | ||||||
1156 | mpParentWindow->SetFloatingMode(false); | ||||||
1157 | break; | ||||||
1158 | |||||||
1159 | case MID_RESTORE_DEFAULT: | ||||||
1160 | mpTabBar->RestoreHideFlags(); | ||||||
1161 | break; | ||||||
1162 | |||||||
1163 | case MID_HIDE_SIDEBAR: | ||||||
1164 | { | ||||||
1165 | if (!comphelper::LibreOfficeKit::isActive()) | ||||||
1166 | { | ||||||
1167 | const util::URL aURL(Tools::GetURL(".uno:Sidebar")); | ||||||
1168 | Reference<frame::XDispatch> xDispatch(Tools::GetDispatch(mxFrame, aURL)); | ||||||
1169 | if (xDispatch.is()) | ||||||
1170 | xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>()); | ||||||
1171 | } | ||||||
1172 | else | ||||||
1173 | { | ||||||
1174 | // In LOK we don't really destroy the sidebar when "closing"; | ||||||
1175 | // we simply hide it. This is because recreating it is problematic | ||||||
1176 | // See notes in SidebarDockingWindow::NotifyResize(). | ||||||
1177 | RequestCloseDeck(); | ||||||
1178 | } | ||||||
1179 | break; | ||||||
1180 | } | ||||||
1181 | default: | ||||||
1182 | { | ||||||
1183 | try | ||||||
1184 | { | ||||||
1185 | if (nIndex >= MID_FIRST_PANEL && nIndex<MID_FIRST_HIDE) | ||||||
1186 | { | ||||||
1187 | RequestOpenDeck(); | ||||||
1188 | SwitchToDeck(mpTabBar->GetDeckIdForIndex(nIndex - MID_FIRST_PANEL)); | ||||||
1189 | } | ||||||
1190 | else if (nIndex >=MID_FIRST_HIDE) | ||||||
1191 | if (pMenu->GetItemBits(nIndex) == MenuItemBits::CHECKABLE) | ||||||
1192 | { | ||||||
1193 | mpTabBar->ToggleHideFlag(nIndex-MID_FIRST_HIDE); | ||||||
1194 | |||||||
1195 | // Find the set of decks that could be displayed for the new context. | ||||||
1196 | ResourceManager::DeckContextDescriptorContainer aDecks; | ||||||
1197 | mpResourceManager->GetMatchingDecks ( | ||||||
1198 | aDecks, | ||||||
1199 | GetCurrentContext(), | ||||||
1200 | IsDocumentReadOnly(), | ||||||
1201 | mxFrame->getController()); | ||||||
1202 | // Notify the tab bar about the updated set of decks. | ||||||
1203 | mpTabBar->SetDecks(aDecks); | ||||||
1204 | mpTabBar->HighlightDeck(mpCurrentDeck->GetId()); | ||||||
1205 | mpTabBar->UpdateFocusManager(maFocusManager); | ||||||
1206 | } | ||||||
1207 | mpParentWindow->GrabFocusToDocument(); | ||||||
1208 | } | ||||||
1209 | catch (RuntimeException&) | ||||||
1210 | { | ||||||
1211 | } | ||||||
1212 | } | ||||||
1213 | break; | ||||||
1214 | } | ||||||
1215 | |||||||
1216 | return true; | ||||||
1217 | } | ||||||
1218 | |||||||
1219 | void SidebarController::RequestCloseDeck() | ||||||
1220 | { | ||||||
1221 | if (comphelper::LibreOfficeKit::isActive() && mpCurrentDeck) | ||||||
1222 | { | ||||||
1223 | const vcl::ILibreOfficeKitNotifier* pNotifier = mpCurrentDeck->GetLOKNotifier(); | ||||||
1224 | auto pMobileNotifier = SfxViewShell::Current(); | ||||||
1225 | const SfxViewShell* pViewShell = SfxViewShell::Current(); | ||||||
1226 | if (pMobileNotifier && pViewShell && pViewShell->isLOKMobilePhone()) | ||||||
1227 | { | ||||||
1228 | // Mobile phone. | ||||||
1229 | std::stringstream aStream; | ||||||
1230 | boost::property_tree::ptree aTree; | ||||||
1231 | aTree.put("id", mpParentWindow->get_id()); // TODO could be missing - sort out | ||||||
1232 | aTree.put("type", "dockingwindow"); | ||||||
1233 | aTree.put("text", mpParentWindow->GetText()); | ||||||
1234 | aTree.put("enabled", false); | ||||||
1235 | boost::property_tree::write_json(aStream, aTree); | ||||||
1236 | const std::string message = aStream.str(); | ||||||
1237 | pMobileNotifier->libreOfficeKitViewCallback(LOK_CALLBACK_JSDIALOG, message.c_str()); | ||||||
1238 | } | ||||||
1239 | else if (pNotifier) | ||||||
1240 | pNotifier->notifyWindow(mpCurrentDeck->GetLOKWindowId(), "close"); | ||||||
1241 | } | ||||||
1242 | |||||||
1243 | mbIsDeckRequestedOpen = false; | ||||||
1244 | UpdateDeckOpenState(); | ||||||
1245 | |||||||
1246 | if (!mpCurrentDeck) | ||||||
1247 | mpTabBar->RemoveDeckHighlight(); | ||||||
1248 | } | ||||||
1249 | |||||||
1250 | void SidebarController::RequestOpenDeck() | ||||||
1251 | { | ||||||
1252 | SfxSplitWindow* pSplitWindow = GetSplitWindow(); | ||||||
1253 | if ( pSplitWindow && !pSplitWindow->IsFadeIn() ) | ||||||
1254 | // tdf#83546 Collapsed sidebar should expand first | ||||||
1255 | pSplitWindow->FadeIn(); | ||||||
1256 | |||||||
1257 | mbIsDeckRequestedOpen = true; | ||||||
1258 | UpdateDeckOpenState(); | ||||||
1259 | } | ||||||
1260 | |||||||
1261 | bool SidebarController::IsDeckOpen(const sal_Int32 nIndex) | ||||||
1262 | { | ||||||
1263 | if (nIndex >= 0) | ||||||
1264 | { | ||||||
1265 | OUString asDeckId(mpTabBar->GetDeckIdForIndex(nIndex)); | ||||||
1266 | return IsDeckVisible(asDeckId); | ||||||
1267 | } | ||||||
1268 | return mbIsDeckOpen && *mbIsDeckOpen; | ||||||
1269 | } | ||||||
1270 | |||||||
1271 | bool SidebarController::IsDeckVisible(const OUString& rsDeckId) | ||||||
1272 | { | ||||||
1273 | return mbIsDeckOpen && *mbIsDeckOpen && msCurrentDeckId == rsDeckId; | ||||||
1274 | } | ||||||
1275 | |||||||
1276 | void SidebarController::UpdateDeckOpenState() | ||||||
1277 | { | ||||||
1278 | if ( ! mbIsDeckRequestedOpen) | ||||||
1279 | // No state requested. | ||||||
1280 | return; | ||||||
1281 | |||||||
1282 | const sal_Int32 nTabBarDefaultWidth = TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor(); | ||||||
1283 | |||||||
1284 | // Update (change) the open state when it either has not yet been initialized | ||||||
1285 | // or when its value differs from the requested state. | ||||||
1286 | if ( mbIsDeckOpen && *mbIsDeckOpen == *mbIsDeckRequestedOpen ) | ||||||
1287 | return; | ||||||
1288 | |||||||
1289 | if (*mbIsDeckRequestedOpen) | ||||||
1290 | { | ||||||
1291 | if (!mpParentWindow->IsFloatingMode()) | ||||||
1292 | { | ||||||
1293 | if (mnSavedSidebarWidth <= nTabBarDefaultWidth) | ||||||
1294 | SetChildWindowWidth(SidebarChildWindow::GetDefaultWidth(mpParentWindow)); | ||||||
1295 | else | ||||||
1296 | SetChildWindowWidth(mnSavedSidebarWidth); | ||||||
1297 | } | ||||||
1298 | else | ||||||
1299 | { | ||||||
1300 | // Show the Deck by resizing back to the original size (before hiding). | ||||||
1301 | Size aNewSize(mpParentWindow->GetFloatingWindow()->GetSizePixel()); | ||||||
1302 | Point aNewPos(mpParentWindow->GetFloatingWindow()->GetPosPixel()); | ||||||
1303 | |||||||
1304 | aNewPos.setX(aNewPos.X() - mnSavedSidebarWidth + nTabBarDefaultWidth); | ||||||
1305 | aNewSize.setWidth(mnSavedSidebarWidth); | ||||||
1306 | |||||||
1307 | mpParentWindow->GetFloatingWindow()->SetPosSizePixel(aNewPos, aNewSize); | ||||||
1308 | |||||||
1309 | if (comphelper::LibreOfficeKit::isActive()) | ||||||
1310 | { | ||||||
1311 | // Sidebar wide enough to render the menu; enable it. | ||||||
1312 | mpTabBar->EnableMenuButton(true); | ||||||
1313 | |||||||
1314 | if (const SfxViewShell* pViewShell = mpViewFrame->GetViewShell()) | ||||||
1315 | { | ||||||
1316 | const std::string uno = UnoNameFromDeckId(msCurrentDeckId, vcl::EnumContext::Application::Impress == vcl::EnumContext::GetApplicationEnum(GetCurrentContext().msApplication)); | ||||||
1317 | if (!uno.empty()) | ||||||
1318 | pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, | ||||||
1319 | (uno + "=true").c_str()); | ||||||
1320 | } | ||||||
1321 | } | ||||||
1322 | } | ||||||
1323 | } | ||||||
1324 | else | ||||||
1325 | { | ||||||
1326 | if ( ! mpParentWindow->IsFloatingMode()) | ||||||
1327 | mnSavedSidebarWidth = SetChildWindowWidth(nTabBarDefaultWidth); | ||||||
1328 | else | ||||||
1329 | { | ||||||
1330 | // Hide the Deck by resizing to the width of the TabBar. | ||||||
1331 | Size aNewSize(mpParentWindow->GetFloatingWindow()->GetSizePixel()); | ||||||
1332 | Point aNewPos(mpParentWindow->GetFloatingWindow()->GetPosPixel()); | ||||||
1333 | mnSavedSidebarWidth = aNewSize.Width(); // Save the current width to restore. | ||||||
1334 | |||||||
1335 | aNewPos.setX(aNewPos.X() + mnSavedSidebarWidth - nTabBarDefaultWidth); | ||||||
1336 | if (comphelper::LibreOfficeKit::isActive()) | ||||||
1337 | { | ||||||
1338 | // Hide by collapsing, otherwise with 0x0 the client might expect | ||||||
1339 | // to get valid dimensions on rendering and not collapse the sidebar. | ||||||
1340 | aNewSize.setWidth(1); | ||||||
1341 | } | ||||||
1342 | else | ||||||
1343 | aNewSize.setWidth(nTabBarDefaultWidth); | ||||||
1344 | |||||||
1345 | mpParentWindow->GetFloatingWindow()->SetPosSizePixel(aNewPos, aNewSize); | ||||||
1346 | |||||||
1347 | if (comphelper::LibreOfficeKit::isActive()) | ||||||
1348 | { | ||||||
1349 | // Sidebar too narrow to render the menu; disable it. | ||||||
1350 | mpTabBar->EnableMenuButton(false); | ||||||
1351 | |||||||
1352 | if (const SfxViewShell* pViewShell = mpViewFrame->GetViewShell()) | ||||||
1353 | { | ||||||
1354 | const std::string uno = UnoNameFromDeckId(msCurrentDeckId, vcl::EnumContext::Application::Impress == vcl::EnumContext::GetApplicationEnum(GetCurrentContext().msApplication)); | ||||||
1355 | if (!uno.empty()) | ||||||
1356 | pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, | ||||||
1357 | (uno + "=false").c_str()); | ||||||
1358 | } | ||||||
1359 | } | ||||||
1360 | } | ||||||
1361 | |||||||
1362 | if (mnWidthOnSplitterButtonDown > nTabBarDefaultWidth) | ||||||
1363 | mnSavedSidebarWidth = mnWidthOnSplitterButtonDown; | ||||||
1364 | mpParentWindow->SetStyle(mpParentWindow->GetStyle() & ~WB_SIZEABLE); | ||||||
1365 | } | ||||||
1366 | |||||||
1367 | mbIsDeckOpen = *mbIsDeckRequestedOpen; | ||||||
1368 | if (*mbIsDeckOpen && mpCurrentDeck) | ||||||
1369 | mpCurrentDeck->Show(*mbIsDeckOpen); | ||||||
1370 | NotifyResize(); | ||||||
1371 | } | ||||||
1372 | |||||||
1373 | bool SidebarController::CanModifyChildWindowWidth() | ||||||
1374 | { | ||||||
1375 | SfxSplitWindow* pSplitWindow = GetSplitWindow(); | ||||||
1376 | if (pSplitWindow == nullptr) | ||||||
1377 | return false; | ||||||
1378 | |||||||
1379 | sal_uInt16 nRow (0xffff); | ||||||
1380 | sal_uInt16 nColumn (0xffff); | ||||||
1381 | if (pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow)) | ||||||
1382 | { | ||||||
1383 | sal_uInt16 nRowCount (pSplitWindow->GetWindowCount(nColumn)); | ||||||
1384 | return nRowCount==1; | ||||||
1385 | } | ||||||
1386 | else | ||||||
1387 | return false; | ||||||
1388 | } | ||||||
1389 | |||||||
1390 | sal_Int32 SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth) | ||||||
1391 | { | ||||||
1392 | SfxSplitWindow* pSplitWindow = GetSplitWindow(); | ||||||
1393 | if (pSplitWindow == nullptr) | ||||||
1394 | return 0; | ||||||
1395 | |||||||
1396 | sal_uInt16 nRow (0xffff); | ||||||
1397 | sal_uInt16 nColumn (0xffff); | ||||||
1398 | pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow); | ||||||
1399 | const long nColumnWidth (pSplitWindow->GetLineSize(nColumn)); | ||||||
1400 | |||||||
1401 | vcl::Window* pWindow = mpParentWindow; | ||||||
1402 | const Size aWindowSize (pWindow->GetSizePixel()); | ||||||
1403 | |||||||
1404 | pSplitWindow->MoveWindow( | ||||||
1405 | mpParentWindow, | ||||||
1406 | Size(nNewWidth, aWindowSize.Height()), | ||||||
1407 | nColumn, | ||||||
1408 | nRow, | ||||||
1409 | false); | ||||||
1410 | static_cast<SplitWindow*>(pSplitWindow)->Split(); | ||||||
1411 | |||||||
1412 | return static_cast<sal_Int32>(nColumnWidth); | ||||||
1413 | } | ||||||
1414 | |||||||
1415 | void SidebarController::RestrictWidth (sal_Int32 nWidth) | ||||||
1416 | { | ||||||
1417 | SfxSplitWindow* pSplitWindow = GetSplitWindow(); | ||||||
1418 | if (pSplitWindow != nullptr) | ||||||
1419 | { | ||||||
1420 | const sal_uInt16 nId (pSplitWindow->GetItemId(mpParentWindow.get())); | ||||||
1421 | const sal_uInt16 nSetId (pSplitWindow->GetSet(nId)); | ||||||
1422 | const sal_Int32 nRequestedWidth | ||||||
1423 | = (TabBar::GetDefaultWidth() + nWidth) * mpTabBar->GetDPIScaleFactor(); | ||||||
1424 | |||||||
1425 | pSplitWindow->SetItemSizeRange( | ||||||
1426 | nSetId, | ||||||
1427 | Range(nRequestedWidth, | ||||||
1428 | getMaximumWidth() * mpTabBar->GetDPIScaleFactor())); | ||||||
1429 | } | ||||||
1430 | } | ||||||
1431 | |||||||
1432 | SfxSplitWindow* SidebarController::GetSplitWindow() | ||||||
1433 | { | ||||||
1434 | if (mpParentWindow != nullptr) | ||||||
1435 | { | ||||||
1436 | SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); | ||||||
1437 | if (pSplitWindow != mpSplitWindow) | ||||||
1438 | { | ||||||
1439 | if (mpSplitWindow != nullptr) | ||||||
1440 | mpSplitWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler)::tools::detail::makeLink( ::tools::detail::castTo<SidebarController *>(this), &SidebarController::LinkStubWindowEventHandler )); | ||||||
1441 | |||||||
1442 | mpSplitWindow = pSplitWindow; | ||||||
1443 | |||||||
1444 | if (mpSplitWindow != nullptr) | ||||||
1445 | mpSplitWindow->AddEventListener(LINK(this, SidebarController, WindowEventHandler)::tools::detail::makeLink( ::tools::detail::castTo<SidebarController *>(this), &SidebarController::LinkStubWindowEventHandler )); | ||||||
1446 | } | ||||||
1447 | return mpSplitWindow; | ||||||
1448 | } | ||||||
1449 | else | ||||||
1450 | return nullptr; | ||||||
1451 | } | ||||||
1452 | |||||||
1453 | void SidebarController::UpdateCloseIndicator (const bool bCloseAfterDrag) | ||||||
1454 | { | ||||||
1455 | if (mpParentWindow == nullptr) | ||||||
1456 | return; | ||||||
1457 | |||||||
1458 | if (bCloseAfterDrag) | ||||||
1459 | { | ||||||
1460 | // Make sure that the indicator exists. | ||||||
1461 | if ( ! mpCloseIndicator) | ||||||
1462 | { | ||||||
1463 | mpCloseIndicator.reset(VclPtr<FixedImage>::Create(mpParentWindow)); | ||||||
1464 | FixedImage* pFixedImage = static_cast<FixedImage*>(mpCloseIndicator.get()); | ||||||
1465 | const Image aImage (Theme::GetImage(Theme::Image_CloseIndicator)); | ||||||
1466 | pFixedImage->SetImage(aImage); | ||||||
1467 | pFixedImage->SetSizePixel(aImage.GetSizePixel()); | ||||||
1468 | pFixedImage->SetBackground(Theme::GetWallpaper(Theme::Paint_DeckBackground)); | ||||||
1469 | } | ||||||
1470 | |||||||
1471 | // Place and show the indicator. | ||||||
1472 | const Size aWindowSize (mpParentWindow->GetSizePixel()); | ||||||
1473 | const Size aImageSize (mpCloseIndicator->GetSizePixel()); | ||||||
1474 | mpCloseIndicator->SetPosPixel( | ||||||
1475 | Point( | ||||||
1476 | aWindowSize.Width() - TabBar::GetDefaultWidth() * mpTabBar->GetDPIScaleFactor() - aImageSize.Width(), | ||||||
1477 | (aWindowSize.Height() - aImageSize.Height())/2)); | ||||||
1478 | mpCloseIndicator->Show(); | ||||||
1479 | } | ||||||
1480 | else | ||||||
1481 | { | ||||||
1482 | // Hide but don't delete the indicator. | ||||||
1483 | if (mpCloseIndicator) | ||||||
1484 | mpCloseIndicator->Hide(); | ||||||
1485 | } | ||||||
1486 | } | ||||||
1487 | |||||||
1488 | void SidebarController::UpdateTitleBarIcons() | ||||||
1489 | { | ||||||
1490 | if ( ! mpCurrentDeck) | ||||||
1491 | return; | ||||||
1492 | |||||||
1493 | const bool bIsHighContrastModeActive (Theme::IsHighContrastMode()); | ||||||
1494 | |||||||
1495 | const ResourceManager& rResourceManager = *mpResourceManager; | ||||||
1496 | |||||||
1497 | // Update the deck icon. | ||||||
1498 | std::shared_ptr<DeckDescriptor> xDeckDescriptor = rResourceManager.GetDeckDescriptor(mpCurrentDeck->GetId()); | ||||||
1499 | if (xDeckDescriptor && mpCurrentDeck->GetTitleBar()) | ||||||
1500 | { | ||||||
1501 | const OUString sIconURL( | ||||||
1502 | bIsHighContrastModeActive | ||||||
1503 | ? xDeckDescriptor->msHighContrastTitleBarIconURL | ||||||
1504 | : xDeckDescriptor->msTitleBarIconURL); | ||||||
1505 | mpCurrentDeck->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL, mxFrame)); | ||||||
1506 | } | ||||||
1507 | |||||||
1508 | // Update the panel icons. | ||||||
1509 | const SharedPanelContainer& rPanels (mpCurrentDeck->GetPanels()); | ||||||
1510 | for (const auto& rxPanel : rPanels) | ||||||
1511 | { | ||||||
1512 | if ( ! rxPanel) | ||||||
1513 | continue; | ||||||
1514 | if (!rxPanel->GetTitleBar()) | ||||||
1515 | continue; | ||||||
1516 | std::shared_ptr<PanelDescriptor> xPanelDescriptor = rResourceManager.GetPanelDescriptor(rxPanel->GetId()); | ||||||
1517 | if (!xPanelDescriptor) | ||||||
1518 | continue; | ||||||
1519 | const OUString sIconURL ( | ||||||
1520 | bIsHighContrastModeActive | ||||||
1521 | ? xPanelDescriptor->msHighContrastTitleBarIconURL | ||||||
1522 | : xPanelDescriptor->msTitleBarIconURL); | ||||||
1523 | rxPanel->GetTitleBar()->SetIcon(Tools::GetImage(sIconURL, mxFrame)); | ||||||
1524 | } | ||||||
1525 | } | ||||||
1526 | |||||||
1527 | void SidebarController::ShowPanel (const Panel& rPanel) | ||||||
1528 | { | ||||||
1529 | if (mpCurrentDeck) | ||||||
1530 | { | ||||||
1531 | if (!IsDeckOpen()) | ||||||
1532 | RequestOpenDeck(); | ||||||
1533 | mpCurrentDeck->ShowPanel(rPanel); | ||||||
1534 | } | ||||||
1535 | } | ||||||
1536 | |||||||
1537 | ResourceManager::DeckContextDescriptorContainer SidebarController::GetMatchingDecks() | ||||||
1538 | { | ||||||
1539 | ResourceManager::DeckContextDescriptorContainer aDecks; | ||||||
1540 | mpResourceManager->GetMatchingDecks (aDecks, | ||||||
1541 | GetCurrentContext(), | ||||||
1542 | IsDocumentReadOnly(), | ||||||
1543 | mxFrame->getController()); | ||||||
1544 | return aDecks; | ||||||
1545 | } | ||||||
1546 | |||||||
1547 | ResourceManager::PanelContextDescriptorContainer SidebarController::GetMatchingPanels(const OUString& rDeckId) | ||||||
1548 | { | ||||||
1549 | ResourceManager::PanelContextDescriptorContainer aPanels; | ||||||
1550 | |||||||
1551 | mpResourceManager->GetMatchingPanels(aPanels, | ||||||
1552 | GetCurrentContext(), | ||||||
1553 | rDeckId, | ||||||
1554 | mxFrame->getController()); | ||||||
1555 | return aPanels; | ||||||
1556 | } | ||||||
1557 | |||||||
1558 | void SidebarController::updateModel(const css::uno::Reference<css::frame::XModel>& xModel) | ||||||
1559 | { | ||||||
1560 | mpResourceManager->UpdateModel(xModel); | ||||||
1561 | } | ||||||
1562 | |||||||
1563 | void SidebarController::FadeOut() | ||||||
1564 | { | ||||||
1565 | if (mpSplitWindow) | ||||||
1566 | mpSplitWindow->FadeOut(); | ||||||
1567 | } | ||||||
1568 | |||||||
1569 | void SidebarController::FadeIn() | ||||||
1570 | { | ||||||
1571 | if (mpSplitWindow) | ||||||
1572 | mpSplitWindow->FadeIn(); | ||||||
1573 | } | ||||||
1574 | |||||||
1575 | tools::Rectangle SidebarController::GetDeckDragArea() const | ||||||
1576 | { | ||||||
1577 | tools::Rectangle aRect; | ||||||
1578 | |||||||
1579 | if(mpCurrentDeck) | ||||||
1580 | { | ||||||
1581 | VclPtr<DeckTitleBar> pTitleBar(mpCurrentDeck->GetTitleBar()); | ||||||
1582 | |||||||
1583 | if(pTitleBar) | ||||||
1584 | { | ||||||
1585 | aRect = DeckTitleBar::GetDragArea(); | ||||||
1586 | } | ||||||
1587 | } | ||||||
1588 | |||||||
1589 | return aRect; | ||||||
1590 | } | ||||||
1591 | |||||||
1592 | void SidebarController::frameAction(const css::frame::FrameActionEvent& rEvent) | ||||||
1593 | { | ||||||
1594 | if (rEvent.Frame == mxFrame) | ||||||
1595 | { | ||||||
1596 | if (rEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING) | ||||||
1597 | unregisterSidebarForFrame(this, mxFrame->getController()); | ||||||
1598 | else if (rEvent.Action == css::frame::FrameAction_COMPONENT_REATTACHED) | ||||||
1599 | registerSidebarForFrame(this, mxFrame->getController()); | ||||||
1600 | } | ||||||
1601 | } | ||||||
1602 | |||||||
1603 | void SidebarController::saveDeckState() | ||||||
1604 | { | ||||||
1605 | // Impress shutdown : context (frame) is disposed before sidebar disposing | ||||||
1606 | // calc writer : context (frame) is disposed after sidebar disposing | ||||||
1607 | // so need to test if GetCurrentContext is still valid regarding msApplication | ||||||
1608 | if (GetCurrentContext().msApplication != "none") | ||||||
1609 | { | ||||||
1610 | mpResourceManager->SaveDecksSettings(GetCurrentContext()); | ||||||
1611 | mpResourceManager->SaveLastActiveDeck(GetCurrentContext(), msCurrentDeckId); | ||||||
1612 | } | ||||||
1613 | } | ||||||
1614 | |||||||
1615 | } // end of namespace sfx2::sidebar | ||||||
1616 | |||||||
1617 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_RTL_REF_HXX | ||||||
21 | #define INCLUDED_RTL_REF_HXX | ||||||
22 | |||||||
23 | #include "sal/config.h" | ||||||
24 | |||||||
25 | #include <cassert> | ||||||
26 | #include <cstddef> | ||||||
27 | #include <functional> | ||||||
28 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||
29 | #include <type_traits> | ||||||
30 | #endif | ||||||
31 | |||||||
32 | #include "sal/types.h" | ||||||
33 | |||||||
34 | namespace rtl | ||||||
35 | { | ||||||
36 | |||||||
37 | /** Template reference class for reference type. | ||||||
38 | */ | ||||||
39 | template <class reference_type> | ||||||
40 | class Reference | ||||||
41 | { | ||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||
43 | */ | ||||||
44 | reference_type * m_pBody; | ||||||
45 | |||||||
46 | |||||||
47 | public: | ||||||
48 | /** Constructor... | ||||||
49 | */ | ||||||
50 | Reference() | ||||||
51 | : m_pBody (NULL__null) | ||||||
52 | {} | ||||||
53 | |||||||
54 | |||||||
55 | /** Constructor... | ||||||
56 | */ | ||||||
57 | Reference (reference_type * pBody, __sal_NoAcquire) | ||||||
58 | : m_pBody (pBody) | ||||||
59 | { | ||||||
60 | } | ||||||
61 | |||||||
62 | /** Constructor... | ||||||
63 | */ | ||||||
64 | Reference (reference_type * pBody) | ||||||
65 | : m_pBody (pBody) | ||||||
66 | { | ||||||
67 | if (m_pBody) | ||||||
68 | m_pBody->acquire(); | ||||||
69 | } | ||||||
70 | |||||||
71 | /** Copy constructor... | ||||||
72 | */ | ||||||
73 | Reference (const Reference<reference_type> & handle) | ||||||
74 | : m_pBody (handle.m_pBody) | ||||||
75 | { | ||||||
76 | if (m_pBody) | ||||||
77 | m_pBody->acquire(); | ||||||
78 | } | ||||||
79 | |||||||
80 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||
81 | /** Move constructor... | ||||||
82 | */ | ||||||
83 | Reference (Reference<reference_type> && handle) noexcept | ||||||
84 | : m_pBody (handle.m_pBody) | ||||||
85 | { | ||||||
86 | handle.m_pBody = nullptr; | ||||||
87 | } | ||||||
88 | #endif | ||||||
89 | |||||||
90 | #if defined LIBO_INTERNAL_ONLY1 | ||||||
91 | /** Up-casting conversion constructor: Copies interface reference. | ||||||
92 | |||||||
93 | Does not work for up-casts to ambiguous bases. | ||||||
94 | |||||||
95 | @param rRef another reference | ||||||
96 | */ | ||||||
97 | template< class derived_type > | ||||||
98 | inline Reference( | ||||||
99 | const Reference< derived_type > & rRef, | ||||||
100 | std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 ) | ||||||
101 | : m_pBody (rRef.get()) | ||||||
102 | { | ||||||
103 | if (m_pBody) | ||||||
104 | m_pBody->acquire(); | ||||||
105 | } | ||||||
106 | #endif | ||||||
107 | |||||||
108 | /** Destructor... | ||||||
109 | */ | ||||||
110 | ~Reference() COVERITY_NOEXCEPT_FALSE | ||||||
111 | { | ||||||
112 | if (m_pBody
| ||||||
113 | m_pBody->release(); | ||||||
| |||||||
114 | } | ||||||
115 | |||||||
116 | /** Set... | ||||||
117 | Similar to assignment. | ||||||
118 | */ | ||||||
119 | Reference<reference_type> & | ||||||
120 | SAL_CALL set (reference_type * pBody) | ||||||
121 | { | ||||||
122 | if (pBody
| ||||||
123 | pBody->acquire(); | ||||||
124 | reference_type * const pOld = m_pBody; | ||||||
125 | m_pBody = pBody; | ||||||
126 | if (pOld
| ||||||
127 | pOld->release(); | ||||||
128 | return *this; | ||||||
129 | } | ||||||
130 | |||||||
131 | /** Assignment. | ||||||
132 | Unbinds this instance from its body (if bound) and | ||||||
133 | bind it to the body represented by the handle. | ||||||
134 | */ | ||||||
135 | Reference<reference_type> & | ||||||
136 | SAL_CALL operator= (const Reference<reference_type> & handle) | ||||||
137 | { | ||||||
138 | return set( handle.m_pBody ); | ||||||
139 | } | ||||||
140 | |||||||
141 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||
142 | /** Assignment. | ||||||
143 | * Unbinds this instance from its body (if bound), | ||||||
144 | * bind it to the body represented by the handle, and | ||||||
145 | * set the body represented by the handle to nullptr. | ||||||
146 | */ | ||||||
147 | Reference<reference_type> & | ||||||
148 | operator= (Reference<reference_type> && handle) | ||||||
149 | { | ||||||
150 | // self-movement guts ourself | ||||||
151 | if (m_pBody) | ||||||
152 | m_pBody->release(); | ||||||
153 | m_pBody = handle.m_pBody; | ||||||
154 | handle.m_pBody = nullptr; | ||||||
155 | return *this; | ||||||
156 | } | ||||||
157 | #endif | ||||||
158 | |||||||
159 | /** Assignment... | ||||||
160 | */ | ||||||
161 | Reference<reference_type> & | ||||||
162 | SAL_CALL operator= (reference_type * pBody) | ||||||
163 | { | ||||||
164 | return set( pBody ); | ||||||
165 | } | ||||||
166 | |||||||
167 | /** Unbind the body from this handle. | ||||||
168 | Note that for a handle representing a large body, | ||||||
169 | "handle.clear().set(new body());" _might_ | ||||||
170 | perform a little bit better than "handle.set(new body());", | ||||||
171 | since in the second case two large objects exist in memory | ||||||
172 | (the old body and the new body). | ||||||
173 | */ | ||||||
174 | Reference<reference_type> & SAL_CALL clear() | ||||||
175 | { | ||||||
176 | if (m_pBody) | ||||||
177 | { | ||||||
178 | reference_type * const pOld = m_pBody; | ||||||
179 | m_pBody = NULL__null; | ||||||
180 | pOld->release(); | ||||||
181 | } | ||||||
182 | return *this; | ||||||
183 | } | ||||||
184 | |||||||
185 | |||||||
186 | /** Get the body. Can be used instead of operator->(). | ||||||
187 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() | ||||||
188 | are the same. | ||||||
189 | */ | ||||||
190 | reference_type * SAL_CALL get() const | ||||||
191 | { | ||||||
192 | return m_pBody; | ||||||
193 | } | ||||||
194 | |||||||
195 | |||||||
196 | /** Probably most common used: handle->someBodyOp(). | ||||||
197 | */ | ||||||
198 | reference_type * SAL_CALL operator->() const | ||||||
199 | { | ||||||
200 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 200, __extension__ __PRETTY_FUNCTION__)); | ||||||
201 | return m_pBody; | ||||||
202 | } | ||||||
203 | |||||||
204 | |||||||
205 | /** Allows (*handle).someBodyOp(). | ||||||
206 | */ | ||||||
207 | reference_type & SAL_CALL operator*() const | ||||||
208 | { | ||||||
209 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 209, __extension__ __PRETTY_FUNCTION__)); | ||||||
210 | return *m_pBody; | ||||||
211 | } | ||||||
212 | |||||||
213 | |||||||
214 | /** Returns True if the handle does point to a valid body. | ||||||
215 | */ | ||||||
216 | bool SAL_CALL is() const | ||||||
217 | { | ||||||
218 | return (m_pBody != NULL__null); | ||||||
219 | } | ||||||
220 | |||||||
221 | #if defined LIBO_INTERNAL_ONLY1 | ||||||
222 | /** Returns True if the handle does point to a valid body. | ||||||
223 | */ | ||||||
224 | explicit operator bool() const | ||||||
225 | { | ||||||
226 | return is(); | ||||||
227 | } | ||||||
228 | #endif | ||||||
229 | |||||||
230 | /** Returns True if this points to pBody. | ||||||
231 | */ | ||||||
232 | bool SAL_CALL operator== (const reference_type * pBody) const | ||||||
233 | { | ||||||
234 | return (m_pBody == pBody); | ||||||
235 | } | ||||||
236 | |||||||
237 | |||||||
238 | /** Returns True if handle points to the same body. | ||||||
239 | */ | ||||||
240 | bool | ||||||
241 | SAL_CALL operator== (const Reference<reference_type> & handle) const | ||||||
242 | { | ||||||
243 | return (m_pBody == handle.m_pBody); | ||||||
244 | } | ||||||
245 | |||||||
246 | |||||||
247 | /** Needed to place References into STL collection. | ||||||
248 | */ | ||||||
249 | bool | ||||||
250 | SAL_CALL operator!= (const Reference<reference_type> & handle) const | ||||||
251 | { | ||||||
252 | return (m_pBody != handle.m_pBody); | ||||||
253 | } | ||||||
254 | |||||||
255 | |||||||
256 | /** Needed to place References into STL collection. | ||||||
257 | */ | ||||||
258 | bool | ||||||
259 | SAL_CALL operator< (const Reference<reference_type> & handle) const | ||||||
260 | { | ||||||
261 | return (m_pBody < handle.m_pBody); | ||||||
262 | } | ||||||
263 | |||||||
264 | |||||||
265 | /** Needed to place References into STL collection. | ||||||
266 | */ | ||||||
267 | bool | ||||||
268 | SAL_CALL operator> (const Reference<reference_type> & handle) const | ||||||
269 | { | ||||||
270 | return (m_pBody > handle.m_pBody); | ||||||
271 | } | ||||||
272 | }; | ||||||
273 | |||||||
274 | } // namespace rtl | ||||||
275 | |||||||
276 | #if defined LIBO_INTERNAL_ONLY1 | ||||||
277 | namespace std | ||||||
278 | { | ||||||
279 | |||||||
280 | /// @cond INTERNAL | ||||||
281 | /** | ||||||
282 | Make rtl::Reference hashable by default for use in STL containers. | ||||||
283 | |||||||
284 | @since LibreOffice 6.3 | ||||||
285 | */ | ||||||
286 | template<typename T> | ||||||
287 | struct hash<::rtl::Reference<T>> | ||||||
288 | { | ||||||
289 | std::size_t operator()(::rtl::Reference<T> const & s) const | ||||||
290 | { return std::size_t(s.get()); } | ||||||
291 | }; | ||||||
292 | /// @endcond | ||||||
293 | |||||||
294 | } | ||||||
295 | |||||||
296 | #endif | ||||||
297 | |||||||
298 | #endif /* ! INCLUDED_RTL_REF_HXX */ | ||||||
299 | |||||||
300 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_VCL_Reference_HXX |
20 | #define INCLUDED_VCL_Reference_HXX |
21 | |
22 | #include <vcl/dllapi.h> |
23 | #include <osl/interlck.h> |
24 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
32 | void acquire() const |
33 | { |
34 | osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1); |
35 | } |
36 | |
37 | void release() const |
38 | { |
39 | if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |