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