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 layout.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 /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -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 VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/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/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -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/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -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/vcl/source/window/layout.cxx

/home/maarten/src/libreoffice/core/vcl/source/window/layout.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
10#include <com/sun/star/accessibility/AccessibleRole.hpp>
11#include <comphelper/base64.hxx>
12#include <o3tl/enumarray.hxx>
13#include <o3tl/enumrange.hxx>
14#include <tools/stream.hxx>
15#include <vcl/toolkit/button.hxx>
16#include <vcl/cvtgrf.hxx>
17#include <vcl/decoview.hxx>
18#include <vcl/toolkit/dialog.hxx>
19#include <vcl/layout.hxx>
20#include <vcl/scrbar.hxx>
21#include <vcl/stdtext.hxx>
22#include <vcl/split.hxx>
23#include <vcl/svapp.hxx>
24#include <vcl/settings.hxx>
25#include <vcl/virdev.hxx>
26#include <bitmaps.hlst>
27#include <messagedialog.hxx>
28#include <svdata.hxx>
29#include <window.h>
30#include <boost/multi_array.hpp>
31#include <boost/property_tree/ptree.hpp>
32#include <vcl/toolkit/vclmedit.hxx>
33#include <sal/log.hxx>
34#include <tools/json_writer.hxx>
35
36VclContainer::VclContainer(vcl::Window *pParent, WinBits nStyle)
37 : Window(WindowType::CONTAINER)
38 , m_bLayoutDirty(true)
39{
40 ImplInit(pParent, nStyle, nullptr);
41 EnableChildTransparentMode();
42 SetPaintTransparent(true);
43 SetBackground();
44}
45
46sal_uInt16 VclContainer::getDefaultAccessibleRole() const
47{
48 return css::accessibility::AccessibleRole::PANEL;
49}
50
51Size VclContainer::GetOptimalSize() const
52{
53 return calculateRequisition();
54}
55
56void VclContainer::setLayoutPosSize(vcl::Window &rWindow, const Point &rPos, const Size &rSize)
57{
58 sal_Int32 nBorderWidth = rWindow.get_border_width();
59 sal_Int32 nLeft = rWindow.get_margin_left() + nBorderWidth;
60 sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth;
61 sal_Int32 nRight = rWindow.get_margin_right() + nBorderWidth;
62 sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth;
63 Point aPos(rPos.X() + nLeft, rPos.Y() + nTop);
64 Size aSize(rSize.Width() - nLeft - nRight, rSize.Height() - nTop - nBottom);
65 rWindow.SetPosSizePixel(aPos, aSize);
66}
67
68void VclContainer::setLayoutAllocation(vcl::Window &rChild, const Point &rAllocPos, const Size &rChildAlloc)
69{
70 VclAlign eHalign = rChild.get_halign();
71 VclAlign eValign = rChild.get_valign();
72
73 //typical case
74 if (eHalign == VclAlign::Fill && eValign == VclAlign::Fill)
75 {
76 setLayoutPosSize(rChild, rAllocPos, rChildAlloc);
77 return;
78 }
79
80 Point aChildPos(rAllocPos);
81 Size aChildSize(rChildAlloc);
82 Size aChildPreferredSize(getLayoutRequisition(rChild));
83
84 switch (eHalign)
85 {
86 case VclAlign::Fill:
87 break;
88 case VclAlign::Start:
89 if (aChildPreferredSize.Width() < rChildAlloc.Width())
90 aChildSize.setWidth( aChildPreferredSize.Width() );
91 break;
92 case VclAlign::End:
93 if (aChildPreferredSize.Width() < rChildAlloc.Width())
94 aChildSize.setWidth( aChildPreferredSize.Width() );
95 aChildPos.AdjustX(rChildAlloc.Width() );
96 aChildPos.AdjustX( -(aChildSize.Width()) );
97 break;
98 case VclAlign::Center:
99 if (aChildPreferredSize.Width() < aChildSize.Width())
100 aChildSize.setWidth( aChildPreferredSize.Width() );
101 aChildPos.AdjustX((rChildAlloc.Width() - aChildSize.Width()) / 2 );
102 break;
103 }
104
105 switch (eValign)
106 {
107 case VclAlign::Fill:
108 break;
109 case VclAlign::Start:
110 if (aChildPreferredSize.Height() < rChildAlloc.Height())
111 aChildSize.setHeight( aChildPreferredSize.Height() );
112 break;
113 case VclAlign::End:
114 if (aChildPreferredSize.Height() < rChildAlloc.Height())
115 aChildSize.setHeight( aChildPreferredSize.Height() );
116 aChildPos.AdjustY(rChildAlloc.Height() );
117 aChildPos.AdjustY( -(aChildSize.Height()) );
118 break;
119 case VclAlign::Center:
120 if (aChildPreferredSize.Height() < aChildSize.Height())
121 aChildSize.setHeight( aChildPreferredSize.Height() );
122 aChildPos.AdjustY((rChildAlloc.Height() - aChildSize.Height()) / 2 );
123 break;
124 }
125
126 setLayoutPosSize(rChild, aChildPos, aChildSize);
127}
128
129namespace
130{
131 Size subtractBorder(const vcl::Window &rWindow, const Size& rSize)
132 {
133 sal_Int32 nBorderWidth = rWindow.get_border_width();
134 sal_Int32 nLeft = rWindow.get_margin_left() + nBorderWidth;
135 sal_Int32 nTop = rWindow.get_margin_top() + nBorderWidth;
136 sal_Int32 nRight = rWindow.get_margin_right() + nBorderWidth;
137 sal_Int32 nBottom = rWindow.get_margin_bottom() + nBorderWidth;
138 Size aSize(rSize);
139 return Size(aSize.Width() + nLeft + nRight, aSize.Height() + nTop + nBottom);
140 }
141}
142
143Size VclContainer::getLayoutRequisition(const vcl::Window &rWindow)
144{
145 return subtractBorder(rWindow, rWindow.get_preferred_size());
146}
147
148void VclContainer::SetPosSizePixel(const Point& rAllocPos, const Size& rAllocation)
149{
150 bool bSizeChanged = rAllocation != GetOutputSizePixel();
151 Window::SetPosSizePixel(rAllocPos, rAllocation);
152 if (m_bLayoutDirty || bSizeChanged)
153 {
154 m_bLayoutDirty = false;
155 setAllocation(rAllocation);
156 }
157}
158
159void VclContainer::SetPosPixel(const Point& rAllocPos)
160{
161 Point aAllocPos = rAllocPos;
162 sal_Int32 nBorderWidth = get_border_width();
163 aAllocPos.AdjustX(nBorderWidth + get_margin_left() );
164 aAllocPos.AdjustY(nBorderWidth + get_margin_top() );
165
166 if (aAllocPos != GetPosPixel())
167 Window::SetPosPixel(aAllocPos);
168}
169
170void VclContainer::SetSizePixel(const Size& rAllocation)
171{
172 Size aAllocation = rAllocation;
173 sal_Int32 nBorderWidth = get_border_width();
174 aAllocation.AdjustWidth( -(nBorderWidth*2 + get_margin_left() + get_margin_right()) );
175 aAllocation.AdjustHeight( -(nBorderWidth*2 + get_margin_top() + get_margin_bottom()) );
176 bool bSizeChanged = aAllocation != GetSizePixel();
177 if (bSizeChanged)
178 Window::SetSizePixel(aAllocation);
179 if (m_bLayoutDirty || bSizeChanged)
180 {
181 m_bLayoutDirty = false;
182 setAllocation(aAllocation);
183 }
184}
185
186void VclContainer::queue_resize(StateChangedType eReason)
187{
188 m_bLayoutDirty = true;
189 Window::queue_resize(eReason);
190}
191
192// support for screenshot context menu
193void VclContainer::Command(const CommandEvent& rCEvt)
194{
195 if (CommandEventId::ContextMenu == rCEvt.GetCommand())
196 {
197 auto pParent = GetParent();
198 if (pParent)
199 {
200 CommandEvent aCEvt(rCEvt.GetMousePosPixel() + GetPosPixel(), rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData());
201 pParent->Command(aCEvt);
202 return;
203 }
204 }
205
206 // call parent (do not consume)
207 Window::Command(rCEvt);
208}
209
210void VclBox::accumulateMaxes(const Size &rChildSize, Size &rSize) const
211{
212 long nSecondaryChildDimension = getSecondaryDimension(rChildSize);
213 long nSecondaryBoxDimension = getSecondaryDimension(rSize);
214 setSecondaryDimension(rSize, std::max(nSecondaryChildDimension, nSecondaryBoxDimension));
215
216 long nPrimaryChildDimension = getPrimaryDimension(rChildSize);
217 long nPrimaryBoxDimension = getPrimaryDimension(rSize);
218 if (m_bHomogeneous)
219 setPrimaryDimension(rSize, std::max(nPrimaryBoxDimension, nPrimaryChildDimension));
220 else
221 setPrimaryDimension(rSize, nPrimaryBoxDimension + nPrimaryChildDimension);
222}
223
224Size VclBox::calculateRequisition() const
225{
226 sal_uInt16 nVisibleChildren = 0;
227
228 Size aSize;
229 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
230 {
231 if (!pChild->IsVisible())
232 continue;
233 ++nVisibleChildren;
234 Size aChildSize = getLayoutRequisition(*pChild);
235
236 long nPrimaryDimension = getPrimaryDimension(aChildSize);
237 nPrimaryDimension += pChild->get_padding() * 2;
238 setPrimaryDimension(aChildSize, nPrimaryDimension);
239
240 accumulateMaxes(aChildSize, aSize);
241 }
242
243 return finalizeMaxes(aSize, nVisibleChildren);
244}
245
246void VclBox::setAllocation(const Size &rAllocation)
247{
248 sal_uInt16 nVisibleChildren = 0, nExpandChildren = 0;
249 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
250 {
251 if (!pChild->IsVisible())
252 continue;
253 ++nVisibleChildren;
254 bool bExpand = getPrimaryDimensionChildExpand(*pChild);
255 if (bExpand)
256 ++nExpandChildren;
257 }
258
259 if (!nVisibleChildren)
260 return;
261
262 long nAllocPrimaryDimension = getPrimaryDimension(rAllocation);
263
264 long nHomogeneousDimension = 0, nExtraSpace = 0;
265 if (m_bHomogeneous)
266 {
267 nHomogeneousDimension = (nAllocPrimaryDimension -
268 (nVisibleChildren - 1) * m_nSpacing) / nVisibleChildren;
269 }
270 else if (nExpandChildren)
271 {
272 Size aRequisition = calculateRequisition();
273 nExtraSpace = (getPrimaryDimension(rAllocation) - getPrimaryDimension(aRequisition)) / nExpandChildren;
274 }
275
276 //Split into those we pack from the start onwards, and those we pack from the end backwards
277 o3tl::enumarray<VclPackType,std::vector<vcl::Window*>> aWindows;
278 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
279 {
280 if (!pChild->IsVisible())
281 continue;
282
283 VclPackType ePacking = pChild->get_pack_type();
284 aWindows[ePacking].push_back(pChild);
285 }
286
287 //See VclBuilder::sortIntoBestTabTraversalOrder for why they are in visual
288 //order under the parent which requires us to reverse them here to
289 //pack from the end back
290 std::reverse(aWindows[VclPackType::End].begin(),aWindows[VclPackType::End].end());
291
292 for (VclPackType ePackType : o3tl::enumrange<VclPackType>())
293 {
294 Point aPos(0, 0);
295 if (ePackType == VclPackType::End)
296 {
297 long nPrimaryCoordinate = getPrimaryCoordinate(aPos);
298 setPrimaryCoordinate(aPos, nPrimaryCoordinate + nAllocPrimaryDimension);
299 }
300
301 for (auto const& window : aWindows[ePackType])
302 {
303 vcl::Window *pChild = window;
304
305 long nPadding = pChild->get_padding();
306
307 Size aBoxSize;
308 if (m_bHomogeneous)
309 setPrimaryDimension(aBoxSize, nHomogeneousDimension);
310 else
311 {
312 aBoxSize = getLayoutRequisition(*pChild);
313 long nPrimaryDimension = getPrimaryDimension(aBoxSize);
314 nPrimaryDimension += nPadding * 2;
315 if (getPrimaryDimensionChildExpand(*pChild))
316 nPrimaryDimension += nExtraSpace;
317 setPrimaryDimension(aBoxSize, nPrimaryDimension);
318 }
319 setSecondaryDimension(aBoxSize, getSecondaryDimension(rAllocation));
320
321 Point aChildPos(aPos);
322 Size aChildSize(aBoxSize);
323 long nPrimaryCoordinate = getPrimaryCoordinate(aPos);
324
325 bool bFill = pChild->get_fill();
326 if (bFill)
327 {
328 setPrimaryDimension(aChildSize, std::max(static_cast<long>(1),
329 getPrimaryDimension(aBoxSize) - nPadding * 2));
330
331 setPrimaryCoordinate(aChildPos, nPrimaryCoordinate + nPadding);
332 }
333 else
334 {
335 setPrimaryDimension(aChildSize,
336 getPrimaryDimension(getLayoutRequisition(*pChild)));
337
338 setPrimaryCoordinate(aChildPos, nPrimaryCoordinate +
339 (getPrimaryDimension(aBoxSize) - getPrimaryDimension(aChildSize)) / 2);
340 }
341
342 long nDiff = getPrimaryDimension(aBoxSize) + m_nSpacing;
343 if (ePackType == VclPackType::Start)
344 setPrimaryCoordinate(aPos, nPrimaryCoordinate + nDiff);
345 else
346 {
347 setPrimaryCoordinate(aPos, nPrimaryCoordinate - nDiff);
348 setPrimaryCoordinate(aChildPos, getPrimaryCoordinate(aChildPos) -
349 getPrimaryDimension(aBoxSize));
350 }
351
352 setLayoutAllocation(*pChild, aChildPos, aChildSize);
353 }
354 }
355}
356
357bool VclBox::set_property(const OString &rKey, const OUString &rValue)
358{
359 if (rKey == "spacing")
360 set_spacing(rValue.toInt32());
361 else if (rKey == "homogeneous")
362 set_homogeneous(toBool(rValue));
363 else
364 return VclContainer::set_property(rKey, rValue);
365 return true;
366}
367
368void VclBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
369{
370 VclContainer::DumpAsPropertyTree(rJsonWriter);
371 rJsonWriter.put("vertical", m_bVerticalContainer);
372}
373
374sal_uInt16 VclBox::getDefaultAccessibleRole() const
375{
376#if defined(_WIN32)
377 //fdo#74284 call Boxes Panels, keep then as "Filler" under
378 //at least Linux seeing as that's what Gtk does for GtkBoxes
379 return css::accessibility::AccessibleRole::PANEL;
380#else
381 return css::accessibility::AccessibleRole::FILLER;
382#endif
383}
384
385#define DEFAULT_CHILD_MIN_WIDTH85 85
386#define DEFAULT_CHILD_MIN_HEIGHT27 27
387
388Size VclBox::finalizeMaxes(const Size &rSize, sal_uInt16 nVisibleChildren) const
389{
390 Size aRet;
391
392 if (nVisibleChildren)
393 {
394 long nPrimaryDimension = getPrimaryDimension(rSize);
395 if (m_bHomogeneous)
396 nPrimaryDimension *= nVisibleChildren;
397 setPrimaryDimension(aRet, nPrimaryDimension + m_nSpacing * (nVisibleChildren-1));
398 setSecondaryDimension(aRet, getSecondaryDimension(rSize));
399 }
400
401 return aRet;
402}
403
404Size VclButtonBox::addReqGroups(const VclButtonBox::Requisition &rReq) const
405{
406 Size aRet;
407
408 long nMainGroupDimension = getPrimaryDimension(rReq.m_aMainGroupSize);
409 long nSubGroupDimension = getPrimaryDimension(rReq.m_aSubGroupSize);
410
411 setPrimaryDimension(aRet, nMainGroupDimension + nSubGroupDimension);
412
413 setSecondaryDimension(aRet,
414 std::max(getSecondaryDimension(rReq.m_aMainGroupSize),
415 getSecondaryDimension(rReq.m_aSubGroupSize)));
416
417 return aRet;
418}
419
420static long getMaxNonOutlier(const std::vector<long> &rG, long nAvgDimension)
421{
422 long nMaxDimensionNonOutlier = 0;
423 for (auto const& nPrimaryChildDimension : rG)
424 {
425 if (nPrimaryChildDimension < nAvgDimension * 1.5)
426 {
427 nMaxDimensionNonOutlier = std::max(nPrimaryChildDimension,
428 nMaxDimensionNonOutlier);
429 }
430 }
431 return nMaxDimensionNonOutlier;
432}
433
434static std::vector<long> setButtonSizes(const std::vector<long> &rG,
435 const std::vector<bool> &rNonHomogeneous,
436 long nAvgDimension, long nMaxNonOutlier, long nMinWidth)
437{
438 std::vector<long> aVec;
439 //set everything < 1.5 times the average to the same width, leave the
440 //outliers un-touched
441 std::vector<bool>::const_iterator aJ = rNonHomogeneous.begin();
442 auto nNonOutlierWidth = std::max(nMaxNonOutlier, nMinWidth);
443 for (auto const& nPrimaryChildDimension : rG)
444 {
445 bool bNonHomogeneous = *aJ;
446 if (!bNonHomogeneous && nPrimaryChildDimension < nAvgDimension * 1.5)
447 {
448 aVec.push_back(nNonOutlierWidth);
449 }
450 else
451 {
452 aVec.push_back(std::max(nPrimaryChildDimension, nMinWidth));
453 }
454 ++aJ;
455 }
456 return aVec;
457}
458
459VclButtonBox::Requisition VclButtonBox::calculatePrimarySecondaryRequisitions() const
460{
461 Requisition aReq;
462
463 Size aMainGroupSize(DEFAULT_CHILD_MIN_WIDTH85, DEFAULT_CHILD_MIN_HEIGHT27); //to-do, pull from theme
464 Size aSubGroupSize(DEFAULT_CHILD_MIN_WIDTH85, DEFAULT_CHILD_MIN_HEIGHT27); //to-do, pull from theme
465
466 long nMinMainGroupPrimary = getPrimaryDimension(aMainGroupSize);
467 long nMinSubGroupPrimary = getPrimaryDimension(aSubGroupSize);
468 long nMainGroupSecondary = getSecondaryDimension(aMainGroupSize);
469 long nSubGroupSecondary = getSecondaryDimension(aSubGroupSize);
470
471 bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VclButtonBoxStyle::Spread || m_eLayoutStyle == VclButtonBoxStyle::Center);
472
473 std::vector<long> aMainGroupSizes;
474 std::vector<bool> aMainGroupNonHomogeneous;
475 std::vector<long> aSubGroupSizes;
476 std::vector<bool> aSubGroupNonHomogeneous;
477
478 for (const vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
479 {
480 if (!pChild->IsVisible())
481 continue;
482 Size aChildSize = getLayoutRequisition(*pChild);
483 if (bIgnoreSecondaryPacking || !pChild->get_secondary())
484 {
485 //set the max secondary dimension
486 nMainGroupSecondary = std::max(nMainGroupSecondary, getSecondaryDimension(aChildSize));
487 //collect the primary dimensions
488 aMainGroupSizes.push_back(getPrimaryDimension(aChildSize));
489 aMainGroupNonHomogeneous.push_back(pChild->get_non_homogeneous());
490 }
491 else
492 {
493 nSubGroupSecondary = std::max(nSubGroupSecondary, getSecondaryDimension(aChildSize));
494 aSubGroupSizes.push_back(getPrimaryDimension(aChildSize));
495 aSubGroupNonHomogeneous.push_back(pChild->get_non_homogeneous());
496 }
497 }
498
499 if (m_bHomogeneous)
500 {
501 long nMaxMainDimension = aMainGroupSizes.empty() ? 0 :
502 *std::max_element(aMainGroupSizes.begin(), aMainGroupSizes.end());
503 nMaxMainDimension = std::max(nMaxMainDimension, nMinMainGroupPrimary);
504 long nMaxSubDimension = aSubGroupSizes.empty() ? 0 :
505 *std::max_element(aSubGroupSizes.begin(), aSubGroupSizes.end());
506 nMaxSubDimension = std::max(nMaxSubDimension, nMinSubGroupPrimary);
507 long nMaxDimension = std::max(nMaxMainDimension, nMaxSubDimension);
508 aReq.m_aMainGroupDimensions.resize(aMainGroupSizes.size(), nMaxDimension);
509 aReq.m_aSubGroupDimensions.resize(aSubGroupSizes.size(), nMaxDimension);
510 }
511 else
512 {
513 //Ideally set everything to the same size, but find outlier widgets
514 //that are way wider than the average and leave them
515 //at their natural size and set the remainder to share the
516 //max size of the remaining members of the buttonbox
517 long nAccDimension = std::accumulate(aMainGroupSizes.begin(),
518 aMainGroupSizes.end(), 0);
519 nAccDimension = std::accumulate(aSubGroupSizes.begin(),
520 aSubGroupSizes.end(), nAccDimension);
521
522 size_t nTotalSize = aMainGroupSizes.size() + aSubGroupSizes.size();
523
524 long nAvgDimension = nTotalSize ? nAccDimension / nTotalSize : 0;
525
526 long nMaxMainNonOutlier = getMaxNonOutlier(aMainGroupSizes,
527 nAvgDimension);
528 long nMaxSubNonOutlier = getMaxNonOutlier(aSubGroupSizes,
529 nAvgDimension);
530 long nMaxNonOutlier = std::max(nMaxMainNonOutlier, nMaxSubNonOutlier);
531
532 aReq.m_aMainGroupDimensions = setButtonSizes(aMainGroupSizes,
533 aMainGroupNonHomogeneous,
534 nAvgDimension, nMaxNonOutlier, nMinMainGroupPrimary);
535 aReq.m_aSubGroupDimensions = setButtonSizes(aSubGroupSizes,
536 aSubGroupNonHomogeneous,
537 nAvgDimension, nMaxNonOutlier, nMinSubGroupPrimary);
538 }
539
540 if (!aReq.m_aMainGroupDimensions.empty())
541 {
542 setSecondaryDimension(aReq.m_aMainGroupSize, nMainGroupSecondary);
543 setPrimaryDimension(aReq.m_aMainGroupSize,
544 std::accumulate(aReq.m_aMainGroupDimensions.begin(),
545 aReq.m_aMainGroupDimensions.end(), 0));
546 }
547 if (!aReq.m_aSubGroupDimensions.empty())
548 {
549 setSecondaryDimension(aReq.m_aSubGroupSize, nSubGroupSecondary);
550 setPrimaryDimension(aReq.m_aSubGroupSize,
551 std::accumulate(aReq.m_aSubGroupDimensions.begin(),
552 aReq.m_aSubGroupDimensions.end(), 0));
553 }
554
555 return aReq;
556}
557
558Size VclButtonBox::addSpacing(const Size &rSize, sal_uInt16 nVisibleChildren) const
559{
560 Size aRet;
561
562 if (nVisibleChildren)
563 {
564 long nPrimaryDimension = getPrimaryDimension(rSize);
565 setPrimaryDimension(aRet,
566 nPrimaryDimension + m_nSpacing * (nVisibleChildren-1));
567 setSecondaryDimension(aRet, getSecondaryDimension(rSize));
568 }
569
570 return aRet;
571}
572
573Size VclButtonBox::calculateRequisition() const
574{
575 Requisition aReq(calculatePrimarySecondaryRequisitions());
576 sal_uInt16 nVisibleChildren = aReq.m_aMainGroupDimensions.size() +
577 aReq.m_aSubGroupDimensions.size();
578 return addSpacing(addReqGroups(aReq), nVisibleChildren);
579}
580
581bool VclButtonBox::set_property(const OString &rKey, const OUString &rValue)
582{
583 if (rKey == "layout-style")
584 {
585 VclButtonBoxStyle eStyle = VclButtonBoxStyle::Default;
586 if (rValue == "spread")
587 eStyle = VclButtonBoxStyle::Spread;
588 else if (rValue == "edge")
589 eStyle = VclButtonBoxStyle::Edge;
590 else if (rValue == "start")
591 eStyle = VclButtonBoxStyle::Start;
592 else if (rValue == "end")
593 eStyle = VclButtonBoxStyle::End;
594 else if (rValue == "center")
595 eStyle = VclButtonBoxStyle::Center;
596 else
597 {
598 SAL_WARN("vcl.layout", "unknown layout style " << rValue)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "unknown layout style "
<< rValue) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "598" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "unknown layout style " << rValue
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "unknown layout style " << rValue; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "598" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "unknown layout style " << rValue) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout")
, ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "598" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "unknown layout style " << rValue
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "unknown layout style " << rValue; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "598" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
599 }
600 m_eLayoutStyle = eStyle;
601 }
602 else
603 return VclBox::set_property(rKey, rValue);
604 return true;
605}
606
607void VclButtonBox::setAllocation(const Size &rAllocation)
608{
609 Requisition aReq(calculatePrimarySecondaryRequisitions());
610
611 if (aReq.m_aMainGroupDimensions.empty() && aReq.m_aSubGroupDimensions.empty())
612 return;
613
614 long nAllocPrimaryDimension = getPrimaryDimension(rAllocation);
615
616 Point aMainGroupPos, aOtherGroupPos;
617 int nSpacing = m_nSpacing;
618
619 //To-Do, other layout styles
620 switch (m_eLayoutStyle)
621 {
622 case VclButtonBoxStyle::Start:
623 if (!aReq.m_aSubGroupDimensions.empty())
624 {
625 long nOtherPrimaryDimension = getPrimaryDimension(
626 addSpacing(aReq.m_aSubGroupSize, aReq.m_aSubGroupDimensions.size()));
627 setPrimaryCoordinate(aOtherGroupPos,
628 nAllocPrimaryDimension - nOtherPrimaryDimension);
629 }
630 break;
631 case VclButtonBoxStyle::Spread:
632 if (!aReq.m_aMainGroupDimensions.empty())
633 {
634 long nMainPrimaryDimension = getPrimaryDimension(
635 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
636 long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension;
637 nExtraSpace += (aReq.m_aMainGroupDimensions.size()-1) * nSpacing;
638 nSpacing = nExtraSpace/(aReq.m_aMainGroupDimensions.size()+1);
639 setPrimaryCoordinate(aMainGroupPos, nSpacing);
640 }
641 break;
642 case VclButtonBoxStyle::Center:
643 if (!aReq.m_aMainGroupDimensions.empty())
644 {
645 long nMainPrimaryDimension = getPrimaryDimension(
646 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
647 long nExtraSpace = nAllocPrimaryDimension - nMainPrimaryDimension;
648 setPrimaryCoordinate(aMainGroupPos, nExtraSpace/2);
649 }
650 break;
651 default:
652 SAL_WARN("vcl.layout", "todo unimplemented layout style")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "todo unimplemented layout style"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "652" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "todo unimplemented layout style"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "todo unimplemented layout style"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "652" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "todo unimplemented layout style") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "652" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "todo unimplemented layout style"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "todo unimplemented layout style"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "652" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
653 [[fallthrough]];
654 case VclButtonBoxStyle::Default:
655 case VclButtonBoxStyle::End:
656 if (!aReq.m_aMainGroupDimensions.empty())
657 {
658 long nMainPrimaryDimension = getPrimaryDimension(
659 addSpacing(aReq.m_aMainGroupSize, aReq.m_aMainGroupDimensions.size()));
660 setPrimaryCoordinate(aMainGroupPos,
661 nAllocPrimaryDimension - nMainPrimaryDimension);
662 }
663 break;
664 }
665
666 Size aChildSize;
667 setSecondaryDimension(aChildSize, getSecondaryDimension(rAllocation));
668
669 std::vector<long>::const_iterator aPrimaryI = aReq.m_aMainGroupDimensions.begin();
670 std::vector<long>::const_iterator aSecondaryI = aReq.m_aSubGroupDimensions.begin();
671 bool bIgnoreSecondaryPacking = (m_eLayoutStyle == VclButtonBoxStyle::Spread || m_eLayoutStyle == VclButtonBoxStyle::Center);
672 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
673 {
674 if (!pChild->IsVisible())
675 continue;
676
677 if (bIgnoreSecondaryPacking || !pChild->get_secondary())
678 {
679 long nMainGroupPrimaryDimension = *aPrimaryI++;
680 setPrimaryDimension(aChildSize, nMainGroupPrimaryDimension);
681 setLayoutAllocation(*pChild, aMainGroupPos, aChildSize);
682 long nPrimaryCoordinate = getPrimaryCoordinate(aMainGroupPos);
683 setPrimaryCoordinate(aMainGroupPos, nPrimaryCoordinate + nMainGroupPrimaryDimension + nSpacing);
684 }
685 else
686 {
687 long nSubGroupPrimaryDimension = *aSecondaryI++;
688 setPrimaryDimension(aChildSize, nSubGroupPrimaryDimension);
689 setLayoutAllocation(*pChild, aOtherGroupPos, aChildSize);
690 long nPrimaryCoordinate = getPrimaryCoordinate(aOtherGroupPos);
691 setPrimaryCoordinate(aOtherGroupPos, nPrimaryCoordinate + nSubGroupPrimaryDimension + nSpacing);
692 }
693 }
694}
695
696namespace {
697
698struct ButtonOrder
699{
700 const char* m_aType;
701 int m_nPriority;
702};
703
704}
705
706static int getButtonPriority(const OString &rType)
707{
708 static const size_t N_TYPES = 6;
709 static const ButtonOrder aDiscardCancelSave[N_TYPES] =
710 {
711 { "/discard", 0 },
712 { "/cancel", 1 },
713 { "/no", 2 },
714 { "/save", 3 },
715 { "/yes", 3 },
716 { "/ok", 3 }
717 };
718
719 static const ButtonOrder aSaveDiscardCancel[N_TYPES] =
720 {
721 { "/save", 0 },
722 { "/yes", 0 },
723 { "/ok", 0 },
724 { "/discard", 1 },
725 { "/no", 1 },
726 { "/cancel", 2 }
727 };
728
729 const ButtonOrder* pOrder = &aDiscardCancelSave[0];
730
731 const OUString &rEnv = Application::GetDesktopEnvironment();
732
733 if (rEnv.equalsIgnoreAsciiCase("windows") ||
734 rEnv.equalsIgnoreAsciiCase("lxqt") ||
735 rEnv.startsWithIgnoreAsciiCase("plasma"))
736 {
737 pOrder = &aSaveDiscardCancel[0];
738 }
739
740 for (size_t i = 0; i < N_TYPES; ++i, ++pOrder)
741 {
742 if (rType.endsWith(pOrder->m_aType))
743 return pOrder->m_nPriority;
744 }
745
746 return -1;
747}
748
749namespace {
750
751class sortButtons
752{
753 bool m_bVerticalContainer;
754public:
755 explicit sortButtons(bool bVerticalContainer)
756 : m_bVerticalContainer(bVerticalContainer)
757 {
758 }
759 bool operator()(const vcl::Window *pA, const vcl::Window *pB) const;
760};
761
762}
763
764bool sortButtons::operator()(const vcl::Window *pA, const vcl::Window *pB) const
765{
766 //sort into two groups of pack start and pack end
767 VclPackType ePackA = pA->get_pack_type();
768 VclPackType ePackB = pB->get_pack_type();
769 if (ePackA < ePackB)
770 return true;
771 if (ePackA > ePackB)
772 return false;
773 bool bPackA = pA->get_secondary();
774 bool bPackB = pB->get_secondary();
775 if (!m_bVerticalContainer)
776 {
777 //for horizontal boxes group secondaries before primaries
778 if (bPackA > bPackB)
779 return true;
780 if (bPackA < bPackB)
781 return false;
782 }
783 else
784 {
785 //for vertical boxes group secondaries after primaries
786 if (bPackA < bPackB)
787 return true;
788 if (bPackA > bPackB)
789 return false;
790 }
791
792 //now order within groups according to platform rules
793 return getButtonPriority(pA->GetHelpId()) < getButtonPriority(pB->GetHelpId());
794}
795
796void sort_native_button_order(const VclBox& rContainer)
797{
798 std::vector<vcl::Window*> aChilds;
799 for (vcl::Window* pChild = rContainer.GetWindow(GetWindowType::FirstChild); pChild;
800 pChild = pChild->GetWindow(GetWindowType::Next))
801 {
802 aChilds.push_back(pChild);
803 }
804
805 //sort child order within parent so that we match the platform
806 //button order
807 std::stable_sort(aChilds.begin(), aChilds.end(), sortButtons(rContainer.get_orientation()));
808 BuilderUtils::reorderWithinParent(aChilds, true);
809}
810
811namespace {
812
813struct GridEntry
814{
815 VclPtr<vcl::Window> pChild;
816 sal_Int32 nSpanWidth;
817 sal_Int32 nSpanHeight;
818 int x;
819 int y;
820 GridEntry()
821 : pChild(nullptr)
822 , nSpanWidth(0)
823 , nSpanHeight(0)
824 , x(-1)
825 , y(-1)
826 {
827 }
828};
829
830}
831
832typedef boost::multi_array<GridEntry, 2> array_type;
833
834static array_type assembleGrid(const VclGrid &rGrid);
835static bool isNullGrid(const array_type& A);
836static void calcMaxs(const array_type &A, std::vector<VclGrid::Value> &rWidths, std::vector<VclGrid::Value> &rHeights);
837
838array_type assembleGrid(const VclGrid &rGrid)
839{
840 array_type A;
841
842 for (vcl::Window* pChild = rGrid.GetWindow(GetWindowType::FirstChild); pChild;
843 pChild = pChild->GetWindow(GetWindowType::Next))
844 {
845 sal_Int32 nLeftAttach = std::max<sal_Int32>(pChild->get_grid_left_attach(), 0);
846 sal_Int32 nWidth = pChild->get_grid_width();
847 sal_Int32 nMaxXPos = nLeftAttach+nWidth-1;
848
849 sal_Int32 nTopAttach = std::max<sal_Int32>(pChild->get_grid_top_attach(), 0);
850 sal_Int32 nHeight = pChild->get_grid_height();
851 sal_Int32 nMaxYPos = nTopAttach+nHeight-1;
852
853 sal_Int32 nCurrentMaxXPos = A.shape()[0]-1;
854 sal_Int32 nCurrentMaxYPos = A.shape()[1]-1;
855 if (nMaxXPos > nCurrentMaxXPos || nMaxYPos > nCurrentMaxYPos)
856 {
857 nCurrentMaxXPos = std::max(nMaxXPos, nCurrentMaxXPos);
858 nCurrentMaxYPos = std::max(nMaxYPos, nCurrentMaxYPos);
859 A.resize(boost::extents[nCurrentMaxXPos+1][nCurrentMaxYPos+1]);
860 }
861
862 GridEntry &rEntry = A[nLeftAttach][nTopAttach];
863 rEntry.pChild = pChild;
864 rEntry.nSpanWidth = nWidth;
865 rEntry.nSpanHeight = nHeight;
866 rEntry.x = nLeftAttach;
867 rEntry.y = nTopAttach;
868
869 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
870 {
871 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
872 {
873 GridEntry &rSpan = A[nLeftAttach+nSpanX][nTopAttach+nSpanY];
874 rSpan.x = nLeftAttach;
875 rSpan.y = nTopAttach;
876 }
877 }
878 }
879
880 //see if we have any empty rows/cols
881 sal_Int32 nMaxX = A.shape()[0];
882 sal_Int32 nMaxY = A.shape()[1];
883
884 std::vector<bool> aNonEmptyCols(nMaxX);
885 std::vector<bool> aNonEmptyRows(nMaxY);
886
887 for (sal_Int32 x = 0; x < nMaxX; ++x)
888 {
889 for (sal_Int32 y = 0; y < nMaxY; ++y)
890 {
891 const GridEntry &rEntry = A[x][y];
892 const vcl::Window *pChild = rEntry.pChild;
893 if (pChild && pChild->IsVisible())
894 {
895 aNonEmptyCols[x] = true;
896 if (rGrid.get_column_homogeneous())
897 {
898 for (sal_Int32 nSpanX = 1; nSpanX < rEntry.nSpanWidth; ++nSpanX)
899 aNonEmptyCols[x+nSpanX] = true;
900 }
901 aNonEmptyRows[y] = true;
902 if (rGrid.get_row_homogeneous())
903 {
904 for (sal_Int32 nSpanY = 1; nSpanY < rEntry.nSpanHeight; ++nSpanY)
905 aNonEmptyRows[y+nSpanY] = true;
906 }
907 }
908 }
909 }
910
911 if (!rGrid.get_column_homogeneous())
912 {
913 //reduce the spans of elements that span empty columns
914 for (sal_Int32 x = 0; x < nMaxX; ++x)
915 {
916 std::set<GridEntry*> candidates;
917 for (sal_Int32 y = 0; y < nMaxY; ++y)
918 {
919 if (aNonEmptyCols[x])
920 continue;
921 GridEntry &rSpan = A[x][y];
922 //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y,
923 //just points back to itself if there's no cell spanning
924 if ((rSpan.x == -1) || (rSpan.y == -1))
925 {
926 //there is no entry for this cell, i.e. this is a cell
927 //with no widget in it, or spanned by any other widget
928 continue;
929 }
930 GridEntry &rEntry = A[rSpan.x][rSpan.y];
931 candidates.insert(&rEntry);
932 }
933 for (auto const& candidate : candidates)
934 {
935 GridEntry *pEntry = candidate;
936 --pEntry->nSpanWidth;
937 }
938 }
939 }
940
941 if (!rGrid.get_row_homogeneous())
942 {
943 //reduce the spans of elements that span empty rows
944 for (sal_Int32 y = 0; y < nMaxY; ++y)
945 {
946 std::set<GridEntry*> candidates;
947 for (sal_Int32 x = 0; x < nMaxX; ++x)
948 {
949 if (aNonEmptyRows[y])
950 continue;
951 GridEntry &rSpan = A[x][y];
952 //cell x/y is spanned by the widget at cell rSpan.x/rSpan.y,
953 //just points back to itself if there's no cell spanning
954 if ((rSpan.x == -1) || (rSpan.y == -1))
955 {
956 //there is no entry for this cell, i.e. this is a cell
957 //with no widget in it, or spanned by any other widget
958 continue;
959 }
960 GridEntry &rEntry = A[rSpan.x][rSpan.y];
961 candidates.insert(&rEntry);
962 }
963 for (auto const& candidate : candidates)
964 {
965 GridEntry *pEntry = candidate;
966 --pEntry->nSpanHeight;
967 }
968 }
969 }
970
971 sal_Int32 nNonEmptyCols = std::count(aNonEmptyCols.begin(), aNonEmptyCols.end(), true);
972 sal_Int32 nNonEmptyRows = std::count(aNonEmptyRows.begin(), aNonEmptyRows.end(), true);
973
974 //make new grid without empty rows and columns
975 array_type B(boost::extents[nNonEmptyCols][nNonEmptyRows]);
976 for (sal_Int32 x = 0, x2 = 0; x < nMaxX; ++x)
977 {
978 if (!aNonEmptyCols[x])
979 continue;
980 for (sal_Int32 y = 0, y2 = 0; y < nMaxY; ++y)
981 {
982 if (!aNonEmptyRows[y])
983 continue;
984 GridEntry &rEntry = A[x][y];
985 B[x2][y2++] = rEntry;
986 }
987 ++x2;
988 }
989
990 return B;
991}
992
993static bool isNullGrid(const array_type &A)
994{
995 sal_Int32 nMaxX = A.shape()[0];
996 sal_Int32 nMaxY = A.shape()[1];
997
998 return !nMaxX || !nMaxY;
999}
1000
1001static void calcMaxs(const array_type &A, std::vector<VclGrid::Value> &rWidths, std::vector<VclGrid::Value> &rHeights)
1002{
1003 sal_Int32 nMaxX = A.shape()[0];
1004 sal_Int32 nMaxY = A.shape()[1];
1005
1006 rWidths.resize(nMaxX);
1007 rHeights.resize(nMaxY);
1008
1009 //first use the non spanning entries to set default width/heights
1010 for (sal_Int32 x = 0; x < nMaxX; ++x)
1011 {
1012 for (sal_Int32 y = 0; y < nMaxY; ++y)
1013 {
1014 const GridEntry &rEntry = A[x][y];
1015 const vcl::Window *pChild = rEntry.pChild;
1016 if (!pChild || !pChild->IsVisible())
1017 continue;
1018
1019 sal_Int32 nWidth = rEntry.nSpanWidth;
1020 sal_Int32 nHeight = rEntry.nSpanHeight;
1021
1022 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1023 rWidths[x+nSpanX].m_bExpand |= pChild->get_hexpand();
1024
1025 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1026 rHeights[y+nSpanY].m_bExpand |= pChild->get_vexpand();
1027
1028 if (nWidth == 1 || nHeight == 1)
1029 {
1030 Size aChildSize = VclContainer::getLayoutRequisition(*pChild);
1031 if (nWidth == 1)
1032 rWidths[x].m_nValue = std::max(rWidths[x].m_nValue, aChildSize.Width());
1033 if (nHeight == 1)
1034 rHeights[y].m_nValue = std::max(rHeights[y].m_nValue, aChildSize.Height());
1035 }
1036 }
1037 }
1038
1039 //now use the spanning entries and split any extra sizes across expanding rows/cols
1040 //where possible
1041 for (sal_Int32 x = 0; x < nMaxX; ++x)
1042 {
1043 for (sal_Int32 y = 0; y < nMaxY; ++y)
1044 {
1045 const GridEntry &rEntry = A[x][y];
1046 const vcl::Window *pChild = rEntry.pChild;
1047 if (!pChild || !pChild->IsVisible())
1048 continue;
1049
1050 sal_Int32 nWidth = rEntry.nSpanWidth;
1051 sal_Int32 nHeight = rEntry.nSpanHeight;
1052
1053 if (nWidth == 1 && nHeight == 1)
1054 continue;
1055
1056 Size aChildSize = VclContainer::getLayoutRequisition(*pChild);
1057
1058 if (nWidth > 1)
1059 {
1060 sal_Int32 nExistingWidth = 0;
1061 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1062 nExistingWidth += rWidths[x+nSpanX].m_nValue;
1063
1064 sal_Int32 nExtraWidth = aChildSize.Width() - nExistingWidth;
1065
1066 if (nExtraWidth > 0)
1067 {
1068 bool bForceExpandAll = false;
1069 sal_Int32 nExpandables = 0;
1070 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1071 if (rWidths[x+nSpanX].m_bExpand)
1072 ++nExpandables;
1073 if (nExpandables == 0)
1074 {
1075 nExpandables = nWidth;
1076 bForceExpandAll = true;
1077 }
1078
1079 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1080 {
1081 if (rWidths[x+nSpanX].m_bExpand || bForceExpandAll)
1082 rWidths[x+nSpanX].m_nValue += nExtraWidth/nExpandables;
1083 }
1084 }
1085 }
1086
1087 if (nHeight > 1)
1088 {
1089 sal_Int32 nExistingHeight = 0;
1090 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1091 nExistingHeight += rHeights[y+nSpanY].m_nValue;
1092
1093 sal_Int32 nExtraHeight = aChildSize.Height() - nExistingHeight;
1094
1095 if (nExtraHeight > 0)
1096 {
1097 bool bForceExpandAll = false;
1098 sal_Int32 nExpandables = 0;
1099 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1100 if (rHeights[y+nSpanY].m_bExpand)
1101 ++nExpandables;
1102 if (nExpandables == 0)
1103 {
1104 nExpandables = nHeight;
1105 bForceExpandAll = true;
1106 }
1107
1108 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1109 {
1110 if (rHeights[y+nSpanY].m_bExpand || bForceExpandAll)
1111 rHeights[y+nSpanY].m_nValue += nExtraHeight/nExpandables;
1112 }
1113 }
1114 }
1115 }
1116 }
1117}
1118
1119static bool compareValues(const VclGrid::Value &i, const VclGrid::Value &j)
1120{
1121 return i.m_nValue < j.m_nValue;
1122}
1123
1124static VclGrid::Value accumulateValues(const VclGrid::Value &i, const VclGrid::Value &j)
1125{
1126 VclGrid::Value aRet;
1127 aRet.m_nValue = i.m_nValue + j.m_nValue;
1128 aRet.m_bExpand = i.m_bExpand || j.m_bExpand;
1129 return aRet;
1130}
1131
1132Size VclGrid::calculateRequisition() const
1133{
1134 return calculateRequisitionForSpacings(get_row_spacing(), get_column_spacing());
1135}
1136
1137Size VclGrid::calculateRequisitionForSpacings(sal_Int32 nRowSpacing, sal_Int32 nColSpacing) const
1138{
1139 array_type A = assembleGrid(*this);
1140
1141 if (isNullGrid(A))
1142 return Size();
1143
1144 std::vector<Value> aWidths;
1145 std::vector<Value> aHeights;
1146 calcMaxs(A, aWidths, aHeights);
1147
1148 long nTotalWidth = 0;
1149 if (get_column_homogeneous())
1150 {
1151 nTotalWidth = std::max_element(aWidths.begin(), aWidths.end(), compareValues)->m_nValue;
1152 nTotalWidth *= aWidths.size();
1153 }
1154 else
1155 {
1156 nTotalWidth = std::accumulate(aWidths.begin(), aWidths.end(), Value(), accumulateValues).m_nValue;
1157 }
1158
1159 nTotalWidth += nColSpacing * (aWidths.size()-1);
1160
1161 long nTotalHeight = 0;
1162 if (get_row_homogeneous())
1163 {
1164 nTotalHeight = std::max_element(aHeights.begin(), aHeights.end(), compareValues)->m_nValue;
1165 nTotalHeight *= aHeights.size();
1166 }
1167 else
1168 {
1169 nTotalHeight = std::accumulate(aHeights.begin(), aHeights.end(), Value(), accumulateValues).m_nValue;
1170 }
1171
1172 nTotalHeight += nRowSpacing * (aHeights.size()-1);
1173
1174 return Size(nTotalWidth, nTotalHeight);
1175}
1176
1177void VclGrid::setAllocation(const Size& rAllocation)
1178{
1179 array_type A = assembleGrid(*this);
1180
1181 if (isNullGrid(A))
1182 return;
1183
1184 sal_Int32 nMaxX = A.shape()[0];
1185 sal_Int32 nMaxY = A.shape()[1];
1186
1187 Size aRequisition;
1188 std::vector<Value> aWidths(nMaxX);
1189 std::vector<Value> aHeights(nMaxY);
1190 if (!get_column_homogeneous() || !get_row_homogeneous())
1191 {
1192 aRequisition = calculateRequisition();
1193 calcMaxs(A, aWidths, aHeights);
1194 }
1195
1196 sal_Int32 nColSpacing(get_column_spacing());
1197 sal_Int32 nRowSpacing(get_row_spacing());
1198
1199 long nAvailableWidth = rAllocation.Width();
1200 if (nMaxX)
1201 nAvailableWidth -= nColSpacing * (nMaxX - 1);
1202 if (get_column_homogeneous())
1203 {
1204 for (sal_Int32 x = 0; x < nMaxX; ++x)
1205 aWidths[x].m_nValue = nAvailableWidth/nMaxX;
1206 }
1207 else if (rAllocation.Width() != aRequisition.Width())
1208 {
1209 sal_Int32 nExpandables = 0;
1210 for (sal_Int32 x = 0; x < nMaxX; ++x)
1211 if (aWidths[x].m_bExpand)
1212 ++nExpandables;
1213 long nExtraWidthForExpanders = nExpandables ? (rAllocation.Width() - aRequisition.Width()) / nExpandables : 0;
1214
1215 //We don't fit and there is no volunteer to be shrunk
1216 if (!nExpandables && rAllocation.Width() < aRequisition.Width())
1217 {
1218 //first reduce spacing
1219 while (nColSpacing)
1220 {
1221 nColSpacing /= 2;
1222 aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing);
1223 if (aRequisition.Width() <= rAllocation.Width())
1224 break;
1225 }
1226
1227 //share out the remaining pain to everyone
1228 long nExtraWidth = (rAllocation.Width() - aRequisition.Width()) / nMaxX;
1229
1230 for (sal_Int32 x = 0; x < nMaxX; ++x)
1231 aWidths[x].m_nValue += nExtraWidth;
1232 }
1233
1234 if (nExtraWidthForExpanders)
1235 {
1236 for (sal_Int32 x = 0; x < nMaxX; ++x)
1237 if (aWidths[x].m_bExpand)
1238 aWidths[x].m_nValue += nExtraWidthForExpanders;
1239 }
1240 }
1241
1242 long nAvailableHeight = rAllocation.Height();
1243 if (nMaxY)
1244 nAvailableHeight -= nRowSpacing * (nMaxY - 1);
1245 if (get_row_homogeneous())
1246 {
1247 for (sal_Int32 y = 0; y < nMaxY; ++y)
1248 aHeights[y].m_nValue = nAvailableHeight/nMaxY;
1249 }
1250 else if (rAllocation.Height() != aRequisition.Height())
1251 {
1252 sal_Int32 nExpandables = 0;
1253 for (sal_Int32 y = 0; y < nMaxY; ++y)
1254 if (aHeights[y].m_bExpand)
1255 ++nExpandables;
1256 long nExtraHeightForExpanders = nExpandables ? (rAllocation.Height() - aRequisition.Height()) / nExpandables : 0;
1257
1258 //We don't fit and there is no volunteer to be shrunk
1259 if (!nExpandables && rAllocation.Height() < aRequisition.Height())
1260 {
1261 //first reduce spacing
1262 while (nRowSpacing)
1263 {
1264 nRowSpacing /= 2;
1265 aRequisition = calculateRequisitionForSpacings(nRowSpacing, nColSpacing);
1266 if (aRequisition.Height() <= rAllocation.Height())
1267 break;
1268 }
1269
1270 //share out the remaining pain to everyone
1271 long nExtraHeight = (rAllocation.Height() - aRequisition.Height()) / nMaxY;
1272
1273 for (sal_Int32 y = 0; y < nMaxY; ++y)
1274 aHeights[y].m_nValue += nExtraHeight;
1275 }
1276
1277 if (nExtraHeightForExpanders)
1278 {
1279 for (sal_Int32 y = 0; y < nMaxY; ++y)
1280 if (aHeights[y].m_bExpand)
1281 aHeights[y].m_nValue += nExtraHeightForExpanders;
1282 }
1283 }
1284
1285 Point aAllocPos(0, 0);
1286 for (sal_Int32 x = 0; x < nMaxX; ++x)
1287 {
1288 for (sal_Int32 y = 0; y < nMaxY; ++y)
1289 {
1290 GridEntry &rEntry = A[x][y];
1291 vcl::Window *pChild = rEntry.pChild;
1292 if (pChild)
1293 {
1294 Size aChildAlloc(0, 0);
1295
1296 sal_Int32 nWidth = rEntry.nSpanWidth;
1297 for (sal_Int32 nSpanX = 0; nSpanX < nWidth; ++nSpanX)
1298 aChildAlloc.AdjustWidth(aWidths[x+nSpanX].m_nValue );
1299 aChildAlloc.AdjustWidth(nColSpacing*(nWidth-1) );
1300
1301 sal_Int32 nHeight = rEntry.nSpanHeight;
1302 for (sal_Int32 nSpanY = 0; nSpanY < nHeight; ++nSpanY)
1303 aChildAlloc.AdjustHeight(aHeights[y+nSpanY].m_nValue );
1304 aChildAlloc.AdjustHeight(nRowSpacing*(nHeight-1) );
1305
1306 setLayoutAllocation(*pChild, aAllocPos, aChildAlloc);
1307 }
1308 aAllocPos.AdjustY(aHeights[y].m_nValue + nRowSpacing );
1309 }
1310 aAllocPos.AdjustX(aWidths[x].m_nValue + nColSpacing );
1311 aAllocPos.setY( 0 );
1312 }
1313}
1314
1315void VclGrid::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
1316{
1317 VclContainer::DumpAsPropertyTree(rJsonWriter);
1318 rJsonWriter.put("type", "grid");
1319}
1320
1321bool toBool(const OUString &rValue)
1322{
1323 return (!rValue.isEmpty() && (rValue[0] == 't' || rValue[0] == 'T' || rValue[0] == '1'));
1324}
1325
1326bool VclGrid::set_property(const OString &rKey, const OUString &rValue)
1327{
1328 if (rKey == "row-spacing")
1329 set_row_spacing(rValue.toInt32());
1330 else if (rKey == "column-spacing")
1331 set_column_spacing(rValue.toInt32());
1332 else if (rKey == "row-homogeneous")
1333 m_bRowHomogeneous = toBool(rValue);
1334 else if (rKey == "column-homogeneous")
1335 m_bColumnHomogeneous = toBool(rValue);
1336 else if (rKey == "n-rows")
1337 /*nothing to do*/;
1338 else
1339 return VclContainer::set_property(rKey, rValue);
1340 return true;
1341}
1342
1343const vcl::Window *VclBin::get_child() const
1344{
1345 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1346
1347 return pWindowImpl->mpFirstChild;
1348}
1349
1350vcl::Window *VclBin::get_child()
1351{
1352 return const_cast<vcl::Window*>(const_cast<const VclBin*>(this)->get_child());
1353}
1354
1355Size VclBin::calculateRequisition() const
1356{
1357 const vcl::Window *pChild = get_child();
1358 if (pChild && pChild->IsVisible())
1359 return getLayoutRequisition(*pChild);
1360 return Size(0, 0);
1361}
1362
1363void VclBin::setAllocation(const Size &rAllocation)
1364{
1365 vcl::Window *pChild = get_child();
1366 if (pChild && pChild->IsVisible())
1367 setLayoutAllocation(*pChild, Point(0, 0), rAllocation);
1368}
1369
1370VclFrame::~VclFrame()
1371{
1372 disposeOnce();
1373}
1374
1375void VclFrame::dispose()
1376{
1377 m_pLabel.clear();
1378 VclBin::dispose();
1379}
1380
1381//To-Do, hook a DecorationView into VclFrame ?
1382
1383Size VclFrame::calculateRequisition() const
1384{
1385 Size aRet(0, 0);
1386
1387 const vcl::Window *pChild = get_child();
1388 const vcl::Window *pLabel = get_label_widget();
1389
1390 if (pChild && pChild->IsVisible())
1391 aRet = getLayoutRequisition(*pChild);
1392
1393 if (pLabel && pLabel->IsVisible())
1394 {
1395 Size aLabelSize = getLayoutRequisition(*pLabel);
1396 aRet.AdjustHeight(aLabelSize.Height() );
1397 aRet.setWidth( std::max(aLabelSize.Width(), aRet.Width()) );
1398 }
1399
1400 return aRet;
1401}
1402
1403void VclFrame::setAllocation(const Size &rAllocation)
1404{
1405 //SetBackground( Color(0xFF, 0x00, 0xFF) );
1406
1407 Size aAllocation(rAllocation);
1408 Point aChildPos;
1409
1410 vcl::Window *pChild = get_child();
1411 vcl::Window *pLabel = get_label_widget();
1412
1413 if (pLabel && pLabel->IsVisible())
1414 {
1415 Size aLabelSize = getLayoutRequisition(*pLabel);
1416 aLabelSize.setHeight( std::min(aLabelSize.Height(), aAllocation.Height()) );
1417 aLabelSize.setWidth( std::min(aLabelSize.Width(), aAllocation.Width()) );
1418 setLayoutAllocation(*pLabel, aChildPos, aLabelSize);
1419 aAllocation.AdjustHeight( -(aLabelSize.Height()) );
1420 aChildPos.AdjustY(aLabelSize.Height() );
1421 }
1422
1423 if (pChild && pChild->IsVisible())
1424 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1425}
1426
1427IMPL_LINK(VclFrame, WindowEventListener, VclWindowEvent&, rEvent, void)void VclFrame::LinkStubWindowEventListener(void * instance, VclWindowEvent
& data) { return static_cast<VclFrame *>(instance)->
WindowEventListener(data); } void VclFrame::WindowEventListener
(VclWindowEvent& rEvent)
1428{
1429 if (rEvent.GetId() == VclEventId::ObjectDying)
1430 designate_label(nullptr);
1431}
1432
1433void VclFrame::designate_label(vcl::Window *pWindow)
1434{
1435 assert(!pWindow || pWindow->GetParent() == this)(static_cast <bool> (!pWindow || pWindow->GetParent(
) == this) ? void (0) : __assert_fail ("!pWindow || pWindow->GetParent() == this"
, "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1435, __extension__ __PRETTY_FUNCTION__))
;
1436 if (m_pLabel)
1437 m_pLabel->RemoveEventListener(LINK(this, VclFrame, WindowEventListener)::tools::detail::makeLink( ::tools::detail::castTo<VclFrame
*>(this), &VclFrame::LinkStubWindowEventListener)
);
1438 m_pLabel = pWindow;
1439 if (m_pLabel)
1440 m_pLabel->AddEventListener(LINK(this, VclFrame, WindowEventListener)::tools::detail::makeLink( ::tools::detail::castTo<VclFrame
*>(this), &VclFrame::LinkStubWindowEventListener)
);
1441}
1442
1443const vcl::Window *VclFrame::get_label_widget() const
1444{
1445 assert(GetChildCount() == 2)(static_cast <bool> (GetChildCount() == 2) ? void (0) :
__assert_fail ("GetChildCount() == 2", "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1445, __extension__ __PRETTY_FUNCTION__))
;
1446 if (m_pLabel)
1447 return m_pLabel;
1448 //The label widget is normally the first (of two) children
1449 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1450 if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //no label exists
1451 return nullptr;
1452 return pWindowImpl->mpFirstChild;
1453}
1454
1455vcl::Window *VclFrame::get_label_widget()
1456{
1457 return const_cast<vcl::Window*>(const_cast<const VclFrame*>(this)->get_label_widget());
1458}
1459
1460const vcl::Window *VclFrame::get_child() const
1461{
1462 //The child widget is the normally the last (of two) children
1463 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1464 assert(GetChildCount() == 2 || pWindowImpl->mbInDispose)(static_cast <bool> (GetChildCount() == 2 || pWindowImpl
->mbInDispose) ? void (0) : __assert_fail ("GetChildCount() == 2 || pWindowImpl->mbInDispose"
, "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1464, __extension__ __PRETTY_FUNCTION__))
;
1465 if (!m_pLabel)
1466 return pWindowImpl->mpLastChild;
1467 if (pWindowImpl->mpFirstChild == pWindowImpl->mpLastChild) //only label exists
1468 return nullptr;
1469 return pWindowImpl->mpLastChild;
1470}
1471
1472vcl::Window *VclFrame::get_child()
1473{
1474 return const_cast<vcl::Window*>(const_cast<const VclFrame*>(this)->get_child());
1475}
1476
1477void VclFrame::set_label(const OUString &rLabel)
1478{
1479 vcl::Window *pLabel = get_label_widget();
1480 assert(pLabel)(static_cast <bool> (pLabel) ? void (0) : __assert_fail
("pLabel", "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1480, __extension__ __PRETTY_FUNCTION__))
;
1481 pLabel->SetText(rLabel);
1482}
1483
1484OUString VclFrame::get_label() const
1485{
1486 const vcl::Window *pLabel = get_label_widget();
1487 assert(pLabel)(static_cast <bool> (pLabel) ? void (0) : __assert_fail
("pLabel", "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1487, __extension__ __PRETTY_FUNCTION__))
;
1488 return pLabel->GetText();
1489}
1490
1491OUString VclFrame::getDefaultAccessibleName() const
1492{
1493 const vcl::Window *pLabel = get_label_widget();
1494 if (pLabel)
1495 return pLabel->GetAccessibleName();
1496 return VclBin::getDefaultAccessibleName();
1497}
1498
1499void VclFrame::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
1500{
1501 VclBin::DumpAsPropertyTree(rJsonWriter);
1502 rJsonWriter.put("type", "frame");
1503}
1504
1505Size VclAlignment::calculateRequisition() const
1506{
1507 Size aRet(m_nLeftPadding + m_nRightPadding,
1508 m_nTopPadding + m_nBottomPadding);
1509
1510 const vcl::Window *pChild = get_child();
1511 if (pChild && pChild->IsVisible())
1512 {
1513 Size aChildSize = getLayoutRequisition(*pChild);
1514 aRet.AdjustWidth(aChildSize.Width() );
1515 aRet.AdjustHeight(aChildSize.Height() );
1516 }
1517
1518 return aRet;
1519}
1520
1521void VclAlignment::setAllocation(const Size &rAllocation)
1522{
1523 vcl::Window *pChild = get_child();
1524 if (!pChild || !pChild->IsVisible())
1525 return;
1526
1527 Point aChildPos(m_nLeftPadding, m_nTopPadding);
1528
1529 Size aAllocation;
1530 aAllocation.setWidth( rAllocation.Width() - (m_nLeftPadding + m_nRightPadding) );
1531 aAllocation.setHeight( rAllocation.Height() - (m_nTopPadding + m_nBottomPadding) );
1532
1533 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1534}
1535
1536bool VclAlignment::set_property(const OString &rKey, const OUString &rValue)
1537{
1538 if (rKey == "bottom-padding")
1539 m_nBottomPadding = rValue.toInt32();
1540 else if (rKey == "left-padding")
1541 m_nLeftPadding = rValue.toInt32();
1542 else if (rKey == "right-padding")
1543 m_nRightPadding = rValue.toInt32();
1544 else if (rKey == "top-padding")
1545 m_nTopPadding = rValue.toInt32();
1546 else
1547 return VclBin::set_property(rKey, rValue);
1548 return true;
1549}
1550
1551class DisclosureButton final : public CheckBox
1552{
1553 virtual void ImplDrawCheckBoxState(vcl::RenderContext& rRenderContext) override
1554 {
1555 /* HACK: DisclosureButton is currently assuming, that the disclosure sign
1556 will fit into the rectangle occupied by a normal checkbox on all themes.
1557 If this does not hold true for some theme, ImplGetCheckImageSize
1558 would have to be overridden for DisclosureButton; also GetNativeControlRegion
1559 for ControlType::ListNode would have to be implemented and taken into account
1560 */
1561
1562 tools::Rectangle aStateRect(GetStateRect());
1563
1564 ImplControlValue aControlValue(GetState() == TRISTATE_TRUE ? ButtonValue::On : ButtonValue::Off);
1565 tools::Rectangle aCtrlRegion(aStateRect);
1566 ControlState nState = ControlState::NONE;
1567
1568 if (HasFocus())
1569 nState |= ControlState::FOCUSED;
1570 if (GetButtonState() & DrawButtonFlags::Default)
1571 nState |= ControlState::DEFAULT;
1572 if (Window::IsEnabled())
1573 nState |= ControlState::ENABLED;
1574 if (IsMouseOver() && GetMouseRect().IsInside(GetPointerPosPixel()))
1575 nState |= ControlState::ROLLOVER;
1576
1577 if (rRenderContext.DrawNativeControl(ControlType::ListNode, ControlPart::Entire, aCtrlRegion,
1578 nState, aControlValue, OUString()))
1579 return;
1580
1581 ImplSVCtrlData& rCtrlData(ImplGetSVData()->maCtrlData);
1582 if (!rCtrlData.mpDisclosurePlus)
1583 rCtrlData.mpDisclosurePlus.reset(new Image(StockImage::Yes, SV_DISCLOSURE_PLUS"res/plus.png"));
1584 if (!rCtrlData.mpDisclosureMinus)
1585 rCtrlData.mpDisclosureMinus.reset(new Image(StockImage::Yes, SV_DISCLOSURE_MINUS"res/minus.png"));
1586
1587 Image* pImg
1588 = IsChecked() ? rCtrlData.mpDisclosureMinus.get() : rCtrlData.mpDisclosurePlus.get();
1589
1590 DrawImageFlags nStyle = DrawImageFlags::NONE;
1591 if (!IsEnabled())
1592 nStyle |= DrawImageFlags::Disable;
1593
1594 Size aSize(aStateRect.GetSize());
1595 Size aImgSize(pImg->GetSizePixel());
1596 Point aOff((aSize.Width() - aImgSize.Width()) / 2,
1597 (aSize.Height() - aImgSize.Height()) / 2);
1598 aOff += aStateRect.TopLeft();
1599 rRenderContext.DrawImage(aOff, *pImg, nStyle);
1600 }
1601
1602public:
1603 explicit DisclosureButton(vcl::Window* pParent)
1604 : CheckBox(pParent, 0)
1605 {
1606 }
1607
1608 virtual void KeyInput( const KeyEvent& rKEvt ) override
1609 {
1610 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1611
1612 if( !aKeyCode.GetModifier() &&
1613 ( ( aKeyCode.GetCode() == KEY_ADD ) ||
1614 ( aKeyCode.GetCode() == KEY_SUBTRACT ) )
1615 )
1616 {
1617 Check( aKeyCode.GetCode() == KEY_ADD );
1618 }
1619 else
1620 CheckBox::KeyInput( rKEvt );
1621 }
1622};
1623
1624VclExpander::VclExpander(vcl::Window *pParent)
1625 : VclBin(pParent)
1626 , m_bResizeTopLevel(true)
1627 , m_pDisclosureButton(VclPtr<DisclosureButton>::Create(this))
1628{
1629 m_pDisclosureButton->SetToggleHdl(LINK(this, VclExpander, ClickHdl)::tools::detail::makeLink( ::tools::detail::castTo<VclExpander
*>(this), &VclExpander::LinkStubClickHdl)
);
1630 m_pDisclosureButton->Show();
1631}
1632
1633VclExpander::~VclExpander()
1634{
1635 disposeOnce();
1636}
1637
1638bool VclExpander::get_expanded() const
1639{
1640 return m_pDisclosureButton->IsChecked();
1641}
1642
1643void VclExpander::set_expanded(bool bExpanded)
1644{
1645 m_pDisclosureButton->Check(bExpanded);
1646}
1647
1648void VclExpander::set_label(const OUString& rLabel)
1649{
1650 m_pDisclosureButton->SetText(rLabel);
1651}
1652
1653void VclExpander::dispose()
1654{
1655 m_pDisclosureButton.disposeAndClear();
1656 VclBin::dispose();
1657}
1658
1659const vcl::Window *VclExpander::get_child() const
1660{
1661 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1662
1663 assert(pWindowImpl->mpFirstChild == m_pDisclosureButton)(static_cast <bool> (pWindowImpl->mpFirstChild == m_pDisclosureButton
) ? void (0) : __assert_fail ("pWindowImpl->mpFirstChild == m_pDisclosureButton"
, "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1663, __extension__ __PRETTY_FUNCTION__))
;
1664
1665 return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next);
1666}
1667
1668vcl::Window *VclExpander::get_child()
1669{
1670 return const_cast<vcl::Window*>(const_cast<const VclExpander*>(this)->get_child());
1671}
1672
1673Size VclExpander::calculateRequisition() const
1674{
1675 Size aRet(0, 0);
1676
1677 WindowImpl* pWindowImpl = ImplGetWindowImpl();
1678
1679 const vcl::Window *pChild = get_child();
1680 const vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild ? pWindowImpl->mpLastChild.get() : nullptr;
1681
1682 if (pChild && pChild->IsVisible() && m_pDisclosureButton->IsChecked())
1683 aRet = getLayoutRequisition(*pChild);
1684
1685 Size aExpanderSize = getLayoutRequisition(*m_pDisclosureButton);
1686
1687 if (pLabel && pLabel->IsVisible())
1688 {
1689 Size aLabelSize = getLayoutRequisition(*pLabel);
1690 aExpanderSize.setHeight( std::max(aExpanderSize.Height(), aLabelSize.Height()) );
1691 aExpanderSize.AdjustWidth(aLabelSize.Width() );
1692 }
1693
1694 aRet.AdjustHeight(aExpanderSize.Height() );
1695 aRet.setWidth( std::max(aExpanderSize.Width(), aRet.Width()) );
1696
1697 return aRet;
1698}
1699
1700void VclExpander::setAllocation(const Size &rAllocation)
1701{
1702 Size aAllocation(rAllocation);
1703 Point aChildPos;
1704
1705 WindowImpl* pWindowImpl = ImplGetWindowImpl();
1706
1707 //The label widget is the last (of two) children
1708 vcl::Window *pChild = get_child();
1709 vcl::Window *pLabel = pChild != pWindowImpl->mpLastChild.get() ? pWindowImpl->mpLastChild.get() : nullptr;
1710
1711 Size aButtonSize = getLayoutRequisition(*m_pDisclosureButton);
1712 Size aLabelSize;
1713 Size aExpanderSize = aButtonSize;
1714 if (pLabel && pLabel->IsVisible())
1715 {
1716 aLabelSize = getLayoutRequisition(*pLabel);
1717 aExpanderSize.setHeight( std::max(aExpanderSize.Height(), aLabelSize.Height()) );
1718 aExpanderSize.AdjustWidth(aLabelSize.Width() );
1719 }
1720
1721 aExpanderSize.setHeight( std::min(aExpanderSize.Height(), aAllocation.Height()) );
1722 aExpanderSize.setWidth( std::min(aExpanderSize.Width(), aAllocation.Width()) );
1723
1724 aButtonSize.setHeight( std::min(aButtonSize.Height(), aExpanderSize.Height()) );
1725 aButtonSize.setWidth( std::min(aButtonSize.Width(), aExpanderSize.Width()) );
1726
1727 long nExtraExpanderHeight = aExpanderSize.Height() - aButtonSize.Height();
1728 Point aButtonPos(aChildPos.X(), aChildPos.Y() + nExtraExpanderHeight/2);
1729 setLayoutAllocation(*m_pDisclosureButton, aButtonPos, aButtonSize);
1730
1731 if (pLabel && pLabel->IsVisible())
1732 {
1733 aLabelSize.setHeight( std::min(aLabelSize.Height(), aExpanderSize.Height()) );
1734 aLabelSize.setWidth( std::min(aLabelSize.Width(),
1735 aExpanderSize.Width() - aButtonSize.Width()) );
1736
1737 long nExtraLabelHeight = aExpanderSize.Height() - aLabelSize.Height();
1738 Point aLabelPos(aChildPos.X() + aButtonSize.Width(), aChildPos.Y() + nExtraLabelHeight/2);
1739 setLayoutAllocation(*pLabel, aLabelPos, aLabelSize);
1740 }
1741
1742 aAllocation.AdjustHeight( -(aExpanderSize.Height()) );
1743 aChildPos.AdjustY(aExpanderSize.Height() );
1744
1745 if (pChild && pChild->IsVisible())
1746 {
1747 if (!m_pDisclosureButton->IsChecked())
1748 aAllocation = Size();
1749 setLayoutAllocation(*pChild, aChildPos, aAllocation);
1750 }
1751}
1752
1753bool VclExpander::set_property(const OString &rKey, const OUString &rValue)
1754{
1755 if (rKey == "expanded")
1756 set_expanded(toBool(rValue));
1757 else if (rKey == "resize-toplevel")
1758 m_bResizeTopLevel = toBool(rValue);
1759 else
1760 return VclBin::set_property(rKey, rValue);
1761 return true;
1762}
1763
1764void VclExpander::StateChanged(StateChangedType nType)
1765{
1766 VclBin::StateChanged( nType );
1767
1768 if (nType == StateChangedType::InitShow)
1769 {
1770 vcl::Window *pChild = get_child();
1771 if (pChild)
1772 pChild->Show(m_pDisclosureButton->IsChecked());
1773 }
1774}
1775
1776IMPL_LINK( VclExpander, ClickHdl, CheckBox&, rBtn, void )void VclExpander::LinkStubClickHdl(void * instance, CheckBox&
data) { return static_cast<VclExpander *>(instance)->
ClickHdl(data); } void VclExpander::ClickHdl(CheckBox& rBtn
)
1777{
1778 vcl::Window *pChild = get_child();
1779 if (pChild)
1780 {
1781 pChild->Show(rBtn.IsChecked());
1782 queue_resize();
1783 Dialog* pResizeDialog = m_bResizeTopLevel ? GetParentDialog() : nullptr;
1784 if (pResizeDialog)
1785 pResizeDialog->setOptimalLayoutSize();
1786 }
1787 maExpandedHdl.Call(*this);
1788}
1789
1790VclScrolledWindow::VclScrolledWindow(vcl::Window *pParent)
1791 : VclBin(pParent, WB_HIDE | WB_CLIPCHILDREN | WB_AUTOHSCROLL | WB_AUTOVSCROLL | WB_TABSTOP)
1792 , m_bUserManagedScrolling(false)
1793 , m_eDrawFrameStyle(DrawFrameStyle::NONE)
1794 , m_eDrawFrameFlags(DrawFrameFlags::NONE)
1795 , m_pVScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_VERT))
1796 , m_pHScroll(VclPtr<ScrollBar>::Create(this, WB_HIDE | WB_HORZ))
1797 , m_aScrollBarBox(VclPtr<ScrollBarBox>::Create(this, WB_HIDE))
1798{
1799 SetType(WindowType::SCROLLWINDOW);
1800
1801 AllSettings aAllSettings = GetSettings();
1802 StyleSettings aStyle = aAllSettings.GetStyleSettings();
1803 aStyle.SetMonoColor(aStyle.GetActiveBorderColor());
1804 aAllSettings.SetStyleSettings(aStyle);
1805 SetSettings(aAllSettings);
1806
1807 Link<ScrollBar*,void> aLink( LINK( this, VclScrolledWindow, ScrollBarHdl )::tools::detail::makeLink( ::tools::detail::castTo<VclScrolledWindow
*>(this), &VclScrolledWindow::LinkStubScrollBarHdl)
);
1808 m_pVScroll->SetScrollHdl(aLink);
1809 m_pHScroll->SetScrollHdl(aLink);
1810}
1811
1812void VclScrolledWindow::dispose()
1813{
1814 m_pVScroll.disposeAndClear();
1815 m_pHScroll.disposeAndClear();
1816 m_aScrollBarBox.disposeAndClear();
1817 VclBin::dispose();
1818}
1819
1820IMPL_LINK_NOARG(VclScrolledWindow, ScrollBarHdl, ScrollBar*, void)void VclScrolledWindow::LinkStubScrollBarHdl(void * instance,
ScrollBar* data) { return static_cast<VclScrolledWindow *
>(instance)->ScrollBarHdl(data); } void VclScrolledWindow
::ScrollBarHdl(__attribute__ ((unused)) ScrollBar*)
1821{
1822 vcl::Window *pChild = get_child();
1823 if (!pChild)
1824 return;
1825
1826 assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport")(static_cast <bool> (dynamic_cast<VclViewport*>(pChild
) && "scrolledwindow child should be a Viewport") ? void
(0) : __assert_fail ("dynamic_cast<VclViewport*>(pChild) && \"scrolledwindow child should be a Viewport\""
, "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1826, __extension__ __PRETTY_FUNCTION__))
;
1827
1828 pChild = pChild->GetWindow(GetWindowType::FirstChild);
1829
1830 if (!pChild)
1831 return;
1832
1833 Point aWinPos(-m_pHScroll->GetThumbPos(), -m_pVScroll->GetThumbPos());
1834 pChild->SetPosPixel(aWinPos);
1835}
1836
1837const vcl::Window *VclScrolledWindow::get_child() const
1838{
1839 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
1840 assert(GetChildCount() == 4 || pWindowImpl->mbInDispose)(static_cast <bool> (GetChildCount() == 4 || pWindowImpl
->mbInDispose) ? void (0) : __assert_fail ("GetChildCount() == 4 || pWindowImpl->mbInDispose"
, "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1840, __extension__ __PRETTY_FUNCTION__))
;
1841 return pWindowImpl->mpLastChild;
1842}
1843
1844vcl::Window *VclScrolledWindow::get_child()
1845{
1846 return const_cast<vcl::Window*>(const_cast<const VclScrolledWindow*>(this)->get_child());
1847}
1848
1849Size VclScrolledWindow::calculateRequisition() const
1850{
1851 Size aRet(0, 0);
1852
1853 const vcl::Window *pChild = get_child();
1854 if (pChild && pChild->IsVisible())
1855 aRet = getLayoutRequisition(*pChild);
1856
1857 if (GetStyle() & WB_VSCROLL)
1858 aRet.AdjustWidth(getLayoutRequisition(*m_pVScroll).Width() );
1859
1860 if (GetStyle() & WB_HSCROLL)
1861 aRet.AdjustHeight(getLayoutRequisition(*m_pHScroll).Height() );
1862
1863 aRet.AdjustHeight(2);
1864 aRet.AdjustWidth(2);
1865
1866 return aRet;
1867}
1868
1869void VclScrolledWindow::InitScrollBars(const Size &rRequest)
1870{
1871 const vcl::Window *pChild = get_child();
1872 if (!pChild || !pChild->IsVisible())
1873 return;
1874
1875 Size aOutSize(getVisibleChildSize());
1876
1877 m_pVScroll->SetRangeMax(rRequest.Height());
1878 m_pVScroll->SetVisibleSize(aOutSize.Height());
1879 m_pVScroll->SetPageSize(16);
1880
1881 m_pHScroll->SetRangeMax(rRequest.Width());
1882 m_pHScroll->SetVisibleSize(aOutSize.Width());
1883 m_pHScroll->SetPageSize(16);
1884
1885 m_pVScroll->Scroll();
1886 m_pHScroll->Scroll();
1887}
1888
1889void VclScrolledWindow::doSetAllocation(const Size &rAllocation, bool bRetryOnFailure)
1890{
1891 Size aChildReq;
1892
1893 vcl::Window *pChild = get_child();
1894 if (pChild && pChild->IsVisible())
1895 aChildReq = getLayoutRequisition(*pChild);
1896
1897 long nAvailHeight = rAllocation.Height() - 2;
1898 long nAvailWidth = rAllocation.Width() - 2;
1899 // vert. ScrollBar
1900 if (GetStyle() & WB_AUTOVSCROLL)
1901 {
1902 m_pVScroll->Show(nAvailHeight < aChildReq.Height());
1903 }
1904 else if (m_pVScroll->IsVisible() != bool(GetStyle() & WB_VSCROLL))
1905 m_pVScroll->Show((GetStyle() & WB_VSCROLL) != 0);
1906
1907 if (m_pVScroll->IsVisible())
1908 nAvailWidth -= getLayoutRequisition(*m_pVScroll).Width();
1909
1910 // horz. ScrollBar
1911 if (GetStyle() & WB_AUTOHSCROLL)
1912 {
1913 bool bShowHScroll = nAvailWidth < aChildReq.Width();
1914 m_pHScroll->Show(bShowHScroll);
1915
1916 if (bShowHScroll)
1917 nAvailHeight -= getLayoutRequisition(*m_pHScroll).Height();
1918
1919 if (GetStyle() & WB_AUTOVSCROLL)
1920 m_pVScroll->Show(nAvailHeight < aChildReq.Height());
1921 }
1922 else if (m_pHScroll->IsVisible() != bool(GetStyle() & WB_HSCROLL))
1923 m_pHScroll->Show((GetStyle() & WB_HSCROLL) != 0);
1924
1925 Size aInnerSize(rAllocation);
1926 aInnerSize.AdjustWidth(-2);
1927 aInnerSize.AdjustHeight(-2);
1928
1929 bool bBothVisible = m_pVScroll->IsVisible() && m_pHScroll->IsVisible();
1930 auto nScrollBarWidth = getLayoutRequisition(*m_pVScroll).Width();
1931 auto nScrollBarHeight = getLayoutRequisition(*m_pHScroll).Height();
1932
1933 if (m_pVScroll->IsVisible())
1934 {
1935 Point aScrollPos(rAllocation.Width() - nScrollBarWidth - 2, 1);
1936 Size aScrollSize(nScrollBarWidth, rAllocation.Height() - 2);
1937 if (bBothVisible)
1938 aScrollSize.AdjustHeight(-nScrollBarHeight);
1939 setLayoutAllocation(*m_pVScroll, aScrollPos, aScrollSize);
1940 aInnerSize.AdjustWidth( -nScrollBarWidth );
1941 }
1942
1943 if (m_pHScroll->IsVisible())
1944 {
1945 Point aScrollPos(1, rAllocation.Height() - nScrollBarHeight);
1946 Size aScrollSize(rAllocation.Width() - 2, nScrollBarHeight);
1947 if (bBothVisible)
1948 aScrollSize.AdjustWidth(-nScrollBarWidth);
1949 setLayoutAllocation(*m_pHScroll, aScrollPos, aScrollSize);
1950 aInnerSize.AdjustHeight( -nScrollBarHeight );
1951 }
1952
1953 if (bBothVisible)
1954 {
1955 Point aBoxPos(aInnerSize.Width() + 1, aInnerSize.Height() + 1);
1956 m_aScrollBarBox->SetPosSizePixel(aBoxPos, Size(nScrollBarWidth, nScrollBarHeight));
1957 m_aScrollBarBox->Show();
1958 }
1959 else
1960 {
1961 m_aScrollBarBox->Hide();
1962 }
1963
1964 if (pChild && pChild->IsVisible())
1965 {
1966 assert(dynamic_cast<VclViewport*>(pChild) && "scrolledwindow child should be a Viewport")(static_cast <bool> (dynamic_cast<VclViewport*>(pChild
) && "scrolledwindow child should be a Viewport") ? void
(0) : __assert_fail ("dynamic_cast<VclViewport*>(pChild) && \"scrolledwindow child should be a Viewport\""
, "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 1966, __extension__ __PRETTY_FUNCTION__))
;
1967
1968 WinBits nOldBits = (GetStyle() & (WB_AUTOVSCROLL | WB_VSCROLL | WB_AUTOHSCROLL | WB_HSCROLL));
1969
1970 setLayoutAllocation(*pChild, Point(1, 1), aInnerSize);
1971
1972 // tdf#128758 if the layout allocation triggered some callback that
1973 // immediately invalidates the layout by adding scrollbars then
1974 // normally this would simply retrigger layout and another toplevel
1975 // attempt is made later. But the initial layout attempt blocks
1976 // relayouts, so just make another single effort here.
1977 WinBits nNewBits = (GetStyle() & (WB_AUTOVSCROLL | WB_VSCROLL | WB_AUTOHSCROLL | WB_HSCROLL));
1978 if (nOldBits != nNewBits && bRetryOnFailure)
1979 {
1980 doSetAllocation(rAllocation, false);
1981 return;
1982 }
1983 }
1984
1985 if (!m_bUserManagedScrolling)
1986 InitScrollBars(aChildReq);
1987}
1988
1989void VclScrolledWindow::setAllocation(const Size &rAllocation)
1990{
1991 doSetAllocation(rAllocation, true);
1992}
1993
1994Size VclScrolledWindow::getVisibleChildSize() const
1995{
1996 Size aRet(GetSizePixel());
1997 if (m_pVScroll->IsVisible())
1998 aRet.AdjustWidth( -(m_pVScroll->GetSizePixel().Width()) );
1999 if (m_pHScroll->IsVisible())
2000 aRet.AdjustHeight( -(m_pHScroll->GetSizePixel().Height()) );
2001 aRet.AdjustHeight(-2);
2002 aRet.AdjustWidth(-2);
2003 return aRet;
2004}
2005
2006bool VclScrolledWindow::set_property(const OString &rKey, const OUString &rValue)
2007{
2008 if (rKey == "shadow-type")
2009 {
2010 // despite the style names, this looks like the best mapping
2011 if (rValue == "in")
2012 m_eDrawFrameStyle = DrawFrameStyle::Out;
2013 else if (rValue == "out")
2014 m_eDrawFrameStyle = DrawFrameStyle::In;
2015 else if (rValue == "etched-in")
2016 m_eDrawFrameStyle = DrawFrameStyle::DoubleOut;
2017 else if (rValue == "etched-out")
2018 m_eDrawFrameStyle = DrawFrameStyle::DoubleIn;
2019 else if (rValue == "none")
2020 m_eDrawFrameStyle = DrawFrameStyle::NONE;
2021 return true;
2022 }
2023 else if (rKey == "name")
2024 {
2025 m_eDrawFrameFlags = rValue == "monoborder" ? DrawFrameFlags::Mono : DrawFrameFlags::NONE;
2026 }
2027
2028 bool bRet = VclBin::set_property(rKey, rValue);
2029 m_pVScroll->Show((GetStyle() & WB_VSCROLL) != 0);
2030 m_pHScroll->Show((GetStyle() & WB_HSCROLL) != 0);
2031 return bRet;
2032}
2033
2034bool VclScrolledWindow::EventNotify(NotifyEvent& rNEvt)
2035{
2036 bool bDone = false;
2037 if ( rNEvt.GetType() == MouseNotifyEvent::COMMAND )
2038 {
2039 const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2040 if ( rCEvt.GetCommand() == CommandEventId::Wheel )
2041 {
2042 const CommandWheelData* pData = rCEvt.GetWheelData();
2043 if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) )
2044 {
2045 bDone = HandleScrollCommand(rCEvt, m_pHScroll, m_pVScroll);
2046 }
2047 }
2048 }
2049
2050 return bDone || VclBin::EventNotify( rNEvt );
2051}
2052
2053void VclScrolledWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
2054{
2055 VclBin::Paint(rRenderContext, rRect);
2056 DecorationView aDecoView(&rRenderContext);
2057 aDecoView.DrawFrame(tools::Rectangle(Point(0,0), GetSizePixel()), m_eDrawFrameStyle, m_eDrawFrameFlags);
2058}
2059
2060void VclViewport::setAllocation(const Size &rAllocation)
2061{
2062 vcl::Window *pChild = get_child();
2063 if (!(pChild && pChild->IsVisible()))
2064 return;
2065
2066 Size aReq(getLayoutRequisition(*pChild));
2067 aReq.setWidth( std::max(aReq.Width(), rAllocation.Width()) );
2068 aReq.setHeight( std::max(aReq.Height(), rAllocation.Height()) );
2069 Point aKeepPos(pChild->GetPosPixel());
2070 if (m_bInitialAllocation)
2071 {
2072 aKeepPos = Point(0, 0);
2073 m_bInitialAllocation = false;
2074 }
2075 setLayoutAllocation(*pChild, aKeepPos, aReq);
2076}
2077
2078const vcl::Window *VclEventBox::get_child() const
2079{
2080 const WindowImpl* pWindowImpl = ImplGetWindowImpl();
2081
2082 assert(pWindowImpl->mpFirstChild.get() == m_aEventBoxHelper.get())(static_cast <bool> (pWindowImpl->mpFirstChild.get()
== m_aEventBoxHelper.get()) ? void (0) : __assert_fail ("pWindowImpl->mpFirstChild.get() == m_aEventBoxHelper.get()"
, "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 2082, __extension__ __PRETTY_FUNCTION__))
;
2083
2084 return pWindowImpl->mpFirstChild->GetWindow(GetWindowType::Next);
2085}
2086
2087vcl::Window *VclEventBox::get_child()
2088{
2089 return const_cast<vcl::Window*>(const_cast<const VclEventBox*>(this)->get_child());
2090}
2091
2092void VclEventBox::setAllocation(const Size& rAllocation)
2093{
2094 Point aChildPos(0, 0);
2095 for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
2096 {
2097 if (!pChild->IsVisible())
2098 continue;
2099 setLayoutAllocation(*pChild, aChildPos, rAllocation);
2100 }
2101}
2102
2103Size VclEventBox::calculateRequisition() const
2104{
2105 Size aRet(0, 0);
2106
2107 for (const vcl::Window* pChild = get_child(); pChild;
2108 pChild = pChild->GetWindow(GetWindowType::Next))
2109 {
2110 if (!pChild->IsVisible())
2111 continue;
2112 Size aChildSize = getLayoutRequisition(*pChild);
2113 aRet.setWidth( std::max(aRet.Width(), aChildSize.Width()) );
2114 aRet.setHeight( std::max(aRet.Height(), aChildSize.Height()) );
2115 }
2116
2117 return aRet;
2118}
2119
2120void VclEventBox::Command(const CommandEvent&)
2121{
2122 //discard events by default to block them reaching children
2123}
2124
2125VclEventBox::~VclEventBox()
2126{
2127 disposeOnce();
2128}
2129
2130void VclEventBox::dispose()
2131{
2132 m_aEventBoxHelper.disposeAndClear();
2133 VclBin::dispose();
2134}
2135
2136void VclSizeGroup::trigger_queue_resize()
2137{
2138 //sufficient to trigger one widget to trigger all of them
2139 if (!m_aWindows.empty())
2140 {
2141 (*m_aWindows.begin())->queue_resize();
2142 }
2143}
2144
2145void VclSizeGroup::set_ignore_hidden(bool bIgnoreHidden)
2146{
2147 if (bIgnoreHidden != m_bIgnoreHidden)
2148 {
2149 m_bIgnoreHidden = bIgnoreHidden;
2150 trigger_queue_resize();
2151 }
2152}
2153
2154void VclSizeGroup::set_mode(VclSizeGroupMode eMode)
2155{
2156 if (eMode != m_eMode)
2157 {
2158 m_eMode = eMode;
2159 trigger_queue_resize();
2160 }
2161
2162}
2163
2164void VclSizeGroup::set_property(const OString &rKey, const OUString &rValue)
2165{
2166 if (rKey == "ignore-hidden")
2167 set_ignore_hidden(toBool(rValue));
2168 else if (rKey == "mode")
2169 {
2170 VclSizeGroupMode eMode = VclSizeGroupMode::Horizontal;
2171 if (rValue == "none")
2172 eMode = VclSizeGroupMode::NONE;
2173 else if (rValue == "horizontal")
2174 eMode = VclSizeGroupMode::Horizontal;
2175 else if (rValue == "vertical")
2176 eMode = VclSizeGroupMode::Vertical;
2177 else if (rValue == "both")
2178 eMode = VclSizeGroupMode::Both;
2179 else
2180 {
2181 SAL_WARN("vcl.layout", "unknown size group mode" << rValue)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "unknown size group mode"
<< rValue) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2181" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown size group mode" << rValue
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "unknown size group mode" << rValue; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2181" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "unknown size group mode" << rValue) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2181" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown size group mode" << rValue
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "unknown size group mode" << rValue; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2181" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2182 }
2183 set_mode(eMode);
2184 }
2185 else
2186 {
2187 SAL_INFO("vcl.layout", "unhandled property: " << rKey)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "unhandled property: "
<< rKey) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2187" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unhandled property: " << rKey
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "unhandled property: " << rKey; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2187" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "unhandled property: " << rKey) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2187" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unhandled property: " << rKey
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "unhandled property: " << rKey; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2187" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2188 }
2189}
2190
2191void MessageDialog::create_message_area()
2192{
2193 setDeferredProperties();
2194
2195 if (m_pGrid)
2196 return;
2197
2198 VclContainer *pContainer = get_content_area();
2199 assert(pContainer)(static_cast <bool> (pContainer) ? void (0) : __assert_fail
("pContainer", "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 2199, __extension__ __PRETTY_FUNCTION__))
;
2200
2201 m_pGrid.set( VclPtr<VclGrid>::Create(pContainer) );
2202 m_pGrid->reorderWithinParent(0);
2203 m_pGrid->set_column_spacing(12);
2204 m_pMessageBox.set(VclPtr<VclVBox>::Create(m_pGrid));
2205 m_pMessageBox->set_grid_left_attach(1);
2206 m_pMessageBox->set_grid_top_attach(0);
2207 m_pMessageBox->set_spacing(GetTextHeight());
2208
2209 m_pImage = VclPtr<FixedImage>::Create(m_pGrid, WB_CENTER | WB_VCENTER | WB_3DLOOK);
2210 switch (m_eMessageType)
2211 {
2212 case VclMessageType::Info:
2213 m_pImage->SetImage(GetStandardInfoBoxImage());
2214 break;
2215 case VclMessageType::Warning:
2216 m_pImage->SetImage(GetStandardWarningBoxImage());
2217 break;
2218 case VclMessageType::Question:
2219 m_pImage->SetImage(GetStandardQueryBoxImage());
2220 break;
2221 case VclMessageType::Error:
2222 m_pImage->SetImage(GetStandardErrorBoxImage());
2223 break;
2224 case VclMessageType::Other:
2225 break;
2226 }
2227 m_pImage->set_grid_left_attach(0);
2228 m_pImage->set_grid_top_attach(0);
2229 m_pImage->set_valign(VclAlign::Start);
2230 m_pImage->Show(m_eMessageType != VclMessageType::Other);
2231
2232 WinBits nWinStyle = WB_CLIPCHILDREN | WB_LEFT | WB_VCENTER | WB_NOLABEL | WB_NOTABSTOP;
2233
2234 bool bHasSecondaryText = !m_sSecondaryString.isEmpty();
2235
2236 m_pPrimaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pMessageBox, nWinStyle);
2237 m_pPrimaryMessage->SetPaintTransparent(true);
2238 m_pPrimaryMessage->EnableCursor(false);
2239
2240 m_pPrimaryMessage->set_hexpand(true);
2241 m_pPrimaryMessage->SetText(m_sPrimaryString);
2242 m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty());
2243
2244 m_pSecondaryMessage = VclPtr<VclMultiLineEdit>::Create(m_pMessageBox, nWinStyle);
2245 m_pSecondaryMessage->SetPaintTransparent(true);
2246 m_pSecondaryMessage->EnableCursor(false);
2247 m_pSecondaryMessage->set_hexpand(true);
2248 m_pSecondaryMessage->SetText(m_sSecondaryString);
2249 m_pSecondaryMessage->Show(bHasSecondaryText);
2250
2251 MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, bHasSecondaryText ? m_pSecondaryMessage.get() : nullptr);
2252
2253 VclButtonBox *pButtonBox = get_action_area();
2254 assert(pButtonBox)(static_cast <bool> (pButtonBox) ? void (0) : __assert_fail
("pButtonBox", "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 2254, __extension__ __PRETTY_FUNCTION__))
;
2255
2256 VclPtr<PushButton> pBtn;
2257 short nDefaultResponse = get_default_response();
2258 switch (m_eButtonsType)
2259 {
2260 case VclButtonsType::NONE:
2261 break;
2262 case VclButtonsType::Ok:
2263 pBtn.set( VclPtr<OKButton>::Create(pButtonBox) );
2264 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2265 pBtn->Show();
2266 pBtn->set_id("ok");
2267 add_button(pBtn, RET_OK, true);
2268 nDefaultResponse = RET_OK;
2269 break;
2270 case VclButtonsType::Close:
2271 pBtn.set( VclPtr<CloseButton>::Create(pButtonBox) );
2272 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2273 pBtn->Show();
2274 pBtn->set_id("close");
2275 add_button(pBtn, RET_CLOSE, true);
2276 nDefaultResponse = RET_CLOSE;
2277 break;
2278 case VclButtonsType::Cancel:
2279 pBtn.set( VclPtr<CancelButton>::Create(pButtonBox) );
2280 pBtn->SetStyle(pBtn->GetStyle() & WB_DEFBUTTON);
2281 pBtn->Show();
2282 pBtn->set_id("cancel");
2283 add_button(pBtn, RET_CANCEL, true);
2284 nDefaultResponse = RET_CANCEL;
2285 break;
2286 case VclButtonsType::YesNo:
2287 pBtn = VclPtr<PushButton>::Create(pButtonBox);
2288 pBtn->SetText(GetStandardText(StandardButtonType::Yes));
2289 pBtn->Show();
2290 pBtn->set_id("yes");
2291 add_button(pBtn, RET_YES, true);
2292
2293 pBtn.set( VclPtr<PushButton>::Create(pButtonBox) );
2294 pBtn->SetText(GetStandardText(StandardButtonType::No));
2295 pBtn->Show();
2296 pBtn->set_id("no");
2297 add_button(pBtn, RET_NO, true);
2298 nDefaultResponse = RET_NO;
2299 break;
2300 case VclButtonsType::OkCancel:
2301 pBtn.set( VclPtr<OKButton>::Create(pButtonBox) );
2302 pBtn->Show();
2303 pBtn->set_id("ok");
2304 add_button(pBtn, RET_OK, true);
2305
2306 pBtn.set( VclPtr<CancelButton>::Create(pButtonBox) );
2307 pBtn->Show();
2308 pBtn->set_id("cancel");
2309 add_button(pBtn, RET_CANCEL, true);
2310 nDefaultResponse = RET_CANCEL;
2311 break;
2312 }
2313 set_default_response(nDefaultResponse);
2314 sort_native_button_order(*pButtonBox);
2315 m_pMessageBox->Show();
2316 m_pGrid->Show();
2317}
2318
2319void MessageDialog::create_owned_areas()
2320{
2321#if defined _WIN32
2322 set_border_width(3);
2323#else
2324 set_border_width(12);
2325#endif
2326 m_pOwnedContentArea.set(VclPtr<VclVBox>::Create(this, false, 24));
2
Calling 'VclPtr::Create'
4
Returned allocated memory
5
Calling implicit destructor for 'VclPtr<VclVBox>'
6
Calling '~Reference'
13
Returning from '~Reference'
14
Returning from destructor for 'VclPtr<VclVBox>'
2327 set_content_area(m_pOwnedContentArea);
15
Calling 'VclPtr::operator VclBox *'
2328 m_pOwnedContentArea->Show();
2329 m_pOwnedActionArea.set( VclPtr<VclHButtonBox>::Create(m_pOwnedContentArea) );
2330 set_action_area(m_pOwnedActionArea);
2331 m_pOwnedActionArea->Show();
2332}
2333
2334MessageDialog::MessageDialog(vcl::Window* pParent, WinBits nStyle)
2335 : Dialog(pParent, nStyle)
2336 , m_eButtonsType(VclButtonsType::NONE)
2337 , m_eMessageType(VclMessageType::Info)
2338 , m_pOwnedContentArea(nullptr)
2339 , m_pOwnedActionArea(nullptr)
2340 , m_pGrid(nullptr)
2341 , m_pMessageBox(nullptr)
2342 , m_pImage(nullptr)
2343 , m_pPrimaryMessage(nullptr)
2344 , m_pSecondaryMessage(nullptr)
2345{
2346 SetType(WindowType::MESSBOX);
2347}
2348
2349MessageDialog::MessageDialog(vcl::Window* pParent,
2350 const OUString &rMessage,
2351 VclMessageType eMessageType,
2352 VclButtonsType eButtonsType)
2353 : Dialog(pParent, WB_MOVEABLE | WB_3DLOOK | WB_CLOSEABLE)
2354 , m_eButtonsType(eButtonsType)
2355 , m_eMessageType(eMessageType)
2356 , m_pGrid(nullptr)
2357 , m_pMessageBox(nullptr)
2358 , m_pImage(nullptr)
2359 , m_pPrimaryMessage(nullptr)
2360 , m_pSecondaryMessage(nullptr)
2361 , m_sPrimaryString(rMessage)
2362{
2363 SetType(WindowType::MESSBOX);
2364 create_owned_areas();
1
Calling 'MessageDialog::create_owned_areas'
2365 create_message_area();
2366
2367 switch (m_eMessageType)
2368 {
2369 case VclMessageType::Info:
2370 SetText(GetStandardInfoBoxText());
2371 break;
2372 case VclMessageType::Warning:
2373 SetText(GetStandardWarningBoxText());
2374 break;
2375 case VclMessageType::Question:
2376 SetText(GetStandardQueryBoxText());
2377 break;
2378 case VclMessageType::Error:
2379 SetText(GetStandardErrorBoxText());
2380 break;
2381 case VclMessageType::Other:
2382 SetText(Application::GetDisplayName());
2383 break;
2384 }
2385}
2386
2387void MessageDialog::dispose()
2388{
2389 disposeOwnedButtons();
2390 m_pPrimaryMessage.disposeAndClear();
2391 m_pSecondaryMessage.disposeAndClear();
2392 m_pImage.disposeAndClear();
2393 m_pMessageBox.disposeAndClear();
2394 m_pGrid.disposeAndClear();
2395 m_pOwnedActionArea.disposeAndClear();
2396 m_pOwnedContentArea.disposeAndClear();
2397 Dialog::dispose();
2398}
2399
2400MessageDialog::~MessageDialog()
2401{
2402 disposeOnce();
2403}
2404
2405void MessageDialog::SetMessagesWidths(vcl::Window const *pParent,
2406 VclMultiLineEdit *pPrimaryMessage, VclMultiLineEdit *pSecondaryMessage)
2407{
2408 if (pSecondaryMessage)
2409 {
2410 assert(pPrimaryMessage)(static_cast <bool> (pPrimaryMessage) ? void (0) : __assert_fail
("pPrimaryMessage", "/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
, 2410, __extension__ __PRETTY_FUNCTION__))
;
2411 vcl::Font aFont = pParent->GetSettings().GetStyleSettings().GetLabelFont();
2412 aFont.SetFontSize(Size(0, aFont.GetFontSize().Height() * 1.2));
2413 aFont.SetWeight(WEIGHT_BOLD);
2414 pPrimaryMessage->SetControlFont(aFont);
2415 pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 44);
2416 pSecondaryMessage->SetMaxTextWidth(pSecondaryMessage->approximate_char_width() * 60);
2417 }
2418 else
2419 pPrimaryMessage->SetMaxTextWidth(pPrimaryMessage->approximate_char_width() * 60);
2420}
2421
2422OUString const & MessageDialog::get_primary_text() const
2423{
2424 const_cast<MessageDialog*>(this)->setDeferredProperties();
2425
2426 return m_sPrimaryString;
2427}
2428
2429OUString const & MessageDialog::get_secondary_text() const
2430{
2431 const_cast<MessageDialog*>(this)->setDeferredProperties();
2432
2433 return m_sSecondaryString;
2434}
2435
2436bool MessageDialog::set_property(const OString &rKey, const OUString &rValue)
2437{
2438 if (rKey == "text")
2439 set_primary_text(rValue);
2440 else if (rKey == "secondary-text")
2441 set_secondary_text(rValue);
2442 else if (rKey == "message-type")
2443 {
2444 VclMessageType eMode = VclMessageType::Info;
2445 if (rValue == "info")
2446 eMode = VclMessageType::Info;
2447 else if (rValue == "warning")
2448 eMode = VclMessageType::Warning;
2449 else if (rValue == "question")
2450 eMode = VclMessageType::Question;
2451 else if (rValue == "error")
2452 eMode = VclMessageType::Error;
2453 else if (rValue == "other")
2454 eMode = VclMessageType::Other;
2455 else
2456 {
2457 SAL_WARN("vcl.layout", "unknown message type mode" << rValue)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "unknown message type mode"
<< rValue) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2457" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown message type mode" <<
rValue), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "unknown message type mode" <<
rValue; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2457" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "unknown message type mode" << rValue) == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2457" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown message type mode" <<
rValue), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "unknown message type mode" <<
rValue; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2457" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2458 }
2459 m_eMessageType = eMode;
2460 }
2461 else if (rKey == "buttons")
2462 {
2463 VclButtonsType eMode = VclButtonsType::NONE;
2464 if (rValue == "none")
2465 eMode = VclButtonsType::NONE;
2466 else if (rValue == "ok")
2467 eMode = VclButtonsType::Ok;
2468 else if (rValue == "cancel")
2469 eMode = VclButtonsType::Cancel;
2470 else if (rValue == "close")
2471 eMode = VclButtonsType::Close;
2472 else if (rValue == "yes-no")
2473 eMode = VclButtonsType::YesNo;
2474 else if (rValue == "ok-cancel")
2475 eMode = VclButtonsType::OkCancel;
2476 else
2477 {
2478 SAL_WARN("vcl.layout", "unknown buttons type mode" << rValue)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "unknown buttons type mode"
<< rValue) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2478" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown buttons type mode" <<
rValue), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "unknown buttons type mode" <<
rValue; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2478" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "unknown buttons type mode" << rValue) == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2478" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown buttons type mode" <<
rValue), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "unknown buttons type mode" <<
rValue; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"vcl.layout"), ("/home/maarten/src/libreoffice/core/vcl/source/window/layout.cxx"
":" "2478" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2479 }
2480 m_eButtonsType = eMode;
2481 }
2482 else
2483 return Dialog::set_property(rKey, rValue);
2484 return true;
2485}
2486
2487void MessageDialog::set_primary_text(const OUString &rPrimaryString)
2488{
2489 m_sPrimaryString = rPrimaryString;
2490 if (m_pPrimaryMessage)
2491 {
2492 m_pPrimaryMessage->SetText(m_sPrimaryString);
2493 m_pPrimaryMessage->Show(!m_sPrimaryString.isEmpty());
2494 MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, !m_sSecondaryString.isEmpty() ? m_pSecondaryMessage.get() : nullptr);
2495 }
2496}
2497
2498void MessageDialog::set_secondary_text(const OUString &rSecondaryString)
2499{
2500 m_sSecondaryString = rSecondaryString;
2501 if (m_pSecondaryMessage)
2502 {
2503 m_pSecondaryMessage->SetText("\n" + m_sSecondaryString);
2504 m_pSecondaryMessage->Show(!m_sSecondaryString.isEmpty());
2505 MessageDialog::SetMessagesWidths(this, m_pPrimaryMessage, !m_sSecondaryString.isEmpty() ? m_pSecondaryMessage.get() : nullptr);
2506 }
2507}
2508
2509void MessageDialog::StateChanged(StateChangedType nType)
2510{
2511 Dialog::StateChanged(nType);
2512 if (nType == StateChangedType::InitShow)
2513 {
2514 // MessageBox should be at least as wide as to see the title
2515 auto nTitleWidth = CalcTitleWidth();
2516 // Extra-Width for Close button
2517 nTitleWidth += mpWindowImpl->mnTopBorder;
2518 if (get_preferred_size().Width() < nTitleWidth)
2519 {
2520 set_width_request(nTitleWidth);
2521 DoInitialLayout();
2522 }
2523 }
2524}
2525
2526VclPaned::VclPaned(vcl::Window *pParent, bool bVertical)
2527 : VclContainer(pParent, WB_HIDE | WB_CLIPCHILDREN)
2528 , m_pSplitter(VclPtr<Splitter>::Create(this, bVertical ? WB_VSCROLL : WB_HSCROLL))
2529 , m_nPosition(-1)
2530{
2531 m_pSplitter->SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFaceColor()));
2532 m_pSplitter->Show();
2533}
2534
2535void VclPaned::dispose()
2536{
2537 m_pSplitter.disposeAndClear();
2538 VclContainer::dispose();
2539}
2540
2541VclVPaned::VclVPaned(vcl::Window *pParent)
2542 : VclPaned(pParent, true)
2543{
2544 m_pSplitter->SetSplitHdl(LINK(this, VclVPaned, SplitHdl)::tools::detail::makeLink( ::tools::detail::castTo<VclVPaned
*>(this), &VclVPaned::LinkStubSplitHdl)
);
2545}
2546
2547IMPL_LINK(VclVPaned, SplitHdl, Splitter*, pSplitter, void)void VclVPaned::LinkStubSplitHdl(void * instance, Splitter* data
) { return static_cast<VclVPaned *>(instance)->SplitHdl
(data); } void VclVPaned::SplitHdl(Splitter* pSplitter)
2548{
2549 long nSize = pSplitter->GetSplitPosPixel();
2550 Size aSplitterSize(m_pSplitter->GetSizePixel());
2551 Size aAllocation(GetSizePixel());
2552 arrange(aAllocation, nSize, aAllocation.Height() - nSize - aSplitterSize.Height());
2553}
2554
2555void VclVPaned::arrange(const Size& rAllocation, long nFirstHeight, long nSecondHeight)
2556{
2557 Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height());
2558 Size aFirstChildSize(rAllocation.Width(), nFirstHeight);
2559 Size aSecondChildSize(rAllocation.Width(), nSecondHeight);
2560 int nElement = 0;
2561 for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2562 pChild = pChild->GetWindow(GetWindowType::Next))
2563 {
2564 if (!pChild->IsVisible())
2565 continue;
2566 if (nElement == 0)
2567 {
2568 Point aSplitterPos(0, aFirstChildSize.Height());
2569 setLayoutAllocation(*m_pSplitter, aSplitterPos, aSplitterSize);
2570 m_nPosition = aSplitterPos.Y() + aSplitterSize.Height() / 2;
2571 }
2572 else if (nElement == 1)
2573 {
2574 Point aChildPos(0, 0);
2575 setLayoutAllocation(*pChild, aChildPos, aFirstChildSize);
2576 }
2577 else if (nElement == 2)
2578 {
2579 Point aChildPos(0, aFirstChildSize.Height() + aSplitterSize.Height());
2580 setLayoutAllocation(*pChild, aChildPos, aSecondChildSize);
2581 }
2582 ++nElement;
2583 }
2584}
2585
2586void VclVPaned::set_position(long nPosition)
2587{
2588 VclPaned::set_position(nPosition);
2589
2590 Size aAllocation(GetSizePixel());
2591 Size aSplitterSize(m_pSplitter->GetSizePixel());
2592
2593 nPosition -= aSplitterSize.Height() / 2;
2594
2595 arrange(aAllocation, nPosition, aAllocation.Height() - nPosition - aSplitterSize.Height());
2596}
2597
2598void VclVPaned::setAllocation(const Size& rAllocation)
2599{
2600 //supporting "shrink" could be done by adjusting the allowed drag rectangle
2601 m_pSplitter->SetDragRectPixel(tools::Rectangle(Point(0, 0), rAllocation));
2602 Size aSplitterSize(rAllocation.Width(), getLayoutRequisition(*m_pSplitter).Height());
2603 const long nHeight = rAllocation.Height() - aSplitterSize.Height();
2604
2605 long nFirstHeight = 0;
2606 long nSecondHeight = 0;
2607 bool bFirstCanResize = true;
2608 bool bSecondCanResize = true;
2609 const bool bInitialAllocation = get_position() < 0;
2610 int nElement = 0;
2611 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2612 pChild = pChild->GetWindow(GetWindowType::Next))
2613 {
2614 if (!pChild->IsVisible())
2615 continue;
2616 if (nElement == 1)
2617 {
2618 if (bInitialAllocation)
2619 nFirstHeight = getLayoutRequisition(*pChild).Height();
2620 else
2621 nFirstHeight = pChild->GetSizePixel().Height();
2622 bFirstCanResize = pChild->get_expand();
2623 }
2624 else if (nElement == 2)
2625 {
2626 if (bInitialAllocation)
2627 nSecondHeight = getLayoutRequisition(*pChild).Height();
2628 else
2629 nSecondHeight = pChild->GetSizePixel().Height();
2630 bSecondCanResize = pChild->get_expand();
2631 }
2632 ++nElement;
2633 }
2634 long nHeightRequest = nFirstHeight + nSecondHeight;
2635 long nHeightDiff = nHeight - nHeightRequest;
2636 if (bFirstCanResize == bSecondCanResize)
2637 nFirstHeight += nHeightDiff/2;
2638 else if (bFirstCanResize)
2639 nFirstHeight += nHeightDiff;
2640 arrange(rAllocation, nFirstHeight, rAllocation.Height() - nFirstHeight - aSplitterSize.Height());
2641}
2642
2643Size VclVPaned::calculateRequisition() const
2644{
2645 Size aRet(0, 0);
2646
2647 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2648 pChild = pChild->GetWindow(GetWindowType::Next))
2649 {
2650 if (!pChild->IsVisible())
2651 continue;
2652 Size aChildSize = getLayoutRequisition(*pChild);
2653 aRet.setWidth( std::max(aRet.Width(), aChildSize.Width()) );
2654 aRet.AdjustHeight(aChildSize.Height() );
2655 }
2656
2657 return aRet;
2658}
2659
2660VclHPaned::VclHPaned(vcl::Window *pParent)
2661 : VclPaned(pParent, false)
2662{
2663 m_pSplitter->SetSplitHdl(LINK(this, VclHPaned, SplitHdl)::tools::detail::makeLink( ::tools::detail::castTo<VclHPaned
*>(this), &VclHPaned::LinkStubSplitHdl)
);
2664}
2665
2666IMPL_LINK(VclHPaned, SplitHdl, Splitter*, pSplitter, void)void VclHPaned::LinkStubSplitHdl(void * instance, Splitter* data
) { return static_cast<VclHPaned *>(instance)->SplitHdl
(data); } void VclHPaned::SplitHdl(Splitter* pSplitter)
2667{
2668 long nSize = pSplitter->GetSplitPosPixel();
2669 Size aSplitterSize(m_pSplitter->GetSizePixel());
2670 Size aAllocation(GetSizePixel());
2671 arrange(aAllocation, nSize, aAllocation.Width() - nSize - aSplitterSize.Width());
2672}
2673
2674void VclHPaned::arrange(const Size& rAllocation, long nFirstWidth, long nSecondWidth)
2675{
2676 Size aSplitterSize(getLayoutRequisition(*m_pSplitter).Width(), rAllocation.Height());
2677 Size aFirstChildSize(nFirstWidth, rAllocation.Height());
2678 Size aSecondChildSize(nSecondWidth, rAllocation.Height());
2679 int nElement = 0;
2680 for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2681 pChild = pChild->GetWindow(GetWindowType::Next))
2682 {
2683 if (!pChild->IsVisible())
2684 continue;
2685 if (nElement == 0)
2686 {
2687 Point aSplitterPos(aFirstChildSize.Width(), 0);
2688 setLayoutAllocation(*m_pSplitter, aSplitterPos, aSplitterSize);
2689 m_nPosition = aSplitterPos.X() + aSplitterSize.Width() / 2;
2690 }
2691 else if (nElement == 1)
2692 {
2693 Point aChildPos(0, 0);
2694 setLayoutAllocation(*pChild, aChildPos, aFirstChildSize);
2695 }
2696 else if (nElement == 2)
2697 {
2698 Point aChildPos(aFirstChildSize.Width() + aSplitterSize.Width(), 0);
2699 setLayoutAllocation(*pChild, aChildPos, aSecondChildSize);
2700 }
2701 ++nElement;
2702 }
2703}
2704
2705void VclHPaned::set_position(long nPosition)
2706{
2707 VclPaned::set_position(nPosition);
2708
2709 Size aAllocation(GetSizePixel());
2710 Size aSplitterSize(m_pSplitter->GetSizePixel());
2711
2712 nPosition -= aSplitterSize.Width() / 2;
2713
2714 arrange(aAllocation, nPosition, aAllocation.Width() - nPosition - aSplitterSize.Width());
2715}
2716
2717void VclHPaned::setAllocation(const Size& rAllocation)
2718{
2719 //supporting "shrink" could be done by adjusting the allowed drag rectangle
2720 m_pSplitter->SetDragRectPixel(tools::Rectangle(Point(0, 0), rAllocation));
2721 Size aSplitterSize(getLayoutRequisition(*m_pSplitter).Width(), rAllocation.Height());
2722 const long nWidth = rAllocation.Width() - aSplitterSize.Width();
2723
2724 long nFirstWidth = 0;
2725 long nSecondWidth = 0;
2726 bool bFirstCanResize = true;
2727 bool bSecondCanResize = true;
2728 const bool bInitialAllocation = get_position() < 0;
2729 int nElement = 0;
2730 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2731 pChild = pChild->GetWindow(GetWindowType::Next))
2732 {
2733 if (!pChild->IsVisible())
2734 continue;
2735 if (nElement == 1)
2736 {
2737 if (bInitialAllocation)
2738 nFirstWidth = getLayoutRequisition(*pChild).Width();
2739 else
2740 nFirstWidth = pChild->GetSizePixel().Width();
2741 bFirstCanResize = pChild->get_expand();
2742 }
2743 else if (nElement == 2)
2744 {
2745 if (bInitialAllocation)
2746 nSecondWidth = getLayoutRequisition(*pChild).Width();
2747 else
2748 nSecondWidth = pChild->GetSizePixel().Width();
2749 bSecondCanResize = pChild->get_expand();
2750 }
2751 ++nElement;
2752 }
2753 long nWidthRequest = nFirstWidth + nSecondWidth;
2754 long nWidthDiff = nWidth - nWidthRequest;
2755 if (bFirstCanResize == bSecondCanResize)
2756 nFirstWidth += nWidthDiff/2;
2757 else if (bFirstCanResize)
2758 nFirstWidth += nWidthDiff;
2759 arrange(rAllocation, nFirstWidth, rAllocation.Width() - nFirstWidth - aSplitterSize.Width());
2760}
2761
2762Size VclHPaned::calculateRequisition() const
2763{
2764 Size aRet(0, 0);
2765
2766 for (const vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
2767 pChild = pChild->GetWindow(GetWindowType::Next))
2768 {
2769 if (!pChild->IsVisible())
2770 continue;
2771 Size aChildSize = getLayoutRequisition(*pChild);
2772 aRet.setHeight( std::max(aRet.Height(), aChildSize.Height()) );
2773 aRet.AdjustWidth(aChildSize.Width() );
2774 }
2775
2776 return aRet;
2777}
2778
2779Size getLegacyBestSizeForChildren(const vcl::Window &rWindow)
2780{
2781 tools::Rectangle aBounds;
2782
2783 for (const vcl::Window* pChild = rWindow.GetWindow(GetWindowType::FirstChild); pChild;
2784 pChild = pChild->GetWindow(GetWindowType::Next))
2785 {
2786 if (!pChild->IsVisible())
2787 continue;
2788
2789 tools::Rectangle aChildBounds(pChild->GetPosPixel(), pChild->GetSizePixel());
2790 aBounds.Union(aChildBounds);
2791 }
2792
2793 if (aBounds.IsEmpty())
2794 return rWindow.GetSizePixel();
2795
2796 Size aRet(aBounds.GetSize());
2797 Point aTopLeft(aBounds.TopLeft());
2798 aRet.AdjustWidth(aTopLeft.X()*2 );
2799 aRet.AdjustHeight(aTopLeft.Y()*2 );
2800
2801 return aRet;
2802}
2803
2804vcl::Window* getNonLayoutParent(vcl::Window *pWindow)
2805{
2806 while (pWindow)
2807 {
2808 pWindow = pWindow->GetParent();
2809 if (!pWindow || !isContainerWindow(*pWindow))
2810 break;
2811 }
2812 return pWindow;
2813}
2814
2815bool isVisibleInLayout(const vcl::Window *pWindow)
2816{
2817 bool bVisible = true;
2818 while (bVisible)
2819 {
2820 bVisible = pWindow->IsVisible();
2821 pWindow = pWindow->GetParent();
2822 if (!pWindow || !isContainerWindow(*pWindow))
2823 break;
2824 }
2825 return bVisible;
2826}
2827
2828bool isEnabledInLayout(const vcl::Window *pWindow)
2829{
2830 bool bEnabled = true;
2831 while (bEnabled)
2832 {
2833 bEnabled = pWindow->IsEnabled();
2834 pWindow = pWindow->GetParent();
2835 if (!pWindow || !isContainerWindow(*pWindow))
2836 break;
2837 }
2838 return bEnabled;
2839}
2840
2841bool isLayoutEnabled(const vcl::Window *pWindow)
2842{
2843 //Child is a container => we're layout enabled
2844 const vcl::Window *pChild = pWindow ? pWindow->GetWindow(GetWindowType::FirstChild) : nullptr;
2845 return pChild && isContainerWindow(*pChild) && !pChild->GetWindow(GetWindowType::Next);
2846}
2847
2848void VclDrawingArea::StartDrag(sal_Int8, const Point&)
2849{
2850 if (m_aStartDragHdl.Call(this))
2851 return;
2852
2853 rtl::Reference<TransferDataContainer> xContainer = m_xTransferHelper;
2854 if (!m_xTransferHelper.is())
2855 return;
2856
2857 xContainer->StartDrag(this, m_nDragAction);
2858}
2859
2860OUString VclDrawingArea::GetSurroundingText() const
2861{
2862 OUString sSurroundingText;
2863 if (m_aGetSurroundingHdl.Call(sSurroundingText) != -1)
2864 return sSurroundingText;
2865 return Control::GetSurroundingText();
2866}
2867
2868Selection VclDrawingArea::GetSurroundingTextSelection() const
2869{
2870 OUString sSurroundingText;
2871 int nCursor = m_aGetSurroundingHdl.Call(sSurroundingText);
2872 if (nCursor != -1)
2873 return Selection(nCursor, nCursor);
2874 return Control::GetSurroundingTextSelection();
2875}
2876
2877VclHPaned::~VclHPaned()
2878{
2879}
2880
2881VclVPaned::~VclVPaned()
2882{
2883}
2884
2885VclPaned::~VclPaned()
2886{
2887 disposeOnce();
2888}
2889
2890VclScrolledWindow::~VclScrolledWindow()
2891{
2892 disposeOnce();
2893}
2894
2895void VclDrawingArea::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
2896{
2897 Control::DumpAsPropertyTree(rJsonWriter);
2898 rJsonWriter.put("type", "drawingarea");
2899
2900 ScopedVclPtrInstance<VirtualDevice> pDevice;
2901 pDevice->SetOutputSize( GetSizePixel() );
2902 tools::Rectangle aRect(Point(0,0), GetSizePixel());
2903 Paint(*pDevice, aRect);
2904 BitmapEx aImage = pDevice->GetBitmapEx( Point(0,0), GetSizePixel() );
2905 SvMemoryStream aOStm(65535, 65535);
2906 if(GraphicConverter::Export(aOStm, aImage, ConvertDataFormat::PNG) == ERRCODE_NONEErrCode(0))
2907 {
2908 css::uno::Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aOStm.GetData()), aOStm.Tell());
2909 OUStringBuffer aBuffer("data:image/png;base64,");
2910 ::comphelper::Base64::encode(aBuffer, aSeq);
2911 rJsonWriter.put("image", aBuffer.makeStringAndClear());
2912 }
2913 rJsonWriter.put("text", GetQuickHelpText());
2914}
2915
2916/* 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 );
3
Memory is allocated
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();
16
Calling 'Reference::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);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.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)
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
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
113 m_pBody->release();
8
Calling 'VclReferenceBase::release'
12
Returning; memory was released
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;
17
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