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 treelistbox.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/treelist/treelistbox.cxx

/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20/*
21 TODO:
22 - delete anchor in SelectionEngine when selecting manually
23 - SelectAll( false ) => only repaint the deselected entries
24*/
25
26#include <vcl/toolkit/treelistbox.hxx>
27#include <vcl/accessiblefactory.hxx>
28#include <com/sun/star/accessibility/AccessibleStateType.hpp>
29#include <vcl/svapp.hxx>
30#include <vcl/accel.hxx>
31#include <vcl/builder.hxx>
32#include <vcl/toolkit/edit.hxx>
33#include <vcl/settings.hxx>
34#include <vcl/commandevent.hxx>
35#include <vcl/uitest/uiobject.hxx>
36#include <sot/formats.hxx>
37#include <unotools/accessiblestatesethelper.hxx>
38#include <rtl/instance.hxx>
39#include <comphelper/string.hxx>
40#include <sal/log.hxx>
41#include <tools/debug.hxx>
42
43#include <vcl/toolkit/svlbitm.hxx>
44#include <vcl/toolkit/treelistentry.hxx>
45#include <vcl/toolkit/viewdataentry.hxx>
46#include <svimpbox.hxx>
47
48#include <set>
49#include <string.h>
50#include <vector>
51
52using namespace css::accessibility;
53
54// Drag&Drop
55static VclPtr<SvTreeListBox> g_pDDSource;
56static VclPtr<SvTreeListBox> g_pDDTarget;
57
58#define SVLBOX_ACC_RETURN1 1
59#define SVLBOX_ACC_ESCAPE2 2
60
61class SvInplaceEdit2
62{
63 Link<SvInplaceEdit2&,void> aCallBackHdl;
64 Accelerator aAccReturn;
65 Accelerator aAccEscape;
66 Idle aIdle;
67 VclPtr<Edit> pEdit;
68 bool bCanceled;
69 bool bAlreadyInCallBack;
70
71 void CallCallBackHdl_Impl();
72 DECL_LINK( Timeout_Impl, Timer *, void )static void LinkStubTimeout_Impl(void *, Timer *); void Timeout_Impl
(Timer *)
;
73 DECL_LINK( ReturnHdl_Impl, Accelerator&, void )static void LinkStubReturnHdl_Impl(void *, Accelerator&);
void ReturnHdl_Impl(Accelerator&)
;
74 DECL_LINK( EscapeHdl_Impl, Accelerator&, void )static void LinkStubEscapeHdl_Impl(void *, Accelerator&);
void EscapeHdl_Impl(Accelerator&)
;
75
76public:
77 SvInplaceEdit2( vcl::Window* pParent, const Point& rPos, const Size& rSize,
78 const OUString& rData, const Link<SvInplaceEdit2&,void>& rNotifyEditEnd,
79 const Selection& );
80 ~SvInplaceEdit2();
81 bool KeyInput( const KeyEvent& rKEvt );
82 void LoseFocus();
83 bool EditingCanceled() const { return bCanceled; }
84 OUString GetText() const;
85 OUString const & GetSavedValue() const;
86 void StopEditing( bool bCancel );
87 void Hide();
88};
89
90// ***************************************************************
91
92namespace {
93
94class MyEdit_Impl : public Edit
95{
96 SvInplaceEdit2* pOwner;
97public:
98 MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* pOwner );
99 virtual ~MyEdit_Impl() override { disposeOnce(); }
100 virtual void dispose() override { pOwner = nullptr; Edit::dispose(); }
101 virtual void KeyInput( const KeyEvent& rKEvt ) override;
102 virtual void LoseFocus() override;
103};
104
105}
106
107MyEdit_Impl::MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* _pOwner ) :
108
109 Edit( pParent, WB_LEFT ),
110
111 pOwner( _pOwner )
112
113{
114}
115
116void MyEdit_Impl::KeyInput( const KeyEvent& rKEvt )
117{
118 if( !pOwner->KeyInput( rKEvt ))
119 Edit::KeyInput( rKEvt );
120}
121
122void MyEdit_Impl::LoseFocus()
123{
124 if (pOwner)
125 pOwner->LoseFocus();
126}
127
128SvInplaceEdit2::SvInplaceEdit2
129(
130 vcl::Window* pParent, const Point& rPos,
131 const Size& rSize,
132 const OUString& rData,
133 const Link<SvInplaceEdit2&,void>& rNotifyEditEnd,
134 const Selection& rSelection
135) :
136
137 aCallBackHdl ( rNotifyEditEnd ),
138 bCanceled ( false ),
139 bAlreadyInCallBack ( false )
140
141{
142
143 pEdit = VclPtr<MyEdit_Impl>::Create( pParent, this );
28
Calling 'VclPtr::Create'
30
Returned allocated memory
31
Calling implicit destructor for 'VclPtr<(anonymous namespace)::MyEdit_Impl>'
32
Calling '~Reference'
39
Returning from '~Reference'
40
Returning from destructor for 'VclPtr<(anonymous namespace)::MyEdit_Impl>'
144
145 vcl::Font aFont( pParent->GetFont() );
146 aFont.SetTransparent( false );
147 Color aColor( pParent->GetBackground().GetColor() );
148 aFont.SetFillColor(aColor );
149 pEdit->SetFont( aFont );
41
Calling 'VclPtr::operator->'
150 pEdit->SetBackground( pParent->GetBackground() );
151 pEdit->SetPosPixel( rPos );
152 pEdit->SetSizePixel( rSize );
153 pEdit->SetText( rData );
154 pEdit->SetSelection( rSelection );
155 pEdit->SaveValue();
156
157 aAccReturn.InsertItem( SVLBOX_ACC_RETURN1, vcl::KeyCode(KEY_RETURN) );
158 aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE2, vcl::KeyCode(KEY_ESCAPE) );
159
160 aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit2, ReturnHdl_Impl)::tools::detail::makeLink( ::tools::detail::castTo<SvInplaceEdit2
*>(this), &SvInplaceEdit2::LinkStubReturnHdl_Impl)
);
161 aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit2, EscapeHdl_Impl)::tools::detail::makeLink( ::tools::detail::castTo<SvInplaceEdit2
*>(this), &SvInplaceEdit2::LinkStubEscapeHdl_Impl)
);
162 Application::InsertAccel( &aAccReturn );
163 Application::InsertAccel( &aAccEscape );
164
165 pEdit->Show();
166 pEdit->GrabFocus();
167}
168
169SvInplaceEdit2::~SvInplaceEdit2()
170{
171 if( !bAlreadyInCallBack )
172 {
173 Application::RemoveAccel( &aAccReturn );
174 Application::RemoveAccel( &aAccEscape );
175 }
176 pEdit.disposeAndClear();
177}
178
179OUString const & SvInplaceEdit2::GetSavedValue() const
180{
181 return pEdit->GetSavedValue();
182}
183
184void SvInplaceEdit2::Hide()
185{
186 pEdit->Hide();
187}
188
189
190IMPL_LINK_NOARG(SvInplaceEdit2, ReturnHdl_Impl, Accelerator&, void)void SvInplaceEdit2::LinkStubReturnHdl_Impl(void * instance, Accelerator
& data) { return static_cast<SvInplaceEdit2 *>(instance
)->ReturnHdl_Impl(data); } void SvInplaceEdit2::ReturnHdl_Impl
(__attribute__ ((unused)) Accelerator&)
191{
192 bCanceled = false;
193 CallCallBackHdl_Impl();
194}
195
196IMPL_LINK_NOARG(SvInplaceEdit2, EscapeHdl_Impl, Accelerator&, void)void SvInplaceEdit2::LinkStubEscapeHdl_Impl(void * instance, Accelerator
& data) { return static_cast<SvInplaceEdit2 *>(instance
)->EscapeHdl_Impl(data); } void SvInplaceEdit2::EscapeHdl_Impl
(__attribute__ ((unused)) Accelerator&)
197{
198 bCanceled = true;
199 CallCallBackHdl_Impl();
200}
201
202bool SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt )
203{
204 vcl::KeyCode aCode = rKEvt.GetKeyCode();
205 sal_uInt16 nCode = aCode.GetCode();
206
207 switch ( nCode )
208 {
209 case KEY_ESCAPE:
210 bCanceled = true;
211 CallCallBackHdl_Impl();
212 return true;
213
214 case KEY_RETURN:
215 bCanceled = false;
216 CallCallBackHdl_Impl();
217 return true;
218 }
219 return false;
220}
221
222void SvInplaceEdit2::StopEditing( bool bCancel )
223{
224 if ( !bAlreadyInCallBack )
225 {
226 bCanceled = bCancel;
227 CallCallBackHdl_Impl();
228 }
229}
230
231void SvInplaceEdit2::LoseFocus()
232{
233 if ( !bAlreadyInCallBack
234 && ((!Application::GetFocusWindow()) || !pEdit->IsChild( Application::GetFocusWindow()) )
235 )
236 {
237 bCanceled = false;
238 aIdle.SetPriority(TaskPriority::REPAINT);
239 aIdle.SetInvokeHandler(LINK(this,SvInplaceEdit2,Timeout_Impl)::tools::detail::makeLink( ::tools::detail::castTo<SvInplaceEdit2
*>(this), &SvInplaceEdit2::LinkStubTimeout_Impl)
);
240 aIdle.SetDebugName( "svtools::SvInplaceEdit2 aIdle" );
241 aIdle.Start();
242 }
243}
244
245IMPL_LINK_NOARG(SvInplaceEdit2, Timeout_Impl, Timer *, void)void SvInplaceEdit2::LinkStubTimeout_Impl(void * instance, Timer
* data) { return static_cast<SvInplaceEdit2 *>(instance
)->Timeout_Impl(data); } void SvInplaceEdit2::Timeout_Impl
(__attribute__ ((unused)) Timer *)
246{
247 CallCallBackHdl_Impl();
248}
249
250void SvInplaceEdit2::CallCallBackHdl_Impl()
251{
252 aIdle.Stop();
253 if ( !bAlreadyInCallBack )
254 {
255 bAlreadyInCallBack = true;
256 Application::RemoveAccel( &aAccReturn );
257 Application::RemoveAccel( &aAccEscape );
258 pEdit->Hide();
259 aCallBackHdl.Call( *this );
260 }
261}
262
263OUString SvInplaceEdit2::GetText() const
264{
265 return pEdit->GetText();
266}
267
268// ***************************************************************
269// class SvLBoxTab
270// ***************************************************************
271
272
273SvLBoxTab::SvLBoxTab()
274{
275 nPos = 0;
276 nFlags = SvLBoxTabFlags::NONE;
277}
278
279SvLBoxTab::SvLBoxTab( long nPosition, SvLBoxTabFlags nTabFlags )
280{
281 nPos = nPosition;
282 nFlags = nTabFlags;
283}
284
285SvLBoxTab::SvLBoxTab( const SvLBoxTab& rTab )
286{
287 nPos = rTab.nPos;
288 nFlags = rTab.nFlags;
289}
290
291SvLBoxTab::~SvLBoxTab()
292{
293}
294
295
296long SvLBoxTab::CalcOffset( long nItemWidth, long nTabWidth )
297{
298 long nOffset = 0;
299 if ( nFlags & SvLBoxTabFlags::ADJUST_RIGHT )
300 {
301 nOffset = nTabWidth - nItemWidth;
302 if( nOffset < 0 )
303 nOffset = 0;
304 }
305 else if ( nFlags & SvLBoxTabFlags::ADJUST_CENTER )
306 {
307 if( nFlags & SvLBoxTabFlags::FORCE )
308 {
309 // correct implementation of centering
310 nOffset = ( nTabWidth - nItemWidth ) / 2;
311 if( nOffset < 0 )
312 nOffset = 0;
313 }
314 else
315 {
316 // historically grown, wrong calculation of tabs which is needed by
317 // Abo-Tabbox, Tools/Options/Customize etc.
318 nItemWidth++;
319 nOffset = -( nItemWidth / 2 );
320 }
321 }
322 return nOffset;
323}
324
325// ***************************************************************
326// class SvLBoxItem
327// ***************************************************************
328
329
330SvLBoxItem::SvLBoxItem()
331 : mbDisabled(false)
332{
333}
334
335SvLBoxItem::~SvLBoxItem()
336{
337}
338
339int SvLBoxItem::GetWidth(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
340{
341 const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
342 int nWidth = pViewData->mnWidth;
343 if (nWidth == -1)
344 {
345 nWidth = CalcWidth(pView);
346 const_cast<SvViewDataItem*>(pViewData)->mnWidth = nWidth;
347 }
348 return nWidth;
349}
350
351int SvLBoxItem::GetHeight(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
352{
353 const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
354 return pViewData->mnHeight;
355}
356
357int SvLBoxItem::GetWidth(const SvTreeListBox* pView, const SvViewDataEntry* pData, sal_uInt16 nItemPos)
358{
359 const SvViewDataItem& rIData = pData->GetItem(nItemPos);
360 int nWidth = rIData.mnWidth;
361 if (nWidth == -1)
362 {
363 nWidth = CalcWidth(pView);
364 const_cast<SvViewDataItem&>(rIData).mnWidth = nWidth;
365 }
366 return nWidth;
367}
368
369int SvLBoxItem::GetHeight(const SvViewDataEntry* pData, sal_uInt16 nItemPos)
370{
371 const SvViewDataItem& rIData = pData->GetItem(nItemPos);
372 return rIData.mnHeight;
373}
374
375int SvLBoxItem::CalcWidth(const SvTreeListBox* /*pView*/) const
376{
377 return 0;
378}
379
380struct SvTreeListBoxImpl
381{
382 bool m_bDoingQuickSelection:1;
383
384 vcl::QuickSelectionEngine m_aQuickSelectionEngine;
385
386 explicit SvTreeListBoxImpl(SvTreeListBox& _rBox) :
387 m_bDoingQuickSelection(false),
388 m_aQuickSelectionEngine(_rBox) {}
389};
390
391SvTreeListBox::SvTreeListBox(vcl::Window* pParent, WinBits nWinStyle) :
392 Control(pParent, nWinStyle | WB_CLIPCHILDREN),
393 DropTargetHelper(this),
394 DragSourceHelper(this),
395 mpImpl(new SvTreeListBoxImpl(*this)),
396 mbContextBmpExpanded(false),
397 mbAlternatingRowColors(false),
398 mbUpdateAlternatingRows(false),
399 mbQuickSearch(false),
400 mbActivateOnSingleClick(false),
401 mbHoverSelection(false),
402 eSelMode(SelectionMode::NONE),
403 nMinWidthInChars(0),
404 mnDragAction(DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE | DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK),
405 mbCenterAndClipText(false)
406{
407 nImpFlags = SvTreeListBoxFlags::NONE;
408 pTargetEntry = nullptr;
409 nDragDropMode = DragDropMode::NONE;
410 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl )::tools::detail::makeLink( ::tools::detail::castTo<SvTreeListBox
*>(this), &SvTreeListBox::LinkStubCloneHdl_Impl)
);
411 pHdlEntry = nullptr;
412 eSelMode = SelectionMode::Single;
413 nDragDropMode = DragDropMode::NONE;
414 SetType(WindowType::TREELISTBOX);
415
416 InitTreeView();
417 pImpl->SetModel( pModel.get() );
418
419 SetSublistOpenWithLeftRight();
420}
421
422void SvTreeListBox::Clear()
423{
424 if (pModel)
425 pModel->Clear(); // Model calls SvTreeListBox::ModelHasCleared()
426}
427
428IMPL_LINK( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry, SvTreeListEntry* )SvTreeListEntry* SvTreeListBox::LinkStubCloneHdl_Impl(void * instance
, SvTreeListEntry* data) { return static_cast<SvTreeListBox
*>(instance)->CloneHdl_Impl(data); } SvTreeListEntry* SvTreeListBox
::CloneHdl_Impl(SvTreeListEntry* pEntry)
429{
430 return CloneEntry(pEntry);
431}
432
433sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos )
434{
435 sal_uLong nInsPos = pModel->Insert( pEntry, pParent, nPos );
436 pEntry->SetBackColor( GetBackground().GetColor() );
437 SetAlternatingRowColors( mbAlternatingRowColors );
438 return nInsPos;
439}
440
441sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry,sal_uLong nRootPos )
442{
443 sal_uLong nInsPos = pModel->Insert( pEntry, nRootPos );
444 pEntry->SetBackColor( GetBackground().GetColor() );
445 SetAlternatingRowColors( mbAlternatingRowColors );
446 return nInsPos;
447}
448
449bool SvTreeListBox::ExpandingHdl()
450{
451 return !aExpandingHdl.IsSet() || aExpandingHdl.Call( this );
452}
453
454void SvTreeListBox::ExpandedHdl()
455{
456 aExpandedHdl.Call( this );
457}
458
459void SvTreeListBox::SelectHdl()
460{
461 aSelectHdl.Call( this );
462}
463
464void SvTreeListBox::DeselectHdl()
465{
466 aDeselectHdl.Call( this );
467}
468
469bool SvTreeListBox::DoubleClickHdl()
470{
471 return !aDoubleClickHdl.IsSet() || aDoubleClickHdl.Call(this);
472}
473
474bool SvTreeListBox::CheckDragAndDropMode( SvTreeListBox const * pSource, sal_Int8 nAction )
475{
476 if ( pSource != this )
477 return false; // no drop
478
479 if ( !(nDragDropMode & DragDropMode::CTRL_MOVE) )
480 return false; // D&D locked within list
481
482 if( DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE == nAction )
483 {
484 if ( !(nDragDropMode & DragDropMode::CTRL_MOVE) )
485 return false; // no local move
486 }
487 else
488 return false; // no local copy
489
490 return true;
491}
492
493
494/*
495 NotifyMoving/Copying
496 ====================
497
498 default behavior:
499
500 1. target doesn't have children
501 - entry becomes sibling of target. entry comes after target
502 (->Window: below the target)
503 2. target is an expanded parent
504 - entry inserted at the beginning of the target childlist
505 3. target is a collapsed parent
506 - entry is inserted at the end of the target childlist
507*/
508TriState SvTreeListBox::NotifyMoving(
509 SvTreeListEntry* pTarget, // D&D dropping position in GetModel()
510 const SvTreeListEntry* pEntry, // entry that we want to move, from
511 // GetSourceListBox()->GetModel()
512 SvTreeListEntry*& rpNewParent, // new target parent
513 sal_uLong& rNewChildPos) // position in childlist of target parent
514{
515 DBG_ASSERT(pEntry,"NotifyMoving:SourceEntry?")do { if (true && (!(pEntry))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "515" ": "), "%s", "NotifyMoving:SourceEntry?"); } } while
(false)
;
516 if( !pTarget )
517 {
518 rpNewParent = nullptr;
519 rNewChildPos = 0;
520 return TRISTATE_TRUE;
521 }
522 if ( !pTarget->HasChildren() && !pTarget->HasChildrenOnDemand() )
523 {
524 // case 1
525 rpNewParent = GetParent( pTarget );
526 rNewChildPos = SvTreeList::GetRelPos( pTarget ) + 1;
527 rNewChildPos += nCurEntrySelPos;
528 nCurEntrySelPos++;
529 }
530 else
531 {
532 // cases 2 & 3
533 rpNewParent = pTarget;
534 if( IsExpanded(pTarget))
535 rNewChildPos = 0;
536 else
537 rNewChildPos = TREELIST_APPEND((9223372036854775807L *2UL+1UL));
538 }
539 return TRISTATE_TRUE;
540}
541
542TriState SvTreeListBox::NotifyCopying(
543 SvTreeListEntry* pTarget, // D&D dropping position in GetModel()
544 const SvTreeListEntry* pEntry, // entry that we want to move, from
545 // GetSourceListBox()->GetModel()
546 SvTreeListEntry*& rpNewParent, // new target parent
547 sal_uLong& rNewChildPos) // position in childlist of target parent
548{
549 return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos);
550}
551
552SvTreeListEntry* SvTreeListBox::FirstChild( SvTreeListEntry* pParent ) const
553{
554 return pModel->FirstChild(pParent);
555}
556
557// return: all entries copied
558bool SvTreeListBox::CopySelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
559{
560 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
561 bool bSuccess = true;
562 std::vector<SvTreeListEntry*> aList;
563 bool bClone = ( pSource->GetModel() != GetModel() );
564 Link<SvTreeListEntry*,SvTreeListEntry*> aCloneLink( pModel->GetCloneLink() );
565 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl )::tools::detail::makeLink( ::tools::detail::castTo<SvTreeListBox
*>(this), &SvTreeListBox::LinkStubCloneHdl_Impl)
);
566
567 // cache selection to simplify iterating over the selection when doing a D&D
568 // exchange within the same listbox
569 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
570 while ( pSourceEntry )
571 {
572 // children are copied automatically
573 pSource->SelectChildren( pSourceEntry, false );
574 aList.push_back( pSourceEntry );
575 pSourceEntry = pSource->NextSelected( pSourceEntry );
576 }
577
578 for (auto const& elem : aList)
579 {
580 pSourceEntry = elem;
581 SvTreeListEntry* pNewParent = nullptr;
582 sal_uLong nInsertionPos = TREELIST_APPEND((9223372036854775807L *2UL+1UL));
583 TriState nOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
584 if ( nOk )
585 {
586 if ( bClone )
587 {
588 sal_uLong nCloneCount = 0;
589 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
590 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
591 }
592 else
593 {
594 sal_uLong nListPos = pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
595 pSourceEntry = GetEntry( pNewParent, nListPos );
596 }
597 }
598 else
599 bSuccess = false;
600
601 if (nOk == TRISTATE_INDET) // HACK: make visible moved entry
602 MakeVisible( pSourceEntry );
603 }
604 pModel->SetCloneLink( aCloneLink );
605 return bSuccess;
606}
607
608// return: all entries were moved
609bool SvTreeListBox::MoveSelectionCopyFallbackPossible( SvTreeListBox* pSource, SvTreeListEntry* pTarget, bool bAllowCopyFallback )
610{
611 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
612 bool bSuccess = true;
613 std::vector<SvTreeListEntry*> aList;
614 bool bClone = ( pSource->GetModel() != GetModel() );
615 Link<SvTreeListEntry*,SvTreeListEntry*> aCloneLink( pModel->GetCloneLink() );
616 if ( bClone )
617 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl )::tools::detail::makeLink( ::tools::detail::castTo<SvTreeListBox
*>(this), &SvTreeListBox::LinkStubCloneHdl_Impl)
);
618
619 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
620 while ( pSourceEntry )
621 {
622 // children are automatically moved
623 pSource->SelectChildren( pSourceEntry, false );
624 aList.push_back( pSourceEntry );
625 pSourceEntry = pSource->NextSelected( pSourceEntry );
626 }
627
628 for (auto const& elem : aList)
629 {
630 pSourceEntry = elem;
631 SvTreeListEntry* pNewParent = nullptr;
632 sal_uLong nInsertionPos = TREELIST_APPEND((9223372036854775807L *2UL+1UL));
633 TriState nOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos);
634 TriState nCopyOk = nOk;
635 if ( !nOk && bAllowCopyFallback )
636 {
637 nInsertionPos = TREELIST_APPEND((9223372036854775807L *2UL+1UL));
638 nCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
639 }
640
641 if ( nOk || nCopyOk )
642 {
643 if ( bClone )
644 {
645 sal_uLong nCloneCount = 0;
646 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
647 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
648 }
649 else
650 {
651 if ( nOk )
652 pModel->Move(pSourceEntry, pNewParent, nInsertionPos);
653 else
654 pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
655 }
656 }
657 else
658 bSuccess = false;
659
660 if (nOk == TRISTATE_INDET) // HACK: make moved entry visible
661 MakeVisible( pSourceEntry );
662 }
663 pModel->SetCloneLink( aCloneLink );
664 return bSuccess;
665}
666
667void SvTreeListBox::RemoveSelection()
668{
669 std::vector<const SvTreeListEntry*> aList;
670 // cache selection, as the implementation deselects everything on the first
671 // remove
672 SvTreeListEntry* pEntry = FirstSelected();
673 while ( pEntry )
674 {
675 aList.push_back( pEntry );
676 if ( pEntry->HasChildren() )
677 // remove deletes all children automatically
678 SelectChildren(pEntry, false);
679 pEntry = NextSelected( pEntry );
680 }
681
682 for (auto const& elem : aList)
683 pModel->Remove(elem);
684}
685
686void SvTreeListBox::RemoveEntry(SvTreeListEntry const * pEntry)
687{
688 pModel->Remove(pEntry);
689}
690
691void SvTreeListBox::RecalcViewData()
692{
693 SvTreeListEntry* pEntry = First();
694 while( pEntry )
695 {
696 sal_uInt16 nCount = pEntry->ItemCount();
697 sal_uInt16 nCurPos = 0;
698 while ( nCurPos < nCount )
699 {
700 SvLBoxItem& rItem = pEntry->GetItem( nCurPos );
701 rItem.InitViewData( this, pEntry );
702 nCurPos++;
703 }
704 pEntry = Next( pEntry );
705 }
706}
707
708void SvTreeListBox::ImplShowTargetEmphasis( SvTreeListEntry* pEntry, bool bShow)
709{
710 if ( bShow && (nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
711 return;
712 if ( !bShow && !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
713 return;
714 pImpl->PaintDDCursor( pEntry, bShow);
715 if( bShow )
716 nImpFlags |= SvTreeListBoxFlags::TARGEMPH_VIS;
717 else
718 nImpFlags &= ~SvTreeListBoxFlags::TARGEMPH_VIS;
719}
720
721void SvTreeListBox::OnCurrentEntryChanged()
722{
723 if ( !mpImpl->m_bDoingQuickSelection )
724 mpImpl->m_aQuickSelectionEngine.Reset();
725}
726
727SvTreeListEntry* SvTreeListBox::GetEntry( SvTreeListEntry* pParent, sal_uLong nPos ) const
728{
729 return pModel->GetEntry(pParent, nPos);
730}
731
732SvTreeListEntry* SvTreeListBox::GetEntry( sal_uLong nRootPos ) const
733{
734 return pModel->GetEntry(nRootPos);
735}
736
737SvTreeListEntry* SvTreeListBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const
738{
739
740 SvTreeListEntry* pEntry = nullptr;
741 SvTreeListEntry* pParent = nullptr;
742 for (auto const& elem : _rPath)
743 {
744 pEntry = GetEntry( pParent, elem );
745 if ( !pEntry )
746 break;
747 pParent = pEntry;
748 }
749
750 return pEntry;
751}
752
753void SvTreeListBox::FillEntryPath( SvTreeListEntry* pEntry, ::std::deque< sal_Int32 >& _rPath ) const
754{
755
756 if ( !pEntry )
757 return;
758
759 SvTreeListEntry* pParentEntry = GetParent( pEntry );
760 while ( true )
761 {
762 sal_uLong i, nCount = GetLevelChildCount( pParentEntry );
763 for ( i = 0; i < nCount; ++i )
764 {
765 SvTreeListEntry* pTemp = GetEntry( pParentEntry, i );
766 DBG_ASSERT( pEntry, "invalid entry" )do { if (true && (!(pEntry))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "766" ": "), "%s", "invalid entry"); } } while (false)
;
767 if ( pEntry == pTemp )
768 {
769 _rPath.push_front( static_cast<sal_Int32>(i) );
770 break;
771 }
772 }
773
774 if ( pParentEntry )
775 {
776 pEntry = pParentEntry;
777 pParentEntry = GetParent( pParentEntry );
778 }
779 else
780 break;
781 }
782}
783
784SvTreeListEntry* SvTreeListBox::GetParent( SvTreeListEntry* pEntry ) const
785{
786 return pModel->GetParent(pEntry);
787}
788
789sal_uLong SvTreeListBox::GetChildCount( SvTreeListEntry const * pParent ) const
790{
791 return pModel->GetChildCount(pParent);
792}
793
794sal_uLong SvTreeListBox::GetLevelChildCount( SvTreeListEntry* _pParent ) const
795{
796
797 //if _pParent is 0, then pEntry is the first child of the root.
798 SvTreeListEntry* pEntry = FirstChild( _pParent );
799
800 if( !pEntry )//there is only root, root don't have children
801 return 0;
802
803 if( !_pParent )//root and children of root
804 return pEntry->pParent->m_Children.size();
805
806 return _pParent->m_Children.size();
807}
808
809SvViewDataEntry* SvTreeListBox::GetViewDataEntry( SvTreeListEntry const * pEntry ) const
810{
811 return const_cast<SvViewDataEntry*>(SvListView::GetViewData(pEntry));
812}
813
814SvViewDataItem* SvTreeListBox::GetViewDataItem(SvTreeListEntry const * pEntry, SvLBoxItem const * pItem)
815{
816 return const_cast<SvViewDataItem*>(static_cast<const SvTreeListBox*>(this)->GetViewDataItem(pEntry, pItem));
817}
818
819const SvViewDataItem* SvTreeListBox::GetViewDataItem(const SvTreeListEntry* pEntry, const SvLBoxItem* pItem) const
820{
821 const SvViewDataEntry* pEntryData = SvListView::GetViewData(pEntry);
822 assert(pEntryData && "Entry not in View")(static_cast <bool> (pEntryData && "Entry not in View"
) ? void (0) : __assert_fail ("pEntryData && \"Entry not in View\""
, "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 822, __extension__ __PRETTY_FUNCTION__))
;
823 sal_uInt16 nItemPos = pEntry->GetPos(pItem);
824 return &pEntryData->GetItem(nItemPos);
825}
826
827void SvTreeListBox::InitViewData( SvViewDataEntry* pData, SvTreeListEntry* pEntry )
828{
829 SvTreeListEntry* pInhEntry = pEntry;
830 SvViewDataEntry* pEntryData = pData;
831
832 pEntryData->Init(pInhEntry->ItemCount());
833 sal_uInt16 nCount = pInhEntry->ItemCount();
834 sal_uInt16 nCurPos = 0;
835 while( nCurPos < nCount )
836 {
837 SvLBoxItem& rItem = pInhEntry->GetItem( nCurPos );
838 SvViewDataItem& rItemData = pEntryData->GetItem(nCurPos);
839 rItem.InitViewData( this, pInhEntry, &rItemData );
840 nCurPos++;
841 }
842}
843
844void SvTreeListBox::EnableSelectionAsDropTarget( bool bEnable )
845{
846 sal_uInt16 nRefDepth;
847 SvTreeListEntry* pTemp;
848
849 SvTreeListEntry* pSelEntry = FirstSelected();
850 while( pSelEntry )
851 {
852 if ( !bEnable )
853 {
854 pSelEntry->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
855 nRefDepth = pModel->GetDepth( pSelEntry );
856 pTemp = Next( pSelEntry );
857 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
858 {
859 pTemp->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
860 pTemp = Next( pTemp );
861 }
862 }
863 else
864 {
865 pSelEntry->nEntryFlags &= ~SvTLEntryFlags::DISABLE_DROP;
866 nRefDepth = pModel->GetDepth( pSelEntry );
867 pTemp = Next( pSelEntry );
868 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
869 {
870 pTemp->nEntryFlags &= ~SvTLEntryFlags::DISABLE_DROP;
871 pTemp = Next( pTemp );
872 }
873 }
874 pSelEntry = NextSelected( pSelEntry );
875 }
876}
877
878// ******************************************************************
879// InplaceEditing
880// ******************************************************************
881
882void SvTreeListBox::EditText( const OUString& rStr, const tools::Rectangle& rRect,
883 const Selection& rSel )
884{
885 pEdCtrl.reset();
886 nImpFlags |= SvTreeListBoxFlags::IN_EDT;
887 nImpFlags &= ~SvTreeListBoxFlags::EDTEND_CALLED;
888 HideFocus();
889 pEdCtrl.reset( new SvInplaceEdit2(
27
Calling constructor for 'SvInplaceEdit2'
890 this, rRect.TopLeft(), rRect.GetSize(), rStr,
891 LINK( this, SvTreeListBox, TextEditEndedHdl_Impl )::tools::detail::makeLink( ::tools::detail::castTo<SvTreeListBox
*>(this), &SvTreeListBox::LinkStubTextEditEndedHdl_Impl
)
,
892 rSel ) );
893}
894
895IMPL_LINK_NOARG(SvTreeListBox, TextEditEndedHdl_Impl, SvInplaceEdit2&, void)void SvTreeListBox::LinkStubTextEditEndedHdl_Impl(void * instance
, SvInplaceEdit2& data) { return static_cast<SvTreeListBox
*>(instance)->TextEditEndedHdl_Impl(data); } void SvTreeListBox
::TextEditEndedHdl_Impl(__attribute__ ((unused)) SvInplaceEdit2
&)
896{
897 if ( nImpFlags & SvTreeListBoxFlags::EDTEND_CALLED ) // avoid nesting
898 return;
899 nImpFlags |= SvTreeListBoxFlags::EDTEND_CALLED;
900 OUString aStr;
901 if ( !pEdCtrl->EditingCanceled() )
902 aStr = pEdCtrl->GetText();
903 else
904 aStr = pEdCtrl->GetSavedValue();
905 EditedText( aStr );
906 // Hide may only be called after the new text was put into the entry, so
907 // that we don't call the selection handler in the GetFocus of the listbox
908 // with the old entry text.
909 pEdCtrl->Hide();
910 nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
911 GrabFocus();
912}
913
914void SvTreeListBox::CancelTextEditing()
915{
916 if ( pEdCtrl )
917 pEdCtrl->StopEditing( true );
918 nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
919}
920
921void SvTreeListBox::EndEditing( bool bCancel )
922{
923 if( pEdCtrl )
924 pEdCtrl->StopEditing( bCancel );
925 nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
926}
927
928vcl::StringEntryIdentifier SvTreeListBox::CurrentEntry( OUString& _out_entryText ) const
929{
930 // always accept the current entry if there is one
931 SvTreeListEntry* pEntry( GetCurEntry() );
932 if (pEntry)
933 {
934 _out_entryText = GetEntryText(pEntry);
935 return pEntry;
936 }
937
938 pEntry = FirstSelected();
939 if ( !pEntry )
940 pEntry = First();
941
942 if ( pEntry )
943 _out_entryText = GetEntryText( pEntry );
944
945 return pEntry;
946}
947
948vcl::StringEntryIdentifier SvTreeListBox::NextEntry(vcl::StringEntryIdentifier _pCurrentSearchEntry, OUString& _out_entryText) const
949{
950 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pCurrentSearchEntry ) );
951
952 if ( ( ( GetChildCount( pEntry ) > 0 )
953 || ( pEntry->HasChildrenOnDemand() )
954 )
955 && !IsExpanded( pEntry )
956 )
957 {
958 SvTreeListEntry* pNextSiblingEntry = pEntry->NextSibling();
959 if ( !pNextSiblingEntry )
960 pEntry = Next( pEntry );
961 else
962 pEntry = pNextSiblingEntry;
963 }
964 else
965 {
966 pEntry = Next( pEntry );
967 }
968
969 if ( !pEntry )
970 pEntry = First();
971
972 if ( pEntry )
973 _out_entryText = GetEntryText( pEntry );
974
975 return pEntry;
976}
977
978void SvTreeListBox::SelectEntry(vcl::StringEntryIdentifier _pEntry)
979{
980 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
981 DBG_ASSERT( pEntry, "SvTreeListBox::SelectSearchEntry: invalid entry!" )do { if (true && (!(pEntry))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "981" ": "), "%s", "SvTreeListBox::SelectSearchEntry: invalid entry!"
); } } while (false)
;
982 if ( !pEntry )
983 return;
984
985 SelectAll( false );
986 SetCurEntry( pEntry );
987 Select( pEntry );
988}
989
990bool SvTreeListBox::HandleKeyInput( const KeyEvent& _rKEvt )
991{
992 if ( _rKEvt.GetKeyCode().IsMod1() )
993 return false;
994
995 if (mbQuickSearch)
996 {
997 mpImpl->m_bDoingQuickSelection = true;
998 const bool bHandled = mpImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt );
999 mpImpl->m_bDoingQuickSelection = false;
1000 if ( bHandled )
1001 return true;
1002 }
1003
1004 return false;
1005}
1006
1007
1008//JP 28.3.2001: new Drag & Drop API
1009sal_Int8 SvTreeListBox::AcceptDrop( const AcceptDropEvent& rEvt )
1010{
1011 sal_Int8 nRet = DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
1012
1013 if (rEvt.mbLeaving || !CheckDragAndDropMode(g_pDDSource, rEvt.mnAction))
1014 {
1015 ImplShowTargetEmphasis( pTargetEntry, false );
1016 }
1017 else if( nDragDropMode == DragDropMode::NONE )
1018 {
1019 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no target" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "svtools.contnr")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "SvTreeListBox::QueryDrop(): no target"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"
), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1019" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SvTreeListBox::QueryDrop(): no target"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SvTreeListBox::QueryDrop(): no target"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1019" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SvTreeListBox::QueryDrop(): no target") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"
), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1019" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SvTreeListBox::QueryDrop(): no target"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SvTreeListBox::QueryDrop(): no target"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1019" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1020 }
1021 else
1022 {
1023 SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
1024 if( !IsDropFormatSupported( SotClipboardFormatId::TREELISTBOX ) )
1025 {
1026 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no format" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "svtools.contnr")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "SvTreeListBox::QueryDrop(): no format"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"
), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1026" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SvTreeListBox::QueryDrop(): no format"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SvTreeListBox::QueryDrop(): no format"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1026" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SvTreeListBox::QueryDrop(): no format") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"
), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1026" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SvTreeListBox::QueryDrop(): no format"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SvTreeListBox::QueryDrop(): no format"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools.contnr"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1026" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1027 }
1028 else
1029 {
1030 DBG_ASSERT(g_pDDSource, "SvTreeListBox::QueryDrop(): SourceBox == 0")do { if (true && (!(g_pDDSource))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "1030" ": "), "%s", "SvTreeListBox::QueryDrop(): SourceBox == 0"
); } } while (false)
;
1031 if (!( pEntry && g_pDDSource->GetModel() == GetModel()
1032 && DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE == rEvt.mnAction
1033 && (pEntry->nEntryFlags & SvTLEntryFlags::DISABLE_DROP)))
1034 {
1035 nRet = rEvt.mnAction;
1036 }
1037 }
1038
1039 // **** draw emphasis ****
1040 if( DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE == nRet )
1041 ImplShowTargetEmphasis( pTargetEntry, false );
1042 else if( pEntry != pTargetEntry || !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
1043 {
1044 ImplShowTargetEmphasis( pTargetEntry, false );
1045 pTargetEntry = pEntry;
1046 ImplShowTargetEmphasis( pTargetEntry, true );
1047 }
1048 }
1049 return nRet;
1050}
1051
1052sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
1053{
1054 assert(pSourceView)(static_cast <bool> (pSourceView) ? void (0) : __assert_fail
("pSourceView", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1054, __extension__ __PRETTY_FUNCTION__))
;
1055 pSourceView->EnableSelectionAsDropTarget();
1056
1057 ImplShowTargetEmphasis( pTargetEntry, false );
1058 g_pDDTarget = this;
1059
1060 TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
1061
1062 sal_Int8 nRet;
1063 if( aData.HasFormat( SotClipboardFormatId::TREELISTBOX ))
1064 nRet = rEvt.mnAction;
1065 else
1066 nRet = DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
1067
1068 if( DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE != nRet )
1069 {
1070 nRet = DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE;
1071
1072 SvTreeListEntry* pTarget = pTargetEntry; // may be 0!
1073
1074 if( DND_ACTION_COPYcss::datatransfer::dnd::DNDConstants::ACTION_COPY == rEvt.mnAction )
1075 {
1076 if (CopySelection(g_pDDSource, pTarget))
1077 nRet = rEvt.mnAction;
1078 }
1079 else if( DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE == rEvt.mnAction )
1080 {
1081 if (MoveSelectionCopyFallbackPossible( g_pDDSource, pTarget, false ))
1082 nRet = rEvt.mnAction;
1083 }
1084 else if( DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE == rEvt.mnAction )
1085 {
1086 if (MoveSelectionCopyFallbackPossible(g_pDDSource, pTarget, true))
1087 nRet = rEvt.mnAction;
1088 }
1089 }
1090 return nRet;
1091}
1092
1093sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
1094{
1095 return ExecuteDrop( rEvt, g_pDDSource );
1096}
1097
1098/**
1099 * This sets the global variables used to determine the
1100 * in-process drag source.
1101 */
1102void SvTreeListBox::SetupDragOrigin()
1103{
1104 g_pDDSource = this;
1105 g_pDDTarget = nullptr;
1106}
1107
1108void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel )
1109{
1110 Point aEventPos( rPosPixel );
1111 MouseEvent aMouseEvt( aEventPos, 1, MouseEventModifiers::SELECT, MOUSE_LEFT(sal_uInt16(0x0001)) );
1112 MouseButtonUp( aMouseEvt );
1113
1114 nOldDragMode = GetDragDropMode();
1115 if ( nOldDragMode == DragDropMode::NONE )
1116 return;
1117
1118 ReleaseMouse();
1119
1120 SvTreeListEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos );
1121 if( !pEntry )
1122 {
1123 DragFinished( DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE );
1124 return;
1125 }
1126
1127 rtl::Reference<TransferDataContainer> xContainer = m_xTransferHelper;
1128
1129 if (!xContainer)
1130 {
1131 xContainer.set(new TransferDataContainer);
1132 // apparently some (unused) content is needed
1133 xContainer->CopyAnyData( SotClipboardFormatId::TREELISTBOX,
1134 "unused", SAL_N_ELEMENTS("unused")(sizeof(sal_n_array_size("unused"))) );
1135 }
1136
1137 nDragDropMode = NotifyStartDrag();
1138 if( nDragDropMode == DragDropMode::NONE || 0 == GetSelectionCount() )
1139 {
1140 nDragDropMode = nOldDragMode;
1141 DragFinished( DND_ACTION_NONEcss::datatransfer::dnd::DNDConstants::ACTION_NONE );
1142 return;
1143 }
1144
1145 SetupDragOrigin();
1146
1147 bool bOldUpdateMode = Control::IsUpdateMode();
1148 Control::SetUpdateMode( true );
1149 PaintImmediately();
1150 Control::SetUpdateMode( bOldUpdateMode );
1151
1152 // Disallow using the selection and its children as drop targets.
1153 // Important: If the selection of the SourceListBox is changed in the
1154 // DropHandler, the entries have to be allowed as drop targets again:
1155 // (GetSourceListBox()->EnableSelectionAsDropTarget( true, true );)
1156 EnableSelectionAsDropTarget( false );
1157
1158 xContainer->StartDrag(this, mnDragAction, GetDragFinishedHdl());
1159}
1160
1161void SvTreeListBox::SetDragHelper(const rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants)
1162{
1163 m_xTransferHelper = rHelper;
1164 mnDragAction = eDNDConstants;
1165}
1166
1167void SvTreeListBox::DragFinished( sal_Int8
1168#ifndef UNX1
1169nAction
1170#endif
1171)
1172{
1173 EnableSelectionAsDropTarget();
1174
1175#ifndef UNX1
1176 if ( (nAction == DND_ACTION_MOVEcss::datatransfer::dnd::DNDConstants::ACTION_MOVE)
1177 && ( (g_pDDTarget && (g_pDDTarget->GetModel() != GetModel()))
1178 || !g_pDDTarget))
1179 {
1180 RemoveSelection();
1181 }
1182#endif
1183
1184 UnsetDropTarget();
1185 g_pDDSource = nullptr;
1186 g_pDDTarget = nullptr;
1187 nDragDropMode = nOldDragMode;
1188}
1189
1190void SvTreeListBox::UnsetDropTarget()
1191{
1192 if (pTargetEntry)
1193 {
1194 ImplShowTargetEmphasis(pTargetEntry, false);
1195 pTargetEntry = nullptr;
1196 }
1197}
1198
1199DragDropMode SvTreeListBox::NotifyStartDrag()
1200{
1201 return DragDropMode(0xffff);
1202}
1203
1204// Handler and methods for Drag - finished handler.
1205// The with get GetDragFinishedHdl() get link can set on the
1206// TransferDataContainer. This link is a callback for the DragFinished
1207// call. AddBox method is called from the GetDragFinishedHdl() and the
1208// remove is called in link callback and in the destructor. So it can't
1209// called to a deleted object.
1210
1211namespace
1212{
1213 struct SortLBoxes : public rtl::Static<std::set<sal_uLong>, SortLBoxes> {};
1214}
1215
1216void SvTreeListBox::AddBoxToDDList_Impl( const SvTreeListBox& rB )
1217{
1218 sal_uLong nVal = reinterpret_cast<sal_uLong>(&rB);
1219 SortLBoxes::get().insert( nVal );
1220}
1221
1222void SvTreeListBox::RemoveBoxFromDDList_Impl( const SvTreeListBox& rB )
1223{
1224 sal_uLong nVal = reinterpret_cast<sal_uLong>(&rB);
1225 SortLBoxes::get().erase( nVal );
1226}
1227
1228IMPL_LINK( SvTreeListBox, DragFinishHdl_Impl, sal_Int8, nAction, void )void SvTreeListBox::LinkStubDragFinishHdl_Impl(void * instance
, sal_Int8 data) { return static_cast<SvTreeListBox *>(
instance)->DragFinishHdl_Impl(data); } void SvTreeListBox::
DragFinishHdl_Impl(sal_Int8 nAction)
1229{
1230 sal_uLong nVal = reinterpret_cast<sal_uLong>(this);
1231 std::set<sal_uLong> &rSortLBoxes = SortLBoxes::get();
1232 std::set<sal_uLong>::const_iterator it = rSortLBoxes.find(nVal);
1233 if( it != rSortLBoxes.end() )
1234 {
1235 DragFinished( nAction );
1236 rSortLBoxes.erase( it );
1237 }
1238}
1239
1240Link<sal_Int8,void> SvTreeListBox::GetDragFinishedHdl() const
1241{
1242 AddBoxToDDList_Impl( *this );
1243 return LINK( const_cast<SvTreeListBox*>(this), SvTreeListBox, DragFinishHdl_Impl )::tools::detail::makeLink( ::tools::detail::castTo<SvTreeListBox
*>(const_cast<SvTreeListBox*>(this)), &SvTreeListBox
::LinkStubDragFinishHdl_Impl)
;
1244}
1245
1246/*
1247 Bugs/TODO
1248
1249 - calculate rectangle when editing in-place (bug with some fonts)
1250 - SetSpaceBetweenEntries: offset is not taken into account in SetEntryHeight
1251*/
1252
1253#define SV_LBOX_DEFAULT_INDENT_PIXEL20 20
1254
1255void SvTreeListBox::InitTreeView()
1256{
1257 pCheckButtonData = nullptr;
1258 pEdEntry = nullptr;
1259 pEdItem = nullptr;
1260 nEntryHeight = 0;
1261 pEdCtrl = nullptr;
1262 nFirstSelTab = 0;
1263 nLastSelTab = 0;
1264 nFocusWidth = -1;
1265 mnCheckboxItemWidth = 0;
1266
1267 nTreeFlags = SvTreeFlags::RECALCTABS;
1268 nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL20;
1269 nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL2;
1270 pImpl.reset( new SvImpLBox( this, GetModel(), GetStyle() ) );
1271
1272 mbContextBmpExpanded = true;
1273 nContextBmpWidthMax = 0;
1274
1275 SetFont( GetFont() );
1276 AdjustEntryHeightAndRecalc();
1277
1278 SetSpaceBetweenEntries( 0 );
1279 SetLineColor();
1280 InitSettings();
1281 ImplInitStyle();
1282 SetTabs();
1283}
1284
1285OUString SvTreeListBox::SearchEntryTextWithHeadTitle( SvTreeListEntry* pEntry )
1286{
1287 assert(pEntry)(static_cast <bool> (pEntry) ? void (0) : __assert_fail
("pEntry", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1287, __extension__ __PRETTY_FUNCTION__))
;
1288 OUStringBuffer sRet;
1289
1290 sal_uInt16 nCount = pEntry->ItemCount();
1291 sal_uInt16 nCur = 0;
1292 while( nCur < nCount )
1293 {
1294 SvLBoxItem& rItem = pEntry->GetItem( nCur );
1295 if ( (rItem.GetType() == SvLBoxItemType::String) &&
1296 !static_cast<SvLBoxString&>( rItem ).GetText().isEmpty() )
1297 {
1298 sRet.append(static_cast<SvLBoxString&>( rItem ).GetText()).append(",");
1299 }
1300 nCur++;
1301 }
1302
1303 if (!sRet.isEmpty())
1304 sRet = sRet.copy(0, sRet.getLength() - 1);
1305 return sRet.makeStringAndClear();
1306}
1307
1308SvTreeListBox::~SvTreeListBox()
1309{
1310 disposeOnce();
1311}
1312
1313void SvTreeListBox::dispose()
1314{
1315 if (IsMouseCaptured())
1316 ReleaseMouse();
1317
1318 if( pImpl )
1319 {
1320 pImpl->CallEventListeners( VclEventId::ObjectDying );
1321 pImpl.reset();
1322 }
1323 if( mpImpl )
1324 {
1325 ClearTabList();
1326
1327 pEdCtrl.reset();
1328
1329 SvListView::dispose();
1330
1331 SvTreeListBox::RemoveBoxFromDDList_Impl( *this );
1332
1333 if (this == g_pDDSource)
1334 g_pDDSource = nullptr;
1335 if (this == g_pDDTarget)
1336 g_pDDTarget = nullptr;
1337 mpImpl.reset();
1338 }
1339
1340 DropTargetHelper::dispose();
1341 DragSourceHelper::dispose();
1342 Control::dispose();
1343}
1344
1345void SvTreeListBox::SetNoAutoCurEntry( bool b )
1346{
1347 pImpl->SetNoAutoCurEntry( b );
1348}
1349
1350void SvTreeListBox::SetSublistOpenWithLeftRight()
1351{
1352 pImpl->m_bSubLstOpLR = true;
1353}
1354
1355void SvTreeListBox::Resize()
1356{
1357 if( IsEditingActive() )
1358 EndEditing( true );
1359
1360 Control::Resize();
1361
1362 pImpl->Resize();
1363 nFocusWidth = -1;
1364 pImpl->ShowCursor( false );
1365 pImpl->ShowCursor( true );
1366}
1367
1368/* Cases:
1369
1370 A) entries have bitmaps
1371 0. no buttons
1372 1. node buttons (can optionally also be on root items)
1373 2. node buttons (can optionally also be on root items) + CheckButton
1374 3. CheckButton
1375 B) entries don't have bitmaps (=>via WindowBits because of D&D!)
1376 0. no buttons
1377 1. node buttons (can optionally also be on root items)
1378 2. node buttons (can optionally also be on root items) + CheckButton
1379 3. CheckButton
1380*/
1381
1382#define NO_BUTTONS0 0
1383#define NODE_BUTTONS1 1
1384#define NODE_AND_CHECK_BUTTONS2 2
1385#define CHECK_BUTTONS3 3
1386
1387#define TABFLAGS_TEXT(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags
::EDITABLE | SvLBoxTabFlags::SHOW_SELECTION)
(SvLBoxTabFlags::DYNAMIC | \
1388 SvLBoxTabFlags::ADJUST_LEFT | \
1389 SvLBoxTabFlags::EDITABLE | \
1390 SvLBoxTabFlags::SHOW_SELECTION)
1391
1392#define TABFLAGS_CONTEXTBMP(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) (SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER)
1393
1394#define TABFLAGS_CHECKBTN(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) (SvLBoxTabFlags::DYNAMIC | \
1395 SvLBoxTabFlags::ADJUST_CENTER)
1396
1397#define TAB_STARTPOS2 2
1398
1399// take care of GetTextOffset when doing changes
1400void SvTreeListBox::SetTabs()
1401{
1402 if( IsEditingActive() )
1403 EndEditing( true );
1404 nTreeFlags &= ~SvTreeFlags::RECALCTABS;
1405 nFocusWidth = -1;
1406 const WinBits nStyle( GetStyle() );
1407 bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0;
1408 bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT |
1409 WB_HASBUTTONSATROOT))!=0;
1410 long nStartPos = TAB_STARTPOS2;
1411 long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width();
1412
1413 // pCheckButtonData->Width() knows nothing about the native checkbox width,
1414 // so we have mnCheckboxItemWidth which becomes valid when something is added.
1415 long nCheckWidth = 0;
1416 if( nTreeFlags & SvTreeFlags::CHKBTN )
1417 nCheckWidth = mnCheckboxItemWidth;
1418 long nCheckWidthDIV2 = nCheckWidth / 2;
1419
1420 long nContextWidth = nContextBmpWidthMax;
1421 long nContextWidthDIV2 = nContextWidth / 2;
1422
1423 ClearTabList();
1424
1425 int nCase = NO_BUTTONS0;
1426 if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
1427 {
1428 if( bHasButtons )
1429 nCase = NODE_BUTTONS1;
1430 }
1431 else
1432 {
1433 if( bHasButtons )
1434 nCase = NODE_AND_CHECK_BUTTONS2;
1435 else
1436 nCase = CHECK_BUTTONS3;
1437 }
1438
1439 switch( nCase )
1440 {
1441 case NO_BUTTONS0 :
1442 nStartPos += nContextWidthDIV2; // because of centering
1443 AddTab( nStartPos, TABFLAGS_CONTEXTBMP(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) );
1444 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1445 // only set a distance if there are bitmaps
1446 if( nContextBmpWidthMax )
1447 nStartPos += 5; // distance context bitmap to text
1448 AddTab( nStartPos, TABFLAGS_TEXT(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags
::EDITABLE | SvLBoxTabFlags::SHOW_SELECTION)
);
1449 break;
1450
1451 case NODE_BUTTONS1 :
1452 if( bHasButtonsAtRoot )
1453 nStartPos += ( nIndent + (nNodeWidthPixel/2) );
1454 else
1455 nStartPos += nContextWidthDIV2;
1456 AddTab( nStartPos, TABFLAGS_CONTEXTBMP(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) );
1457 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1458 // only set a distance if there are bitmaps
1459 if( nContextBmpWidthMax )
1460 nStartPos += 5; // distance context bitmap to text
1461 AddTab( nStartPos, TABFLAGS_TEXT(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags
::EDITABLE | SvLBoxTabFlags::SHOW_SELECTION)
);
1462 break;
1463
1464 case NODE_AND_CHECK_BUTTONS2 :
1465 if( bHasButtonsAtRoot )
1466 nStartPos += ( nIndent + nNodeWidthPixel );
1467 else
1468 nStartPos += nCheckWidthDIV2;
1469 AddTab( nStartPos, TABFLAGS_CHECKBTN(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) );
1470 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1471 nStartPos += 3; // distance CheckButton to context bitmap
1472 nStartPos += nContextWidthDIV2; // center of context bitmap
1473 AddTab( nStartPos, TABFLAGS_CONTEXTBMP(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) );
1474 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1475 // only set a distance if there are bitmaps
1476 if( nContextBmpWidthMax )
1477 nStartPos += 5; // distance context bitmap to text
1478 AddTab( nStartPos, TABFLAGS_TEXT(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags
::EDITABLE | SvLBoxTabFlags::SHOW_SELECTION)
);
1479 break;
1480
1481 case CHECK_BUTTONS3 :
1482 nStartPos += nCheckWidthDIV2;
1483 AddTab( nStartPos, TABFLAGS_CHECKBTN(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) );
1484 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1485 nStartPos += 3; // distance CheckButton to context bitmap
1486 nStartPos += nContextWidthDIV2; // center of context bitmap
1487 AddTab( nStartPos, TABFLAGS_CONTEXTBMP(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER) );
1488 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1489 // only set a distance if there are bitmaps
1490 if( nContextBmpWidthMax )
1491 nStartPos += 5; // distance context bitmap to text
1492 AddTab( nStartPos, TABFLAGS_TEXT(SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_LEFT | SvLBoxTabFlags
::EDITABLE | SvLBoxTabFlags::SHOW_SELECTION)
);
1493 break;
1494 }
1495 pImpl->NotifyTabsChanged();
1496}
1497
1498void SvTreeListBox::InitEntry(SvTreeListEntry* pEntry,
1499 const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp)
1500{
1501 if( nTreeFlags & SvTreeFlags::CHKBTN )
1502 {
1503 pEntry->AddItem(std::make_unique<SvLBoxButton>(pCheckButtonData));
1504 }
1505
1506 pEntry->AddItem(std::make_unique<SvLBoxContextBmp>( aCollEntryBmp,aExpEntryBmp, mbContextBmpExpanded));
1507
1508 pEntry->AddItem(std::make_unique<SvLBoxString>(aStr));
1509}
1510
1511OUString SvTreeListBox::GetEntryText(SvTreeListEntry* pEntry) const
1512{
1513 assert(pEntry)(static_cast <bool> (pEntry) ? void (0) : __assert_fail
("pEntry", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1513, __extension__ __PRETTY_FUNCTION__))
;
1514 SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SvLBoxItemType::String));
1515 assert(pItem)(static_cast <bool> (pItem) ? void (0) : __assert_fail (
"pItem", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1515, __extension__ __PRETTY_FUNCTION__))
;
1516 return pItem->GetText();
1517}
1518
1519const Image& SvTreeListBox::GetExpandedEntryBmp(const SvTreeListEntry* pEntry)
1520{
1521 assert(pEntry)(static_cast <bool> (pEntry) ? void (0) : __assert_fail
("pEntry", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1521, __extension__ __PRETTY_FUNCTION__))
;
1522 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1523 assert(pItem)(static_cast <bool> (pItem) ? void (0) : __assert_fail (
"pItem", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1523, __extension__ __PRETTY_FUNCTION__))
;
1524 return pItem->GetBitmap2( );
1525}
1526
1527const Image& SvTreeListBox::GetCollapsedEntryBmp( const SvTreeListEntry* pEntry )
1528{
1529 assert(pEntry)(static_cast <bool> (pEntry) ? void (0) : __assert_fail
("pEntry", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1529, __extension__ __PRETTY_FUNCTION__))
;
1530 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1531 assert(pItem)(static_cast <bool> (pItem) ? void (0) : __assert_fail (
"pItem", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1531, __extension__ __PRETTY_FUNCTION__))
;
1532 return pItem->GetBitmap1( );
1533}
1534
1535IMPL_LINK( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData, void )void SvTreeListBox::LinkStubCheckButtonClick(void * instance,
SvLBoxButtonData * data) { return static_cast<SvTreeListBox
*>(instance)->CheckButtonClick(data); } void SvTreeListBox
::CheckButtonClick(SvLBoxButtonData * pData)
1536{
1537 pHdlEntry = pData->GetActEntry();
1538 CheckButtonHdl();
1539}
1540
1541SvTreeListEntry* SvTreeListBox::InsertEntry(
1542 const OUString& rText,
1543 SvTreeListEntry* pParent,
1544 bool bChildrenOnDemand, sal_uLong nPos,
1545 void* pUser
1546)
1547{
1548 nTreeFlags |= SvTreeFlags::MANINS;
1549
1550 const Image& rDefExpBmp = pImpl->GetDefaultEntryExpBmp( );
1551 const Image& rDefColBmp = pImpl->GetDefaultEntryColBmp( );
1552
1553 aCurInsertedExpBmp = rDefExpBmp;
1554 aCurInsertedColBmp = rDefColBmp;
1555
1556 SvTreeListEntry* pEntry = new SvTreeListEntry;
1557 pEntry->SetUserData( pUser );
1558 InitEntry( pEntry, rText, rDefColBmp, rDefExpBmp );
1559 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1560
1561 if( !pParent )
1562 Insert( pEntry, nPos );
1563 else
1564 Insert( pEntry, pParent, nPos );
1565
1566 aPrevInsertedExpBmp = rDefExpBmp;
1567 aPrevInsertedColBmp = rDefColBmp;
1568
1569 nTreeFlags &= ~SvTreeFlags::MANINS;
1570
1571 return pEntry;
1572}
1573
1574SvTreeListEntry* SvTreeListBox::InsertEntry( const OUString& rText,
1575 const Image& aExpEntryBmp, const Image& aCollEntryBmp,
1576 SvTreeListEntry* pParent, bool bChildrenOnDemand, sal_uLong nPos, void* pUser )
1577{
1578 nTreeFlags |= SvTreeFlags::MANINS;
1579
1580 aCurInsertedExpBmp = aExpEntryBmp;
1581 aCurInsertedColBmp = aCollEntryBmp;
1582
1583 SvTreeListEntry* pEntry = new SvTreeListEntry;
1584 pEntry->SetUserData( pUser );
1585 InitEntry( pEntry, rText, aCollEntryBmp, aExpEntryBmp );
1586
1587 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1588
1589 if( !pParent )
1590 Insert( pEntry, nPos );
1591 else
1592 Insert( pEntry, pParent, nPos );
1593
1594 aPrevInsertedExpBmp = aExpEntryBmp;
1595 aPrevInsertedColBmp = aCollEntryBmp;
1596
1597 nTreeFlags &= ~SvTreeFlags::MANINS;
1598
1599 return pEntry;
1600}
1601
1602void SvTreeListBox::SetEntryText(SvTreeListEntry* pEntry, const OUString& rStr)
1603{
1604 SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SvLBoxItemType::String));
1605 assert(pItem)(static_cast <bool> (pItem) ? void (0) : __assert_fail (
"pItem", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1605, __extension__ __PRETTY_FUNCTION__))
;
1606 pItem->SetText(rStr);
1607 pItem->InitViewData( this, pEntry );
1608 GetModel()->InvalidateEntry( pEntry );
1609}
1610
1611void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* pEntry, const Image& aBmp )
1612{
1613 SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1614
1615 assert(pItem)(static_cast <bool> (pItem) ? void (0) : __assert_fail (
"pItem", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1615, __extension__ __PRETTY_FUNCTION__))
;
1616 pItem->SetBitmap2( aBmp );
1617
1618 ModelHasEntryInvalidated(pEntry);
1619 SetEntryHeight( pEntry );
1620 Size aSize = aBmp.GetSizePixel();
1621 short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, static_cast<short>(aSize.Width()) );
1622 if( nWidth > nContextBmpWidthMax )
1623 {
1624 nContextBmpWidthMax = nWidth;
1625 SetTabs();
1626 }
1627}
1628
1629void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* pEntry,const Image& aBmp )
1630{
1631 SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1632
1633 assert(pItem)(static_cast <bool> (pItem) ? void (0) : __assert_fail (
"pItem", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 1633, __extension__ __PRETTY_FUNCTION__))
;
1634 pItem->SetBitmap1( aBmp );
1635
1636 ModelHasEntryInvalidated(pEntry);
1637 SetEntryHeight( pEntry );
1638 Size aSize = aBmp.GetSizePixel();
1639 short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, static_cast<short>(aSize.Width()) );
1640 if( nWidth > nContextBmpWidthMax )
1641 {
1642 nContextBmpWidthMax = nWidth;
1643 SetTabs();
1644 }
1645}
1646
1647void SvTreeListBox::CheckBoxInserted(SvTreeListEntry* pEntry)
1648{
1649 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
1650 if( pItem )
1651 {
1652 auto nWidth = pItem->GetWidth(this, pEntry);
1653 if( mnCheckboxItemWidth < nWidth )
1654 {
1655 mnCheckboxItemWidth = nWidth;
1656 nTreeFlags |= SvTreeFlags::RECALCTABS;
1657 }
1658 }
1659}
1660
1661void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* pEntry )
1662{
1663
1664 SvTreeListEntry* pParent = pModel->GetParent( pEntry );
1665 if( pParent )
1666 {
1667 SvTLEntryFlags nFlags = pParent->GetFlags();
1668 nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
1669 pParent->SetFlags( nFlags );
1670 }
1671
1672 if(!((nTreeFlags & SvTreeFlags::MANINS) &&
1673 (aPrevInsertedExpBmp == aCurInsertedExpBmp) &&
1674 (aPrevInsertedColBmp == aCurInsertedColBmp) ))
1675 {
1676 Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel();
1677 if( aSize.Width() > nContextBmpWidthMax )
1678 {
1679 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1680 nTreeFlags |= SvTreeFlags::RECALCTABS;
1681 }
1682 aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel();
1683 if( aSize.Width() > nContextBmpWidthMax )
1684 {
1685 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1686 nTreeFlags |= SvTreeFlags::RECALCTABS;
1687 }
1688 }
1689 SetEntryHeight( pEntry );
1690
1691 if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
1692 return;
1693
1694 CheckBoxInserted(pEntry);
1695}
1696
1697void SvTreeListBox::SetCheckButtonState( SvTreeListEntry* pEntry, SvButtonState eState)
1698{
1699 if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
1700 return;
1701
1702 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
1703 if(!pItem)
1704 return ;
1705 switch( eState )
1706 {
1707 case SvButtonState::Checked:
1708 pItem->SetStateChecked();
1709 break;
1710
1711 case SvButtonState::Unchecked:
1712 pItem->SetStateUnchecked();
1713 break;
1714
1715 case SvButtonState::Tristate:
1716 pItem->SetStateTristate();
1717 break;
1718 }
1719 InvalidateEntry( pEntry );
1720}
1721
1722SvButtonState SvTreeListBox::GetCheckButtonState( SvTreeListEntry* pEntry ) const
1723{
1724 SvButtonState eState = SvButtonState::Unchecked;
1725 if( pEntry && ( nTreeFlags & SvTreeFlags::CHKBTN ) )
1726 {
1727 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
1728 if(!pItem)
1729 return SvButtonState::Tristate;
1730 SvItemStateFlags nButtonFlags = pItem->GetButtonFlags();
1731 eState = SvLBoxButtonData::ConvertToButtonState( nButtonFlags );
1732 }
1733 return eState;
1734}
1735
1736void SvTreeListBox::CheckButtonHdl()
1737{
1738 if ( pCheckButtonData )
1739 pImpl->CallEventListeners( VclEventId::CheckboxToggle, static_cast<void*>(pCheckButtonData->GetActEntry()) );
1740}
1741
1742
1743// TODO: Currently all data is cloned so that they conform to the default tree
1744// view format. Actually, the model should be used as a reference here. This
1745// leads to us _not_ calling SvTreeListEntry::Clone, but only its base class
1746// SvTreeListEntry.
1747
1748
1749SvTreeListEntry* SvTreeListBox::CloneEntry( SvTreeListEntry* pSource )
1750{
1751 OUString aStr;
1752 Image aCollEntryBmp;
1753 Image aExpEntryBmp;
1754
1755 SvLBoxString* pStringItem = static_cast<SvLBoxString*>(pSource->GetFirstItem(SvLBoxItemType::String));
1756 if( pStringItem )
1757 aStr = pStringItem->GetText();
1758 SvLBoxContextBmp* pBmpItem = static_cast<SvLBoxContextBmp*>(pSource->GetFirstItem(SvLBoxItemType::ContextBmp));
1759 if( pBmpItem )
1760 {
1761 aCollEntryBmp = pBmpItem->GetBitmap1( );
1762 aExpEntryBmp = pBmpItem->GetBitmap2( );
1763 }
1764 SvTreeListEntry* pClone = new SvTreeListEntry;
1765 InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp );
1766 pClone->SvTreeListEntry::Clone( pSource );
1767 pClone->EnableChildrenOnDemand( pSource->HasChildrenOnDemand() );
1768 pClone->SetUserData( pSource->GetUserData() );
1769
1770 return pClone;
1771}
1772
1773const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( ) const
1774{
1775 return pImpl->GetDefaultEntryExpBmp( );
1776}
1777
1778const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( ) const
1779{
1780 return pImpl->GetDefaultEntryColBmp( );
1781}
1782
1783void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp )
1784{
1785 Size aSize = aBmp.GetSizePixel();
1786 if( aSize.Width() > nContextBmpWidthMax )
1787 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1788 SetTabs();
1789
1790 pImpl->SetDefaultEntryExpBmp( aBmp );
1791}
1792
1793void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp )
1794{
1795 Size aSize = aBmp.GetSizePixel();
1796 if( aSize.Width() > nContextBmpWidthMax )
1797 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1798 SetTabs();
1799
1800 pImpl->SetDefaultEntryColBmp( aBmp );
1801}
1802
1803void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData )
1804{
1805 if( !pData )
1806 nTreeFlags &= ~SvTreeFlags::CHKBTN;
1807 else
1808 {
1809 SetCheckButtonData( pData );
1810 nTreeFlags |= SvTreeFlags::CHKBTN;
1811 pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick)::tools::detail::makeLink( ::tools::detail::castTo<SvTreeListBox
*>(this), &SvTreeListBox::LinkStubCheckButtonClick)
);
1812 }
1813
1814 SetTabs();
1815 if( IsUpdateMode() )
1816 Invalidate();
1817}
1818
1819void SvTreeListBox::SetCheckButtonData( SvLBoxButtonData* pData )
1820{
1821 if ( pData )
1822 pCheckButtonData = pData;
1823}
1824
1825const Image& SvTreeListBox::GetDefaultExpandedNodeImage( )
1826{
1827 return SvImpLBox::GetDefaultExpandedNodeImage( );
1828}
1829
1830const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( )
1831{
1832 return SvImpLBox::GetDefaultCollapsedNodeImage( );
1833}
1834
1835void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, const Image& rExpandedNodeBmp )
1836{
1837 SetExpandedNodeBmp( rExpandedNodeBmp );
1838 SetCollapsedNodeBmp( rCollapsedNodeBmp );
1839 SetTabs();
1840}
1841
1842bool SvTreeListBox::EditingEntry( SvTreeListEntry* )
1843{
1844 return true;
1845}
1846
1847bool SvTreeListBox::EditedEntry( SvTreeListEntry* /*pEntry*/,const OUString& /*rNewText*/)
1848{
1849 return true;
1850}
1851
1852void SvTreeListBox::EnableInplaceEditing( bool bOn )
1853{
1854 if (bOn)
1855 nImpFlags |= SvTreeListBoxFlags::EDT_ENABLED;
1856 else
1857 nImpFlags &= ~SvTreeListBoxFlags::EDT_ENABLED;
1858}
1859
1860void SvTreeListBox::KeyInput( const KeyEvent& rKEvt )
1861{
1862 // under OS/2, we get key up/down even while editing
1863 if( IsEditingActive() )
1864 return;
1865
1866 if( !pImpl->KeyInput( rKEvt ) )
1867 {
1868 bool bHandled = HandleKeyInput( rKEvt );
1869 if ( !bHandled )
1870 Control::KeyInput( rKEvt );
1871 }
1872}
1873
1874void SvTreeListBox::RequestingChildren( SvTreeListEntry* pParent )
1875{
1876 if( !pParent->HasChildren() )
1877 InsertEntry( "<dummy>", pParent );
1878}
1879
1880void SvTreeListBox::GetFocus()
1881{
1882 //If there is no item in the tree, draw focus.
1883 if( !First())
1884 {
1885 Invalidate();
1886 }
1887 pImpl->GetFocus();
1888 Control::GetFocus();
1889
1890 SvTreeListEntry* pEntry = FirstSelected();
1891 if ( !pEntry )
1892 {
1893 pEntry = pImpl->GetCurEntry();
1894 }
1895 if (pImpl->m_pCursor)
1896 {
1897 if (pEntry != pImpl->m_pCursor)
1898 pEntry = pImpl->m_pCursor;
1899 }
1900 if ( pEntry )
1901 pImpl->CallEventListeners( VclEventId::ListboxTreeFocus, pEntry );
1902
1903}
1904
1905void SvTreeListBox::LoseFocus()
1906{
1907 // If there is no item in the tree, delete visual focus.
1908 if ( !First() )
1909 Invalidate();
1910 if ( pImpl )
1911 pImpl->LoseFocus();
1912 Control::LoseFocus();
1913}
1914
1915void SvTreeListBox::ModelHasCleared()
1916{
1917 pImpl->m_pCursor = nullptr; // else we crash in GetFocus when editing in-place
1918 pTargetEntry = nullptr;
1919 pEdCtrl.reset();
1920 pImpl->Clear();
1921 nFocusWidth = -1;
1922
1923 nContextBmpWidthMax = 0;
1924 SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() );
1925 SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() );
1926
1927 if( !(nTreeFlags & SvTreeFlags::FIXEDHEIGHT ))
1928 nEntryHeight = 0;
1929 AdjustEntryHeight();
1930 AdjustEntryHeight( GetDefaultExpandedEntryBmp() );
1931 AdjustEntryHeight( GetDefaultCollapsedEntryBmp() );
1932
1933 SvListView::ModelHasCleared();
1934}
1935
1936bool SvTreeListBox::PosOverBody(const Point& rPos) const
1937{
1938 if (rPos.X() < 0 || rPos.Y() < 0)
1939 return false;
1940 Size aSize(GetSizePixel());
1941 if (rPos.X() > aSize.Width() || rPos.Y() > aSize.Height())
1942 return false;
1943 if (pImpl->m_aVerSBar->IsVisible())
1944 {
1945 tools::Rectangle aRect(pImpl->m_aVerSBar->GetPosPixel(), pImpl->m_aVerSBar->GetSizePixel());
1946 if (aRect.IsInside(rPos))
1947 return false;
1948 }
1949 if (pImpl->m_aHorSBar->IsVisible())
1950 {
1951 tools::Rectangle aRect(pImpl->m_aHorSBar->GetPosPixel(), pImpl->m_aHorSBar->GetSizePixel());
1952 if (aRect.IsInside(rPos))
1953 return false;
1954 }
1955 return true;
1956}
1957
1958void SvTreeListBox::ScrollOutputArea( short nDeltaEntries )
1959{
1960 if( !nDeltaEntries || !pImpl->m_aVerSBar->IsVisible() )
1961 return;
1962
1963 long nThumb = pImpl->m_aVerSBar->GetThumbPos();
1964 long nMax = pImpl->m_aVerSBar->GetRange().Max();
1965
1966 if( nDeltaEntries < 0 )
1967 {
1968 // move window up
1969 nDeltaEntries *= -1;
1970 long nVis = pImpl->m_aVerSBar->GetVisibleSize();
1971 long nTemp = nThumb + nVis;
1972 if( nDeltaEntries > (nMax - nTemp) )
1973 nDeltaEntries = static_cast<short>(nMax - nTemp);
1974 pImpl->PageDown( static_cast<sal_uInt16>(nDeltaEntries) );
1975 }
1976 else
1977 {
1978 if( nDeltaEntries > nThumb )
1979 nDeltaEntries = static_cast<short>(nThumb);
1980 pImpl->PageUp( static_cast<sal_uInt16>(nDeltaEntries) );
1981 }
1982 pImpl->SyncVerThumb();
1983}
1984
1985void SvTreeListBox::ScrollToAbsPos( long nPos )
1986{
1987 pImpl->ScrollToAbsPos( nPos );
1988}
1989
1990void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode )
1991{
1992 eSelMode = eSelectMode;
1993 pImpl->SetSelectionMode( eSelectMode );
1994}
1995
1996void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode )
1997{
1998 nDragDropMode = nDDMode;
1999 pImpl->SetDragDropMode( nDDMode );
2000}
2001
2002void SvTreeListBox::SetEntryHeight( SvTreeListEntry const * pEntry )
2003{
2004 short nHeightMax=0;
2005 sal_uInt16 nCount = pEntry->ItemCount();
2006 sal_uInt16 nCur = 0;
2007 SvViewDataEntry* pViewData = GetViewDataEntry( pEntry );
2008 while( nCur < nCount )
2009 {
2010 auto nHeight = SvLBoxItem::GetHeight(pViewData, nCur);
2011 if( nHeight > nHeightMax )
2012 nHeightMax = nHeight;
2013 nCur++;
2014 }
2015
2016 if( nHeightMax > nEntryHeight )
2017 {
2018 nEntryHeight = nHeightMax;
2019 Control::SetFont( GetFont() );
2020 pImpl->SetEntryHeight();
2021 }
2022}
2023
2024void SvTreeListBox::SetEntryHeight( short nHeight )
2025{
2026 if( nHeight > nEntryHeight )
2027 {
2028 nEntryHeight = nHeight;
2029 if( nEntryHeight )
2030 nTreeFlags |= SvTreeFlags::FIXEDHEIGHT;
2031 else
2032 nTreeFlags &= ~SvTreeFlags::FIXEDHEIGHT;
2033 Control::SetFont( GetFont() );
2034 pImpl->SetEntryHeight();
2035 }
2036}
2037
2038void SvTreeListBox::SetEntryWidth( short nWidth )
2039{
2040 nEntryWidth = nWidth;
2041}
2042
2043void SvTreeListBox::AdjustEntryHeight( const Image& rBmp )
2044{
2045 const Size aSize( rBmp.GetSizePixel() );
2046 if( aSize.Height() > nEntryHeight )
2047 {
2048 nEntryHeight = static_cast<short>(aSize.Height()) + nEntryHeightOffs;
2049 pImpl->SetEntryHeight();
2050 }
2051}
2052
2053void SvTreeListBox::AdjustEntryHeight()
2054{
2055 Size aSize( GetTextWidth(OUString('X')), GetTextHeight() );
2056 if( aSize.Height() > nEntryHeight )
2057 {
2058 nEntryHeight = static_cast<short>(aSize.Height()) + nEntryHeightOffs;
2059 pImpl->SetEntryHeight();
2060 }
2061}
2062
2063bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
2064{
2065 pHdlEntry = pParent;
2066 bool bExpanded = false;
2067 SvTLEntryFlags nFlags;
2068
2069 if( pParent->HasChildrenOnDemand() )
2070 RequestingChildren( pParent );
2071 bool bExpandAllowed = pParent->HasChildren() && ExpandingHdl();
2072 // double check if the expander callback ended up removing all children
2073 if (pParent->HasChildren())
2074 {
2075 if (bExpandAllowed)
2076 {
2077 bExpanded = true;
2078 ExpandListEntry( pParent );
2079 pImpl->EntryExpanded( pParent );
2080 pHdlEntry = pParent;
2081 ExpandedHdl();
2082 SetAlternatingRowColors( mbAlternatingRowColors );
2083 }
2084 nFlags = pParent->GetFlags();
2085 nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
2086 nFlags |= SvTLEntryFlags::HAD_CHILDREN;
2087 pParent->SetFlags( nFlags );
2088 }
2089 else
2090 {
2091 nFlags = pParent->GetFlags();
2092 nFlags |= SvTLEntryFlags::NO_NODEBMP;
2093 pParent->SetFlags( nFlags );
2094 GetModel()->InvalidateEntry( pParent ); // repaint
2095 }
2096
2097 // #i92103#
2098 if ( bExpanded )
2099 {
2100 pImpl->CallEventListeners( VclEventId::ItemExpanded, pParent );
2101 }
2102
2103 return bExpanded;
2104}
2105
2106bool SvTreeListBox::Collapse( SvTreeListEntry* pParent )
2107{
2108 pHdlEntry = pParent;
2109 bool bCollapsed = false;
2110
2111 if( ExpandingHdl() )
2112 {
2113 bCollapsed = true;
2114 pImpl->CollapsingEntry( pParent );
2115 CollapseListEntry( pParent );
2116 pImpl->EntryCollapsed( pParent );
2117 pHdlEntry = pParent;
2118 ExpandedHdl();
2119 SetAlternatingRowColors( mbAlternatingRowColors );
2120 }
2121
2122 // #i92103#
2123 if ( bCollapsed )
2124 {
2125 pImpl->CallEventListeners( VclEventId::ItemCollapsed, pParent );
2126 }
2127
2128 return bCollapsed;
2129}
2130
2131bool SvTreeListBox::Select( SvTreeListEntry* pEntry, bool bSelect )
2132{
2133 DBG_ASSERT(pEntry,"Select: Null-Ptr")do { if (true && (!(pEntry))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "2133" ": "), "%s", "Select: Null-Ptr"); } } while (false
)
;
2134 bool bRetVal = SelectListEntry( pEntry, bSelect );
2135 DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed")do { if (true && (!(IsSelected(pEntry)==bSelect))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "2135" ": "), "%s", "Select failed"); } } while (false)
;
2136 if( bRetVal )
2137 {
2138 pImpl->EntrySelected( pEntry, bSelect );
2139 pHdlEntry = pEntry;
2140 if( bSelect )
2141 {
2142 SelectHdl();
2143 CallEventListeners( VclEventId::ListboxTreeSelect, pEntry);
2144 }
2145 else
2146 DeselectHdl();
2147 }
2148 return bRetVal;
2149}
2150
2151sal_uLong SvTreeListBox::SelectChildren( SvTreeListEntry* pParent, bool bSelect )
2152{
2153 pImpl->DestroyAnchor();
2154 sal_uLong nRet = 0;
2155 if( !pParent->HasChildren() )
2156 return 0;
2157 sal_uInt16 nRefDepth = pModel->GetDepth( pParent );
2158 SvTreeListEntry* pChild = FirstChild( pParent );
2159 do {
2160 nRet++;
2161 Select( pChild, bSelect );
2162 pChild = Next( pChild );
2163 } while( pChild && pModel->GetDepth( pChild ) > nRefDepth );
2164 return nRet;
2165}
2166
2167void SvTreeListBox::SelectAll( bool bSelect )
2168{
2169 pImpl->SelAllDestrAnch(
2170 bSelect,
2171 true, // delete anchor,
2172 true ); // even when using SelectionMode::Single, deselect the cursor
2173}
2174
2175void SvTreeListBox::ModelHasInsertedTree( SvTreeListEntry* pEntry )
2176{
2177 sal_uInt16 nRefDepth = pModel->GetDepth( pEntry );
2178 SvTreeListEntry* pTmp = pEntry;
2179 do
2180 {
2181 ImpEntryInserted( pTmp );
2182 pTmp = Next( pTmp );
2183 } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) );
2184 pImpl->TreeInserted( pEntry );
2185}
2186
2187void SvTreeListBox::ModelHasInserted( SvTreeListEntry* pEntry )
2188{
2189 ImpEntryInserted( pEntry );
2190 pImpl->EntryInserted( pEntry );
2191}
2192
2193void SvTreeListBox::ModelIsMoving(SvTreeListEntry* pSource )
2194{
2195 pImpl->MovingEntry( pSource );
2196}
2197
2198void SvTreeListBox::ModelHasMoved( SvTreeListEntry* pSource )
2199{
2200 pImpl->EntryMoved( pSource );
2201}
2202
2203void SvTreeListBox::ModelIsRemoving( SvTreeListEntry* pEntry )
2204{
2205 if(pEdEntry == pEntry)
2206 pEdEntry = nullptr;
2207
2208 pImpl->RemovingEntry( pEntry );
2209}
2210
2211void SvTreeListBox::ModelHasRemoved( SvTreeListEntry* pEntry )
2212{
2213 if (pEntry == pHdlEntry)
2214 pHdlEntry = nullptr;
2215
2216 if (pEntry == pTargetEntry)
2217 pTargetEntry = nullptr;
2218
2219 pImpl->EntryRemoved();
2220}
2221
2222void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp)
2223{
2224 AdjustEntryHeight( rBmp );
2225 pImpl->SetCollapsedNodeBmp( rBmp );
2226}
2227
2228void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp )
2229{
2230 AdjustEntryHeight( rBmp );
2231 pImpl->SetExpandedNodeBmp( rBmp );
2232}
2233
2234
2235void SvTreeListBox::SetFont( const vcl::Font& rFont )
2236{
2237 vcl::Font aTempFont( rFont );
2238 vcl::Font aOrigFont( GetFont() );
2239 aTempFont.SetTransparent( true );
2240 if (aTempFont == aOrigFont)
2241 return;
2242 Control::SetFont( aTempFont );
2243
2244 aTempFont.SetColor(aOrigFont.GetColor());
2245 aTempFont.SetFillColor(aOrigFont.GetFillColor());
2246 aTempFont.SetTransparent(aOrigFont.IsTransparent());
2247
2248 if (aTempFont == aOrigFont)
2249 return;
2250
2251 AdjustEntryHeightAndRecalc();
2252}
2253
2254void SvTreeListBox::AdjustEntryHeightAndRecalc()
2255{
2256 AdjustEntryHeight();
2257 // always invalidate, else things go wrong in SetEntryHeight
2258 RecalcViewData();
2259}
2260
2261void SvTreeListBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
2262{
2263 Control::Paint(rRenderContext, rRect);
2264 if (nTreeFlags & SvTreeFlags::RECALCTABS)
2265 SetTabs();
2266 pImpl->Paint(rRenderContext, rRect);
2267
2268 //Add visual focus draw
2269 if (First())
2270 return;
2271
2272 if (HasFocus())
2273 {
2274 long nHeight = rRenderContext.GetTextHeight();
2275 tools::Rectangle aRect(Point(0, 0), Size(GetSizePixel().Width(), nHeight));
2276 ShowFocus(aRect);
2277 }
2278 else
2279 {
2280 HideFocus();
2281 }
2282}
2283
2284void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
2285{
2286 pImpl->MouseButtonDown( rMEvt );
2287}
2288
2289void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt )
2290{
2291 pImpl->MouseButtonUp( rMEvt );
2292}
2293
2294void SvTreeListBox::MouseMove( const MouseEvent& rMEvt )
2295{
2296 pImpl->MouseMove( rMEvt );
2297}
2298
2299void SvTreeListBox::SetUpdateMode( bool bUpdate )
2300{
2301 pImpl->SetUpdateMode( bUpdate );
2302 mbUpdateAlternatingRows = bUpdate;
2303 SetAlternatingRowColors( mbAlternatingRowColors );
2304}
2305
2306void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic )
2307{
2308 if( nOffsLogic != nEntryHeightOffs )
2309 {
2310 nEntryHeight = nEntryHeight - nEntryHeightOffs;
2311 nEntryHeightOffs = nOffsLogic;
2312 nEntryHeight = nEntryHeight + nOffsLogic;
2313 AdjustEntryHeightAndRecalc();
2314 pImpl->SetEntryHeight();
2315 }
2316}
2317
2318void SvTreeListBox::SetCurEntry( SvTreeListEntry* pEntry )
2319{
2320 pImpl->SetCurEntry( pEntry );
2321}
2322
2323Image const & SvTreeListBox::GetExpandedNodeBmp( ) const
2324{
2325 return pImpl->GetExpandedNodeBmp( );
2326}
2327
2328Point SvTreeListBox::GetEntryPosition(const SvTreeListEntry* pEntry) const
2329{
2330 return pImpl->GetEntryPosition( pEntry );
2331}
2332
2333void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry )
2334{
2335 pImpl->MakeVisible(pEntry);
2336}
2337
2338void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop )
2339{
2340 pImpl->MakeVisible( pEntry, bMoveToTop );
2341}
2342
2343void SvTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* pEntry )
2344{
2345
2346 // reinitialize the separate items of the entries
2347 sal_uInt16 nCount = pEntry->ItemCount();
2348 for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++ )
2349 {
2350 SvLBoxItem& rItem = pEntry->GetItem( nIdx );
2351 rItem.InitViewData( this, pEntry );
2352 }
2353
2354 // repaint
2355 pImpl->InvalidateEntry( pEntry );
2356}
2357
2358void SvTreeListBox::EditItemText(SvTreeListEntry* pEntry, SvLBoxString* pItem, const Selection& rSelection)
2359{
2360 assert(pEntry && pItem)(static_cast <bool> (pEntry && pItem) ? void (0
) : __assert_fail ("pEntry && pItem", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 2360, __extension__ __PRETTY_FUNCTION__))
;
18
'?' condition is true
2361 if( IsSelected( pEntry ))
19
Assuming the condition is false
20
Taking false branch
2362 {
2363 pImpl->ShowCursor( false );
2364 SelectListEntry( pEntry, false );
2365 pImpl->InvalidateEntry(pEntry);
2366 SelectListEntry( pEntry, true );
2367 pImpl->ShowCursor( true );
2368 }
2369 pEdEntry = pEntry;
2370 pEdItem = pItem;
2371 SvLBoxTab* pTab = GetTab( pEntry, pItem );
2372 DBG_ASSERT(pTab,"EditItemText:Tab not found")do { if (true && (!(pTab))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "2372" ": "), "%s", "EditItemText:Tab not found"); } } while
(false)
;
21
Assuming 'pTab' is non-null
22
Taking false branch
23
Loop condition is false. Exiting loop
2373
2374 auto nItemHeight( pItem->GetHeight(this, pEntry) );
2375 Point aPos = GetEntryPosition( pEntry );
2376 aPos.AdjustY(( nEntryHeight - nItemHeight ) / 2 );
2377 aPos.setX( GetTabPos( pEntry, pTab ) );
2378 long nOutputWidth = pImpl->GetOutputSize().Width();
2379 Size aSize( nOutputWidth - aPos.X(), nItemHeight );
2380 sal_uInt16 nPos = std::find_if( aTabs.begin(), aTabs.end(),
2381 [pTab](const std::unique_ptr<SvLBoxTab>& p) { return p.get() == pTab; })
2382 - aTabs.begin();
2383 if( nPos+1 < static_cast<sal_uInt16>(aTabs.size()) )
24
Assuming the condition is false
25
Taking false branch
2384 {
2385 SvLBoxTab* pRightTab = aTabs[ nPos + 1 ].get();
2386 long nRight = GetTabPos( pEntry, pRightTab );
2387 if( nRight <= nOutputWidth )
2388 aSize.setWidth( nRight - aPos.X() );
2389 }
2390 Point aOrigin( GetMapMode().GetOrigin() );
2391 aPos += aOrigin; // convert to win coordinates
2392 aSize.AdjustWidth( -(aOrigin.X()) );
2393 tools::Rectangle aRect( aPos, aSize );
2394 EditText( pItem->GetText(), aRect, rSelection );
26
Calling 'SvTreeListBox::EditText'
2395}
2396
2397void SvTreeListBox::EditEntry( SvTreeListEntry* pEntry )
2398{
2399 pImpl->m_aEditClickPos = Point( -1, -1 );
2400 ImplEditEntry( pEntry );
1
Calling 'SvTreeListBox::ImplEditEntry'
2401}
2402
2403void SvTreeListBox::ImplEditEntry( SvTreeListEntry* pEntry )
2404{
2405 if( IsEditingActive() )
2
Taking false branch
2406 EndEditing();
2407 if( !pEntry )
3
Assuming 'pEntry' is non-null
4
Taking false branch
2408 pEntry = GetCurEntry();
2409 if( !pEntry
4.1
'pEntry' is non-null
4.1
'pEntry' is non-null
4.1
'pEntry' is non-null
4.1
'pEntry' is non-null
)
5
Taking false branch
2410 return;
2411
2412 long nClickX = pImpl->m_aEditClickPos.X();
2413 bool bIsMouseTriggered = nClickX >= 0;
2414
2415 SvLBoxString* pItem = nullptr;
2416 sal_uInt16 nCount = pEntry->ItemCount();
2417 long nTabPos, nNextTabPos = 0;
2418 for( sal_uInt16 i = 0 ; i < nCount ; i++ )
6
Assuming 'i' is < 'nCount'
7
Loop condition is true. Entering loop body
2419 {
2420 SvLBoxItem& rTmpItem = pEntry->GetItem( i );
2421 if (rTmpItem.GetType() != SvLBoxItemType::String)
8
Assuming the condition is false
9
Taking false branch
2422 continue;
2423
2424 SvLBoxTab* pTab = GetTab( pEntry, &rTmpItem );
2425 nNextTabPos = -1;
2426 if( i < nCount - 1 )
10
Assuming the condition is false
11
Taking false branch
2427 {
2428 SvLBoxItem& rNextItem = pEntry->GetItem( i + 1 );
2429 SvLBoxTab* pNextTab = GetTab( pEntry, &rNextItem );
2430 nNextTabPos = pNextTab->GetPos();
2431 }
2432
2433 if( pTab && pTab->IsEditable() )
12
Assuming 'pTab' is non-null
13
Taking true branch
2434 {
2435 nTabPos = pTab->GetPos();
2436 if( !bIsMouseTriggered
13.1
'bIsMouseTriggered' is false
13.1
'bIsMouseTriggered' is false
13.1
'bIsMouseTriggered' is false
13.1
'bIsMouseTriggered' is false
|| (nClickX > nTabPos && (nNextTabPos == -1 || nClickX < nNextTabPos ) ) )
2437 {
2438 pItem = static_cast<SvLBoxString*>( &rTmpItem );
2439 break;
14
Execution continues on line 2444
2440 }
2441 }
2442 }
2443
2444 if( pItem
14.1
'pItem' is non-null
14.1
'pItem' is non-null
14.1
'pItem' is non-null
14.1
'pItem' is non-null
&& EditingEntry( pEntry ) )
15
Assuming the condition is true
16
Taking true branch
2445 {
2446 Selection aSel( SELECTION_MIN(-9223372036854775807L -1L), SELECTION_MAX9223372036854775807L );
2447 SelectAll( false );
2448 MakeVisible( pEntry );
2449 EditItemText( pEntry, pItem, aSel );
17
Calling 'SvTreeListBox::EditItemText'
2450 }
2451}
2452
2453void SvTreeListBox::EditedText( const OUString& rStr )
2454
2455{
2456 if(pEdEntry) // we have to check if this entry is null that means that it is removed while editing
2457 {
2458 if( EditedEntry( pEdEntry, rStr ) )
2459 {
2460 static_cast<SvLBoxString*>(pEdItem)->SetText( rStr );
2461 pModel->InvalidateEntry( pEdEntry );
2462 }
2463 if( GetSelectionCount() == 0 )
2464 Select( pEdEntry );
2465 if( GetSelectionMode() == SelectionMode::Multiple && !GetCurEntry() )
2466 SetCurEntry( pEdEntry );
2467 }
2468}
2469
2470SvTreeListEntry* SvTreeListBox::GetDropTarget( const Point& rPos )
2471{
2472 // scroll
2473 if( rPos.Y() < 12 )
2474 {
2475 ImplShowTargetEmphasis(pTargetEntry, false);
2476 ScrollOutputArea( +1 );
2477 }
2478 else
2479 {
2480 Size aSize( pImpl->GetOutputSize() );
2481 if( rPos.Y() > aSize.Height() - 12 )
2482 {
2483 ImplShowTargetEmphasis(pTargetEntry, false);
2484 ScrollOutputArea( -1 );
2485 }
2486 }
2487
2488 SvTreeListEntry* pTarget = pImpl->GetEntry( rPos );
2489 // when dropping in a vacant space, use the last entry
2490 if( !pTarget )
2491 return LastVisible();
2492 else if( (GetDragDropMode() & DragDropMode::ENABLE_TOP) &&
2493 pTarget == First() && rPos.Y() < 6 )
2494 return nullptr;
2495
2496 return pTarget;
2497}
2498
2499
2500SvTreeListEntry* SvTreeListBox::GetEntry( const Point& rPos, bool bHit ) const
2501{
2502 SvTreeListEntry* pEntry = pImpl->GetEntry( rPos );
2503 if( pEntry && bHit )
2504 {
2505 long nLine = pImpl->GetEntryLine( pEntry );
2506 if( !(pImpl->EntryReallyHit( pEntry, rPos, nLine)) )
2507 return nullptr;
2508 }
2509 return pEntry;
2510}
2511
2512SvTreeListEntry* SvTreeListBox::GetCurEntry() const
2513{
2514 return pImpl ? pImpl->GetCurEntry() : nullptr;
2515}
2516
2517void SvTreeListBox::ImplInitStyle()
2518{
2519 const WinBits nWindowStyle = GetStyle();
2520
2521 nTreeFlags |= SvTreeFlags::RECALCTABS;
2522 if (nWindowStyle & WB_SORT)
2523 {
2524 GetModel()->SetSortMode(SortAscending);
2525 GetModel()->SetCompareHdl(LINK(this, SvTreeListBox, DefaultCompare)::tools::detail::makeLink( ::tools::detail::castTo<SvTreeListBox
*>(this), &SvTreeListBox::LinkStubDefaultCompare)
);
2526 }
2527 else
2528 {
2529 GetModel()->SetSortMode(SortNone);
2530 GetModel()->SetCompareHdl(Link<const SvSortData&,sal_Int32>());
2531 }
2532 pImpl->SetStyle(nWindowStyle);
2533 pImpl->Resize();
2534 Invalidate();
2535}
2536
2537void SvTreeListBox::InvalidateEntry(SvTreeListEntry* pEntry)
2538{
2539 DBG_ASSERT(pEntry,"InvalidateEntry:No Entry")do { if (true && (!(pEntry))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "2539" ": "), "%s", "InvalidateEntry:No Entry"); } } while
(false)
;
2540 if (pEntry)
2541 {
2542 GetModel()->InvalidateEntry(pEntry);
2543 }
2544}
2545
2546void SvTreeListBox::PaintEntry1(SvTreeListEntry& rEntry, long nLine, vcl::RenderContext& rRenderContext)
2547{
2548 tools::Rectangle aRect; // multi purpose
2549
2550 bool bHorSBar = pImpl->HasHorScrollBar();
2551
2552 pImpl->UpdateContextBmpWidthMax(&rEntry);
2553
2554 if (nTreeFlags & SvTreeFlags::RECALCTABS)
2555 SetTabs();
2556
2557 short nTempEntryHeight = GetEntryHeight();
2558 long nWidth = pImpl->GetOutputSize().Width();
2559
2560 // Did we turn on the scrollbar within PreparePaints? If yes, we have to set
2561 // the ClipRegion anew.
2562 if (!bHorSBar && pImpl->HasHorScrollBar())
2563 rRenderContext.SetClipRegion(vcl::Region(pImpl->GetClipRegionRect()));
2564
2565 Point aEntryPos(rRenderContext.GetMapMode().GetOrigin());
2566 aEntryPos.setX( aEntryPos.X() * -1 ); // conversion document coordinates
2567 long nMaxRight = nWidth + aEntryPos.X() - 1;
2568
2569 Color aBackupTextColor(rRenderContext.GetTextColor());
2570 vcl::Font aBackupFont(rRenderContext.GetFont());
2571 Color aBackupColor = rRenderContext.GetFillColor();
2572
2573 bool bCurFontIsSel = false;
2574 // if a ClipRegion was set from outside, we don't have to reset it
2575 const WinBits nWindowStyle = GetStyle();
2576 const bool bHideSelection = (nWindowStyle & WB_HIDESELECTION) !=0 && !HasFocus();
2577 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
2578
2579 vcl::Font aHighlightFont(rRenderContext.GetFont());
2580 const Color aHighlightTextColor(rSettings.GetHighlightTextColor());
2581 aHighlightFont.SetColor(aHighlightTextColor);
2582
2583 Size aRectSize(0, nTempEntryHeight);
2584
2585 SvViewDataEntry* pViewDataEntry = GetViewDataEntry( &rEntry );
2586
2587 const size_t nTabCount = aTabs.size();
2588 const size_t nItemCount = rEntry.ItemCount();
2589 size_t nCurTab = 0;
2590 size_t nCurItem = 0;
2591
2592 while (nCurTab < nTabCount && nCurItem < nItemCount)
2593 {
2594 SvLBoxTab* pTab = aTabs[nCurTab].get();
2595 const size_t nNextTab = nCurTab + 1;
2596 SvLBoxTab* pNextTab = nNextTab < nTabCount ? aTabs[nNextTab].get() : nullptr;
2597 SvLBoxItem& rItem = rEntry.GetItem(nCurItem);
2598
2599 SvLBoxTabFlags nFlags = pTab->nFlags;
2600 Size aSize(rItem.GetWidth(this, pViewDataEntry, nCurItem),
2601 SvLBoxItem::GetHeight(pViewDataEntry, nCurItem));
2602 long nTabPos = GetTabPos(&rEntry, pTab);
2603
2604 long nNextTabPos;
2605 if (pNextTab)
2606 nNextTabPos = GetTabPos(&rEntry, pNextTab);
2607 else
2608 {
2609 nNextTabPos = nMaxRight;
2610 if (nTabPos > nMaxRight)
2611 nNextTabPos += 50;
2612 }
2613
2614 long nX;
2615 if( pTab->nFlags & SvLBoxTabFlags::ADJUST_RIGHT )
2616 // avoid cutting the right edge off the tab separation
2617 nX = nTabPos + pTab->CalcOffset(aSize.Width(), (nNextTabPos - SV_TAB_BORDER8 - 1) - nTabPos);
2618 else
2619 nX = nTabPos + pTab->CalcOffset(aSize.Width(), nNextTabPos - nTabPos);
2620
2621 aEntryPos.setX( nX );
2622 aEntryPos.setY( nLine );
2623
2624 // set background pattern/color
2625
2626 Wallpaper aWallpaper = rRenderContext.GetBackground();
2627
2628 bool bSelTab = bool(nFlags & SvLBoxTabFlags::SHOW_SELECTION);
2629
2630 if (pViewDataEntry->IsHighlighted() && bSelTab)
2631 {
2632 Color aNewWallColor = rSettings.GetHighlightColor();
2633 // if the face color is bright then the deactivate color is also bright
2634 // -> so you can't see any deactivate selection
2635 if (bHideSelection && !rSettings.GetFaceColor().IsBright()
2636 && aWallpaper.GetColor().IsBright() != rSettings.GetDeactiveColor().IsBright())
2637 {
2638 aNewWallColor = rSettings.GetDeactiveColor();
2639 }
2640 // set font color to highlight
2641 if (!bCurFontIsSel)
2642 {
2643 rRenderContext.SetTextColor(aHighlightTextColor);
2644 rRenderContext.SetFont(aHighlightFont);
2645 bCurFontIsSel = true;
2646 }
2647 aWallpaper.SetColor(aNewWallColor);
2648 }
2649 else // no selection
2650 {
2651 if (bCurFontIsSel || rEntry.GetTextColor())
2652 {
2653 bCurFontIsSel = false;
2654 if (const auto & xCustomTextColor = rEntry.GetTextColor())
2655 rRenderContext.SetTextColor(*xCustomTextColor);
2656 else
2657 rRenderContext.SetTextColor(aBackupTextColor);
2658 rRenderContext.SetFont(aBackupFont);
2659 }
2660 else
2661 {
2662 aWallpaper.SetColor(rEntry.GetBackColor());
2663 }
2664 }
2665
2666 // draw background
2667 if (!(nTreeFlags & SvTreeFlags::USESEL))
2668 {
2669 // only draw the area that is used by the item
2670 aRectSize.setWidth( aSize.Width() );
2671 aRect.SetPos(aEntryPos);
2672 aRect.SetSize(aRectSize);
2673 }
2674 else
2675 {
2676 // draw from the current to the next tab
2677 if (nCurTab != 0)
2678 aRect.SetLeft( nTabPos );
2679 else
2680 // if we're in the 0th tab, always draw from column 0 --
2681 // else we get problems with centered tabs
2682 aRect.SetLeft( 0 );
2683 aRect.SetTop( nLine );
2684 aRect.SetBottom( nLine + nTempEntryHeight - 1 );
2685 if (pNextTab)
2686 {
2687 long nRight;
2688 nRight = GetTabPos(&rEntry, pNextTab) - 1;
2689 if (nRight > nMaxRight)
2690 nRight = nMaxRight;
2691 aRect.SetRight( nRight );
2692 }
2693 else
2694 {
2695 aRect.SetRight( nMaxRight );
2696 }
2697 }
2698 // A custom selection that starts at a tab position > 0, do not fill
2699 // the background of the 0th item, else e.g. we might not be able to
2700 // realize tab listboxes with lines.
2701 if (!(nCurTab == 0 && (nTreeFlags & SvTreeFlags::USESEL) && nFirstSelTab))
2702 {
2703 Color aBackgroundColor = aWallpaper.GetColor();
2704 if (aBackgroundColor != COL_TRANSPARENT)
2705 {
2706 rRenderContext.SetFillColor(aBackgroundColor);
2707 // this case may occur for smaller horizontal resizes
2708 if (aRect.Left() < aRect.Right())
2709 rRenderContext.DrawRect(aRect);
2710 }
2711 }
2712 // draw item
2713 // center vertically
2714 aEntryPos.AdjustY((nTempEntryHeight - aSize.Height()) / 2 );
2715
2716 rItem.Paint(aEntryPos, *this, rRenderContext, pViewDataEntry, rEntry);
2717
2718 // division line between tabs
2719 if (pNextTab && rItem.GetType() == SvLBoxItemType::String &&
2720 // not at the right edge of the window!
2721 aRect.Right() < nMaxRight)
2722 {
2723 aRect.SetLeft( aRect.Right() - SV_TAB_BORDER8 );
2724 rRenderContext.DrawRect(aRect);
2725 }
2726
2727 rRenderContext.SetFillColor(aBackupColor);
2728
2729 nCurItem++;
2730 nCurTab++;
2731 }
2732
2733 if (pViewDataEntry->IsDragTarget())
2734 {
2735 rRenderContext.Push();
2736 rRenderContext.SetLineColor(rSettings.GetDeactiveColor());
2737 rRenderContext.SetFillColor(rSettings.GetDeactiveColor());
2738 rRenderContext.DrawRect(tools::Rectangle(Point(0, nLine), Size(nWidth, 2)));
2739 rRenderContext.Pop();
2740 }
2741
2742 if (bCurFontIsSel || rEntry.GetTextColor())
2743 {
2744 rRenderContext.SetTextColor(aBackupTextColor);
2745 rRenderContext.SetFont(aBackupFont);
2746 }
2747
2748 sal_uInt16 nFirstDynTabPos(0);
2749 SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab(nFirstDynTabPos);
2750 long nDynTabPos = GetTabPos(&rEntry, pFirstDynamicTab);
2751 nDynTabPos += pImpl->m_nNodeBmpTabDistance;
2752 nDynTabPos += pImpl->m_nNodeBmpWidth / 2;
2753 nDynTabPos += 4; // 4 pixels of buffer, so the node bitmap is not too close
2754 // to the next tab
2755
2756 if( !((!(rEntry.GetFlags() & SvTLEntryFlags::NO_NODEBMP)) &&
2757 (nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab &&
2758 (rEntry.HasChildren() || rEntry.HasChildrenOnDemand())))
2759 return;
2760
2761 // find first tab and check if the node bitmap extends into it
2762 sal_uInt16 nNextTab = nFirstDynTabPos;
2763 SvLBoxTab* pNextTab;
2764 do
2765 {
2766 nNextTab++;
2767 pNextTab = nNextTab < nTabCount ? aTabs[nNextTab].get() : nullptr;
2768 } while (pNextTab && pNextTab->IsDynamic());
2769
2770 if (pNextTab && (GetTabPos( &rEntry, pNextTab ) <= nDynTabPos))
2771 return;
2772
2773 if (!((nWindowStyle & WB_HASBUTTONSATROOT) || pModel->GetDepth(&rEntry) > 0))
2774 return;
2775
2776 Point aPos(GetTabPos(&rEntry, pFirstDynamicTab), nLine);
2777 aPos.AdjustX(pImpl->m_nNodeBmpTabDistance );
2778
2779 const Image* pImg = nullptr;
2780
2781 if (IsExpanded(&rEntry))
2782 pImg = &pImpl->GetExpandedNodeBmp();
2783 else
2784 {
2785 if ((!rEntry.HasChildren()) && rEntry.HasChildrenOnDemand() &&
2786 (!(rEntry.GetFlags() & SvTLEntryFlags::HAD_CHILDREN)) &&
2787 pImpl->GetDontKnowNodeBmp().GetSizePixel().Width())
2788 {
2789 pImg = &pImpl->GetDontKnowNodeBmp( );
2790 }
2791 else
2792 {
2793 pImg = &pImpl->GetCollapsedNodeBmp( );
2794 }
2795 }
2796 aPos.AdjustY((nTempEntryHeight - pImg->GetSizePixel().Height()) / 2 );
2797
2798 DrawImageFlags nStyle = DrawImageFlags::NONE;
2799 if (!IsEnabled())
2800 nStyle |= DrawImageFlags::Disable;
2801
2802 //native
2803 bool bNativeOK = false;
2804 if (rRenderContext.IsNativeControlSupported(ControlType::ListNode, ControlPart::Entire))
2805 {
2806 ImplControlValue aControlValue;
2807 tools::Rectangle aCtrlRegion(aPos, pImg->GetSizePixel());
2808 ControlState nState = ControlState::NONE;
2809
2810 if (IsEnabled())
2811 nState |= ControlState::ENABLED;
2812
2813 if (IsExpanded(&rEntry))
2814 aControlValue.setTristateVal(ButtonValue::On); //expanded node
2815 else
2816 {
2817 if ((!rEntry.HasChildren()) && rEntry.HasChildrenOnDemand() &&
2818 (!(rEntry.GetFlags() & SvTLEntryFlags::HAD_CHILDREN)) &&
2819 pImpl->GetDontKnowNodeBmp().GetSizePixel().Width())
2820 {
2821 aControlValue.setTristateVal( ButtonValue::DontKnow ); //don't know
2822 }
2823 else
2824 {
2825 aControlValue.setTristateVal( ButtonValue::Off ); //collapsed node
2826 }
2827 }
2828
2829 bNativeOK = rRenderContext.DrawNativeControl(ControlType::ListNode, ControlPart::Entire, aCtrlRegion, nState, aControlValue, OUString());
2830 }
2831
2832 if (!bNativeOK)
2833 {
2834 rRenderContext.DrawImage(aPos, *pImg ,nStyle);
2835 }
2836}
2837
2838void SvTreeListBox::DrawCustomEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const SvTreeListEntry& rEntry)
2839{
2840 aCustomRenderHdl.Call(std::tuple<vcl::RenderContext&, const tools::Rectangle&, const SvTreeListEntry&>(rRenderContext, rRect, rEntry));
2841}
2842
2843Size SvTreeListBox::MeasureCustomEntry(vcl::RenderContext& rRenderContext, const SvTreeListEntry& rEntry)
2844{
2845 return aCustomMeasureHdl.Call(std::pair<vcl::RenderContext&, const SvTreeListEntry&>(rRenderContext, rEntry));
2846}
2847
2848tools::Rectangle SvTreeListBox::GetFocusRect(const SvTreeListEntry* pEntry, long nLine )
2849{
2850 pImpl->UpdateContextBmpWidthMax( pEntry );
2851
2852 Size aSize;
2853 tools::Rectangle aRect;
2854 aRect.SetTop( nLine );
2855 aSize.setHeight( GetEntryHeight() );
2856
2857 long nRealWidth = pImpl->GetOutputSize().Width();
2858 nRealWidth -= GetMapMode().GetOrigin().X();
2859
2860 sal_uInt16 nCurTab;
2861 SvLBoxTab* pTab = GetFirstTab( SvLBoxTabFlags::SHOW_SELECTION, nCurTab );
2862 long nTabPos = 0;
2863 if( pTab )
2864 nTabPos = GetTabPos( pEntry, pTab );
2865 long nNextTabPos;
2866 if( pTab && nCurTab < aTabs.size() - 1 )
2867 {
2868 SvLBoxTab* pNextTab = aTabs[ nCurTab + 1 ].get();
2869 nNextTabPos = GetTabPos( pEntry, pNextTab );
2870 }
2871 else
2872 {
2873 nNextTabPos = nRealWidth;
2874 if( nTabPos > nRealWidth )
2875 nNextTabPos += 50;
2876 }
2877
2878 bool bUserSelection = bool( nTreeFlags & SvTreeFlags::USESEL );
2879 if( !bUserSelection )
2880 {
2881 if( pTab && nCurTab < pEntry->ItemCount() )
2882 {
2883 const SvLBoxItem& rItem = pEntry->GetItem( nCurTab );
2884 aSize.setWidth(rItem.GetWidth(this, pEntry));
2885 if( !aSize.Width() )
2886 aSize.setWidth( 15 );
2887 long nX = nTabPos; //GetTabPos( pEntry, pTab );
2888 // alignment
2889 nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos );
2890 aRect.SetLeft( nX );
2891 // make sure that first and last letter aren't cut off slightly
2892 aRect.SetSize( aSize );
2893 if( aRect.Left() > 0 )
2894 aRect.AdjustLeft( -1 );
2895 aRect.AdjustRight( 1 );
2896 }
2897 }
2898 else
2899 {
2900 // if SelTab != 0, we have to calculate also
2901 if( nFocusWidth == -1 || nFirstSelTab )
2902 {
2903 SvLBoxTab* pLastTab = nullptr; // default to select whole width
2904
2905 sal_uInt16 nLastTab;
2906 GetLastTab(SvLBoxTabFlags::SHOW_SELECTION,nLastTab);
2907 nLastTab++;
2908 if( nLastTab < aTabs.size() ) // is there another one?
2909 pLastTab = aTabs[ nLastTab ].get();
2910
2911 aSize.setWidth( pLastTab ? pLastTab->GetPos() : 0x0fffffff );
2912 nFocusWidth = static_cast<short>(aSize.Width());
2913 if( pTab )
2914 nFocusWidth = nFocusWidth - static_cast<short>(nTabPos); //pTab->GetPos();
2915 }
2916 else
2917 {
2918 aSize.setWidth( nFocusWidth );
2919 if( pTab )
2920 {
2921 if( nCurTab )
2922 aSize.AdjustWidth(nTabPos );
2923 else
2924 aSize.AdjustWidth(pTab->GetPos() ); // Tab0 always from the leftmost position
2925 }
2926 }
2927 // if selection starts with 0th tab, draw from column 0 on
2928 if( nCurTab != 0 )
2929 {
2930 aRect.SetLeft( nTabPos );
2931 aSize.AdjustWidth( -nTabPos );
2932 }
2933 aRect.SetSize( aSize );
2934 }
2935 // adjust right edge because of clipping
2936 if( aRect.Right() >= nRealWidth )
2937 {
2938 aRect.SetRight( nRealWidth-1 );
2939 nFocusWidth = static_cast<short>(aRect.GetWidth());
2940 }
2941 return aRect;
2942}
2943
2944sal_IntPtr SvTreeListBox::GetTabPos(const SvTreeListEntry* pEntry, const SvLBoxTab* pTab)
2945{
2946 assert(pTab)(static_cast <bool> (pTab) ? void (0) : __assert_fail (
"pTab", "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 2946, __extension__ __PRETTY_FUNCTION__))
;
2947 sal_IntPtr nPos = pTab->GetPos();
2948 if( pTab->IsDynamic() )
2949 {
2950 sal_uInt16 nDepth = pModel->GetDepth( pEntry );
2951 nDepth = nDepth * static_cast<sal_uInt16>(nIndent);
2952 nPos += static_cast<sal_IntPtr>(nDepth);
2953 }
2954 return nPos + (pEntry->GetExtraIndent() * nIndent);
2955}
2956
2957SvLBoxItem* SvTreeListBox::GetItem_Impl( SvTreeListEntry* pEntry, long nX,
2958 SvLBoxTab** ppTab )
2959{
2960 SvLBoxItem* pItemClicked = nullptr;
2961 sal_uInt16 nTabCount = aTabs.size();
2962 sal_uInt16 nItemCount = pEntry->ItemCount();
2963 SvLBoxTab* pTab = aTabs.front().get();
2964 SvLBoxItem* pItem = &pEntry->GetItem(0);
2965 sal_uInt16 nNextItem = 1;
2966 nX -= GetMapMode().GetOrigin().X();
2967 long nRealWidth = pImpl->GetOutputSize().Width();
2968 nRealWidth -= GetMapMode().GetOrigin().X();
2969
2970 while( true )
2971 {
2972 SvLBoxTab* pNextTab=nNextItem<nTabCount ? aTabs[nNextItem].get() : nullptr;
2973 long nStart = GetTabPos( pEntry, pTab );
2974
2975 long nNextTabPos;
2976 if( pNextTab )
2977 nNextTabPos = GetTabPos( pEntry, pNextTab );
2978 else
2979 {
2980 nNextTabPos = nRealWidth;
2981 if( nStart > nRealWidth )
2982 nNextTabPos += 50;
2983 }
2984
2985 auto nItemWidth(pItem->GetWidth(this, pEntry));
2986 nStart += pTab->CalcOffset(nItemWidth, nNextTabPos - nStart);
2987 auto nLen = nItemWidth;
2988 if( pNextTab )
2989 {
2990 long nTabWidth = GetTabPos( pEntry, pNextTab ) - nStart;
2991 if( nTabWidth < nLen )
2992 nLen = nTabWidth;
2993 }
2994
2995 if( nX >= nStart && nX < (nStart+nLen ) )
2996 {
2997 pItemClicked = pItem;
2998 if( ppTab )
2999 {
3000 *ppTab = pTab;
3001 break;
3002 }
3003 }
3004 if( nNextItem >= nItemCount || nNextItem >= nTabCount)
3005 break;
3006 pTab = aTabs[ nNextItem ].get();
3007 pItem = &pEntry->GetItem( nNextItem );
3008 nNextItem++;
3009 }
3010 return pItemClicked;
3011}
3012
3013long SvTreeListBox::getPreferredDimensions(std::vector<long> &rWidths) const
3014{
3015 long nHeight = 0;
3016 rWidths.clear();
3017 SvTreeListEntry* pEntry = First();
3018 while (pEntry)
3019 {
3020 sal_uInt16 nCount = pEntry->ItemCount();
3021 sal_uInt16 nCurPos = 0;
3022 if (nCount > rWidths.size())
3023 rWidths.resize(nCount);
3024 while (nCurPos < nCount)
3025 {
3026 SvLBoxItem& rItem = pEntry->GetItem( nCurPos );
3027 auto nWidth = rItem.GetWidth(this, pEntry);
3028 if (nWidth)
3029 {
3030 nWidth += SV_TAB_BORDER8 * 2;
3031 if (nWidth > rWidths[nCurPos])
3032 rWidths[nCurPos] = nWidth;
3033 }
3034 ++nCurPos;
3035 }
3036 pEntry = Next( pEntry );
3037 nHeight += GetEntryHeight();
3038 }
3039 return nHeight;
3040}
3041
3042Size SvTreeListBox::GetOptimalSize() const
3043{
3044 std::vector<long> aWidths;
3045 Size aRet(0, getPreferredDimensions(aWidths));
3046 for (long aWidth : aWidths)
3047 aRet.AdjustWidth(aWidth );
3048 if (GetStyle() & WB_BORDER)
3049 {
3050 aRet.AdjustWidth(StyleSettings::GetBorderSize() * 2 );
3051 aRet.AdjustHeight(StyleSettings::GetBorderSize() * 2 );
3052 }
3053 long nMinWidth = nMinWidthInChars * approximate_char_width();
3054 aRet.setWidth( std::max(aRet.Width(), nMinWidth) );
3055
3056 if (GetStyle() & WB_VSCROLL)
3057 aRet.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize());
3058
3059 return aRet;
3060}
3061
3062void SvTreeListBox::SetAlternatingRowColors( bool bEnable )
3063{
3064 if( !mbUpdateAlternatingRows )
3065 {
3066 mbAlternatingRowColors = bEnable;
3067 return;
3068 }
3069
3070 if( bEnable )
3071 {
3072 SvTreeListEntry* pEntry = pModel->First();
3073 for(size_t i = 0; pEntry; ++i)
3074 {
3075 pEntry->SetBackColor( i % 2 == 0 ? GetBackground().GetColor() : GetSettings().GetStyleSettings().GetAlternatingRowColor());
3076 SvTreeListEntry *pNextEntry = nullptr;
3077 if( IsExpanded( pEntry ) )
3078 pNextEntry = pModel->FirstChild( pEntry );
3079 else
3080 pNextEntry = pEntry->NextSibling();
3081
3082 if( !pNextEntry )
3083 pEntry = pModel->Next( pEntry );
3084 else
3085 pEntry = pNextEntry;
3086 }
3087 }
3088 else if( mbAlternatingRowColors )
3089 for(SvTreeListEntry* pEntry = pModel->First(); pEntry; pEntry = pModel->Next(pEntry))
3090 pEntry->SetBackColor( GetBackground().GetColor() );
3091
3092 mbAlternatingRowColors = bEnable;
3093 pImpl->UpdateAll(true);
3094}
3095
3096void SvTreeListBox::SetForceMakeVisible( bool bEnable )
3097{
3098 pImpl->SetForceMakeVisible(bEnable);
3099}
3100
3101SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX,SvLBoxTab** ppTab)
3102{
3103 return GetItem_Impl( pEntry, nX, ppTab );
3104}
3105
3106SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX )
3107{
3108 SvLBoxTab* pDummyTab;
3109 return GetItem_Impl( pEntry, nX, &pDummyTab );
3110}
3111
3112void SvTreeListBox::AddTab(long nTabPos, SvLBoxTabFlags nFlags )
3113{
3114 nFocusWidth = -1;
3115 SvLBoxTab* pTab = new SvLBoxTab( nTabPos, nFlags );
3116 aTabs.emplace_back( pTab );
3117 if( nTreeFlags & SvTreeFlags::USESEL )
3118 {
3119 sal_uInt16 nPos = aTabs.size() - 1;
3120 if( nPos >= nFirstSelTab && nPos <= nLastSelTab )
3121 pTab->nFlags |= SvLBoxTabFlags::SHOW_SELECTION;
3122 else
3123 // string items usually have to be selected -- turn this off
3124 // explicitly
3125 pTab->nFlags &= ~SvLBoxTabFlags::SHOW_SELECTION;
3126 }
3127}
3128
3129
3130SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( sal_uInt16& rPos ) const
3131{
3132 sal_uInt16 nCurTab = 0;
3133 sal_uInt16 nTabCount = aTabs.size();
3134 while( nCurTab < nTabCount )
3135 {
3136 SvLBoxTab* pTab = aTabs[nCurTab].get();
3137 if( pTab->nFlags & SvLBoxTabFlags::DYNAMIC )
3138 {
3139 rPos = nCurTab;
3140 return pTab;
3141 }
3142 nCurTab++;
3143 }
3144 return nullptr;
3145}
3146
3147SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const
3148{
3149 sal_uInt16 nDummy;
3150 return GetFirstDynamicTab( nDummy );
3151}
3152
3153SvLBoxTab* SvTreeListBox::GetTab( SvTreeListEntry const * pEntry, SvLBoxItem const * pItem) const
3154{
3155 sal_uInt16 nPos = pEntry->GetPos( pItem );
3156 return aTabs[ nPos ].get();
3157}
3158
3159void SvTreeListBox::ClearTabList()
3160{
3161 aTabs.clear();
3162}
3163
3164
3165Size SvTreeListBox::GetOutputSizePixel() const
3166{
3167 Size aSize = pImpl->GetOutputSize();
3168 return aSize;
3169}
3170
3171void SvTreeListBox::NotifyScrolled()
3172{
3173 aScrolledHdl.Call( this );
3174}
3175
3176void SvTreeListBox::Invalidate( InvalidateFlags nInvalidateFlags )
3177{
3178 if (!pImpl)
3179 return;
3180 if( nFocusWidth == -1 )
3181 // to make sure that the control doesn't show the wrong focus rectangle
3182 // after painting
3183 pImpl->RecalcFocusRect();
3184 Control::Invalidate( nInvalidateFlags );
3185 pImpl->Invalidate();
3186}
3187
3188void SvTreeListBox::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nInvalidateFlags )
3189{
3190 if( nFocusWidth == -1 )
3191 // to make sure that the control doesn't show the wrong focus rectangle
3192 // after painting
3193 pImpl->RecalcFocusRect();
3194 Control::Invalidate( rRect, nInvalidateFlags );
3195}
3196
3197
3198void SvTreeListBox::SetHighlightRange( sal_uInt16 nStart, sal_uInt16 nEnd)
3199{
3200
3201 nTreeFlags |= SvTreeFlags::USESEL;
3202 if( nStart > nEnd )
3203 std::swap(nStart, nEnd);
3204 // select all tabs that lie within the area
3205 nTreeFlags |= SvTreeFlags::RECALCTABS;
3206 nFirstSelTab = nStart;
3207 nLastSelTab = nEnd;
3208 pImpl->RecalcFocusRect();
3209}
3210
3211void SvTreeListBox::Command(const CommandEvent& rCEvt)
3212{
3213 if (!aPopupMenuHdl.Call(rCEvt))
3214 pImpl->Command(rCEvt);
3215 //pass at least alt press/release to parent impl
3216 if (rCEvt.GetCommand() == CommandEventId::ModKeyChange)
3217 Control::Command(rCEvt);
3218}
3219
3220SvLBoxTab* SvTreeListBox::GetFirstTab( SvLBoxTabFlags nFlagMask, sal_uInt16& rPos )
3221{
3222 sal_uInt16 nTabCount = aTabs.size();
3223 for( sal_uInt16 nPos = 0; nPos < nTabCount; nPos++ )
3224 {
3225 SvLBoxTab* pTab = aTabs[ nPos ].get();
3226 if( pTab->nFlags & nFlagMask )
3227 {
3228 rPos = nPos;
3229 return pTab;
3230 }
3231 }
3232 rPos = 0xffff;
3233 return nullptr;
3234}
3235
3236void SvTreeListBox::GetLastTab( SvLBoxTabFlags nFlagMask, sal_uInt16& rTabPos )
3237{
3238 sal_uInt16 nPos = static_cast<sal_uInt16>(aTabs.size());
3239 while( nPos )
3240 {
3241 --nPos;
3242 SvLBoxTab* pTab = aTabs[ nPos ].get();
3243 if( pTab->nFlags & nFlagMask )
3244 {
3245 rTabPos = nPos;
3246 return;
3247 }
3248 }
3249 rTabPos = 0xffff;
3250}
3251
3252void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt )
3253{
3254 if (aTooltipHdl.IsSet() && aTooltipHdl.Call(rHEvt))
3255 return;
3256
3257 if( !pImpl->RequestHelp( rHEvt ) )
3258 Control::RequestHelp( rHEvt );
3259}
3260
3261sal_Int32 SvTreeListBox::DefaultCompare(const SvLBoxString* pLeftText, const SvLBoxString* pRightText)
3262{
3263 OUString aLeft = pLeftText ? pLeftText->GetText() : OUString();
3264 OUString aRight = pRightText ? pRightText->GetText() : OUString();
3265 pImpl->UpdateStringSorter();
3266 return pImpl->m_pStringSorter->compare(aLeft, aRight);
3267}
3268
3269IMPL_LINK( SvTreeListBox, DefaultCompare, const SvSortData&, rData, sal_Int32 )sal_Int32 SvTreeListBox::LinkStubDefaultCompare(void * instance
, const SvSortData& data) { return static_cast<SvTreeListBox
*>(instance)->DefaultCompare(data); } sal_Int32 SvTreeListBox
::DefaultCompare(const SvSortData& rData)
3270{
3271 const SvTreeListEntry* pLeft = rData.pLeft;
3272 const SvTreeListEntry* pRight = rData.pRight;
3273 const SvLBoxString* pLeftText = static_cast<const SvLBoxString*>(pLeft->GetFirstItem(SvLBoxItemType::String));
3274 const SvLBoxString* pRightText = static_cast<const SvLBoxString*>(pRight->GetFirstItem(SvLBoxItemType::String));
3275 return DefaultCompare(pLeftText, pRightText);
3276}
3277
3278void SvTreeListBox::ModelNotification( SvListAction nActionId, SvTreeListEntry* pEntry1,
3279 SvTreeListEntry* pEntry2, sal_uLong nPos )
3280{
3281 SolarMutexGuard aSolarGuard;
3282
3283 if( nActionId == SvListAction::CLEARING )
3284 CancelTextEditing();
3285
3286 SvListView::ModelNotification( nActionId, pEntry1, pEntry2, nPos );
3287 switch( nActionId )
3288 {
3289 case SvListAction::INSERTED:
3290 {
3291 SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry1->GetFirstItem( SvLBoxItemType::ContextBmp ) );
3292 if ( !pBmpItem )
3293 break;
3294 const Image& rBitmap1( pBmpItem->GetBitmap1() );
3295 const Image& rBitmap2( pBmpItem->GetBitmap2() );
3296 short nMaxWidth = short( std::max( rBitmap1.GetSizePixel().Width(), rBitmap2.GetSizePixel().Width() ) );
3297 nMaxWidth = pImpl->UpdateContextBmpWidthVector( pEntry1, nMaxWidth );
3298 if( nMaxWidth > nContextBmpWidthMax )
3299 {
3300 nContextBmpWidthMax = nMaxWidth;
3301 SetTabs();
3302 }
3303 if (get_width_request() == -1)
3304 queue_resize();
3305 }
3306 break;
3307
3308 case SvListAction::RESORTING:
3309 SetUpdateMode( false );
3310 break;
3311
3312 case SvListAction::RESORTED:
3313 // after a selection: show first entry and also keep the selection
3314 MakeVisible( pModel->First(), true );
3315 SetUpdateMode( true );
3316 break;
3317
3318 case SvListAction::CLEARED:
3319 if( IsUpdateMode() )
3320 PaintImmediately();
3321 break;
3322
3323 default: break;
3324 }
3325}
3326
3327SvTreeListEntry* SvTreeListBox::GetFirstEntryInView() const
3328{
3329 return GetEntry( Point() );
3330}
3331
3332SvTreeListEntry* SvTreeListBox::GetNextEntryInView(SvTreeListEntry* pEntry ) const
3333{
3334 SvTreeListEntry* pNext = NextVisible( pEntry );
3335 if( pNext )
3336 {
3337 Point aPos( GetEntryPosition(pNext) );
3338 const Size& rSize = pImpl->GetOutputSize();
3339 if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() )
3340 return nullptr;
3341 }
3342 return pNext;
3343}
3344
3345
3346void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt )
3347{
3348 if( (rDCEvt.GetType()==DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
3349 {
3350 nEntryHeight = 0; // _together_ with true of 1. par (bFont) of InitSettings() a zero-height
3351 // forces complete recalc of heights!
3352 InitSettings();
3353 Invalidate();
3354 }
3355 else
3356 Control::DataChanged( rDCEvt );
3357}
3358
3359void SvTreeListBox::StateChanged( StateChangedType eType )
3360{
3361 if( eType == StateChangedType::Enable )
3362 Invalidate( InvalidateFlags::Children );
3363
3364 Control::StateChanged( eType );
3365
3366 if ( eType == StateChangedType::Style )
3367 ImplInitStyle();
3368}
3369
3370void SvTreeListBox::ApplySettings(vcl::RenderContext& rRenderContext)
3371{
3372 SetPointFont(rRenderContext, GetPointFont(*this));
3373
3374 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
3375 rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor());
3376 rRenderContext.SetTextFillColor();
3377 rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
3378
3379 // always try to re-create default-SvLBoxButtonData
3380 if (pCheckButtonData && pCheckButtonData->HasDefaultImages())
3381 pCheckButtonData->SetDefaultImages(this);
3382}
3383
3384void SvTreeListBox::InitSettings()
3385{
3386 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3387 vcl::Font aFont = rStyleSettings.GetFieldFont();
3388 SetPointFont(*this, aFont);
3389 AdjustEntryHeightAndRecalc();
3390
3391 SetTextColor(rStyleSettings.GetFieldTextColor());
3392 SetTextFillColor();
3393
3394 SetBackground(rStyleSettings.GetFieldColor());
3395
3396 // always try to re-create default-SvLBoxButtonData
3397 if( pCheckButtonData && pCheckButtonData->HasDefaultImages() )
3398 pCheckButtonData->SetDefaultImages(this);
3399}
3400
3401css::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible()
3402{
3403 vcl::Window* pParent = GetAccessibleParentWindow();
3404 DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" )do { if (true && (!(pParent))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
":" "3404" ": "), "%s", "SvTreeListBox::CreateAccessible - accessible parent not found"
); } } while (false)
;
3405
3406 css::uno::Reference< XAccessible > xAccessible;
3407 if ( pParent )
3408 {
3409 css::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
3410 if ( xAccParent.is() )
3411 {
3412 // need to be done here to get the vclxwindow later on in the accessible
3413 css::uno::Reference< css::awt::XWindowPeer > xHoldAlive(GetComponentInterface());
3414 xAccessible = pImpl->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent );
3415 }
3416 }
3417 return xAccessible;
3418}
3419
3420void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const
3421{
3422 assert(pEntry && "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry")(static_cast <bool> (pEntry && "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry"
) ? void (0) : __assert_fail ("pEntry && \"SvTreeListBox::FillAccessibleEntryStateSet: invalid entry\""
, "/home/maarten/src/libreoffice/core/vcl/source/treelist/treelistbox.cxx"
, 3422, __extension__ __PRETTY_FUNCTION__))
;
3423
3424 if ( pEntry->HasChildrenOnDemand() || pEntry->HasChildren() )
3425 {
3426 rStateSet.AddState( AccessibleStateType::EXPANDABLE );
3427 if ( IsExpanded( pEntry ) )
3428 rStateSet.AddState( sal_Int16(AccessibleStateType::EXPANDED) );
3429 }
3430
3431 if ( GetCheckButtonState( pEntry ) == SvButtonState::Checked )
3432 rStateSet.AddState( AccessibleStateType::CHECKED );
3433 if ( IsEntryVisible( pEntry ) )
3434 rStateSet.AddState( AccessibleStateType::VISIBLE );
3435 if ( IsSelected( pEntry ) )
3436 rStateSet.AddState( AccessibleStateType::SELECTED );
3437 if ( IsEnabled() )
3438 {
3439 rStateSet.AddState( AccessibleStateType::ENABLED );
3440 rStateSet.AddState( AccessibleStateType::FOCUSABLE );
3441 rStateSet.AddState( AccessibleStateType::SELECTABLE );
3442 SvViewDataEntry* pViewDataNewCur = GetViewDataEntry(pEntry);
3443 if (pViewDataNewCur && pViewDataNewCur->HasFocus())
3444 rStateSet.AddState( AccessibleStateType::FOCUSED );
3445 }
3446}
3447
3448tools::Rectangle SvTreeListBox::GetBoundingRect(const SvTreeListEntry* pEntry)
3449{
3450 Point aPos = GetEntryPosition( pEntry );
3451 tools::Rectangle aRect = GetFocusRect( pEntry, aPos.Y() );
3452 return aRect;
3453}
3454
3455void SvTreeListBox::CallImplEventListeners(VclEventId nEvent, void* pData)
3456{
3457 CallEventListeners(nEvent, pData);
3458}
3459
3460void SvTreeListBox::set_min_width_in_chars(sal_Int32 nChars)
3461{
3462 nMinWidthInChars = nChars;
3463 queue_resize();
3464}
3465
3466bool SvTreeListBox::set_property(const OString &rKey, const OUString &rValue)
3467{
3468 if (rKey == "min-width-chars")
3469 {
3470 set_min_width_in_chars(rValue.toInt32());
3471 }
3472 else if (rKey == "enable-tree-lines")
3473 {
3474 auto nStyle = GetStyle();
3475 nStyle &= ~(WB_HASLINES | WB_HASLINESATROOT);
3476 if (toBool(rValue))
3477 nStyle |= (WB_HASLINES | WB_HASLINESATROOT);
3478 SetStyle(nStyle);
3479 }
3480 else if (rKey == "show-expanders")
3481 {
3482 auto nStyle = GetStyle();
3483 nStyle &= ~(WB_HASBUTTONS | WB_HASBUTTONSATROOT);
3484 if (toBool(rValue))
3485 nStyle |= (WB_HASBUTTONS | WB_HASBUTTONSATROOT);
3486 SetStyle(nStyle);
3487 }
3488 else if (rKey == "rules-hint")
3489 {
3490 SetAlternatingRowColors(toBool(rValue));
3491 }
3492 else if (rKey == "enable-search")
3493 {
3494 SetQuickSearch(toBool(rValue));
3495 }
3496 else if (rKey == "activate-on-single-click")
3497 {
3498 SetActivateOnSingleClick(toBool(rValue));
3499 }
3500 else if (rKey == "hover-selection")
3501 {
3502 SetHoverSelection(toBool(rValue));
3503 }
3504 else if (rKey == "reorderable")
3505 {
3506 if (toBool(rValue))
3507 SetDragDropMode(DragDropMode::CTRL_MOVE | DragDropMode::ENABLE_TOP);
3508 }
3509 else
3510 return Control::set_property(rKey, rValue);
3511 return true;
3512}
3513
3514FactoryFunction SvTreeListBox::GetUITestFactory() const
3515{
3516 return TreeListUIObject::create;
3517}
3518
3519/* 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 );
29
Memory is allocated
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
42
Calling 'Reference::get'
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
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
32.1
Field 'm_pBody' is non-null
32.1
Field 'm_pBody' is non-null
32.1
Field 'm_pBody' is non-null
32.1
Field 'm_pBody' is non-null
)
33
Taking true branch
113 m_pBody->release();
34
Calling 'VclReferenceBase::release'
38
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;
43
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)
35
Assuming the condition is true
36
Taking true branch
40 delete this;
37
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