Bug Summary

File:home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx
Warning:line 1715, column 10
Called C++ object pointer is null

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 svimpbox.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/svimpbox.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#include <sal/config.h>
21
22#include <o3tl/safeint.hxx>
23#include <vcl/svapp.hxx>
24#include <vcl/salnativewidgets.hxx>
25#include <vcl/help.hxx>
26#include <vcl/settings.hxx>
27#include <vcl/commandevent.hxx>
28
29#include <cstdlib>
30#include <memory>
31#include <stack>
32
33#include <vcl/toolkit/treelistbox.hxx>
34#include <vcl/toolkit/svlbitm.hxx>
35#include <tools/wintypes.hxx>
36#include <bitmaps.hlst>
37#include <svimpbox.hxx>
38#include <comphelper/processfactory.hxx>
39#include <comphelper/string.hxx>
40#include <i18nlangtag/languagetag.hxx>
41#include <tools/debug.hxx>
42
43#include <vcl/toolkit/treelistentry.hxx>
44#include <vcl/toolkit/viewdataentry.hxx>
45
46// #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors
47Image* SvImpLBox::s_pDefCollapsed = nullptr;
48Image* SvImpLBox::s_pDefExpanded = nullptr;
49oslInterlockedCount SvImpLBox::s_nImageRefCount = 0;
50
51SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvTreeList* pLBTree, WinBits nWinStyle)
52 : m_aHorSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_HSCROLL))
53 , m_aScrBarBox(VclPtr<ScrollBarBox>::Create(pLBView))
54 , m_aFctSet(this, pLBView)
55 , mbForceMakeVisible (false)
56 , m_aVerSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_VSCROLL))
57 , m_aOutputSize(0, 0)
58 , mbNoAutoCurEntry(false)
59 , m_aSelEng(pLBView, nullptr)
60 , m_nNextVerVisSize(0)
61{
62 osl_atomic_increment(&s_nImageRefCount)__sync_add_and_fetch((&s_nImageRefCount), 1);
63 m_pView = pLBView;
64 m_pTree = pLBTree;
65 m_aSelEng.SetFunctionSet( static_cast<FunctionSet*>(&m_aFctSet) );
66 m_aSelEng.ExpandSelectionOnMouseMove( false );
67 SetStyle( nWinStyle );
68 SetSelectionMode( SelectionMode::Single );
69 SetDragDropMode( DragDropMode::NONE );
70
71 m_aVerSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollUpDownHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox
*>(this), &SvImpLBox::LinkStubScrollUpDownHdl)
);
72 m_aHorSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollLeftRightHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox
*>(this), &SvImpLBox::LinkStubScrollLeftRightHdl)
);
73 m_aHorSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox
*>(this), &SvImpLBox::LinkStubEndScrollHdl)
);
74 m_aVerSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox
*>(this), &SvImpLBox::LinkStubEndScrollHdl)
);
75 m_aVerSBar->SetRange( Range(0,0) );
76 m_aVerSBar->Hide();
77 m_aHorSBar->SetRange( Range(0,0) );
78 m_aHorSBar->SetPageSize( 24 ); // pixels
79 m_aHorSBar->SetLineSize( 8 ); // pixels
80
81 m_nHorSBarHeight = static_cast<short>(m_aHorSBar->GetSizePixel().Height());
82 m_nVerSBarWidth = static_cast<short>(m_aVerSBar->GetSizePixel().Width());
83
84 m_pStartEntry = nullptr;
85 m_pCursor = nullptr;
86 m_pAnchor = nullptr;
87 m_nVisibleCount = 0; // number of rows of data in control
88 m_nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID-2000000;
89 m_nNodeBmpWidth = 0;
90
91 // button animation in listbox
92 m_pActiveButton = nullptr;
93 m_pActiveEntry = nullptr;
94 m_pActiveTab = nullptr;
95
96 m_nFlags = LBoxFlags::NONE;
97
98 m_aEditIdle.SetPriority( TaskPriority::LOWEST );
99 m_aEditIdle.SetInvokeHandler( LINK(this,SvImpLBox,EditTimerCall)::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox
*>(this), &SvImpLBox::LinkStubEditTimerCall)
);
100
101 m_nMostRight = -1;
102 m_pMostRightEntry = nullptr;
103 m_nCurUserEvent = nullptr;
104
105 m_bUpdateMode = true;
106 m_bInVScrollHdl = false;
107 m_nFlags |= LBoxFlags::Filling;
108
109 m_bSubLstOpLR = false;
110}
111
112SvImpLBox::~SvImpLBox()
113{
114 m_aEditIdle.Stop();
115 StopUserEvent();
116
117 if ( osl_atomic_decrement(&s_nImageRefCount)__sync_sub_and_fetch((&s_nImageRefCount), 1) == 0 )
118 {
119 delete s_pDefCollapsed;
120 s_pDefCollapsed = nullptr;
121 delete s_pDefExpanded;
122 s_pDefExpanded = nullptr;
123 }
124 m_aVerSBar.disposeAndClear();
125 m_aHorSBar.disposeAndClear();
126 m_aScrBarBox.disposeAndClear();
127}
128
129void SvImpLBox::UpdateStringSorter()
130{
131 const css::lang::Locale& rNewLocale = Application::GetSettings().GetLanguageTag().getLocale();
132
133 if( m_pStringSorter )
134 {
135 // different Locale from the older one, drop it and force recreate
136 const css::lang::Locale &aLocale = m_pStringSorter->getLocale();
137 if( aLocale.Language != rNewLocale.Language ||
138 aLocale.Country != rNewLocale.Country ||
139 aLocale.Variant != rNewLocale.Variant )
140 m_pStringSorter.reset();
141 }
142
143 if( !m_pStringSorter )
144 {
145 m_pStringSorter.reset(new comphelper::string::NaturalStringSorter(
146 ::comphelper::getProcessComponentContext(),
147 rNewLocale));
148 }
149}
150
151short SvImpLBox::UpdateContextBmpWidthVector( SvTreeListEntry const * pEntry, short nWidth )
152{
153 DBG_ASSERT( m_pView->pModel, "View and Model aren't valid!" )do { if (true && (!(m_pView->pModel))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "153" ": "), "%s", "View and Model aren't valid!"); } } while
(false)
;
154
155 sal_uInt16 nDepth = m_pView->pModel->GetDepth( pEntry );
156 // initialize vector if necessary
157 std::vector< short >::size_type nSize = m_aContextBmpWidthVector.size();
158 while ( nDepth > nSize )
159 {
160 m_aContextBmpWidthVector.resize( nSize + 1 );
161 m_aContextBmpWidthVector.at( nSize ) = nWidth;
162 ++nSize;
163 }
164 if( m_aContextBmpWidthVector.size() == nDepth )
165 {
166 m_aContextBmpWidthVector.resize( nDepth + 1 );
167 m_aContextBmpWidthVector.at( nDepth ) = 0;
168 }
169 short nContextBmpWidth = m_aContextBmpWidthVector[ nDepth ];
170 if( nContextBmpWidth < nWidth )
171 {
172 m_aContextBmpWidthVector.at( nDepth ) = nWidth;
173 return nWidth;
174 }
175 else
176 return nContextBmpWidth;
177}
178
179void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry* pEntry )
180{
181 DBG_ASSERT( pEntry, "Moved Entry is invalid!" )do { if (true && (!(pEntry))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "181" ": "), "%s", "Moved Entry is invalid!"); } } while
(false)
;
182
183 SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem(SvLBoxItemType::ContextBmp) );
184 short nExpWidth = static_cast<short>(pBmpItem->GetBitmap1().GetSizePixel().Width());
185 short nColWidth = static_cast<short>(pBmpItem->GetBitmap2().GetSizePixel().Width());
186 short nMax = std::max(nExpWidth, nColWidth);
187 UpdateContextBmpWidthVector( pEntry, nMax );
188
189 if( pEntry->HasChildren() ) // recursive call, whether expanded or not
190 {
191 SvTreeListEntry* pChild = m_pView->FirstChild( pEntry );
192 DBG_ASSERT( pChild, "The first child is invalid!" )do { if (true && (!(pChild))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "192" ": "), "%s", "The first child is invalid!"); } } while
(false)
;
193 do
194 {
195 UpdateContextBmpWidthVectorFromMovedEntry( pChild );
196 pChild = m_pView->Next( pChild );
197 } while ( pChild );
198 }
199}
200
201void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry const * pEntry )
202{
203 sal_uInt16 nDepth = m_pView->pModel->GetDepth( pEntry );
204 if( m_aContextBmpWidthVector.empty() )
205 return;
206 short nWidth = m_aContextBmpWidthVector[ nDepth ];
207 if( nWidth != m_pView->nContextBmpWidthMax ) {
208 m_pView->nContextBmpWidthMax = nWidth;
209 m_nFlags |= LBoxFlags::IgnoreChangedTabs;
210 m_pView->SetTabs();
211 m_nFlags &= ~LBoxFlags::IgnoreChangedTabs;
212 }
213}
214
215void SvImpLBox::SetStyle( WinBits i_nWinStyle )
216{
217 m_nStyle = i_nWinStyle;
218 if ( ( m_nStyle & WB_SIMPLEMODE) && ( m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) )
219 m_aSelEng.AddAlways( true );
220}
221
222void SvImpLBox::SetNoAutoCurEntry( bool b )
223{
224 mbNoAutoCurEntry = b;
225}
226
227// don't touch the model any more
228void SvImpLBox::Clear()
229{
230 StopUserEvent();
231 m_pStartEntry = nullptr;
232 m_pAnchor = nullptr;
233
234 m_pActiveButton = nullptr;
235 m_pActiveEntry = nullptr;
236 m_pActiveTab = nullptr;
237
238 m_nMostRight = -1;
239 m_pMostRightEntry = nullptr;
240
241 // don't touch the cursor any more
242 if( m_pCursor )
243 {
244 if( m_pView->HasFocus() )
245 m_pView->HideFocus();
246 m_pCursor = nullptr;
247 }
248 m_aVerSBar->Hide();
249 m_aVerSBar->SetThumbPos( 0 );
250 Range aRange( 0, 0 );
251 m_aVerSBar->SetRange( aRange );
252 m_aOutputSize = m_pView->Control::GetOutputSizePixel();
253 m_aHorSBar->Hide();
254 m_aHorSBar->SetThumbPos( 0 );
255 MapMode aMapMode( m_pView->GetMapMode());
256 aMapMode.SetOrigin( Point(0,0) );
257 m_pView->Control::SetMapMode( aMapMode );
258 m_aHorSBar->SetRange( aRange );
259 m_aHorSBar->SetSizePixel(Size(m_aOutputSize.Width(),m_nHorSBarHeight));
260 m_pView->SetClipRegion();
261 if( GetUpdateMode() )
262 m_pView->Invalidate( GetVisibleArea() );
263 m_nFlags |= LBoxFlags::Filling;
264 if( !m_aHorSBar->IsVisible() && !m_aVerSBar->IsVisible() )
265 m_aScrBarBox->Hide();
266
267 m_aContextBmpWidthVector.clear();
268
269 CallEventListeners( VclEventId::ListboxItemRemoved );
270}
271
272// *********************************************************************
273// Paint, navigate, scroll
274// *********************************************************************
275
276IMPL_LINK_NOARG(SvImpLBox, EndScrollHdl, ScrollBar*, void)void SvImpLBox::LinkStubEndScrollHdl(void * instance, ScrollBar
* data) { return static_cast<SvImpLBox *>(instance)->
EndScrollHdl(data); } void SvImpLBox::EndScrollHdl(__attribute__
((unused)) ScrollBar*)
277{
278 if( m_nFlags & LBoxFlags::EndScrollSetVisSize )
279 {
280 m_aVerSBar->SetVisibleSize( m_nNextVerVisSize );
281 m_nFlags &= ~LBoxFlags::EndScrollSetVisSize;
282 }
283}
284
285// handler for vertical scrollbar
286
287IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar, void )void SvImpLBox::LinkStubScrollUpDownHdl(void * instance, ScrollBar
* data) { return static_cast<SvImpLBox *>(instance)->
ScrollUpDownHdl(data); } void SvImpLBox::ScrollUpDownHdl(ScrollBar
* pScrollBar)
288{
289 DBG_ASSERT(!m_bInVScrollHdl,"Scroll handler out-paces itself!")do { if (true && (!(!m_bInVScrollHdl))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "289" ": "), "%s", "Scroll handler out-paces itself!"); }
} while (false)
;
290 long nDelta = pScrollBar->GetDelta();
291 if( !nDelta )
292 return;
293
294 m_nFlags &= ~LBoxFlags::Filling;
295
296 m_bInVScrollHdl = true;
297
298 if( m_pView->IsEditingActive() )
299 {
300 m_pView->EndEditing( true ); // Cancel
301 m_pView->PaintImmediately();
302 }
303
304 if( nDelta > 0 )
305 {
306 if( nDelta == 1 )
307 CursorDown();
308 else
309 PageDown( static_cast<sal_uInt16>(nDelta) );
310 }
311 else
312 {
313 nDelta *= -1;
314 if( nDelta == 1 )
315 CursorUp();
316 else
317 PageUp( static_cast<sal_uInt16>(nDelta) );
318 }
319 m_bInVScrollHdl = false;
320}
321
322
323void SvImpLBox::CursorDown()
324{
325 if (!m_pStartEntry)
326 return;
327
328 SvTreeListEntry* pNextFirstToDraw = m_pView->NextVisible(m_pStartEntry);
329 if( pNextFirstToDraw )
330 {
331 m_nFlags &= ~LBoxFlags::Filling;
332 ShowCursor( false );
333 m_pView->PaintImmediately();
334 m_pStartEntry = pNextFirstToDraw;
335 tools::Rectangle aArea( GetVisibleArea() );
336 m_pView->Scroll( 0, -(m_pView->GetEntryHeight()), aArea, ScrollFlags::NoChildren );
337 m_pView->PaintImmediately();
338 ShowCursor( true );
339 m_pView->NotifyScrolled();
340 }
341}
342
343void SvImpLBox::CursorUp()
344{
345 if (!m_pStartEntry)
346 return;
347
348 SvTreeListEntry* pPrevFirstToDraw = m_pView->PrevVisible(m_pStartEntry);
349 if( !pPrevFirstToDraw )
350 return;
351
352 m_nFlags &= ~LBoxFlags::Filling;
353 long nEntryHeight = m_pView->GetEntryHeight();
354 ShowCursor( false );
355 m_pView->PaintImmediately();
356 m_pStartEntry = pPrevFirstToDraw;
357 tools::Rectangle aArea( GetVisibleArea() );
358 aArea.AdjustBottom( -nEntryHeight );
359 m_pView->Scroll( 0, nEntryHeight, aArea, ScrollFlags::NoChildren );
360 m_pView->PaintImmediately();
361 ShowCursor( true );
362 m_pView->NotifyScrolled();
363}
364
365void SvImpLBox::PageDown( sal_uInt16 nDelta )
366{
367 sal_uInt16 nRealDelta = nDelta;
368
369 if( !nDelta )
370 return;
371
372 if (!m_pStartEntry)
373 return;
374
375 SvTreeListEntry* pNext = m_pView->NextVisible(m_pStartEntry, nRealDelta);
376 if( pNext == m_pStartEntry )
377 return;
378
379 ShowCursor( false );
380
381 m_nFlags &= ~LBoxFlags::Filling;
382 m_pStartEntry = pNext;
383
384 if( nRealDelta >= m_nVisibleCount )
385 {
386 m_pView->Invalidate( GetVisibleArea() );
387 m_pView->PaintImmediately();
388 }
389 else
390 {
391 tools::Rectangle aArea( GetVisibleArea() );
392 long nScroll = m_pView->GetEntryHeight() * static_cast<long>(nRealDelta);
393 nScroll = -nScroll;
394 m_pView->PaintImmediately();
395 m_pView->Scroll( 0, nScroll, aArea, ScrollFlags::NoChildren );
396 m_pView->PaintImmediately();
397 m_pView->NotifyScrolled();
398 }
399
400 ShowCursor( true );
401}
402
403void SvImpLBox::PageUp( sal_uInt16 nDelta )
404{
405 sal_uInt16 nRealDelta = nDelta;
406 if( !nDelta )
407 return;
408
409 if (!m_pStartEntry)
410 return;
411
412 SvTreeListEntry* pPrev = m_pView->PrevVisible(m_pStartEntry, nRealDelta);
413 if( pPrev == m_pStartEntry )
414 return;
415
416 m_nFlags &= ~LBoxFlags::Filling;
417 ShowCursor( false );
418
419 m_pStartEntry = pPrev;
420 if( nRealDelta >= m_nVisibleCount )
421 {
422 m_pView->Invalidate( GetVisibleArea() );
423 m_pView->PaintImmediately();
424 }
425 else
426 {
427 long nEntryHeight = m_pView->GetEntryHeight();
428 tools::Rectangle aArea( GetVisibleArea() );
429 m_pView->PaintImmediately();
430 m_pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, ScrollFlags::NoChildren );
431 m_pView->PaintImmediately();
432 m_pView->NotifyScrolled();
433 }
434
435 ShowCursor( true );
436}
437
438void SvImpLBox::KeyUp( bool bPageUp )
439{
440 if( !m_aVerSBar->IsVisible() )
441 return;
442
443 long nDelta;
444 if( bPageUp )
445 nDelta = m_aVerSBar->GetPageSize();
446 else
447 nDelta = 1;
448
449 long nThumbPos = m_aVerSBar->GetThumbPos();
450
451 if( nThumbPos < nDelta )
452 nDelta = nThumbPos;
453
454 if( nDelta <= 0 )
455 return;
456
457 m_nFlags &= ~LBoxFlags::Filling;
458
459 m_aVerSBar->SetThumbPos( nThumbPos - nDelta );
460 if( bPageUp )
461 PageUp( static_cast<short>(nDelta) );
462 else
463 CursorUp();
464}
465
466
467void SvImpLBox::KeyDown( bool bPageDown )
468{
469 if( !m_aVerSBar->IsVisible() )
470 return;
471
472 long nDelta;
473 if( bPageDown )
474 nDelta = m_aVerSBar->GetPageSize();
475 else
476 nDelta = 1;
477
478 long nThumbPos = m_aVerSBar->GetThumbPos();
479 long nVisibleSize = m_aVerSBar->GetVisibleSize();
480 long nRange = m_aVerSBar->GetRange().Len();
481
482 long nTmp = nThumbPos+nVisibleSize;
483 while( (nDelta > 0) && (nTmp+nDelta) >= nRange )
484 nDelta--;
485
486 if( nDelta <= 0 )
487 return;
488
489 m_nFlags &= ~LBoxFlags::Filling;
490
491 m_aVerSBar->SetThumbPos( nThumbPos+nDelta );
492 if( bPageDown )
493 PageDown( static_cast<short>(nDelta) );
494 else
495 CursorDown();
496}
497
498
499void SvImpLBox::InvalidateEntriesFrom( long nY ) const
500{
501 if( !(m_nFlags & LBoxFlags::InPaint ))
502 {
503 tools::Rectangle aRect( GetVisibleArea() );
504 aRect.SetTop( nY );
505 m_pView->Invalidate( aRect );
506 }
507}
508
509void SvImpLBox::InvalidateEntry( long nY ) const
510{
511 if( m_nFlags & LBoxFlags::InPaint )
512 return;
513
514 tools::Rectangle aRect( GetVisibleArea() );
515 long nMaxBottom = aRect.Bottom();
516 aRect.SetTop( nY );
517 aRect.SetBottom( nY ); aRect.AdjustBottom(m_pView->GetEntryHeight() );
518 if( aRect.Top() > nMaxBottom )
519 return;
520 if( aRect.Bottom() > nMaxBottom )
521 aRect.SetBottom( nMaxBottom );
522 if (m_pView->SupportsDoubleBuffering())
523 // Perform full paint when flicker is to be avoided explicitly.
524 m_pView->Invalidate();
525 else
526 m_pView->Invalidate(aRect);
527}
528
529void SvImpLBox::InvalidateEntry( SvTreeListEntry* pEntry )
530{
531 if( GetUpdateMode() )
532 {
533 long nPrev = m_nMostRight;
534 SetMostRight( pEntry );
535 if( nPrev < m_nMostRight )
536 ShowVerSBar();
537 }
538 if( !(m_nFlags & LBoxFlags::InPaint ))
539 {
540 bool bHasFocusRect = false;
541 if( pEntry==m_pCursor && m_pView->HasFocus() )
542 {
543 bHasFocusRect = true;
544 ShowCursor( false );
545 }
546 InvalidateEntry( GetEntryLine( pEntry ) );
547 if( bHasFocusRect )
548 ShowCursor( true );
549 }
550}
551
552
553void SvImpLBox::RecalcFocusRect()
554{
555 if( m_pView->HasFocus() && m_pCursor )
556 {
557 m_pView->HideFocus();
558 long nY = GetEntryLine( m_pCursor );
559 tools::Rectangle aRect = m_pView->GetFocusRect( m_pCursor, nY );
560 vcl::Region aOldClip( m_pView->GetClipRegion());
561 vcl::Region aClipRegion( GetClipRegionRect() );
562 m_pView->SetClipRegion( aClipRegion );
563 m_pView->ShowFocus( aRect );
564 m_pView->SetClipRegion( aOldClip );
565 }
566}
567
568
569// Sets cursor. When using SingleSelection, the selection is adjusted.
570void SvImpLBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect )
571{
572 SvViewDataEntry* pViewDataNewCur = nullptr;
573 if( pEntry )
574 pViewDataNewCur= m_pView->GetViewDataEntry(pEntry);
575 if( pEntry &&
576 pEntry == m_pCursor &&
577 pViewDataNewCur &&
578 pViewDataNewCur->HasFocus() &&
579 pViewDataNewCur->IsSelected())
580 {
581 return;
582 }
583
584 // if this cursor is not selectable, find first visible that is and use it
585 while( pEntry && pViewDataNewCur && !pViewDataNewCur->IsSelectable() )
586 {
587 pEntry = m_pView->NextVisible(pEntry);
588 pViewDataNewCur = pEntry ? m_pView->GetViewDataEntry(pEntry) : nullptr;
589 }
590
591 SvTreeListEntry* pOldCursor = m_pCursor;
592 if( m_pCursor && pEntry != m_pCursor )
593 {
594 m_pView->SetEntryFocus( m_pCursor, false );
595 if( m_bSimpleTravel )
596 m_pView->Select( m_pCursor, false );
597 m_pView->HideFocus();
598 }
599 m_pCursor = pEntry;
600 if( m_pCursor )
601 {
602 if (pViewDataNewCur)
603 pViewDataNewCur->SetFocus( true );
604 if(!bForceNoSelect && m_bSimpleTravel && !(m_nFlags & LBoxFlags::DeselectAll) && GetUpdateMode())
605 {
606 m_pView->Select( m_pCursor );
607 CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor );
608 }
609 // multiple selection: select in cursor move if we're not in
610 // Add mode (Ctrl-F8)
611 else if( GetUpdateMode() &&
612 m_pView->GetSelectionMode() == SelectionMode::Multiple &&
613 !(m_nFlags & LBoxFlags::DeselectAll) && !m_aSelEng.IsAddMode() &&
614 !bForceNoSelect )
615 {
616 m_pView->Select( m_pCursor );
617 CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor );
618 }
619 else
620 {
621 ShowCursor( true );
622 if (bForceNoSelect && GetUpdateMode())
623 {
624 CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor);
625 }
626 }
627
628 if( m_pAnchor )
629 {
630 DBG_ASSERT(m_aSelEng.GetSelectionMode() != SelectionMode::Single,"Mode?")do { if (true && (!(m_aSelEng.GetSelectionMode() != SelectionMode
::Single))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "630" ": "), "%s", "Mode?"); } } while (false)
;
631 SetAnchorSelection( pOldCursor, m_pCursor );
632 }
633 }
634 m_nFlags &= ~LBoxFlags::DeselectAll;
635
636 m_pView->OnCurrentEntryChanged();
637}
638
639void SvImpLBox::ShowCursor( bool bShow )
640{
641 if( !bShow || !m_pCursor || !m_pView->HasFocus() )
642 {
643 vcl::Region aOldClip( m_pView->GetClipRegion());
644 vcl::Region aClipRegion( GetClipRegionRect() );
645 m_pView->SetClipRegion( aClipRegion );
646 m_pView->HideFocus();
647 m_pView->SetClipRegion( aOldClip );
648 }
649 else
650 {
651 long nY = GetEntryLine( m_pCursor );
652 tools::Rectangle aRect = m_pView->GetFocusRect( m_pCursor, nY );
653 vcl::Region aOldClip( m_pView->GetClipRegion());
654 vcl::Region aClipRegion( GetClipRegionRect() );
655 m_pView->SetClipRegion( aClipRegion );
656 m_pView->ShowFocus( aRect );
657 m_pView->SetClipRegion( aOldClip );
658 }
659}
660
661
662void SvImpLBox::UpdateAll( bool bInvalidateCompleteView )
663{
664 FindMostRight();
665 m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) );
666 SyncVerThumb();
667 FillView();
668 ShowVerSBar();
669 if( m_bSimpleTravel && m_pCursor && m_pView->HasFocus() )
670 m_pView->Select( m_pCursor );
671 ShowCursor( true );
672 if( bInvalidateCompleteView )
673 m_pView->Invalidate();
674 else
675 m_pView->Invalidate( GetVisibleArea() );
676}
677
678IMPL_LINK( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar, void )void SvImpLBox::LinkStubScrollLeftRightHdl(void * instance, ScrollBar
* data) { return static_cast<SvImpLBox *>(instance)->
ScrollLeftRightHdl(data); } void SvImpLBox::ScrollLeftRightHdl
(ScrollBar * pScrollBar)
679{
680 long nDelta = pScrollBar->GetDelta();
681 if( nDelta )
682 {
683 if( m_pView->IsEditingActive() )
684 {
685 m_pView->EndEditing( true ); // Cancel
686 m_pView->PaintImmediately();
687 }
688 m_pView->nFocusWidth = -1;
689 KeyLeftRight( nDelta );
690 }
691}
692
693void SvImpLBox::KeyLeftRight( long nDelta )
694{
695 if( !(m_nFlags & LBoxFlags::InResize) )
696 m_pView->PaintImmediately();
697 m_nFlags &= ~LBoxFlags::Filling;
698 ShowCursor( false );
699
700 // calculate new origin
701 long nPos = m_aHorSBar->GetThumbPos();
702 Point aOrigin( -nPos, 0 );
703
704 MapMode aMapMode( m_pView->GetMapMode() );
705 aMapMode.SetOrigin( aOrigin );
706 m_pView->SetMapMode( aMapMode );
707
708 if( !(m_nFlags & LBoxFlags::InResize) )
709 {
710 tools::Rectangle aRect( GetVisibleArea() );
711 m_pView->Scroll( -nDelta, 0, aRect, ScrollFlags::NoChildren );
712 }
713 else
714 m_pView->Invalidate();
715 RecalcFocusRect();
716 ShowCursor( true );
717 m_pView->NotifyScrolled();
718}
719
720
721// returns the last entry if position is just past the last entry
722SvTreeListEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const
723{
724 DBG_ASSERT( m_pView->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" )do { if (true && (!(m_pView->GetModel()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "724" ": "), "%s", "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!"
); } } while (false)
;
725 if ( !m_pView->GetModel() )
726 // this is quite impossible. Nevertheless, stack traces from the crash reporter
727 // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it
728 // reliably :-\ ...
729 // #122359# / 2005-05-23 / frank.schoenheit@sun.com
730 return nullptr;
731 if( m_pView->GetEntryCount() == 0 || !m_pStartEntry || !m_pView->GetEntryHeight())
732 return nullptr;
733
734 sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() );
735 sal_uInt16 nTemp = nClickedEntry;
736 SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
737 return pEntry;
738}
739
740
741// checks if the entry was hit "the right way"
742// (Focusrect+ ContextBitmap at TreeListBox)
743
744bool SvImpLBox::EntryReallyHit(SvTreeListEntry* pEntry, const Point& rPosPixel, long nLine)
745{
746 bool bRet;
747 // we are not too exact when it comes to "special" entries
748 // (with CheckButtons etc.)
749 if( pEntry->ItemCount() >= 3 )
750 return true;
751
752 tools::Rectangle aRect( m_pView->GetFocusRect( pEntry, nLine ));
753 aRect.SetRight( GetOutputSize().Width() - m_pView->GetMapMode().GetOrigin().X() );
754
755 SvLBoxContextBmp* pBmp = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
756 aRect.AdjustLeft( -pBmp->GetWidth(m_pView,pEntry) );
757 aRect.AdjustLeft( -4 ); // a little tolerance
758
759 Point aPos( rPosPixel );
760 aPos -= m_pView->GetMapMode().GetOrigin();
761 bRet = aRect.IsInside( aPos );
762 return bRet;
763}
764
765
766// returns 0 if position is just past the last entry
767SvTreeListEntry* SvImpLBox::GetEntry( const Point& rPoint ) const
768{
769 if( (m_pView->GetEntryCount() == 0) || !m_pStartEntry ||
770 (rPoint.Y() > m_aOutputSize.Height())
771 || !m_pView->GetEntryHeight())
772 return nullptr;
773
774 sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() );
775 sal_uInt16 nTemp = nClickedEntry;
776 SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
777 if( nTemp != nClickedEntry )
778 pEntry = nullptr;
779 return pEntry;
780}
781
782
783SvTreeListEntry* SvImpLBox::MakePointVisible(const Point& rPoint)
784{
785 if( !m_pCursor )
786 return nullptr;
787 long nY = rPoint.Y();
788 SvTreeListEntry* pEntry = nullptr;
789 long nMax = m_aOutputSize.Height();
790 if( nY < 0 || nY >= nMax ) // aOutputSize.Height() )
791 {
792 if( nY < 0 )
793 pEntry = m_pView->PrevVisible(m_pCursor);
794 else
795 pEntry = m_pView->NextVisible(m_pCursor);
796
797 if( pEntry && pEntry != m_pCursor )
798 m_pView->SetEntryFocus( m_pCursor, false );
799
800 if( nY < 0 )
801 KeyUp( false );
802 else
803 KeyDown( false );
804 }
805 else
806 {
807 pEntry = GetClickedEntry( rPoint );
808 if( !pEntry )
809 {
810 sal_uInt16 nSteps = 0xFFFF;
811 // TODO: LastVisible is not yet implemented!
812 pEntry = m_pView->NextVisible(m_pStartEntry, nSteps);
813 }
814 if( pEntry )
815 {
816 if( pEntry != m_pCursor &&
817 m_aSelEng.GetSelectionMode() == SelectionMode::Single
818 )
819 m_pView->Select( m_pCursor, false );
820 }
821 }
822 return pEntry;
823}
824
825tools::Rectangle SvImpLBox::GetClipRegionRect() const
826{
827 Point aOrigin( m_pView->GetMapMode().GetOrigin() );
828 aOrigin.setX( aOrigin.X() * -1 ); // conversion document coordinates
829 tools::Rectangle aClipRect( aOrigin, m_aOutputSize );
830 aClipRect.AdjustBottom( 1 );
831 return aClipRect;
832}
833
834
835void SvImpLBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
836{
837 if (!m_pView->GetVisibleCount())
838 return;
839
840 m_nFlags |= LBoxFlags::InPaint;
841
842 if (m_nFlags & LBoxFlags::Filling)
843 {
844 SvTreeListEntry* pFirst = m_pView->First();
845 if (pFirst != m_pStartEntry)
846 {
847 ShowCursor(false);
848 m_pStartEntry = m_pView->First();
849 m_aVerSBar->SetThumbPos( 0 );
850 StopUserEvent();
851 ShowCursor(true);
852 m_nCurUserEvent = Application::PostUserEvent(LINK(this, SvImpLBox, MyUserEvent)::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox
*>(this), &SvImpLBox::LinkStubMyUserEvent)
,
853 reinterpret_cast<void*>(1));
854 return;
855 }
856 }
857
858 if (!m_pStartEntry)
859 {
860 m_pStartEntry = m_pView->First();
861 }
862
863 if (m_nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID-2000000)
864 SetNodeBmpTabDistance();
865
866 long nRectHeight = rRect.GetHeight();
867 long nEntryHeight = m_pView->GetEntryHeight();
868
869 // calculate area for the entries we want to draw
870 sal_uInt16 nStartLine = static_cast<sal_uInt16>(rRect.Top() / nEntryHeight);
871 sal_uInt16 nCount = static_cast<sal_uInt16>(nRectHeight / nEntryHeight);
872 nCount += 2; // don't miss a row
873
874 long nY = nStartLine * nEntryHeight;
875 SvTreeListEntry* pEntry = m_pStartEntry;
876 while (nStartLine && pEntry)
877 {
878 pEntry = m_pView->NextVisible(pEntry);
879 nStartLine--;
880 }
881
882 vcl::Region aClipRegion(GetClipRegionRect());
883
884 // first draw the lines, then clip them!
885 rRenderContext.SetClipRegion();
886 if (m_nStyle & (WB_HASLINES | WB_HASLINESATROOT))
887 DrawNet(rRenderContext);
888
889 rRenderContext.SetClipRegion(aClipRegion);
890
891 if (!m_pCursor && !mbNoAutoCurEntry)
892 {
893 // do not select if multiselection or explicit set
894 bool bNotSelect = (m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) || ((m_nStyle & WB_NOINITIALSELECTION) == WB_NOINITIALSELECTION);
895 SetCursor(m_pStartEntry, bNotSelect);
896 }
897
898 for(sal_uInt16 n=0; n< nCount && pEntry; n++)
899 {
900 /*long nMaxRight=*/
901 m_pView->PaintEntry1(*pEntry, nY, rRenderContext );
902 nY += nEntryHeight;
903 pEntry = m_pView->NextVisible(pEntry);
904 }
905
906 m_nFlags &= ~LBoxFlags::DeselectAll;
907 rRenderContext.SetClipRegion();
908 m_nFlags &= ~LBoxFlags::InPaint;
909}
910
911void SvImpLBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop )
912{
913 if( !pEntry )
914 return;
915
916 bool bInView = IsEntryInView( pEntry );
917
918 if( bInView && (!bMoveToTop || m_pStartEntry == pEntry) )
919 return; // is already visible
920
921 if( m_pStartEntry || mbForceMakeVisible )
922 m_nFlags &= ~LBoxFlags::Filling;
923 if( !bInView )
924 {
925 if( !m_pView->IsEntryVisible(pEntry) ) // Parent(s) collapsed?
926 {
927 SvTreeListEntry* pParent = m_pView->GetParent( pEntry );
928 while( pParent )
929 {
930 if( !m_pView->IsExpanded( pParent ) )
931 {
932 bool bRet = m_pView->Expand( pParent );
933 DBG_ASSERT(bRet,"Not expanded!")do { if (true && (!(bRet))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "933" ": "), "%s", "Not expanded!"); } } while (false)
;
934 }
935 pParent = m_pView->GetParent( pParent );
936 }
937 // do the parent's children fit into the view or do we have to scroll?
938 if( IsEntryInView( pEntry ) && !bMoveToTop )
939 return; // no need to scroll
940 }
941 }
942
943 m_pStartEntry = pEntry;
944 ShowCursor( false );
945 FillView();
946 m_aVerSBar->SetThumbPos( static_cast<long>(m_pView->GetVisiblePos( m_pStartEntry )) );
947 ShowCursor( true );
948 m_pView->Invalidate();
949}
950
951void SvImpLBox::ScrollToAbsPos( long nPos )
952{
953 if( m_pView->GetVisibleCount() == 0 )
954 return;
955 long nLastEntryPos = m_pView->GetAbsPos( m_pView->Last() );
956
957 if( nPos < 0 )
958 nPos = 0;
959 else if( nPos > nLastEntryPos )
960 nPos = nLastEntryPos;
961
962 SvTreeListEntry* pEntry = m_pView->GetEntryAtAbsPos( nPos );
963 if( !pEntry || pEntry == m_pStartEntry )
964 return;
965
966 if( m_pStartEntry || mbForceMakeVisible )
967 m_nFlags &= ~LBoxFlags::Filling;
968
969 if( m_pView->IsEntryVisible(pEntry) )
970 {
971 m_pStartEntry = pEntry;
972 ShowCursor( false );
973 m_aVerSBar->SetThumbPos( nPos );
974 ShowCursor( true );
975 if (GetUpdateMode())
976 m_pView->Invalidate();
977 }
978}
979
980void SvImpLBox::DrawNet(vcl::RenderContext& rRenderContext)
981{
982 if (m_pView->GetVisibleCount() < 2 && !m_pStartEntry->HasChildrenOnDemand() &&
983 !m_pStartEntry->HasChildren())
984 {
985 return;
986 }
987
988 // for platforms that don't have nets, DrawNativeControl does nothing and returns true
989 // so that SvImpLBox::DrawNet() doesn't draw anything either
990 if (rRenderContext.IsNativeControlSupported(ControlType::ListNet, ControlPart::Entire))
991 {
992 ImplControlValue aControlValue;
993 if (rRenderContext.DrawNativeControl(ControlType::ListNet, ControlPart::Entire,
994 tools::Rectangle(), ControlState::ENABLED, aControlValue, OUString()))
995 {
996 return;
997 }
998 }
999
1000 long nEntryHeight = m_pView->GetEntryHeight();
1001 long nEntryHeightDIV2 = nEntryHeight / 2;
1002 if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001))
1003 nEntryHeightDIV2--;
1004
1005 SvTreeListEntry* pChild;
1006 SvTreeListEntry* pEntry = m_pStartEntry;
1007
1008 SvLBoxTab* pFirstDynamicTab = m_pView->GetFirstDynamicTab();
1009 while (m_pTree->GetDepth( pEntry ) > 0)
1010 {
1011 pEntry = m_pView->GetParent(pEntry);
1012 }
1013 sal_uInt16 nOffs = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pStartEntry) - m_pView->GetVisiblePos(pEntry));
1014 long nY = 0;
1015 nY -= (nOffs * nEntryHeight);
1016
1017 DBG_ASSERT(pFirstDynamicTab,"No Tree!")do { if (true && (!(pFirstDynamicTab))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "1017" ": "), "%s", "No Tree!"); } } while (false)
;
1018
1019 rRenderContext.Push(PushFlags::LINECOLOR);
1020
1021 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1022 Color aCol = rStyleSettings.GetFaceColor();
1023
1024 if (aCol.IsRGBEqual(rRenderContext.GetBackground().GetColor()))
1025 aCol = rStyleSettings.GetShadowColor();
1026 rRenderContext.SetLineColor(aCol);
1027 Point aPos1, aPos2;
1028 sal_uInt16 nDistance;
1029 sal_uLong nMax = m_nVisibleCount + nOffs + 1;
1030
1031 const Image& rExpandedNodeBitmap = GetExpandedNodeBmp();
1032
1033 for (sal_uLong n=0; n< nMax && pEntry; n++)
1034 {
1035 if (m_pView->IsExpanded(pEntry))
1036 {
1037 aPos1.setX( m_pView->GetTabPos(pEntry, pFirstDynamicTab) );
1038 // if it is not a context bitmap, go a little to the right below the
1039 // first text (node bitmap, too)
1040 if (!m_pView->nContextBmpWidthMax)
1041 aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 );
1042
1043 aPos1.setY( nY );
1044 aPos1.AdjustY(nEntryHeightDIV2 );
1045
1046 pChild = m_pView->FirstChild( pEntry );
1047 assert(pChild && "Child?")(static_cast <bool> (pChild && "Child?") ? void
(0) : __assert_fail ("pChild && \"Child?\"", "/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
, 1047, __extension__ __PRETTY_FUNCTION__))
;
1048 pChild = pChild->LastSibling();
1049 nDistance = static_cast<sal_uInt16>(m_pView->GetVisiblePos(pChild) - m_pView->GetVisiblePos(pEntry));
1050 aPos2 = aPos1;
1051 aPos2.AdjustY(nDistance * nEntryHeight );
1052 rRenderContext.DrawLine(aPos1, aPos2);
1053 }
1054 // visible in control?
1055 if (n >= nOffs && ((m_nStyle & WB_HASLINESATROOT) || !m_pTree->IsAtRootDepth(pEntry)))
1056 {
1057 // can we recycle aPos1?
1058 if (!m_pView->IsExpanded(pEntry))
1059 {
1060 // nope
1061 aPos1.setX( m_pView->GetTabPos(pEntry, pFirstDynamicTab) );
1062 // if it is not a context bitmap, go a little to the right below
1063 // the first text (node bitmap, too)
1064 if (!m_pView->nContextBmpWidthMax)
1065 aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 );
1066 aPos1.setY( nY );
1067 aPos1.AdjustY(nEntryHeightDIV2 );
1068 aPos2.setX( aPos1.X() );
1069 }
1070 aPos2.setY( aPos1.Y() );
1071 aPos2.AdjustX( -(m_pView->GetIndent()) );
1072 rRenderContext.DrawLine(aPos1, aPos2);
1073 }
1074 nY += nEntryHeight;
1075 pEntry = m_pView->NextVisible(pEntry);
1076 }
1077 if (m_nStyle & WB_HASLINESATROOT)
1078 {
1079 pEntry = m_pView->First();
1080 aPos1.setX( m_pView->GetTabPos(pEntry, pFirstDynamicTab) );
1081 // if it is not a context bitmap, go a little to the right below the
1082 // first text (node bitmap, too)
1083 if (!m_pView->nContextBmpWidthMax)
1084 aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 );
1085 aPos1.AdjustX( -(m_pView->GetIndent()) );
1086 aPos1.setY( GetEntryLine( pEntry ) );
1087 aPos1.AdjustY(nEntryHeightDIV2 );
1088 pChild = pEntry->LastSibling();
1089 aPos2.setX( aPos1.X() );
1090 aPos2.setY( GetEntryLine( pChild ) );
1091 aPos2.AdjustY(nEntryHeightDIV2 );
1092 rRenderContext.DrawLine(aPos1, aPos2);
1093 }
1094 rRenderContext.Pop();
1095}
1096
1097void SvImpLBox::PositionScrollBars( Size& rSize, sal_uInt16 nMask )
1098{
1099 long nOverlap = 0;
1100
1101 Size aVerSize( m_nVerSBarWidth, rSize.Height() );
1102 Size aHorSize( rSize.Width(), m_nHorSBarHeight );
1103
1104 if( nMask & 0x0001 )
1105 aHorSize.AdjustWidth( -m_nVerSBarWidth );
1106 if( nMask & 0x0002 )
1107 aVerSize.AdjustHeight( -m_nHorSBarHeight );
1108
1109 aVerSize.AdjustHeight(2 * nOverlap );
1110 Point aVerPos( rSize.Width() - aVerSize.Width() + nOverlap, -nOverlap );
1111 m_aVerSBar->SetPosSizePixel( aVerPos, aVerSize );
1112
1113 aHorSize.AdjustWidth(2 * nOverlap );
1114 Point aHorPos( -nOverlap, rSize.Height() - aHorSize.Height() + nOverlap );
1115
1116 m_aHorSBar->SetPosSizePixel( aHorPos, aHorSize );
1117
1118 if( nMask & 0x0001 )
1119 rSize.setWidth( aVerPos.X() );
1120 if( nMask & 0x0002 )
1121 rSize.setHeight( aHorPos.Y() );
1122
1123 if( (nMask & (0x0001|0x0002)) == (0x0001|0x0002) )
1124 m_aScrBarBox->Show();
1125 else
1126 m_aScrBarBox->Hide();
1127}
1128
1129void SvImpLBox::AdjustScrollBars( Size& rSize )
1130{
1131 long nEntryHeight = m_pView->GetEntryHeight();
1132 if( !nEntryHeight )
1133 return;
1134
1135 sal_uInt16 nResult = 0;
1136
1137 Size aOSize( m_pView->Control::GetOutputSizePixel() );
1138
1139 const WinBits nWindowStyle = m_pView->GetStyle();
1140 bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
1141 bool bHorBar = false;
1142 long nMaxRight = aOSize.Width(); //GetOutputSize().Width();
1143 Point aOrigin( m_pView->GetMapMode().GetOrigin() );
1144 aOrigin.setX( aOrigin.X() * -1 );
1145 nMaxRight += aOrigin.X() - 1;
1146 long nVis = m_nMostRight - aOrigin.X();
1147 if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) &&
1148 (nVis < m_nMostRight || nMaxRight < m_nMostRight) )
1149 {
1150 bHorBar = true;
1151 }
1152
1153 // number of entries that are not collapsed
1154 sal_uLong nTotalCount = m_pView->GetVisibleCount();
1155
1156 // number of entries visible within the view
1157 m_nVisibleCount = aOSize.Height() / nEntryHeight;
1158
1159 // do we need a vertical scrollbar?
1160 if( bVerSBar || nTotalCount > m_nVisibleCount )
1161 {
1162 nResult = 1;
1163 nMaxRight -= m_nVerSBarWidth;
1164 if( !bHorBar )
1165 {
1166 if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) &&
1167 (nVis < m_nMostRight || nMaxRight < m_nMostRight) )
1168 bHorBar = true;
1169 }
1170 }
1171
1172 // do we need a horizontal scrollbar?
1173 if( bHorBar )
1174 {
1175 nResult |= 0x0002;
1176 // the number of entries visible within the view has to be recalculated
1177 // because the horizontal scrollbar is now visible.
1178 m_nVisibleCount = (aOSize.Height() - m_nHorSBarHeight) / nEntryHeight;
1179 // we might actually need a vertical scrollbar now
1180 if( !(nResult & 0x0001) &&
1181 ((nTotalCount > m_nVisibleCount) || bVerSBar) )
1182 {
1183 nResult = 3;
1184 }
1185 }
1186
1187 PositionScrollBars( aOSize, nResult );
1188
1189 // adapt Range, VisibleRange etc.
1190
1191 // refresh output size, in case we have to scroll
1192 tools::Rectangle aRect;
1193 aRect.SetSize( aOSize );
1194 m_aSelEng.SetVisibleArea( aRect );
1195
1196 // vertical scrollbar
1197 long nTemp = static_cast<long>(m_nVisibleCount);
1198 nTemp--;
1199 if( nTemp != m_aVerSBar->GetVisibleSize() )
1200 {
1201 if( !m_bInVScrollHdl )
1202 {
1203 m_aVerSBar->SetPageSize( nTemp - 1 );
1204 m_aVerSBar->SetVisibleSize( nTemp );
1205 }
1206 else
1207 {
1208 m_nFlags |= LBoxFlags::EndScrollSetVisSize;
1209 m_nNextVerVisSize = nTemp;
1210 }
1211 }
1212
1213 // horizontal scrollbar
1214 nTemp = m_aHorSBar->GetThumbPos();
1215 m_aHorSBar->SetVisibleSize( aOSize.Width() );
1216 long nNewThumbPos = m_aHorSBar->GetThumbPos();
1217 Range aRange( m_aHorSBar->GetRange() );
1218 if( aRange.Max() < m_nMostRight+25 )
1219 {
1220 aRange.Max() = m_nMostRight+25;
1221 m_aHorSBar->SetRange( aRange );
1222 }
1223
1224 if( nTemp != nNewThumbPos )
1225 {
1226 nTemp = nNewThumbPos - nTemp;
1227 if( m_pView->IsEditingActive() )
1228 {
1229 m_pView->EndEditing( true ); // Cancel
1230 m_pView->PaintImmediately();
1231 }
1232 m_pView->nFocusWidth = -1;
1233 KeyLeftRight( nTemp );
1234 }
1235
1236 if( nResult & 0x0001 )
1237 m_aVerSBar->Show();
1238 else
1239 m_aVerSBar->Hide();
1240
1241 if( nResult & 0x0002 )
1242 m_aHorSBar->Show();
1243 else
1244 {
1245 m_aHorSBar->Hide();
1246 }
1247 rSize = aOSize;
1248}
1249
1250void SvImpLBox::InitScrollBarBox()
1251{
1252 m_aScrBarBox->SetSizePixel( Size(m_nVerSBarWidth, m_nHorSBarHeight) );
1253 Size aSize( m_pView->Control::GetOutputSizePixel() );
1254 m_aScrBarBox->SetPosPixel( Point(aSize.Width()-m_nVerSBarWidth, aSize.Height()-m_nHorSBarHeight));
1255}
1256
1257void SvImpLBox::Resize()
1258{
1259 m_aOutputSize = m_pView->Control::GetOutputSizePixel();
1260 if( m_aOutputSize.IsEmpty() )
1261 return;
1262 m_nFlags |= LBoxFlags::InResize;
1263 InitScrollBarBox();
1264
1265 if( m_pView->GetEntryHeight())
1266 {
1267 AdjustScrollBars( m_aOutputSize );
1268 UpdateAll(false);
1269 }
1270 // HACK, as in floating and docked windows the scrollbars might not be drawn
1271 // correctly/not be drawn at all after resizing!
1272 if( m_aHorSBar->IsVisible())
1273 m_aHorSBar->Invalidate();
1274 if( m_aVerSBar->IsVisible())
1275 m_aVerSBar->Invalidate();
1276 m_nFlags &= ~LBoxFlags::InResize;
1277}
1278
1279void SvImpLBox::FillView()
1280{
1281 if( !m_pStartEntry )
1282 {
1283 sal_uLong nVisibleViewCount = m_pView->GetVisibleCount();
1284 long nTempThumb = m_aVerSBar->GetThumbPos();
1285 if( nTempThumb < 0 )
1286 nTempThumb = 0;
1287 else if( o3tl::make_unsigned(nTempThumb) >= nVisibleViewCount )
1288 nTempThumb = nVisibleViewCount == 0 ? 0 : nVisibleViewCount - 1;
1289 m_pStartEntry = m_pView->GetEntryAtVisPos(nTempThumb);
1290 }
1291 if( !m_pStartEntry )
1292 return;
1293
1294 sal_uInt16 nLast = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pView->LastVisible()));
1295 sal_uInt16 nThumb = static_cast<sal_uInt16>(m_pView->GetVisiblePos( m_pStartEntry ));
1296 sal_uLong nCurDispEntries = nLast-nThumb+1;
1297 if( nCurDispEntries >= m_nVisibleCount )
1298 return;
1299
1300 ShowCursor( false );
1301 // fill window by moving the thumb up incrementally
1302 bool bFound = false;
1303 SvTreeListEntry* pTemp = m_pStartEntry;
1304 while( nCurDispEntries < m_nVisibleCount && pTemp )
1305 {
1306 pTemp = m_pView->PrevVisible(m_pStartEntry);
1307 if( pTemp )
1308 {
1309 nThumb--;
1310 m_pStartEntry = pTemp;
1311 nCurDispEntries++;
1312 bFound = true;
1313 }
1314 }
1315 if( bFound )
1316 {
1317 m_aVerSBar->SetThumbPos( nThumb );
1318 ShowCursor( true ); // recalculate focus rectangle
1319 m_pView->Invalidate();
1320 }
1321}
1322
1323
1324void SvImpLBox::ShowVerSBar()
1325{
1326 bool bVerBar = ( m_pView->GetStyle() & WB_VSCROLL ) != 0;
1327 sal_uLong nVis = 0;
1328 if( !bVerBar )
1329 nVis = m_pView->GetVisibleCount();
1330 if( bVerBar || (m_nVisibleCount && nVis > static_cast<sal_uLong>(m_nVisibleCount-1)) )
1331 {
1332 if( !m_aVerSBar->IsVisible() )
1333 {
1334 m_pView->nFocusWidth = -1;
1335 AdjustScrollBars( m_aOutputSize );
1336 if( GetUpdateMode() )
1337 m_aVerSBar->Invalidate();
1338 }
1339 }
1340 else
1341 {
1342 if( m_aVerSBar->IsVisible() )
1343 {
1344 m_pView->nFocusWidth = -1;
1345 AdjustScrollBars( m_aOutputSize );
1346 }
1347 }
1348
1349 long nMaxRight = GetOutputSize().Width();
1350 Point aPos( m_pView->GetMapMode().GetOrigin() );
1351 aPos.setX( aPos.X() * -1 ); // convert document coordinates
1352 nMaxRight = nMaxRight + aPos.X() - 1;
1353 if( nMaxRight < m_nMostRight )
1354 {
1355 if( !m_aHorSBar->IsVisible() )
1356 {
1357 m_pView->nFocusWidth = -1;
1358 AdjustScrollBars( m_aOutputSize );
1359 if( GetUpdateMode() )
1360 m_aHorSBar->Invalidate();
1361 }
1362 else
1363 {
1364 Range aRange( m_aHorSBar->GetRange() );
1365 if( aRange.Max() < m_nMostRight+25 )
1366 {
1367 aRange.Max() = m_nMostRight+25;
1368 m_aHorSBar->SetRange( aRange );
1369 }
1370 else
1371 {
1372 m_pView->nFocusWidth = -1;
1373 AdjustScrollBars( m_aOutputSize );
1374 }
1375 }
1376 }
1377 else
1378 {
1379 if( m_aHorSBar->IsVisible() )
1380 {
1381 m_pView->nFocusWidth = -1;
1382 AdjustScrollBars( m_aOutputSize );
1383 }
1384 }
1385}
1386
1387
1388void SvImpLBox::SyncVerThumb()
1389{
1390 if( m_pStartEntry )
1391 {
1392 long nEntryPos = m_pView->GetVisiblePos( m_pStartEntry );
1393 m_aVerSBar->SetThumbPos( nEntryPos );
1394 }
1395 else
1396 m_aVerSBar->SetThumbPos( 0 );
1397}
1398
1399bool SvImpLBox::IsEntryInView( SvTreeListEntry* pEntry ) const
1400{
1401 // parent collapsed
1402 if( !m_pView->IsEntryVisible(pEntry) )
1403 return false;
1404 long nY = GetEntryLine( pEntry );
1405 if( nY < 0 )
1406 return false;
1407 long nMax = m_nVisibleCount * m_pView->GetEntryHeight();
1408 return nY < nMax;
1409}
1410
1411
1412long SvImpLBox::GetEntryLine(const SvTreeListEntry* pEntry) const
1413{
1414 if(!m_pStartEntry )
1415 return -1; // invisible position
1416
1417 long nFirstVisPos = m_pView->GetVisiblePos( m_pStartEntry );
1418 long nEntryVisPos = m_pView->GetVisiblePos( pEntry );
1419 nFirstVisPos = nEntryVisPos - nFirstVisPos;
1420 nFirstVisPos *= m_pView->GetEntryHeight();
1421 return nFirstVisPos;
1422}
1423
1424void SvImpLBox::SetEntryHeight()
1425{
1426 SetNodeBmpWidth( GetExpandedNodeBmp() );
1427 SetNodeBmpWidth( GetCollapsedNodeBmp() );
1428 if(!m_pView->HasViewData()) // are we within the Clear?
1429 {
1430 Size aSize = m_pView->Control::GetOutputSizePixel();
1431 AdjustScrollBars( aSize );
1432 }
1433 else
1434 {
1435 Resize();
1436 if( GetUpdateMode() )
1437 m_pView->Invalidate();
1438 }
1439}
1440
1441
1442// ***********************************************************************
1443// Callback Functions
1444// ***********************************************************************
1445
1446void SvImpLBox::EntryExpanded( SvTreeListEntry* pEntry )
1447{
1448 // SelAllDestrAnch( false, true ); //DeselectAll();
1449 if( !GetUpdateMode() )
1450 return;
1451
1452 ShowCursor( false );
1453 long nY = GetEntryLine( pEntry );
1454 if( IsLineVisible(nY) )
1455 {
1456 InvalidateEntriesFrom( nY );
1457 FindMostRight( pEntry );
1458 }
1459 m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) );
1460 // if we expanded before the thumb, the thumb's position has to be
1461 // corrected
1462 SyncVerThumb();
1463 ShowVerSBar();
1464 ShowCursor( true );
1465}
1466
1467void SvImpLBox::EntryCollapsed( SvTreeListEntry* pEntry )
1468{
1469 if( !m_pView->IsEntryVisible( pEntry ) )
1470 return;
1471
1472 ShowCursor( false );
1473
1474 if( !m_pMostRightEntry || m_pTree->IsChild( pEntry,m_pMostRightEntry ) )
1475 {
1476 FindMostRight();
1477 }
1478
1479 if( m_pStartEntry )
1480 {
1481 long nOldThumbPos = m_aVerSBar->GetThumbPos();
1482 sal_uLong nVisList = m_pView->GetVisibleCount();
1483 m_aVerSBar->SetRange( Range(0, nVisList-1) );
1484 long nNewThumbPos = m_aVerSBar->GetThumbPos();
1485 if( nNewThumbPos != nOldThumbPos )
1486 {
1487 m_pStartEntry = m_pView->First();
1488 sal_uInt16 nDistance = static_cast<sal_uInt16>(nNewThumbPos);
1489 if( nDistance )
1490 m_pStartEntry = m_pView->NextVisible(m_pStartEntry, nDistance);
1491 if( GetUpdateMode() )
1492 m_pView->Invalidate();
1493 }
1494 else
1495 SyncVerThumb();
1496 ShowVerSBar();
1497 }
1498 // has the cursor been collapsed?
1499 if( m_pTree->IsChild( pEntry, m_pCursor ) )
1500 SetCursor( pEntry );
1501 if( GetUpdateMode() )
1502 ShowVerSBar();
1503 ShowCursor( true );
1504 if( GetUpdateMode() && m_pCursor )
1505 m_pView->Select( m_pCursor );
1506}
1507
1508void SvImpLBox::CollapsingEntry( SvTreeListEntry* pEntry )
1509{
1510 if( !m_pView->IsEntryVisible( pEntry ) || !m_pStartEntry )
1511 return;
1512
1513 SelAllDestrAnch( false ); // deselect all
1514
1515 // is the collapsed cursor visible?
1516 long nY = GetEntryLine( pEntry );
1517 if( IsLineVisible(nY) )
1518 {
1519 if( GetUpdateMode() )
1520 InvalidateEntriesFrom( nY );
1521 }
1522 else
1523 {
1524 if( m_pTree->IsChild(pEntry, m_pStartEntry) )
1525 {
1526 m_pStartEntry = pEntry;
1527 if( GetUpdateMode() )
1528 m_pView->Invalidate();
1529 }
1530 }
1531}
1532
1533
1534void SvImpLBox::SetNodeBmpWidth( const Image& rBmp )
1535{
1536 const Size aSize( rBmp.GetSizePixel() );
1537 m_nNodeBmpWidth = aSize.Width();
1538}
1539
1540void SvImpLBox::SetNodeBmpTabDistance()
1541{
1542 m_nNodeBmpTabDistance = -m_pView->GetIndent();
1543 if( m_pView->nContextBmpWidthMax )
1544 {
1545 // only if the first dynamic tab is centered (we currently assume that)
1546 Size aSize = GetExpandedNodeBmp().GetSizePixel();
1547 m_nNodeBmpTabDistance -= aSize.Width() / 2;
1548 }
1549}
1550
1551
1552// corrects the cursor when using SingleSelection
1553
1554void SvImpLBox::EntrySelected( SvTreeListEntry* pEntry, bool bSelect )
1555{
1556 if( m_nFlags & LBoxFlags::IgnoreSelect )
1557 return;
1558
1559 m_nFlags &= ~LBoxFlags::DeselectAll;
1560 if( bSelect &&
1561 m_aSelEng.GetSelectionMode() == SelectionMode::Single &&
1562 pEntry != m_pCursor )
1563 {
1564 SetCursor( pEntry );
1565 DBG_ASSERT(m_pView->GetSelectionCount()==1,"selection count?")do { if (true && (!(m_pView->GetSelectionCount()==
1))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "1565" ": "), "%s", "selection count?"); } } while (false
)
;
1566 }
1567
1568 if( GetUpdateMode() && m_pView->IsEntryVisible(pEntry) )
1569 {
1570 long nY = GetEntryLine( pEntry );
1571 if( IsLineVisible( nY ) )
1572 {
1573 ShowCursor(false);
1574 InvalidateEntry(pEntry);
1575 ShowCursor(true);
1576 }
1577 }
1578}
1579
1580
1581void SvImpLBox::RemovingEntry( SvTreeListEntry* pEntry )
1582{
1583 CallEventListeners( VclEventId::ListboxItemRemoved , pEntry );
1584
1585 DestroyAnchor();
1586
1587 if( !m_pView->IsEntryVisible( pEntry ) )
1588 {
1589 // if parent is collapsed => bye!
1590 m_nFlags |= LBoxFlags::RemovedEntryInvisible;
1591 return;
1592 }
1593
1594 if( pEntry == m_pMostRightEntry || (
1595 pEntry->HasChildren() && m_pView->IsExpanded(pEntry) &&
1596 m_pTree->IsChild(pEntry, m_pMostRightEntry)))
1597 {
1598 m_nFlags |= LBoxFlags::RemovedRecalcMostRight;
1599 }
1600
1601 SvTreeListEntry* pOldStartEntry = m_pStartEntry;
1602
1603 SvTreeListEntry* pParent = m_pView->GetModel()->GetParent(pEntry);
1604
1605 if (pParent && m_pView->GetModel()->GetChildList(pParent).size() == 1)
1606 {
1607 DBG_ASSERT( m_pView->IsExpanded( pParent ), "Parent not expanded")do { if (true && (!(m_pView->IsExpanded( pParent )
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "1607" ": "), "%s", "Parent not expanded"); } } while (false
)
;
1608 pParent->SetFlags( pParent->GetFlags() | SvTLEntryFlags::NO_NODEBMP);
1609 InvalidateEntry( pParent );
1610 }
1611
1612 if( m_pCursor && m_pTree->IsChild( pEntry, m_pCursor) )
1613 m_pCursor = pEntry;
1614 if( m_pStartEntry && m_pTree->IsChild(pEntry,m_pStartEntry) )
1615 m_pStartEntry = pEntry;
1616
1617 SvTreeListEntry* pTemp;
1618 if( m_pCursor && m_pCursor == pEntry )
1619 {
1620 if( m_bSimpleTravel )
1621 m_pView->Select( m_pCursor, false );
1622 ShowCursor( false ); // focus rectangle gone
1623 // NextSibling, because we also delete the children of the cursor
1624 pTemp = m_pCursor->NextSibling();
1625 if( !pTemp )
1626 pTemp = m_pView->PrevVisible(m_pCursor);
1627
1628 SetCursor( pTemp, true );
1629 }
1630 if( m_pStartEntry && m_pStartEntry == pEntry )
1631 {
1632 pTemp = m_pStartEntry->NextSibling();
1633 if( !pTemp )
1634 pTemp = m_pView->PrevVisible(m_pStartEntry);
1635 m_pStartEntry = pTemp;
1636 }
1637 if( GetUpdateMode())
1638 {
1639 // if it is the last one, we have to invalidate it, so the lines are
1640 // drawn correctly (in this case they're deleted)
1641 if( m_pStartEntry && (m_pStartEntry != pOldStartEntry || pEntry == m_pView->GetModel()->Last()) )
1642 {
1643 m_aVerSBar->SetThumbPos( m_pView->GetVisiblePos( m_pStartEntry ));
1644 m_pView->Invalidate( GetVisibleArea() );
1645 }
1646 else
1647 InvalidateEntriesFrom( GetEntryLine( pEntry ) );
1648 }
1649}
1650
1651void SvImpLBox::EntryRemoved()
1652{
1653 if( m_nFlags & LBoxFlags::RemovedEntryInvisible )
1654 {
1655 m_nFlags &= ~LBoxFlags::RemovedEntryInvisible;
1656 return;
1657 }
1658 if( !m_pStartEntry )
1659 m_pStartEntry = m_pTree->First();
1660 if( !m_pCursor )
1661 SetCursor( m_pStartEntry, true );
1662
1663 if( m_pCursor && (m_bSimpleTravel || !m_pView->GetSelectionCount() ))
1664 m_pView->Select( m_pCursor );
1665
1666 if( GetUpdateMode())
1667 {
1668 if( m_nFlags & LBoxFlags::RemovedRecalcMostRight )
1669 FindMostRight();
1670 m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) );
1671 FillView();
1672 if( m_pStartEntry )
1673 // if something above the thumb was deleted
1674 m_aVerSBar->SetThumbPos( m_pView->GetVisiblePos( m_pStartEntry) );
1675
1676 ShowVerSBar();
1677 if( m_pCursor && m_pView->HasFocus() && !m_pView->IsSelected(m_pCursor) )
1678 {
1679 if( m_pView->GetSelectionCount() )
1680 {
1681 // is a neighboring entry selected?
1682 SvTreeListEntry* pNextCursor = m_pView->PrevVisible( m_pCursor );
1683 if( !pNextCursor || !m_pView->IsSelected( pNextCursor ))
1684 pNextCursor = m_pView->NextVisible( m_pCursor );
1685 if( !pNextCursor || !m_pView->IsSelected( pNextCursor ))
1686 // no neighbor selected: use first selected
1687 pNextCursor = m_pView->FirstSelected();
1688 SetCursor( pNextCursor );
1689 MakeVisible( m_pCursor );
1690 }
1691 else
1692 m_pView->Select( m_pCursor );
1693 }
1694 ShowCursor( true );
1695 }
1696 m_nFlags &= ~LBoxFlags::RemovedRecalcMostRight;
1697}
1698
1699
1700void SvImpLBox::MovingEntry( SvTreeListEntry* pEntry )
1701{
1702 bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll);
1703 SelAllDestrAnch( false ); // DeselectAll();
1704 if( !bDeselAll
0.1
'bDeselAll' is false
)
1
Taking true branch
1705 m_nFlags &= ~LBoxFlags::DeselectAll;
1706
1707 if( pEntry == m_pCursor )
2
Assuming 'pEntry' is not equal to field 'm_pCursor'
3
Taking false branch
1708 ShowCursor( false );
1709 if( IsEntryInView( pEntry ) )
4
Taking false branch
1710 m_pView->Invalidate();
1711 if( pEntry != m_pStartEntry )
5
Assuming 'pEntry' is equal to field 'm_pStartEntry'
6
Taking false branch
1712 return;
1713
1714 SvTreeListEntry* pNew = nullptr;
1715 if( !pEntry->HasChildren() )
7
Called C++ object pointer is null
1716 {
1717 pNew = m_pView->NextVisible(m_pStartEntry);
1718 if( !pNew )
1719 pNew = m_pView->PrevVisible(m_pStartEntry);
1720 }
1721 else
1722 {
1723 pNew = pEntry->NextSibling();
1724 if( !pNew )
1725 pNew = pEntry->PrevSibling();
1726 }
1727 m_pStartEntry = pNew;
1728}
1729
1730void SvImpLBox::EntryMoved( SvTreeListEntry* pEntry )
1731{
1732 UpdateContextBmpWidthVectorFromMovedEntry( pEntry );
1733
1734 if ( !m_pStartEntry )
1735 // this might happen if the only entry in the view is moved to its very same position
1736 // #i97346#
1737 m_pStartEntry = m_pView->First();
1738
1739 m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1));
1740 sal_uInt16 nFirstPos = static_cast<sal_uInt16>(m_pTree->GetAbsPos( m_pStartEntry ));
1741 sal_uInt16 nNewPos = static_cast<sal_uInt16>(m_pTree->GetAbsPos( pEntry ));
1742 FindMostRight();
1743 if( nNewPos < nFirstPos ) // HACK!
1744 m_pStartEntry = pEntry;
1745 SyncVerThumb();
1746 if( pEntry == m_pCursor )
1747 {
1748 if( m_pView->IsEntryVisible( m_pCursor ) )
1749 ShowCursor( true );
1750 else
1751 {
1752 SvTreeListEntry* pParent = pEntry;
1753 do {
1754 pParent = m_pTree->GetParent( pParent );
1755 }
1756 while( !m_pView->IsEntryVisible( pParent ) );
1757 SetCursor( pParent );
1758 }
1759 }
1760 if( IsEntryInView( pEntry ) )
1761 m_pView->Invalidate();
1762}
1763
1764
1765void SvImpLBox::EntryInserted( SvTreeListEntry* pEntry )
1766{
1767 if( !GetUpdateMode() )
1768 return;
1769
1770 SvTreeListEntry* pParent = m_pTree->GetParent(pEntry);
1771 if (pParent && m_pTree->GetChildList(pParent).size() == 1)
1772 // draw plus sign
1773 m_pTree->InvalidateEntry( pParent );
1774
1775 if( !m_pView->IsEntryVisible( pEntry ) )
1776 return;
1777 bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll);
1778 if( bDeselAll )
1779 SelAllDestrAnch( false );
1780 else
1781 DestroyAnchor();
1782 // nFlags &= (~LBoxFlags::DeselectAll);
1783// ShowCursor( false ); // if cursor is moved lower
1784 long nY = GetEntryLine( pEntry );
1785 bool bEntryVisible = IsLineVisible( nY );
1786 if( bEntryVisible )
1787 {
1788 ShowCursor( false ); // if cursor is moved lower
1789 nY -= m_pView->GetEntryHeight(); // because of lines
1790 InvalidateEntriesFrom( nY );
1791 }
1792 else if( m_pStartEntry && nY < GetEntryLine(m_pStartEntry) )
1793 {
1794 // Check if the view is filled completely. If not, then adjust
1795 // pStartEntry and the Cursor (automatic scrolling).
1796 sal_uInt16 nLast = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pView->LastVisible()));
1797 sal_uInt16 nThumb = static_cast<sal_uInt16>(m_pView->GetVisiblePos( m_pStartEntry ));
1798 sal_uInt16 nCurDispEntries = nLast-nThumb+1;
1799 if( nCurDispEntries < m_nVisibleCount )
1800 {
1801 // set at the next paint event
1802 m_pStartEntry = nullptr;
1803 SetCursor( nullptr );
1804 m_pView->Invalidate();
1805 }
1806 }
1807 else if( !m_pStartEntry )
1808 m_pView->Invalidate();
1809
1810 SetMostRight( pEntry );
1811 m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1));
1812 SyncVerThumb(); // if something was inserted before the thumb
1813 ShowVerSBar();
1814 ShowCursor( true );
1815 if( m_pStartEntry != m_pView->First() && (m_nFlags & LBoxFlags::Filling) )
1816 m_pView->PaintImmediately();
1817}
1818
1819
1820// ********************************************************************
1821// Event handler
1822// ********************************************************************
1823
1824
1825// ****** Control the control animation
1826
1827bool SvImpLBox::ButtonDownCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry* pEntry)
1828{
1829 SvLBoxItem* pItem = m_pView->GetItem(pEntry,rMEvt.GetPosPixel().X(),&m_pActiveTab);
1830 if (pItem && pItem->GetType() == SvLBoxItemType::Button)
1831 {
1832 m_pActiveButton = static_cast<SvLBoxButton*>(pItem);
1833 m_pActiveEntry = pEntry;
1834 if( m_pCursor == m_pActiveEntry )
1835 m_pView->HideFocus();
1836 m_pView->CaptureMouse();
1837 m_pActiveButton->SetStateHilighted( true );
1838 InvalidateEntry(m_pActiveEntry);
1839 return true;
1840 }
1841 else
1842 m_pActiveButton = nullptr;
1843 return false;
1844}
1845
1846bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry const * pEntry)
1847{
1848 if( m_pActiveButton )
1849 {
1850 long nMouseX = rMEvt.GetPosPixel().X();
1851 if( pEntry == m_pActiveEntry &&
1852 m_pView->GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton )
1853 {
1854 if( !m_pActiveButton->IsStateHilighted() )
1855 {
1856 m_pActiveButton->SetStateHilighted(true );
1857 InvalidateEntry(m_pActiveEntry);
1858 }
1859 }
1860 else
1861 {
1862 if( m_pActiveButton->IsStateHilighted() )
1863 {
1864 m_pActiveButton->SetStateHilighted(false );
1865 InvalidateEntry(m_pActiveEntry);
1866 }
1867 }
1868 return true;
1869 }
1870 return false;
1871}
1872
1873bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt )
1874{
1875 if( m_pActiveButton )
1876 {
1877 m_pView->ReleaseMouse();
1878 SvTreeListEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() );
1879 m_pActiveButton->SetStateHilighted( false );
1880 long nMouseX = rMEvt.GetPosPixel().X();
1881 if (pEntry == m_pActiveEntry && m_pView->GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton)
1882 m_pActiveButton->ClickHdl(m_pActiveEntry);
1883 InvalidateEntry(m_pActiveEntry);
1884 if (m_pCursor == m_pActiveEntry)
1885 ShowCursor(true);
1886 m_pActiveButton = nullptr;
1887 m_pActiveEntry = nullptr;
1888 m_pActiveTab = nullptr;
1889 return true;
1890 }
1891 return false;
1892}
1893
1894// ******* Control plus/minus button for expanding/collapsing
1895
1896// false == no expand/collapse button hit
1897bool SvImpLBox::IsNodeButton( const Point& rPosPixel, const SvTreeListEntry* pEntry ) const
1898{
1899 if( !pEntry->HasChildren() && !pEntry->HasChildrenOnDemand() )
1900 return false;
1901
1902 SvLBoxTab* pFirstDynamicTab = m_pView->GetFirstDynamicTab();
1903 if( !pFirstDynamicTab )
1904 return false;
1905
1906 long nMouseX = rPosPixel.X();
1907 // convert to document coordinates
1908 Point aOrigin( m_pView->GetMapMode().GetOrigin() );
1909 nMouseX -= aOrigin.X();
1910
1911 long nX = m_pView->GetTabPos( pEntry, pFirstDynamicTab);
1912 nX += m_nNodeBmpTabDistance;
1913 if( nMouseX < nX )
1914 return false;
1915 nX += m_nNodeBmpWidth;
1916 return nMouseX <= nX;
1917}
1918
1919// false == hit no node button
1920bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, SvTreeListEntry* pEntry )
1921{
1922 bool bRet = false;
1923
1924 if ( m_pView->IsEditingActive() && pEntry == m_pView->pEdEntry )
1925 // inplace editing -> nothing to do
1926 bRet = true;
1927 else if ( IsNodeButton( rMEvt.GetPosPixel(), pEntry ) )
1928 {
1929 if ( m_pView->IsExpanded( pEntry ) )
1930 {
1931 m_pView->EndEditing( true );
1932 m_pView->Collapse( pEntry );
1933 }
1934 else
1935 {
1936 // you can expand an entry, which is in editing
1937 m_pView->Expand( pEntry );
1938 }
1939 bRet = true;
1940 }
1941
1942 return bRet;
1943}
1944
1945void SvImpLBox::MouseButtonDown( const MouseEvent& rMEvt )
1946{
1947 if ( !rMEvt.IsLeft() && !rMEvt.IsRight())
1948 return;
1949
1950 m_aEditIdle.Stop();
1951 Point aPos( rMEvt.GetPosPixel());
1952
1953 if( aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height() )
1954 return;
1955
1956 if( !m_pCursor )
1957 m_pCursor = m_pStartEntry;
1958 m_nFlags &= ~LBoxFlags::Filling;
1959 m_pView->GrabFocus();
1960 //fdo#82270 Grabbing focus can invalidate the entries, re-fetch
1961 SvTreeListEntry* pEntry = GetEntry(aPos);
1962 // the entry can still be invalid!
1963 if( !pEntry || !m_pView->GetViewData( pEntry ))
1964 return;
1965
1966 long nY = GetEntryLine( pEntry );
1967 // Node-Button?
1968 if( ButtonDownCheckExpand( rMEvt, pEntry ) )
1969 return;
1970
1971 if( !EntryReallyHit(pEntry,aPos,nY))
1972 return;
1973
1974 SvLBoxItem* pXItem = m_pView->GetItem( pEntry, aPos.X() );
1975 if( pXItem )
1976 {
1977 SvLBoxTab* pXTab = m_pView->GetTab( pEntry, pXItem );
1978 if ( !rMEvt.IsMod1() && !rMEvt.IsMod2() && rMEvt.IsLeft() && pXTab->IsEditable()
1979 && pEntry == m_pView->FirstSelected() && nullptr == m_pView->NextSelected( pEntry ) )
1980 // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected
1981 m_nFlags |= LBoxFlags::StartEditTimer;
1982 if ( !m_pView->IsSelected( pEntry ) )
1983 m_nFlags &= ~LBoxFlags::StartEditTimer;
1984 }
1985
1986
1987 if( (rMEvt.GetClicks() % 2) == 0)
1988 {
1989 m_nFlags &= ~LBoxFlags::StartEditTimer;
1990 m_pView->pHdlEntry = pEntry;
1991 if( !m_pView->DoubleClickHdl() )
1992 {
1993 // Handler signals nothing to be done anymore, bail out, 'this' may
1994 // even be dead and destroyed.
1995 return;
1996 }
1997 else
1998 {
1999 // if the entry was deleted within the handler
2000 pEntry = GetClickedEntry( aPos );
2001 if( !pEntry )
2002 return;
2003 if( pEntry != m_pView->pHdlEntry )
2004 {
2005 // select anew & bye
2006 if( !m_bSimpleTravel && !m_aSelEng.IsAlwaysAdding())
2007 SelAllDestrAnch( false ); // DeselectAll();
2008 SetCursor( pEntry );
2009
2010 return;
2011 }
2012 if( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() )
2013 {
2014 if( m_pView->IsExpanded(pEntry) )
2015 m_pView->Collapse( pEntry );
2016 else
2017 m_pView->Expand( pEntry );
2018 if( pEntry == m_pCursor ) // only if Entryitem was clicked
2019 // (Nodebutton is not an Entryitem!)
2020 m_pView->Select( m_pCursor );
2021 return;
2022 }
2023 }
2024 }
2025 else
2026 {
2027 // CheckButton? (TreeListBox: Check + Info)
2028 if( ButtonDownCheckCtrl(rMEvt, pEntry) )
2029 return;
2030 // Inplace-Editing?
2031 }
2032 if ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE
2033 && !rMEvt.IsRight() ) // tdf#128824
2034 m_aSelEng.SelMouseButtonDown( rMEvt );
2035}
2036
2037void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt)
2038{
2039 if ( !ButtonUpCheckCtrl( rMEvt ) && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
2040 m_aSelEng.SelMouseButtonUp( rMEvt );
2041 if( m_nFlags & LBoxFlags::StartEditTimer )
2042 {
2043 m_nFlags &= ~LBoxFlags::StartEditTimer;
2044 m_aEditClickPos = rMEvt.GetPosPixel();
2045 m_aEditIdle.Start();
2046 }
2047
2048 if (m_pView->mbActivateOnSingleClick)
2049 m_pView->DoubleClickHdl();
2050}
2051
2052void SvImpLBox::MouseMove( const MouseEvent& rMEvt)
2053{
2054 Point aPos = rMEvt.GetPosPixel();
2055 SvTreeListEntry* pEntry = GetClickedEntry(aPos);
2056 if ( !MouseMoveCheckCtrl( rMEvt, pEntry ) && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
2057 {
2058 m_aSelEng.SelMouseMove(rMEvt);
2059 if (m_pView->mbHoverSelection)
2060 {
2061 if (aPos.X() < 0 || aPos.Y() < 0 || aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height())
2062 pEntry = nullptr;
2063 else
2064 pEntry = GetEntry(aPos);
2065 if (!pEntry)
2066 m_pView->SelectAll(false);
2067 else if (!m_pView->IsSelected(pEntry) && IsSelectable(pEntry))
2068 m_pView->Select(pEntry);
2069 }
2070 }
2071}
2072
2073void SvImpLBox::ExpandAll()
2074{
2075 sal_uInt16 nRefDepth = m_pTree->GetDepth(m_pCursor);
2076 SvTreeListEntry* pCur = m_pTree->Next(m_pCursor);
2077 while (pCur && m_pTree->GetDepth(pCur) > nRefDepth)
2078 {
2079 if (pCur->HasChildren() && !m_pView->IsExpanded(pCur))
2080 m_pView->Expand(pCur);
2081 pCur = m_pTree->Next(pCur);
2082 }
2083}
2084
2085void SvImpLBox::CollapseTo(SvTreeListEntry* pParentToCollapse)
2086{
2087 // collapse all parents until we get to the given parent to collapse
2088 if (!pParentToCollapse)
2089 return;
2090
2091 sal_uInt16 nRefDepth;
2092 // special case explorer: if the root only has a single
2093 // entry, don't collapse the root entry
2094 if (m_pTree->GetChildList(nullptr).size() < 2)
2095 {
2096 nRefDepth = 1;
2097 pParentToCollapse = m_pCursor;
2098 while (m_pTree->GetParent(pParentToCollapse)
2099 && m_pTree->GetDepth(m_pTree->GetParent(pParentToCollapse)) > 0)
2100 {
2101 pParentToCollapse = m_pTree->GetParent(pParentToCollapse);
2102 }
2103 }
2104 else
2105 nRefDepth = m_pTree->GetDepth(pParentToCollapse);
2106
2107 if (m_pView->IsExpanded(pParentToCollapse))
2108 m_pView->Collapse(pParentToCollapse);
2109 SvTreeListEntry* pCur = m_pTree->Next(pParentToCollapse);
2110 while (pCur && m_pTree->GetDepth(pCur) > nRefDepth)
2111 {
2112 if (pCur->HasChildren() && m_pView->IsExpanded(pCur))
2113 m_pView->Collapse(pCur);
2114 pCur = m_pTree->Next(pCur);
2115 }
2116}
2117
2118bool SvImpLBox::KeyInput( const KeyEvent& rKEvt)
2119{
2120 m_aEditIdle.Stop();
2121 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
2122
2123 if( rKeyCode.IsMod2() )
2124 return false; // don't evaluate Alt key
2125
2126 m_nFlags &= ~LBoxFlags::Filling;
2127
2128 if( !m_pCursor )
2129 m_pCursor = m_pStartEntry;
2130 if( !m_pCursor )
2131 return false;
2132
2133 bool bKeyUsed = true;
2134
2135 sal_uInt16 nDelta = static_cast<sal_uInt16>(m_aVerSBar->GetPageSize());
2136 sal_uInt16 aCode = rKeyCode.GetCode();
2137
2138 bool bShift = rKeyCode.IsShift();
2139 bool bMod1 = rKeyCode.IsMod1();
2140
2141 SvTreeListEntry* pNewCursor;
2142
2143 switch( aCode )
2144 {
2145 case KEY_UP:
2146 if( !IsEntryInView( m_pCursor ) )
2147 MakeVisible( m_pCursor );
2148
2149 pNewCursor = m_pCursor;
2150 do
2151 {
2152 pNewCursor = m_pView->PrevVisible(pNewCursor);
2153 } while( pNewCursor && !IsSelectable(pNewCursor) );
2154
2155 // if there is no next entry, take the current one
2156 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2157 // the cursor key
2158 if (!pNewCursor)
2159 pNewCursor = m_pCursor;
2160
2161 m_aSelEng.CursorPosChanging( bShift, bMod1 );
2162 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2163 if( !IsEntryInView( pNewCursor ) )
2164 KeyUp( false );
2165 break;
2166
2167 case KEY_DOWN:
2168 if( !IsEntryInView( m_pCursor ) )
2169 MakeVisible( m_pCursor );
2170
2171 pNewCursor = m_pCursor;
2172 do
2173 {
2174 pNewCursor = m_pView->NextVisible(pNewCursor);
2175 } while( pNewCursor && !IsSelectable(pNewCursor) );
2176
2177 // if there is no next entry, take the current one
2178 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2179 // the cursor key
2180 // 06.09.20001 - 83416 - frank.schoenheit@sun.com
2181 if ( !pNewCursor && m_pCursor )
2182 pNewCursor = m_pCursor;
2183
2184 if( pNewCursor )
2185 {
2186 m_aSelEng.CursorPosChanging( bShift, bMod1 );
2187 if( IsEntryInView( pNewCursor ) )
2188 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2189 else
2190 {
2191 if( m_pCursor )
2192 m_pView->Select( m_pCursor, false );
2193 KeyDown( false );
2194 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2195 }
2196 }
2197 else
2198 KeyDown( false ); // because scrollbar range might still
2199 // allow scrolling
2200 break;
2201
2202 case KEY_RIGHT:
2203 {
2204 if( m_bSubLstOpLR )
2205 {
2206 // only try to expand if sublist is expandable,
2207 // otherwise ignore the key press
2208 if( IsExpandable() && !m_pView->IsExpanded( m_pCursor ) )
2209 m_pView->Expand( m_pCursor );
2210 }
2211 else if (m_aHorSBar->IsVisible())
2212 {
2213 long nThumb = m_aHorSBar->GetThumbPos();
2214 nThumb += m_aHorSBar->GetLineSize();
2215 long nOldThumb = m_aHorSBar->GetThumbPos();
2216 m_aHorSBar->SetThumbPos( nThumb );
2217 nThumb = nOldThumb;
2218 nThumb -= m_aHorSBar->GetThumbPos();
2219 nThumb *= -1;
2220 if( nThumb )
2221 {
2222 KeyLeftRight( nThumb );
2223 }
2224 }
2225 else
2226 bKeyUsed = false;
2227 break;
2228 }
2229
2230 case KEY_LEFT:
2231 {
2232 if (m_aHorSBar->IsVisible())
2233 {
2234 long nThumb = m_aHorSBar->GetThumbPos();
2235 nThumb -= m_aHorSBar->GetLineSize();
2236 long nOldThumb = m_aHorSBar->GetThumbPos();
2237 m_aHorSBar->SetThumbPos( nThumb );
2238 nThumb = nOldThumb;
2239 nThumb -= m_aHorSBar->GetThumbPos();
2240 if( nThumb )
2241 {
2242 KeyLeftRight( -nThumb );
2243 }
2244 else if( m_bSubLstOpLR )
2245 {
2246 if( IsExpandable() && m_pView->IsExpanded( m_pCursor ) )
2247 m_pView->Collapse( m_pCursor );
2248 else
2249 {
2250 pNewCursor = m_pView->GetParent( m_pCursor );
2251 if( pNewCursor )
2252 SetCursor( pNewCursor );
2253 }
2254 }
2255 }
2256 else if( m_bSubLstOpLR )
2257 {
2258 if( IsExpandable() && m_pView->IsExpanded( m_pCursor ) )
2259 m_pView->Collapse( m_pCursor );
2260 else
2261 {
2262 pNewCursor = m_pView->GetParent( m_pCursor );
2263 if( pNewCursor )
2264 SetCursor( pNewCursor );
2265 }
2266 }
2267 else
2268 bKeyUsed = false;
2269 break;
2270 }
2271
2272 case KEY_PAGEUP:
2273 if( !bMod1 )
2274 {
2275 pNewCursor = m_pView->PrevVisible(m_pCursor, nDelta);
2276
2277 while( nDelta && pNewCursor && !IsSelectable(pNewCursor) )
2278 {
2279 pNewCursor = m_pView->NextVisible(pNewCursor);
2280 nDelta--;
2281 }
2282
2283 if( nDelta )
2284 {
2285 DBG_ASSERT(pNewCursor && pNewCursor!=m_pCursor, "Cursor?")do { if (true && (!(pNewCursor && pNewCursor!=
m_pCursor))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "2285" ": "), "%s", "Cursor?"); } } while (false)
;
2286 m_aSelEng.CursorPosChanging( bShift, bMod1 );
2287 if( IsEntryInView( pNewCursor ) )
2288 SetCursor( pNewCursor );
2289 else
2290 {
2291 SetCursor( pNewCursor );
2292 KeyUp( true );
2293 }
2294 }
2295 }
2296 else
2297 bKeyUsed = false;
2298 break;
2299
2300 case KEY_PAGEDOWN:
2301 if( !bMod1 )
2302 {
2303 pNewCursor= m_pView->NextVisible(m_pCursor, nDelta);
2304
2305 while( nDelta && pNewCursor && !IsSelectable(pNewCursor) )
2306 {
2307 pNewCursor = m_pView->PrevVisible(pNewCursor);
2308 nDelta--;
2309 }
2310
2311 if( nDelta && pNewCursor )
2312 {
2313 DBG_ASSERT(pNewCursor && pNewCursor!=m_pCursor, "Cursor?")do { if (true && (!(pNewCursor && pNewCursor!=
m_pCursor))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx"
":" "2313" ": "), "%s", "Cursor?"); } } while (false)
;
2314 m_aSelEng.CursorPosChanging( bShift, bMod1 );
2315 if( IsEntryInView( pNewCursor ) )
2316 SetCursor( pNewCursor );
2317 else
2318 {
2319 SetCursor( pNewCursor );
2320 KeyDown( true );
2321 }
2322 }
2323 else
2324 KeyDown( false ); // see also: KEY_DOWN
2325 }
2326 else
2327 bKeyUsed = false;
2328 break;
2329
2330 case KEY_SPACE:
2331 if ( m_pView->GetSelectionMode() != SelectionMode::NONE )
2332 {
2333 if ( bMod1 )
2334 {
2335 if ( m_pView->GetSelectionMode() == SelectionMode::Multiple && !bShift )
2336 // toggle selection
2337 m_pView->Select( m_pCursor, !m_pView->IsSelected( m_pCursor ) );
2338 }
2339 else if ( !bShift /*&& !bMod1*/ )
2340 {
2341 if ( m_aSelEng.IsAddMode() )
2342 {
2343 // toggle selection
2344 m_pView->Select( m_pCursor, !m_pView->IsSelected( m_pCursor ) );
2345 }
2346 else if ( !m_pView->IsSelected( m_pCursor ) )
2347 {
2348 SelAllDestrAnch( false );
2349 m_pView->Select( m_pCursor );
2350 }
2351 else
2352 bKeyUsed = false;
2353 }
2354 else
2355 bKeyUsed = false;
2356 }
2357 else
2358 bKeyUsed = false;
2359 break;
2360
2361 case KEY_RETURN:
2362 bKeyUsed = !m_pView->DoubleClickHdl();
2363 break;
2364
2365 case KEY_F2:
2366 if( !bShift && !bMod1 )
2367 {
2368 m_aEditClickPos = Point( -1, -1 );
2369 EditTimerCall( nullptr );
2370 }
2371 else
2372 bKeyUsed = false;
2373 break;
2374
2375 case KEY_F8:
2376 if( bShift && m_pView->GetSelectionMode()==SelectionMode::Multiple &&
2377 !(m_nStyle & WB_SIMPLEMODE))
2378 {
2379 if( m_aSelEng.IsAlwaysAdding() )
2380 m_aSelEng.AddAlways( false );
2381 else
2382 m_aSelEng.AddAlways( true );
2383 }
2384 else
2385 bKeyUsed = false;
2386 break;
2387
2388 case KEY_ADD:
2389 if (!m_pView->IsExpanded(m_pCursor))
2390 m_pView->Expand(m_pCursor);
2391 if (bMod1)
2392 ExpandAll();
2393 break;
2394
2395 case KEY_A:
2396 if( bMod1 )
2397 SelAllDestrAnch( true );
2398 else
2399 bKeyUsed = false;
2400 break;
2401
2402 case KEY_SUBTRACT:
2403 if (m_pView->IsExpanded(m_pCursor))
2404 m_pView->Collapse(m_pCursor);
2405 if (bMod1)
2406 CollapseTo(m_pTree->GetRootLevelParent(m_pCursor));
2407 break;
2408
2409 case KEY_MULTIPLY:
2410 if( bMod1 )
2411 {
2412 // only try to expand/collapse if sublist is expandable,
2413 // otherwise ignore the key press
2414 if( IsExpandable() )
2415 {
2416 if (!m_pView->IsAllExpanded(m_pCursor))
2417 {
2418 m_pView->Expand(m_pCursor);
2419 ExpandAll();
2420 }
2421 else
2422 CollapseTo(m_pCursor);
2423 }
2424 }
2425 else
2426 bKeyUsed = false;
2427 break;
2428
2429 case KEY_DIVIDE :
2430 if( bMod1 )
2431 SelAllDestrAnch( true );
2432 else
2433 bKeyUsed = false;
2434 break;
2435
2436 case KEY_COMMA :
2437 if( bMod1 )
2438 SelAllDestrAnch( false );
2439 else
2440 bKeyUsed = false;
2441 break;
2442
2443 case KEY_HOME :
2444 pNewCursor = m_pView->GetModel()->First();
2445
2446 while( pNewCursor && !IsSelectable(pNewCursor) )
2447 {
2448 pNewCursor = m_pView->NextVisible(pNewCursor);
2449 }
2450
2451 if( pNewCursor && pNewCursor != m_pCursor )
2452 {
2453// SelAllDestrAnch( false );
2454 m_aSelEng.CursorPosChanging( bShift, bMod1 );
2455 SetCursor( pNewCursor );
2456 if( !IsEntryInView( pNewCursor ) )
2457 MakeVisible( pNewCursor );
2458 }
2459 else
2460 bKeyUsed = false;
2461 break;
2462
2463 case KEY_END :
2464 pNewCursor = m_pView->GetModel()->Last();
2465
2466 while( pNewCursor && !IsSelectable(pNewCursor) )
2467 {
2468 pNewCursor = m_pView->PrevVisible(pNewCursor);
2469 }
2470
2471 if( pNewCursor && pNewCursor != m_pCursor)
2472 {
2473// SelAllDestrAnch( false );
2474 m_aSelEng.CursorPosChanging( bShift, bMod1 );
2475 SetCursor( pNewCursor );
2476 if( !IsEntryInView( pNewCursor ) )
2477 MakeVisible( pNewCursor );
2478 }
2479 else
2480 bKeyUsed = false;
2481 break;
2482
2483 case KEY_ESCAPE:
2484 case KEY_TAB:
2485 case KEY_DELETE:
2486 case KEY_BACKSPACE:
2487 // must not be handled because this quits dialogs and does other magic things...
2488 // if there are other single keys which should not be handled, they can be added here
2489 bKeyUsed = false;
2490 break;
2491
2492 default:
2493 // is there any reason why we should eat the events here? The only place where this is called
2494 // is from SvTreeListBox::KeyInput. If we set bKeyUsed to true here, then the key input
2495 // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection
2496 // handling.
2497 // (The old code here which intentionally set bKeyUsed to sal_True said this was because of "quick search"
2498 // handling, but actually there was no quick search handling anymore. We just re-implemented it.)
2499 // #i31275# / 2009-06-16 / frank.schoenheit@sun.com
2500 bKeyUsed = false;
2501 break;
2502 }
2503 return bKeyUsed;
2504}
2505
2506void SvImpLBox::GetFocus()
2507{
2508 if( m_pCursor )
2509 {
2510 m_pView->SetEntryFocus( m_pCursor, true );
2511 ShowCursor( true );
2512// auskommentiert wg. deselectall
2513// if( bSimpleTravel && !pView->IsSelected(pCursor) )
2514// pView->Select( pCursor, true );
2515 }
2516 if( m_nStyle & WB_HIDESELECTION )
2517 {
2518 SvTreeListEntry* pEntry = m_pView->FirstSelected();
2519 while( pEntry )
2520 {
2521 InvalidateEntry( pEntry );
2522 pEntry = m_pView->NextSelected( pEntry );
2523 }
2524 }
2525}
2526
2527void SvImpLBox::LoseFocus()
2528{
2529 m_aEditIdle.Stop();
2530 if( m_pCursor )
2531 m_pView->SetEntryFocus( m_pCursor,false );
2532 ShowCursor( false );
2533
2534 if( m_nStyle & WB_HIDESELECTION )
2535 {
2536 SvTreeListEntry* pEntry = m_pView ? m_pView->FirstSelected() : nullptr;
2537 while( pEntry )
2538 {
2539 InvalidateEntry( pEntry );
2540 pEntry = m_pView->NextSelected( pEntry );
2541 }
2542 }
2543}
2544
2545
2546// ********************************************************************
2547// SelectionEngine
2548// ********************************************************************
2549
2550void SvImpLBox::SelectEntry( SvTreeListEntry* pEntry, bool bSelect )
2551{
2552 m_pView->Select( pEntry, bSelect );
2553}
2554
2555ImpLBSelEng::ImpLBSelEng( SvImpLBox* pImpl, SvTreeListBox* pV )
2556{
2557 pImp = pImpl;
2558 pView = pV;
2559}
2560
2561ImpLBSelEng::~ImpLBSelEng()
2562{
2563}
2564
2565void ImpLBSelEng::BeginDrag()
2566{
2567 pImp->BeginDrag();
2568}
2569
2570void ImpLBSelEng::CreateAnchor()
2571{
2572 pImp->m_pAnchor = pImp->m_pCursor;
2573}
2574
2575void ImpLBSelEng::DestroyAnchor()
2576{
2577 pImp->m_pAnchor = nullptr;
2578}
2579
2580void ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, bool bDontSelectAtCursor)
2581{
2582 SvTreeListEntry* pNewCursor = pImp->MakePointVisible( rPoint );
2583 if( pNewCursor )
2584 {
2585 // at SimpleTravel, the SetCursor is selected and the select handler is
2586 // called
2587 //if( !bDontSelectAtCursor && !pImp->bSimpleTravel )
2588 // pImp->SelectEntry( pNewCursor, true );
2589 pImp->SetCursor( pNewCursor, bDontSelectAtCursor );
2590 }
2591}
2592
2593bool ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint )
2594{
2595 SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint );
2596 if( pEntry )
2597 return pView->IsSelected(pEntry);
2598 return false;
2599}
2600
2601void ImpLBSelEng::DeselectAtPoint( const Point& rPoint )
2602{
2603 SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint );
2604 if( !pEntry )
2605 return;
2606 pImp->SelectEntry( pEntry, false );
2607}
2608
2609void ImpLBSelEng::DeselectAll()
2610{
2611 pImp->SelAllDestrAnch( false, false ); // don't reset SelectionEngine!
2612 pImp->m_nFlags &= ~LBoxFlags::DeselectAll;
2613}
2614
2615// ***********************************************************************
2616// Selection
2617// ***********************************************************************
2618
2619void SvImpLBox::SetAnchorSelection(SvTreeListEntry* pOldCursor,SvTreeListEntry* pNewCursor)
2620{
2621 SvTreeListEntry* pEntry;
2622 sal_uLong nAnchorVisPos = m_pView->GetVisiblePos( m_pAnchor );
2623 sal_uLong nOldVisPos = m_pView->GetVisiblePos( pOldCursor );
2624 sal_uLong nNewVisPos = m_pView->GetVisiblePos( pNewCursor );
2625
2626 if( nOldVisPos > nAnchorVisPos ||
2627 ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) )
2628 {
2629 if( nNewVisPos > nOldVisPos )
2630 {
2631 pEntry = pOldCursor;
2632 while( pEntry && pEntry != pNewCursor )
2633 {
2634 m_pView->Select( pEntry );
2635 pEntry = m_pView->NextVisible(pEntry);
2636 }
2637 if( pEntry )
2638 m_pView->Select( pEntry );
2639 return;
2640 }
2641
2642 if( nNewVisPos < nAnchorVisPos )
2643 {
2644 pEntry = m_pAnchor;
2645 while( pEntry && pEntry != pOldCursor )
2646 {
2647 m_pView->Select( pEntry, false );
2648 pEntry = m_pView->NextVisible(pEntry);
2649 }
2650 if( pEntry )
2651 m_pView->Select( pEntry, false );
2652
2653 pEntry = pNewCursor;
2654 while( pEntry && pEntry != m_pAnchor )
2655 {
2656 m_pView->Select( pEntry );
2657 pEntry = m_pView->NextVisible(pEntry);
2658 }
2659 if( pEntry )
2660 m_pView->Select( pEntry );
2661 return;
2662 }
2663
2664 if( nNewVisPos < nOldVisPos )
2665 {
2666 pEntry = m_pView->NextVisible(pNewCursor);
2667 while( pEntry && pEntry != pOldCursor )
2668 {
2669 m_pView->Select( pEntry, false );
2670 pEntry = m_pView->NextVisible(pEntry);
2671 }
2672 if( pEntry )
2673 m_pView->Select( pEntry, false );
2674 return;
2675 }
2676 }
2677 else
2678 {
2679 if( nNewVisPos < nOldVisPos ) // enlarge selection
2680 {
2681 pEntry = pNewCursor;
2682 while( pEntry && pEntry != pOldCursor )
2683 {
2684 m_pView->Select( pEntry );
2685 pEntry = m_pView->NextVisible(pEntry);
2686 }
2687 if( pEntry )
2688 m_pView->Select( pEntry );
2689 return;
2690 }
2691
2692 if( nNewVisPos > nAnchorVisPos )
2693 {
2694 pEntry = pOldCursor;
2695 while( pEntry && pEntry != m_pAnchor )
2696 {
2697 m_pView->Select( pEntry, false );
2698 pEntry = m_pView->NextVisible(pEntry);
2699 }
2700 if( pEntry )
2701 m_pView->Select( pEntry, false );
2702 pEntry = m_pAnchor;
2703 while( pEntry && pEntry != pNewCursor )
2704 {
2705 m_pView->Select( pEntry );
2706 pEntry = m_pView->NextVisible(pEntry);
2707 }
2708 if( pEntry )
2709 m_pView->Select( pEntry );
2710 return;
2711 }
2712
2713 if( nNewVisPos > nOldVisPos )
2714 {
2715 pEntry = pOldCursor;
2716 while( pEntry && pEntry != pNewCursor )
2717 {
2718 m_pView->Select( pEntry, false );
2719 pEntry = m_pView->NextVisible(pEntry);
2720 }
2721 return;
2722 }
2723 }
2724}
2725
2726void SvImpLBox::SelAllDestrAnch(
2727 bool bSelect, bool bDestroyAnchor, bool bSingleSelToo )
2728{
2729 SvTreeListEntry* pEntry;
2730 m_nFlags &= ~LBoxFlags::DeselectAll;
2731 if( bSelect && m_bSimpleTravel )
2732 {
2733 if( m_pCursor && !m_pView->IsSelected( m_pCursor ))
2734 {
2735 m_pView->Select( m_pCursor );
2736 }
2737 return;
2738 }
2739 if( !bSelect && m_pView->GetSelectionCount() == 0 )
2740 {
2741 if( m_bSimpleTravel && ( !GetUpdateMode() || !m_pCursor) )
2742 m_nFlags |= LBoxFlags::DeselectAll;
2743 return;
2744 }
2745 if( bSelect && m_pView->GetSelectionCount() == m_pView->GetEntryCount())
2746 return;
2747 if( !bSingleSelToo && m_bSimpleTravel )
2748 return;
2749
2750 if( !bSelect && m_pView->GetSelectionCount()==1 && m_pCursor &&
2751 m_pView->IsSelected( m_pCursor ))
2752 {
2753 m_pView->Select( m_pCursor, false );
2754 if( bDestroyAnchor )
2755 DestroyAnchor(); // delete anchor & reset SelectionEngine
2756 else
2757 m_pAnchor = nullptr; // always delete internal anchor
2758 return;
2759 }
2760
2761 if( m_bSimpleTravel && !m_pCursor && !GetUpdateMode() )
2762 m_nFlags |= LBoxFlags::DeselectAll;
2763
2764 ShowCursor( false );
2765 bool bUpdate = GetUpdateMode();
2766
2767 m_nFlags |= LBoxFlags::IgnoreSelect; // EntryInserted should not do anything
2768 pEntry = m_pTree->First();
2769 while( pEntry )
2770 {
2771 if( m_pView->Select( pEntry, bSelect ) )
2772 {
2773 if( bUpdate && m_pView->IsEntryVisible(pEntry) )
2774 {
2775 long nY = GetEntryLine( pEntry );
2776 if( IsLineVisible( nY ) )
2777 InvalidateEntry(pEntry);
2778 }
2779 }
2780 pEntry = m_pTree->Next( pEntry );
2781 }
2782 m_nFlags &= ~LBoxFlags::IgnoreSelect;
2783
2784 if( bDestroyAnchor )
2785 DestroyAnchor(); // delete anchor & reset SelectionEngine
2786 else
2787 m_pAnchor = nullptr; // always delete internal anchor
2788 ShowCursor( true );
2789}
2790
2791void SvImpLBox::SetSelectionMode( SelectionMode eSelMode )
2792{
2793 m_aSelEng.SetSelectionMode( eSelMode);
2794 if( eSelMode == SelectionMode::Single )
2795 m_bSimpleTravel = true;
2796 else
2797 m_bSimpleTravel = false;
2798 if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == SelectionMode::Multiple) )
2799 m_aSelEng.AddAlways( true );
2800}
2801
2802// ***********************************************************************
2803// Drag & Drop
2804// ***********************************************************************
2805
2806void SvImpLBox::SetDragDropMode( DragDropMode eDDMode )
2807{
2808 if( eDDMode != DragDropMode::NONE )
2809 {
2810 m_aSelEng.ExpandSelectionOnMouseMove( false );
2811 m_aSelEng.EnableDrag( true );
2812 }
2813 else
2814 {
2815 m_aSelEng.ExpandSelectionOnMouseMove();
2816 m_aSelEng.EnableDrag( false );
2817 }
2818}
2819
2820void SvImpLBox::BeginDrag()
2821{
2822 m_nFlags &= ~LBoxFlags::Filling;
2823 m_pView->StartDrag( 0, m_aSelEng.GetMousePosPixel() );
2824}
2825
2826void SvImpLBox::PaintDDCursor(SvTreeListEntry* pEntry, bool bShow)
2827{
2828 if (pEntry)
2829 {
2830
2831 SvViewDataEntry* pViewData = m_pView->GetViewData(pEntry);
2832 pViewData->SetDragTarget(bShow);
2833#ifdef MACOSX
2834 // in MacOS we need to draw directly (as we are synchronous) or no invalidation happens
2835 m_pView->PaintEntry1(*pEntry, GetEntryLine(pEntry), *m_pView);
2836#else
2837 InvalidateEntry(pEntry);
2838#endif
2839 }
2840}
2841
2842void SvImpLBox::Command( const CommandEvent& rCEvt )
2843{
2844 CommandEventId nCommand = rCEvt.GetCommand();
2845
2846 if( nCommand == CommandEventId::ContextMenu )
2847 m_aEditIdle.Stop();
2848
2849 // scroll mouse event?
2850 if (nCommand == CommandEventId::Wheel ||
2851 nCommand == CommandEventId::StartAutoScroll ||
2852 nCommand == CommandEventId::AutoScroll ||
2853 nCommand == CommandEventId::Gesture)
2854 {
2855 if (m_pView->HandleScrollCommand(rCEvt, m_aHorSBar.get(), m_aVerSBar.get()))
2856 return;
2857 }
2858
2859 const Point& rPos = rCEvt.GetMousePosPixel();
2860 if( rPos.X() < m_aOutputSize.Width() && rPos.Y() < m_aOutputSize.Height() )
2861 m_aSelEng.Command( rCEvt );
2862}
2863
2864tools::Rectangle SvImpLBox::GetVisibleArea() const
2865{
2866 Point aPos( m_pView->GetMapMode().GetOrigin() );
2867 aPos.setX( aPos.X() * -1 );
2868 tools::Rectangle aRect( aPos, m_aOutputSize );
2869 return aRect;
2870}
2871
2872void SvImpLBox::Invalidate()
2873{
2874 m_pView->SetClipRegion();
2875}
2876
2877void SvImpLBox::SetCurEntry( SvTreeListEntry* pEntry )
2878{
2879 if ( ( m_aSelEng.GetSelectionMode() != SelectionMode::Single )
2880 && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE )
2881 )
2882 SelAllDestrAnch( false );
2883 if ( pEntry )
2884 MakeVisible( pEntry );
2885 SetCursor( pEntry );
2886 if ( pEntry && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
2887 m_pView->Select( pEntry );
2888}
2889
2890IMPL_LINK_NOARG(SvImpLBox, EditTimerCall, Timer *, void)void SvImpLBox::LinkStubEditTimerCall(void * instance, Timer *
data) { return static_cast<SvImpLBox *>(instance)->
EditTimerCall(data); } void SvImpLBox::EditTimerCall(__attribute__
((unused)) Timer *)
2891{
2892 if( !m_pView->IsInplaceEditingEnabled() )
2893 return;
2894
2895 bool bIsMouseTriggered = m_aEditClickPos.X() >= 0;
2896 if ( bIsMouseTriggered )
2897 {
2898 Point aCurrentMousePos = m_pView->GetPointerPosPixel();
2899 if ( ( std::abs( aCurrentMousePos.X() - m_aEditClickPos.X() ) > 5 )
2900 || ( std::abs( aCurrentMousePos.Y() - m_aEditClickPos.Y() ) > 5 )
2901 )
2902 {
2903 return;
2904 }
2905 }
2906
2907 SvTreeListEntry* pEntry = GetCurEntry();
2908 if( pEntry )
2909 {
2910 ShowCursor( false );
2911 m_pView->ImplEditEntry( pEntry );
2912 ShowCursor( true );
2913 }
2914}
2915
2916bool SvImpLBox::RequestHelp( const HelpEvent& rHEvt )
2917{
2918 if( rHEvt.GetMode() & HelpEventMode::QUICK )
2919 {
2920 Point aPos( m_pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() ));
2921 if( !GetVisibleArea().IsInside( aPos ))
2922 return false;
2923
2924 SvTreeListEntry* pEntry = GetEntry( aPos );
2925 if( pEntry )
2926 {
2927 // recalculate text rectangle
2928 SvLBoxTab* pTab;
2929 SvLBoxItem* pItem = m_pView->GetItem( pEntry, aPos.X(), &pTab );
2930 if (!pItem || pItem->GetType() != SvLBoxItemType::String)
2931 return false;
2932
2933 aPos = GetEntryPosition( pEntry );
2934 aPos.setX( m_pView->GetTabPos( pEntry, pTab ) ); //pTab->GetPos();
2935 Size aSize(pItem->GetWidth(m_pView, pEntry), pItem->GetHeight(m_pView, pEntry));
2936 SvLBoxTab* pNextTab = NextTab( pTab );
2937 bool bItemClipped = false;
2938 // is the item cut off by its right neighbor?
2939 if( pNextTab && m_pView->GetTabPos(pEntry,pNextTab) < aPos.X()+aSize.Width() )
2940 {
2941 aSize.setWidth( pNextTab->GetPos() - pTab->GetPos() );
2942 bItemClipped = true;
2943 }
2944 tools::Rectangle aItemRect( aPos, aSize );
2945
2946 tools::Rectangle aViewRect( GetVisibleArea() );
2947
2948 if( bItemClipped || !aViewRect.IsInside( aItemRect ) )
2949 {
2950 // clip the right edge of the item at the edge of the view
2951 //if( aItemRect.Right() > aViewRect.Right() )
2952 // aItemRect.Right() = aViewRect.Right();
2953
2954 Point aPt = m_pView->OutputToScreenPixel( aItemRect.TopLeft() );
2955 aItemRect.SetLeft( aPt.X() );
2956 aItemRect.SetTop( aPt.Y() );
2957 aPt = m_pView->OutputToScreenPixel( aItemRect.BottomRight() );
2958 aItemRect.SetRight( aPt.X() );
2959 aItemRect.SetBottom( aPt.Y() );
2960
2961 Help::ShowQuickHelp( m_pView, aItemRect,
2962 static_cast<SvLBoxString*>(pItem)->GetText(), QuickHelpFlags::Left | QuickHelpFlags::VCenter );
2963 return true;
2964 }
2965 }
2966 }
2967 return false;
2968}
2969
2970SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab const * pTab )
2971{
2972 sal_uInt16 nTabCount = m_pView->TabCount();
2973 if( nTabCount <= 1 )
2974 return nullptr;
2975 for( int nTab=0; nTab < (nTabCount-1); nTab++)
2976 {
2977 if( m_pView->aTabs[nTab].get() == pTab )
2978 return m_pView->aTabs[nTab+1].get();
2979 }
2980 return nullptr;
2981}
2982
2983void SvImpLBox::SetUpdateMode( bool bMode )
2984{
2985 if( m_bUpdateMode != bMode )
2986 {
2987 m_bUpdateMode = bMode;
2988 if( m_bUpdateMode )
2989 UpdateAll( false );
2990 }
2991}
2992
2993bool SvImpLBox::SetMostRight( SvTreeListEntry* pEntry )
2994{
2995 if( m_pView->nTreeFlags & SvTreeFlags::RECALCTABS )
2996 {
2997 m_nFlags |= LBoxFlags::IgnoreChangedTabs;
2998 m_pView->SetTabs();
2999 m_nFlags &= ~LBoxFlags::IgnoreChangedTabs;
3000 }
3001
3002 sal_uInt16 nLastTab = m_pView->aTabs.size() - 1;
3003 sal_uInt16 nLastItem = pEntry->ItemCount() - 1;
3004 if( !m_pView->aTabs.empty() && nLastItem != USHRT_MAX(32767 *2 +1) )
3005 {
3006 if( nLastItem < nLastTab )
3007 nLastTab = nLastItem;
3008
3009 SvLBoxTab* pTab = m_pView->aTabs[ nLastTab ].get();
3010 SvLBoxItem& rItem = pEntry->GetItem( nLastTab );
3011
3012 long nTabPos = m_pView->GetTabPos( pEntry, pTab );
3013
3014 long nMaxRight = GetOutputSize().Width();
3015 Point aPos( m_pView->GetMapMode().GetOrigin() );
3016 aPos.setX( aPos.X() * -1 ); // conversion document coordinates
3017 nMaxRight = nMaxRight + aPos.X() - 1;
3018
3019 long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50;
3020 long nTabWidth = nNextTab - nTabPos + 1;
3021 auto nItemSize = rItem.GetWidth(m_pView,pEntry);
3022 long nOffset = pTab->CalcOffset( nItemSize, nTabWidth );
3023
3024 long nRight = nTabPos + nOffset + nItemSize;
3025 if( nRight > m_nMostRight )
3026 {
3027 m_nMostRight = nRight;
3028 m_pMostRightEntry = pEntry;
3029 return true;
3030 }
3031 }
3032 return false;
3033}
3034
3035void SvImpLBox::FindMostRight()
3036{
3037 m_nMostRight = -1;
3038 m_pMostRightEntry = nullptr;
3039 if( !m_pView->GetModel() )
3040 return;
3041
3042 SvTreeListEntry* pEntry = m_pView->FirstVisible();
3043 while( pEntry )
3044 {
3045 SetMostRight( pEntry );
3046 pEntry = m_pView->NextVisible( pEntry );
3047 }
3048}
3049
3050void SvImpLBox::FindMostRight( SvTreeListEntry* pParent )
3051{
3052 if( !pParent )
3053 FindMostRight();
3054 else
3055 FindMostRight_Impl( pParent );
3056}
3057
3058void SvImpLBox::FindMostRight_Impl( SvTreeListEntry* pParent )
3059{
3060 SvTreeListEntries& rList = m_pTree->GetChildList( pParent );
3061
3062 size_t nCount = rList.size();
3063 for( size_t nCur = 0; nCur < nCount; nCur++ )
3064 {
3065 SvTreeListEntry* pChild = rList[nCur].get();
3066 SetMostRight( pChild );
3067 if( pChild->HasChildren() && m_pView->IsExpanded( pChild ))
3068 FindMostRight_Impl( pChild );
3069 }
3070}
3071
3072void SvImpLBox::NotifyTabsChanged()
3073{
3074 if( GetUpdateMode() && !(m_nFlags & LBoxFlags::IgnoreChangedTabs ) &&
3075 m_nCurUserEvent == nullptr )
3076 {
3077 m_nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent)::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox
*>(this), &SvImpLBox::LinkStubMyUserEvent)
);
3078 }
3079}
3080
3081bool SvImpLBox::IsExpandable() const
3082{
3083 return m_pCursor->HasChildren() || m_pCursor->HasChildrenOnDemand();
3084}
3085
3086IMPL_LINK(SvImpLBox, MyUserEvent, void*, pArg, void )void SvImpLBox::LinkStubMyUserEvent(void * instance, void* data
) { return static_cast<SvImpLBox *>(instance)->MyUserEvent
(data); } void SvImpLBox::MyUserEvent(void* pArg)
3087{
3088 m_nCurUserEvent = nullptr;
3089 if( !pArg )
3090 {
3091 m_pView->Invalidate();
3092 m_pView->PaintImmediately();
3093 }
3094 else
3095 {
3096 FindMostRight();
3097 ShowVerSBar();
3098 m_pView->Invalidate( GetVisibleArea() );
3099 }
3100}
3101
3102
3103void SvImpLBox::StopUserEvent()
3104{
3105 if( m_nCurUserEvent != nullptr )
3106 {
3107 Application::RemoveUserEvent( m_nCurUserEvent );
3108 m_nCurUserEvent = nullptr;
3109 }
3110}
3111
3112void SvImpLBox::implInitDefaultNodeImages()
3113{
3114 if ( s_pDefCollapsed )
3115 // assume that all or nothing is initialized
3116 return;
3117
3118 s_pDefCollapsed = new Image(StockImage::Yes, RID_BMP_TREENODE_COLLAPSED"res/plus.png");
3119 s_pDefExpanded = new Image(StockImage::Yes, RID_BMP_TREENODE_EXPANDED"res/minus.png");
3120}
3121
3122
3123const Image& SvImpLBox::GetDefaultExpandedNodeImage( )
3124{
3125 implInitDefaultNodeImages();
3126 return *s_pDefExpanded;
3127}
3128
3129
3130const Image& SvImpLBox::GetDefaultCollapsedNodeImage( )
3131{
3132 implInitDefaultNodeImages();
3133 return *s_pDefCollapsed;
3134}
3135
3136
3137void SvImpLBox::CallEventListeners( VclEventId nEvent, void* pData )
3138{
3139 if ( m_pView )
3140 m_pView->CallImplEventListeners( nEvent, pData);
3141}
3142
3143
3144bool SvImpLBox::IsSelectable( const SvTreeListEntry* pEntry )
3145{
3146 if( pEntry )
3147 {
3148 SvViewDataEntry* pViewDataNewCur = m_pView->GetViewDataEntry(pEntry);
3149 return (pViewDataNewCur == nullptr) || pViewDataNewCur->IsSelectable();
3150 }
3151 else
3152 {
3153 return false;
3154 }
3155}
3156
3157/* vim:set shiftwidth=4 softtabstop=4 expandtab: */