Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name SidebarController.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SFX2_DLLIMPLEMENTATION -D ENABLE_CUPS -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sfx2/inc -I /home/maarten/src/libreoffice/core/sfx2/source/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sfx2/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx

/home/maarten/src/libreoffice/core/sfx2/source/sidebar/SidebarController.cxx

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
65using namespace css;
66using namespace css::uno;
67
68namespace
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
101namespace sfx2::sidebar {
102
103namespace {
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
120SidebarController::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
157rtl::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
185SidebarController::~SidebarController()
186{
187}
188
189SidebarController* 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
207void 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
218void 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
231void 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
253void SAL_CALL SidebarController::disposing()
254{
255 mpCloseIndicator.disposeAndClear();
256
257 maFocusManager.Clear();
258 mpTabBar.disposeAndClear();
1
Calling 'VclPtr::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
308void 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
327void SAL_CALL SidebarController::disposing (const css::lang::EventObject& )
328{
329 dispose();
330}
331
332void SAL_CALL SidebarController::propertyChange (const css::beans::PropertyChangeEvent& )
333{
334 maPropertyChangeForwarder.RequestCall();
335}
336
337void 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
356void 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
367void SidebarController::BroadcastPropertyChange()
368{
369 mpParentWindow->Invalidate(InvalidateFlags::Children);
370}
371
372void 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
465void 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
490void SidebarController::SyncUpdate()
491{
492 maPropertyChangeForwarder.Sync();
493 maContextChangeUpdate.Sync();
494}
495
496void 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
573namespace {
574
575void 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
588void 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
622void SidebarController::OpenThenSwitchToDeck (
623 const OUString& rsDeckId)
624{
625 RequestOpenDeck();
626 SwitchToDeck(rsDeckId);
627
628}
629
630void SidebarController::SwitchToDefaultDeck()
631{
632 SwitchToDeck(gsDefaultDeckId);
633}
634
635void 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
649void SidebarController::CreateDeck(const OUString& rDeckId) {
650 CreateDeck(rDeckId, maCurrentContext);
651}
652
653void 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
675void 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
749void 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
876void 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
886VclPtr<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
926Reference<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
981IMPL_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
1038void 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
1055VclPtr<PopupMenu>
1056SidebarController::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
1137IMPL_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
1219void 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
1250void 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
1261bool 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
1271bool SidebarController::IsDeckVisible(const OUString& rsDeckId)
1272{
1273 return mbIsDeckOpen && *mbIsDeckOpen && msCurrentDeckId == rsDeckId;
1274}
1275
1276void 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
1373bool 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
1390sal_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
1415void 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
1432SfxSplitWindow* 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
1453void 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
1488void 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
1527void SidebarController::ShowPanel (const Panel& rPanel)
1528{
1529 if (mpCurrentDeck)
1530 {
1531 if (!IsDeckOpen())
1532 RequestOpenDeck();
1533 mpCurrentDeck->ShowPanel(rPanel);
1534 }
1535}
1536
1537ResourceManager::DeckContextDescriptorContainer SidebarController::GetMatchingDecks()
1538{
1539 ResourceManager::DeckContextDescriptorContainer aDecks;
1540 mpResourceManager->GetMatchingDecks (aDecks,
1541 GetCurrentContext(),
1542 IsDocumentReadOnly(),
1543 mxFrame->getController());
1544 return aDecks;
1545}
1546
1547ResourceManager::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
1558void SidebarController::updateModel(const css::uno::Reference<css::frame::XModel>& xModel)
1559{
1560 mpResourceManager->UpdateModel(xModel);
1561}
1562
1563void SidebarController::FadeOut()
1564{
1565 if (mpSplitWindow)
1566 mpSplitWindow->FadeOut();
1567}
1568
1569void SidebarController::FadeIn()
1570{
1571 if (mpSplitWindow)
1572 mpSplitWindow->FadeIn();
1573}
1574
1575tools::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
1592void 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
1603void 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: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
2
Calling copy constructor for 'Reference<sfx2::sidebar::TabBar>'
5
Returning from copy constructor for 'Reference<sfx2::sidebar::TabBar>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
6
Calling 'Reference::clear'
13
Returning; memory was released
205 if (aTmp.get()) {
14
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
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)
3
Assuming field 'm_pBody' is non-null
4
Taking true branch
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
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
)
7
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
8
Calling 'VclReferenceBase::release'
12
Returning; memory was released
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;
15
Use of memory after it is freed
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
277namespace 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*/
286template<typename T>
287struct 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: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
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)
9
Assuming the condition is true
10
Taking true branch
40 delete this;
11
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif