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