Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/source/treelist/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 105 kB image not shown  

Quelle  treelistbox.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


/*
    TODO:
        - delete anchor in SelectionEngine when selecting manually
        - SelectAll( false ) => only repaint the deselected entries
*/


#include <accessibility/accessiblelistbox.hxx>

#include <vcl/toolkit/treelistbox.hxx>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <vcl/help.hxx>
#include <vcl/svapp.hxx>
#include <vcl/builder.hxx>
#include <vcl/toolkit/edit.hxx>
#include <vcl/settings.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/decoview.hxx>
#include <vcl/uitest/uiobject.hxx>
#include <sot/formats.hxx>
#include <comphelper/string.hxx>
#include <sal/log.hxx>
#include <tools/debug.hxx>

#include <vcl/toolkit/svlbitm.hxx>
#include <vcl/toolkit/treelistentry.hxx>
#include <vcl/toolkit/viewdataentry.hxx>
#include <accel.hxx>
#include <svimpbox.hxx>

#include <set>
#include <string.h>
#include <vector>

using namespace css::accessibility;

// Drag&Drop
static VclPtr<SvTreeListBox> g_pDDSource;
static VclPtr<SvTreeListBox> g_pDDTarget;

#define SVLBOX_ACC_RETURN 1
#define SVLBOX_ACC_ESCAPE 2

class SvInplaceEdit2
{
    Link<SvInplaceEdit2&,void> aCallBackHdl;
    Accelerator   aAccReturn;
    Accelerator   aAccEscape;
    Idle          aIdle { "svtools::SvInplaceEdit2 aIdle" };
    VclPtr<Edit>  pEdit;
    bool          bCanceled;
    bool          bAlreadyInCallBack;

    void        CallCallBackHdl_Impl();
    DECL_LINK( Timeout_Impl, Timer *, void );
    DECL_LINK( ReturnHdl_Impl, Accelerator&, void );
    DECL_LINK( EscapeHdl_Impl, Accelerator&, void );

public:
                SvInplaceEdit2( vcl::Window* pParent, const Point& rPos, const Size& rSize,
                   const OUString& rData, const Link<SvInplaceEdit2&,void>& rNotifyEditEnd,
                   const Selection& );
               ~SvInplaceEdit2();
    bool        KeyInput( const KeyEvent& rKEvt );
    void        LoseFocus();
    bool        EditingCanceled() const { return bCanceled; }
    OUString    GetText() const;
    OUString const & GetSavedValue() const;
    void        StopEditing( bool bCancel );
    void        Hide();
    const VclPtr<Edit> & GetEditWidget() const { return pEdit; };

    void RemoveEscapeAccel() { Application::RemoveAccel(&aAccEscape); }
    void InsertEscapeAccel() { Application::InsertAccel(&aAccEscape); }
};
// ***************************************************************

namespace {

class MyEdit_Impl : public Edit
{
    SvInplaceEdit2* pOwner;
public:
                 MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* pOwner );
    virtual     ~MyEdit_Impl() override { disposeOnce(); }
    virtual void dispose() override { pOwner = nullptr; Edit::dispose(); }
    virtual void KeyInput( const KeyEvent& rKEvt ) override;
    virtual void LoseFocus() override;
    virtual void Command(const CommandEvent& rCEvt) override;
};

}

MyEdit_Impl::MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* _pOwner ) :

    Edit( pParent, WB_LEFT ),

    pOwner( _pOwner )

{
}

void MyEdit_Impl::KeyInput( const KeyEvent& rKEvt )
{
    if( !pOwner->KeyInput( rKEvt ))
        Edit::KeyInput( rKEvt );
}

void MyEdit_Impl::LoseFocus()
{
    if (pOwner)
        pOwner->LoseFocus();
}

void MyEdit_Impl::Command(const CommandEvent& rCEvt)
{
    if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
    {
        pOwner->RemoveEscapeAccel();  // so escape ends the popup
        Edit::Command(rCEvt);
        pOwner->InsertEscapeAccel();
    }
    else
        Edit::Command(rCEvt);
}

SvInplaceEdit2::SvInplaceEdit2
(
    vcl::Window* pParent, const Point& rPos,
    const Size& rSize,
    const OUString& rData,
    const Link<SvInplaceEdit2&,void>& rNotifyEditEnd,
    const Selection& rSelection
) :

    aCallBackHdl       ( rNotifyEditEnd ),
    bCanceled           ( false ),
    bAlreadyInCallBack  ( false )

{

    pEdit = VclPtr<MyEdit_Impl>::Create( pParent, this );

    vcl::Font aFont( pParent->GetFont() );
    aFont.SetTransparent( false );
    Color aColor( pParent->GetBackground().GetColor() );
    aFont.SetFillColor(aColor );
    pEdit->SetFont( aFont );
    pEdit->SetBackground( pParent->GetBackground() );
    pEdit->SetPosPixel( rPos );
    pEdit->SetSizePixel( rSize );
    pEdit->SetText( rData );
    pEdit->SetSelection( rSelection );
    pEdit->SaveValue();

    aAccReturn.InsertItem( SVLBOX_ACC_RETURN, vcl::KeyCode(KEY_RETURN) );
    aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, vcl::KeyCode(KEY_ESCAPE) );

    aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit2, ReturnHdl_Impl) );
    aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit2, EscapeHdl_Impl) );
    Application::InsertAccel( &aAccReturn );
    Application::InsertAccel( &aAccEscape );

    pEdit->Show();
    pEdit->GrabFocus();
}

SvInplaceEdit2::~SvInplaceEdit2()
{
    if( !bAlreadyInCallBack )
    {
        Application::RemoveAccel( &aAccReturn );
        Application::RemoveAccel( &aAccEscape );
    }
    pEdit.disposeAndClear();
}

OUString const & SvInplaceEdit2::GetSavedValue() const
{
    return pEdit->GetSavedValue();
}

void SvInplaceEdit2::Hide()
{
    pEdit->Hide();
}


IMPL_LINK_NOARG(SvInplaceEdit2, ReturnHdl_Impl, Accelerator&, void)
{
    bCanceled = false;
    CallCallBackHdl_Impl();
}

IMPL_LINK_NOARG(SvInplaceEdit2, EscapeHdl_Impl, Accelerator&, void)
{
    bCanceled = true;
    CallCallBackHdl_Impl();
}

bool SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt )
{
    vcl::KeyCode aCode = rKEvt.GetKeyCode();
    sal_uInt16 nCode = aCode.GetCode();

    switch ( nCode )
    {
        case KEY_ESCAPE:
            bCanceled = true;
            CallCallBackHdl_Impl();
            return true;

        case KEY_RETURN:
            bCanceled = false;
            CallCallBackHdl_Impl();
            return true;
    }
    return false;
}

void SvInplaceEdit2::StopEditing( bool bCancel )
{
    if ( !bAlreadyInCallBack )
    {
        bCanceled = bCancel;
        CallCallBackHdl_Impl();
    }
}

void SvInplaceEdit2::LoseFocus()
{
    if (!bAlreadyInCallBack && !pEdit->IsActivePopup()
        && ((!Application::GetFocusWindow()) || !pEdit->IsChild(Application::GetFocusWindow())))
    {
        bCanceled = false;
        aIdle.SetPriority(TaskPriority::REPAINT);
        aIdle.SetInvokeHandler(LINK(this,SvInplaceEdit2,Timeout_Impl));
        aIdle.Start();
    }
}

IMPL_LINK_NOARG(SvInplaceEdit2, Timeout_Impl, Timer *, void)
{
    CallCallBackHdl_Impl();
}

void SvInplaceEdit2::CallCallBackHdl_Impl()
{
    aIdle.Stop();
    if ( !bAlreadyInCallBack )
    {
        bAlreadyInCallBack = true;
        Application::RemoveAccel( &aAccReturn );
        Application::RemoveAccel( &aAccEscape );
        pEdit->Hide();
        aCallBackHdl.Call( *this );
    }
}

OUString SvInplaceEdit2::GetText() const
{
    return pEdit->GetText();
}

// ***************************************************************
// class SvLBoxTab
// ***************************************************************


SvLBoxTab::SvLBoxTab()
{
    nPos = 0;
    nFlags = SvLBoxTabFlags::NONE;
}

SvLBoxTab::SvLBoxTab( tools::Long nPosition, SvLBoxTabFlags nTabFlags )
{
    nPos = nPosition;
    nFlags = nTabFlags;
}

SvLBoxTab::SvLBoxTab( const SvLBoxTab& rTab )
{
    nPos = rTab.nPos;
    nFlags = rTab.nFlags;
}

tools::Long SvLBoxTab::CalcOffset( tools::Long nItemWidth, tools::Long nTabWidth )
{
    tools::Long nOffset = 0;
    if ( nFlags & SvLBoxTabFlags::ADJUST_RIGHT )
    {
        nOffset = nTabWidth - nItemWidth;
        if( nOffset < 0 )
            nOffset = 0;
    }
    else if ( nFlags & SvLBoxTabFlags::ADJUST_CENTER )
    {
        if( nFlags & SvLBoxTabFlags::FORCE )
        {
            // correct implementation of centering
            nOffset = ( nTabWidth - nItemWidth ) / 2;
            if( nOffset < 0 )
                nOffset = 0;
        }
        else
        {
            // historically grown, wrong calculation of tabs which is needed by
            // Abo-Tabbox, Tools/Options/Customize etc.
            nItemWidth++;
            nOffset = -( nItemWidth / 2 );
        }
    }
    return nOffset;
}

// ***************************************************************
// class SvLBoxItem
// ***************************************************************


SvLBoxItem::SvLBoxItem()
    : mbDisabled(false)
{
}

SvLBoxItem::~SvLBoxItem()
{
}

int SvLBoxItem::GetWidth(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
{
    const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
    int nWidth = pViewData->mnWidth;
    if (nWidth == -1)
    {
        nWidth = CalcWidth(pView);
        const_cast<SvViewDataItem*>(pViewData)->mnWidth = nWidth;
    }
    return nWidth;
}

int SvLBoxItem::GetHeight(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
{
    const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
    return pViewData->mnHeight;
}

int SvLBoxItem::GetWidth(const SvTreeListBox* pView, const SvViewDataEntry* pData, sal_uInt16 nItemPos) const
{
    const SvViewDataItem& rIData = pData->GetItem(nItemPos);
    int nWidth = rIData.mnWidth;
    if (nWidth == -1)
    {
        nWidth = CalcWidth(pView);
        const_cast<SvViewDataItem&>(rIData).mnWidth = nWidth;
    }
    return nWidth;
}

int SvLBoxItem::GetHeight(const SvViewDataEntry* pData, sal_uInt16 nItemPos)
{
    const SvViewDataItem& rIData = pData->GetItem(nItemPos);
    return rIData.mnHeight;
}

int SvLBoxItem::CalcWidth(const SvTreeListBox* /*pView*/) const
{
    return 0;
}

struct SvTreeListBoxImpl
{
    bool m_bDoingQuickSelection:1;

    vcl::QuickSelectionEngine m_aQuickSelectionEngine;

    explicit SvTreeListBoxImpl(SvTreeListBox& _rBox) :
        m_bDoingQuickSelection(false),
        m_aQuickSelectionEngine(_rBox) {}
};

SvTreeListBox::SvTreeListBox(vcl::Window* pParent, WinBits nWinStyle) :
    Control(pParent, nWinStyle | WB_CLIPCHILDREN),
    DropTargetHelper(this),
    DragSourceHelper(this),
    mpImpl(new SvTreeListBoxImpl(*this)),
    mbContextBmpExpanded(false),
    mbQuickSearch(false),
    mbActivateOnSingleClick(false),
    mbHoverSelection(false),
    mbSelectingByHover(false),
    mbIsTextColumEnabled(false),
    mnClicksToToggle(0), //at default clicking on a row won't toggle its default checkbox
    eSelMode(SelectionMode::NONE),
    nMinWidthInChars(0),
    mnDragAction(DND_ACTION_COPYMOVE | DND_ACTION_LINK),
    mbCenterAndClipText(false)
{
    nImpFlags = SvTreeListBoxFlags::NONE;
    pTargetEntry = nullptr;
    nDragDropMode = DragDropMode::NONE;
    pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
    pHdlEntry = nullptr;
    eSelMode = SelectionMode::Single;
    nDragDropMode = DragDropMode::NONE;
    SetType(WindowType::TREELISTBOX);

    InitTreeView();
    pImpl->SetModel( pModel.get() );

    SetSublistOpenWithLeftRight();
}

void SvTreeListBox::Clear()
{
    if (pModel)
        pModel->Clear();  // Model calls SvTreeListBox::ModelHasCleared()
}

IMPL_LINK( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry, SvTreeListEntry* )
{
    return CloneEntry(pEntry);
}

sal_uInt32 SvTreeListBox::Insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uInt32 nPos )
{
    sal_uInt32 nInsPos = pModel->Insert( pEntry, pParent, nPos );
    return nInsPos;
}

sal_uInt32 SvTreeListBox::Insert( SvTreeListEntry* pEntry,sal_uInt32 nRootPos )
{
    sal_uInt32 nInsPos = pModel->Insert( pEntry, nRootPos );
    return nInsPos;
}

bool SvTreeListBox::ExpandingHdl()
{
    return !aExpandingHdl.IsSet() || aExpandingHdl.Call( this );
}

void SvTreeListBox::ExpandedHdl()
{
    aExpandedHdl.Call( this );
}

void SvTreeListBox::SelectHdl()
{
    aSelectHdl.Call( this );
}

void SvTreeListBox::DeselectHdl()
{
    aDeselectHdl.Call( this );
}

bool SvTreeListBox::DoubleClickHdl()
{
    return !aDoubleClickHdl.IsSet() || aDoubleClickHdl.Call(this);
}

bool SvTreeListBox::CheckDragAndDropMode( SvTreeListBox const * pSource, sal_Int8 nAction )
{
    if ( pSource != this )
        return false// no drop

    if ( !(nDragDropMode & DragDropMode::CTRL_MOVE) )
        return false// D&D locked within list

    if( DND_ACTION_MOVE == nAction )
    {
        if ( !(nDragDropMode & DragDropMode::CTRL_MOVE) )
             return false// no local move
    }
    else
        return false// no local copy

    return true;
}


/*
    NotifyMoving/Copying
    ====================

    default behavior:

    1. target doesn't have children
        - entry becomes sibling of target. entry comes after target
          (->Window: below the target)
    2. target is an expanded parent
        - entry inserted at the beginning of the target childlist
    3. target is a collapsed parent
        - entry is inserted at the end of the target childlist
*/

TriState SvTreeListBox::NotifyMoving(
    SvTreeListEntry*  pTarget,       // D&D dropping position in GetModel()
    const SvTreeListEntry*  pEntry,        // entry that we want to move, from
                                 // GetSourceListBox()->GetModel()
    SvTreeListEntry*& rpNewParent,   // new target parent
    sal_uInt32&        rNewChildPos)  // position in childlist of target parent
{
    DBG_ASSERT(pEntry,"NotifyMoving:SourceEntry?");
    if( !pTarget )
    {
        rpNewParent = nullptr;
        rNewChildPos = 0;
        return TRISTATE_TRUE;
    }
    if ( !pTarget->HasChildren() && !pTarget->HasChildrenOnDemand() )
    {
        // case 1
        rpNewParent = GetParent( pTarget );
        rNewChildPos = SvTreeList::GetRelPos( pTarget ) + 1;
        rNewChildPos += nCurEntrySelPos;
        nCurEntrySelPos++;
    }
    else
    {
        // cases 2 & 3
        rpNewParent = pTarget;
        if( IsExpanded(pTarget))
            rNewChildPos = 0;
        else
            rNewChildPos = TREELIST_APPEND;
    }
    return TRISTATE_TRUE;
}

TriState SvTreeListBox::NotifyCopying(
    SvTreeListEntry*  pTarget,       // D&D dropping position in GetModel()
    const SvTreeListEntry*  pEntry,        // entry that we want to move, from
                                 // GetSourceListBox()->GetModel()
    SvTreeListEntry*& rpNewParent,   // new target parent
    sal_uInt32&        rNewChildPos)  // position in childlist of target parent
{
    return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos);
}

SvTreeListEntry* SvTreeListBox::FirstChild( SvTreeListEntry* pParent ) const
{
    return pModel->FirstChild(pParent);
}

// return: all entries copied
bool SvTreeListBox::CopySelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
{
    nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
    bool bSuccess = true;
    std::vector<SvTreeListEntry*> aList;
    bool bClone = ( pSource->GetModel() != GetModel() );
    Link<SvTreeListEntry*,SvTreeListEntry*> aCloneLink( pModel->GetCloneLink() );
    pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));

    // cache selection to simplify iterating over the selection when doing a D&D
    // exchange within the same listbox
    SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
    while ( pSourceEntry )
    {
        // children are copied automatically
        pSource->SelectChildren( pSourceEntry, false );
        aList.push_back( pSourceEntry );
        pSourceEntry = pSource->NextSelected( pSourceEntry );
    }

    for (auto const& elem : aList)
    {
        pSourceEntry = elem;
        SvTreeListEntry* pNewParent = nullptr;
        sal_uInt32 nInsertionPos = TREELIST_APPEND;
        TriState nOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
        if ( nOk )
        {
            if ( bClone )
            {
                sal_uInt32 nCloneCount = 0;
                pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
                pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
            }
            else
            {
                sal_uInt32 nListPos = pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
                pSourceEntry = GetEntry( pNewParent, nListPos );
            }
        }
        else
            bSuccess = false;

        if (nOk == TRISTATE_INDET)  // HACK: make visible moved entry
            MakeVisible( pSourceEntry );
    }
    pModel->SetCloneLink( aCloneLink );
    return bSuccess;
}

// return: all entries were moved
bool SvTreeListBox::MoveSelectionCopyFallbackPossible( SvTreeListBox* pSource, SvTreeListEntry* pTarget, bool bAllowCopyFallback )
{
    nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
    bool bSuccess = true;
    std::vector<SvTreeListEntry*> aList;
    bool bClone = ( pSource->GetModel() != GetModel() );
    Link<SvTreeListEntry*,SvTreeListEntry*> aCloneLink( pModel->GetCloneLink() );
    if ( bClone )
        pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));

    SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
    while ( pSourceEntry )
    {
        // children are automatically moved
        pSource->SelectChildren( pSourceEntry, false );
        aList.push_back( pSourceEntry );
        pSourceEntry = pSource->NextSelected( pSourceEntry );
    }

    for (auto const& elem : aList)
    {
        pSourceEntry = elem;
        SvTreeListEntry* pNewParent = nullptr;
        sal_uInt32 nInsertionPos = TREELIST_APPEND;
        TriState nOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos);
        TriState nCopyOk = nOk;
        if ( !nOk && bAllowCopyFallback )
        {
            nInsertionPos = TREELIST_APPEND;
            nCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
        }

        if ( nOk || nCopyOk )
        {
            if ( bClone )
            {
                sal_uInt32 nCloneCount = 0;
                pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
                pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
            }
            else
            {
                if ( nOk )
                    pModel->Move(pSourceEntry, pNewParent, nInsertionPos);
                else
                    pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
            }
        }
        else
            bSuccess = false;

        if (nOk == TRISTATE_INDET)  // HACK: make moved entry visible
            MakeVisible( pSourceEntry );
    }
    pModel->SetCloneLink( aCloneLink );
    return bSuccess;
}

void SvTreeListBox::RemoveSelection()
{
    std::vector<const SvTreeListEntry*> aList;
    // cache selection, as the implementation deselects everything on the first
    // remove
    SvTreeListEntry* pEntry = FirstSelected();
    while ( pEntry )
    {
        aList.push_back( pEntry );
        if ( pEntry->HasChildren() )
            // remove deletes all children automatically
            SelectChildren(pEntry, false);
        pEntry = NextSelected( pEntry );
    }

    for (auto const& elem : aList)
        pModel->Remove(elem);
}

void SvTreeListBox::RemoveEntry(SvTreeListEntry const * pEntry)
{
    pModel->Remove(pEntry);
}

void SvTreeListBox::RecalcViewData()
{
    SvTreeListEntry* pEntry = First();
    while( pEntry )
    {
        sal_uInt16 nCount = pEntry->ItemCount();
        sal_uInt16 nCurPos = 0;
        while ( nCurPos < nCount )
        {
            SvLBoxItem& rItem = pEntry->GetItem( nCurPos );
            rItem.InitViewData( this, pEntry );
            nCurPos++;
        }
        pEntry = Next( pEntry );
    }
}

void SvTreeListBox::ImplShowTargetEmphasis( SvTreeListEntry* pEntry, bool bShow)
{
    if ( bShow && (nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
        return;
    if ( !bShow && !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
        return;
    pImpl->PaintDDCursor( pEntry, bShow);
    if( bShow )
        nImpFlags |= SvTreeListBoxFlags::TARGEMPH_VIS;
    else
        nImpFlags &= ~SvTreeListBoxFlags::TARGEMPH_VIS;
}

void SvTreeListBox::OnCurrentEntryChanged()
{
    if ( !mpImpl->m_bDoingQuickSelection )
        mpImpl->m_aQuickSelectionEngine.Reset();
}

SvTreeListEntry* SvTreeListBox::GetEntry( SvTreeListEntry* pParent, sal_uInt32 nPos ) const
{
    return pModel->GetEntry(pParent, nPos);
}

SvTreeListEntry* SvTreeListBox::GetEntry( sal_uInt32 nRootPos ) const
{
    return pModel->GetEntry(nRootPos);
}

SvTreeListEntry* SvTreeListBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const
{

    SvTreeListEntry* pEntry = nullptr;
    SvTreeListEntry* pParent = nullptr;
    for (auto const& elem : _rPath)
    {
        pEntry = GetEntry( pParent, elem );
        if ( !pEntry )
            break;
        pParent = pEntry;
    }

    return pEntry;
}

void SvTreeListBox::FillEntryPath( SvTreeListEntry* pEntry, ::std::deque< sal_Int32 >&&nbsp;_rPath ) const
{

    if ( !pEntry )
        return;

    SvTreeListEntry* pParentEntry = GetParent( pEntry );
    while ( true )
    {
        sal_uInt32 i, nCount = GetLevelChildCount( pParentEntry );
        for ( i = 0; i < nCount; ++i )
        {
            SvTreeListEntry* pTemp = GetEntry( pParentEntry, i );
            DBG_ASSERT( pEntry, "invalid entry" );
            if ( pEntry == pTemp )
            {
                _rPath.push_front( static_cast<sal_Int32>(i) );
                break;
            }
        }

        if ( pParentEntry )
        {
            pEntry = pParentEntry;
            pParentEntry = GetParent( pParentEntry );
        }
        else
            break;
    }
}

SvTreeListEntry* SvTreeListBox::GetParent( SvTreeListEntry* pEntry ) const
{
    return pModel->GetParent(pEntry);
}

sal_uInt32 SvTreeListBox::GetChildCount( SvTreeListEntry const * pParent ) const
{
    return pModel->GetChildCount(pParent);
}

sal_uInt32 SvTreeListBox::GetLevelChildCount( SvTreeListEntry* _pParent ) const
{

    //if _pParent is 0, then pEntry is the first child of the root.
    SvTreeListEntry* pEntry = FirstChild( _pParent );

    if( !pEntry )//there is only root, root don't have children
        return 0;

    if( !_pParent )//root and children of root
        return pEntry->pParent->m_Children.size();

    return _pParent->m_Children.size();
}

SvViewDataEntry* SvTreeListBox::GetViewDataEntry( SvTreeListEntry const * pEntry ) const
{
    return const_cast<SvViewDataEntry*>(SvListView::GetViewData(pEntry));
}

SvViewDataItem* SvTreeListBox::GetViewDataItem(SvTreeListEntry const * pEntry, SvLBoxItem const * pItem)
{
    return const_cast<SvViewDataItem*>(static_cast<const SvTreeListBox*>(this)->GetViewDataItem(pEntry, pItem));
}

const SvViewDataItem* SvTreeListBox::GetViewDataItem(const SvTreeListEntry* pEntry, const SvLBoxItem* pItem) const
{
    const SvViewDataEntry* pEntryData = SvListView::GetViewData(pEntry);
    assert(pEntryData && "Entry not in View");
    sal_uInt16 nItemPos = pEntry->GetPos(pItem);
    return &pEntryData->GetItem(nItemPos);
}

void SvTreeListBox::InitViewData( SvViewDataEntry* pData, SvTreeListEntry* pEntry )
{
    SvTreeListEntry* pInhEntry = pEntry;
    SvViewDataEntry* pEntryData = pData;

    pEntryData->Init(pInhEntry->ItemCount());
    sal_uInt16 nCount = pInhEntry->ItemCount();
    sal_uInt16 nCurPos = 0;
    while( nCurPos < nCount )
    {
        SvLBoxItem& rItem = pInhEntry->GetItem( nCurPos );
        SvViewDataItem& rItemData = pEntryData->GetItem(nCurPos);
        rItem.InitViewData( this, pInhEntry, &rItemData );
        nCurPos++;
    }
}

void SvTreeListBox::EnableSelectionAsDropTarget( bool bEnable )
{
    sal_uInt16 nRefDepth;
    SvTreeListEntry* pTemp;

    SvTreeListEntry* pSelEntry = FirstSelected();
    while( pSelEntry )
    {
        if ( !bEnable )
        {
            pSelEntry->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
            nRefDepth = pModel->GetDepth( pSelEntry );
            pTemp = Next( pSelEntry );
            while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
            {
                pTemp->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
                pTemp = Next( pTemp );
            }
        }
        else
        {
            pSelEntry->nEntryFlags &= ~SvTLEntryFlags::DISABLE_DROP;
            nRefDepth = pModel->GetDepth( pSelEntry );
            pTemp = Next( pSelEntry );
            while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
            {
                pTemp->nEntryFlags &= ~SvTLEntryFlags::DISABLE_DROP;
                pTemp = Next( pTemp );
            }
        }
        pSelEntry = NextSelected( pSelEntry );
    }
}

// ******************************************************************
// InplaceEditing
// ******************************************************************

VclPtr<Edit> SvTreeListBox::GetEditWidget() const
{
    return pEdCtrl ? pEdCtrl->GetEditWidget() : nullptr;
}

void SvTreeListBox::EditText( const OUString& rStr, const tools::Rectangle& rRect,
    const Selection& rSel )
{
    pEdCtrl.reset();
    nImpFlags |= SvTreeListBoxFlags::IN_EDT;
    nImpFlags &= ~SvTreeListBoxFlags::EDTEND_CALLED;
    HideFocus();
    pEdCtrl.reset( new SvInplaceEdit2(
        this, rRect.TopLeft(), rRect.GetSize(), rStr,
        LINK( this, SvTreeListBox, TextEditEndedHdl_Impl ),
        rSel ) );
}

IMPL_LINK_NOARG(SvTreeListBox, TextEditEndedHdl_Impl, SvInplaceEdit2&, void)
{
    if ( nImpFlags & SvTreeListBoxFlags::EDTEND_CALLED ) // avoid nesting
        return;
    nImpFlags |= SvTreeListBoxFlags::EDTEND_CALLED;
    OUString aStr;
    if ( !pEdCtrl->EditingCanceled() )
        aStr = pEdCtrl->GetText();
    else
        aStr = pEdCtrl->GetSavedValue();
    EditedText( aStr );
    // Hide may only be called after the new text was put into the entry, so
    // that we don't call the selection handler in the GetFocus of the listbox
    // with the old entry text.
    pEdCtrl->Hide();
    nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
    GrabFocus();
}

void SvTreeListBox::CancelTextEditing()
{
    if ( pEdCtrl )
        pEdCtrl->StopEditing( true );
    nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
}

void SvTreeListBox::EndEditing( bool bCancel )
{
    if( pEdCtrl )
        pEdCtrl->StopEditing( bCancel );
    nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
}

vcl::StringEntryIdentifier SvTreeListBox::CurrentEntry( OUString& _out_entryText ) const
{
    // always accept the current entry if there is one
    SvTreeListEntry* pEntry( GetCurEntry() );
    if (pEntry)
    {
        _out_entryText = GetEntryText(pEntry);
        return pEntry;
    }

    pEntry = FirstSelected();
    if ( !pEntry )
        pEntry = First();

    if ( pEntry )
        _out_entryText = GetEntryText( pEntry );

    return pEntry;
}

vcl::StringEntryIdentifier SvTreeListBox::NextEntry(vcl::StringEntryIdentifier _pCurrentSearchEntry, OUString& _out_entryText) const
{
    SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_castconst SvTreeListEntry* >( _pCurrentSearchEntry ) );

    if  (   (   ( GetChildCount( pEntry ) > 0 )
            ||  ( pEntry->HasChildrenOnDemand() )
            )
        &&  !IsExpanded( pEntry )
        )
    {
        SvTreeListEntry* pNextSiblingEntry = pEntry->NextSibling();
        if ( !pNextSiblingEntry )
            pEntry = Next( pEntry );
        else
            pEntry = pNextSiblingEntry;
    }
    else
    {
        pEntry = Next( pEntry );
    }

    if ( !pEntry )
        pEntry = First();

    if ( pEntry )
        _out_entryText = GetEntryText( pEntry );

    return pEntry;
}

void SvTreeListBox::SelectEntry(vcl::StringEntryIdentifier _pEntry)
{
    SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_castconst SvTreeListEntry* >( _pEntry ) );
    DBG_ASSERT( pEntry, "SvTreeListBox::SelectSearchEntry: invalid entry!" );
    if ( !pEntry )
        return;

    SelectAll( false );
    SetCurEntry( pEntry );
    Select( pEntry );
}

bool SvTreeListBox::HandleKeyInput( const KeyEvent& _rKEvt )
{
    if ( _rKEvt.GetKeyCode().IsMod1() )
        return false;

    if (mbQuickSearch)
    {
        mpImpl->m_bDoingQuickSelection = true;
        const bool bHandled = mpImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt );
        mpImpl->m_bDoingQuickSelection = false;
        if ( bHandled )
            return true;
    }

    return false;
}


//JP 28.3.2001: new Drag & Drop API
sal_Int8 SvTreeListBox::AcceptDrop( const AcceptDropEvent& rEvt )
{
    sal_Int8 nRet = DND_ACTION_NONE;

    if (rEvt.mbLeaving || !CheckDragAndDropMode(g_pDDSource, rEvt.mnAction))
    {
        ImplShowTargetEmphasis( pTargetEntry, false );
    }
    else if( nDragDropMode == DragDropMode::NONE )
    {
        SAL_WARN( "svtools.contnr""SvTreeListBox::QueryDrop(): no target" );
    }
    else
    {
        SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
        if( !IsDropFormatSupported( SotClipboardFormatId::TREELISTBOX ) )
        {
            SAL_WARN( "svtools.contnr""SvTreeListBox::QueryDrop(): no format" );
        }
        else
        {
            DBG_ASSERT(g_pDDSource, "SvTreeListBox::QueryDrop(): SourceBox == 0");
            if (!( pEntry && g_pDDSource->GetModel() == GetModel()
                    && DND_ACTION_MOVE == rEvt.mnAction
                    && (pEntry->nEntryFlags & SvTLEntryFlags::DISABLE_DROP)))
            {
                nRet = rEvt.mnAction;
            }
        }

        // **** draw emphasis ****
        if( DND_ACTION_NONE == nRet )
               ImplShowTargetEmphasis( pTargetEntry, false );
        else if( pEntry != pTargetEntry || !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
        {
            ImplShowTargetEmphasis( pTargetEntry, false );
            pTargetEntry = pEntry;
            ImplShowTargetEmphasis( pTargetEntry, true );
        }
    }
    return nRet;
}

sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
{
    assert(pSourceView);
    pSourceView->EnableSelectionAsDropTarget();

    ImplShowTargetEmphasis( pTargetEntry, false );
    g_pDDTarget = this;

    TransferableDataHelper aData( rEvt.maDropEvent.Transferable );

    sal_Int8 nRet;
    if( aData.HasFormat( SotClipboardFormatId::TREELISTBOX ))
        nRet = rEvt.mnAction;
    else
        nRet = DND_ACTION_NONE;

    if( DND_ACTION_NONE != nRet )
    {
        nRet = DND_ACTION_NONE;

        SvTreeListEntry* pTarget = pTargetEntry; // may be 0!

        if( DND_ACTION_COPY == rEvt.mnAction )
        {
            if (CopySelection(g_pDDSource, pTarget))
                nRet = rEvt.mnAction;
        }
        else if( DND_ACTION_MOVE == rEvt.mnAction )
        {
            if (MoveSelectionCopyFallbackPossible( g_pDDSource, pTarget, false ))
                nRet = rEvt.mnAction;
        }
        else if( DND_ACTION_COPYMOVE == rEvt.mnAction )
        {
            if (MoveSelectionCopyFallbackPossible(g_pDDSource, pTarget, true))
                nRet = rEvt.mnAction;
        }
    }
    return nRet;
}

sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
{
    return ExecuteDrop( rEvt, g_pDDSource );
}

/**
 * This sets the global variables used to determine the
 * in-process drag source.
 */

void SvTreeListBox::SetupDragOrigin()
{
    g_pDDSource = this;
    g_pDDTarget = nullptr;
}

void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel )
{
    if(!isDisposed())
    {
        // tdf#143114 do not start drag when a Button/Checkbox is in
        // drag-before-ButtonUp mode (CaptureMouse() active)
        if(pImpl->IsCaptureOnButtonActive())
            return;
    }

    nOldDragMode = GetDragDropMode();
    if ( nOldDragMode == DragDropMode::NONE )
        return;

    ReleaseMouse();

    SvTreeListEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos );
    if( !pEntry )
    {
        DragFinished( DND_ACTION_NONE );
        return;
    }

    rtl::Reference<TransferDataContainer> xContainer = m_xTransferHelper;

    if (!xContainer)
    {
        xContainer.set(new TransferDataContainer);
        // apparently some (unused) content is needed
        xContainer->CopyAnyData( SotClipboardFormatId::TREELISTBOX,
                                    "unused", SAL_N_ELEMENTS("unused") );
    }

    nDragDropMode = NotifyStartDrag();
    if( nDragDropMode == DragDropMode::NONE || 0 == GetSelectionCount() )
    {
        nDragDropMode = nOldDragMode;
        DragFinished( DND_ACTION_NONE );
        return;
    }

    SetupDragOrigin();

    bool bOldUpdateMode = Control::IsUpdateMode();
    Control::SetUpdateMode( true );
    PaintImmediately();
    Control::SetUpdateMode( bOldUpdateMode );

    // Disallow using the selection and its children as drop targets.
    // Important: If the selection of the SourceListBox is changed in the
    // DropHandler, the entries have to be allowed as drop targets again:
    // (GetSourceListBox()->EnableSelectionAsDropTarget( true, true );)
    EnableSelectionAsDropTarget( false );

    xContainer->StartDrag(this, mnDragAction, GetDragFinishedHdl());
}

void SvTreeListBox::SetDragHelper(const rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants)
{
    m_xTransferHelper = rHelper;
    mnDragAction = eDNDConstants;
}

void SvTreeListBox::DragFinished( sal_Int8
#ifndef UNX
nAction
#endif
)
{
    EnableSelectionAsDropTarget();

#ifndef UNX
    if (   (nAction == DND_ACTION_MOVE)
        && (   (g_pDDTarget && (g_pDDTarget->GetModel() != GetModel()))
            || !g_pDDTarget))
    {
        RemoveSelection();
    }
#endif

    UnsetDropTarget();
    g_pDDSource = nullptr;
    g_pDDTarget = nullptr;
    nDragDropMode = nOldDragMode;
}

void SvTreeListBox::UnsetDropTarget()
{
    if (pTargetEntry)
    {
        ImplShowTargetEmphasis(pTargetEntry, false);
        pTargetEntry = nullptr;
    }
}

DragDropMode SvTreeListBox::NotifyStartDrag()
{
    return DragDropMode(0xffff);
}

// Handler and methods for Drag - finished handler.
// The with get GetDragFinishedHdl() get link can set on the
// TransferDataContainer. This link is a callback for the DragFinished
// call. AddBox method is called from the GetDragFinishedHdl() and the
// remove is called in link callback and in the destructor. So it can't
// called to a deleted object.

namespace
{
    // void* to avoid loplugin:vclwidgets, we don't need ownership here
    std::set<const void*> gSortLBoxes;
}

void SvTreeListBox::AddBoxToDDList_Impl( const SvTreeListBox& rB )
{
    gSortLBoxes.insert( &rB );
}

void SvTreeListBox::RemoveBoxFromDDList_Impl( const SvTreeListBox& rB )
{
    gSortLBoxes.erase( &rB );
}

IMPL_LINK( SvTreeListBox, DragFinishHdl_Impl, sal_Int8, nAction, void )
{
    auto &rSortLBoxes = gSortLBoxes;
    auto it = rSortLBoxes.find(this);
    if( it != rSortLBoxes.end() )
    {
        DragFinished( nAction );
        rSortLBoxes.erase( it );
    }
}

Link<sal_Int8,void> SvTreeListBox::GetDragFinishedHdl() const
{
    AddBoxToDDList_Impl( *this );
    return LINK( const_cast<SvTreeListBox*>(this), SvTreeListBox, DragFinishHdl_Impl );
}

/*
    Bugs/TODO

    - calculate rectangle when editing in-place (bug with some fonts)
    - SetSpaceBetweenEntries: offset is not taken into account in SetEntryHeight
*/


#define SV_LBOX_DEFAULT_INDENT_PIXEL 20

void SvTreeListBox::InitTreeView()
{
    pCheckButtonData = nullptr;
    pEdEntry = nullptr;
    pEdItem = nullptr;
    nEntryHeight = 0;
    pEdCtrl = nullptr;
    nFirstSelTab = 0;
    nLastSelTab = 0;
    nFocusWidth = -1;
    mnCheckboxItemWidth = 0;

    nTreeFlags = SvTreeFlags::RECALCTABS;
    nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL;
    nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL;
    pImpl.reset( new SvImpLBox( this, GetModel(), GetStyle() ) );

    mbContextBmpExpanded = true;
    nContextBmpWidthMax = 0;

    SetFont( GetFont() );
    AdjustEntryHeightAndRecalc();

    SetSpaceBetweenEntries( 0 );
    GetOutDev()->SetLineColor();
    InitSettings();
    ImplInitStyle();
    SetTabs();
}

OUString SvTreeListBox::SearchEntryTextWithHeadTitle( SvTreeListEntry* pEntry )
{
    assert(pEntry);
    OUStringBuffer sRet;

    sal_uInt16 nCount = pEntry->ItemCount();
    sal_uInt16 nCur = 0;
    while( nCur < nCount )
    {
        SvLBoxItem& rItem = pEntry->GetItem( nCur );
        if ( (rItem.GetType() == SvLBoxItemType::String) &&
             !static_cast<SvLBoxString&>( rItem ).GetText().isEmpty() )
        {
            sRet.append(static_cast<SvLBoxString&>( rItem ).GetText() + ",");
        }
        nCur++;
    }

    if (!sRet.isEmpty())
        sRet.remove(sRet.getLength() - 1, 1);
    return sRet.makeStringAndClear();
}

SvTreeListBox::~SvTreeListBox()
{
    disposeOnce();
}

void SvTreeListBox::dispose()
{
    if (IsMouseCaptured())
        ReleaseMouse();

    if( pImpl )
    {
        pImpl->CallEventListeners( VclEventId::ObjectDying );
        pImpl.reset();
    }
    if( mpImpl )
    {
        ClearTabList();

        pEdCtrl.reset();

        SvListView::dispose();

        SvTreeListBox::RemoveBoxFromDDList_Impl( *this );

        if (this == g_pDDSource)
            g_pDDSource = nullptr;
        if (this == g_pDDTarget)
            g_pDDTarget = nullptr;
        mpImpl.reset();
    }

    DropTargetHelper::dispose();
    DragSourceHelper::dispose();
    Control::dispose();
}

void SvTreeListBox::SetNoAutoCurEntry( bool b )
{
    pImpl->SetNoAutoCurEntry( b );
}

void SvTreeListBox::SetSublistOpenWithLeftRight()
{
    pImpl->m_bSubLstOpLR = true;
}

void SvTreeListBox::Resize()
{
    if( IsEditingActive() )
        EndEditing( true );

    Control::Resize();

    pImpl->Resize();
    nFocusWidth = -1;
    pImpl->ShowCursor( false );
    pImpl->ShowCursor( true );
}


namespace {

/* Cases:

   A) entries have bitmaps
       0. no buttons
       1. node buttons (can optionally also be on root items)
       2. node buttons (can optionally also be on root items) + CheckButton
       3. CheckButton
   B) entries don't have bitmaps  (=>via WindowBits because of D&D!)
       0. no buttons
       1. node buttons (can optionally also be on root items)
       2. node buttons (can optionally also be on root items) + CheckButton
       3. CheckButton
*/

enum class TreeListButtonType
{
    NO_BUTTONS,
    NODE_BUTTONS,
    NODE_AND_CHECK_BUTTONS,
    CHECK_BUTTONS,
};

}

#define TABFLAGS_TEXT (SvLBoxTabFlags::DYNAMIC |        \
                       SvLBoxTabFlags::ADJUST_LEFT |    \
                       SvLBoxTabFlags::EDITABLE |       \
                       SvLBoxTabFlags::SHOW_SELECTION)

#define TABFLAGS_CONTEXTBMP (SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER)

#define TABFLAGS_CHECKBTN (SvLBoxTabFlags::DYNAMIC |        \
                           SvLBoxTabFlags::ADJUST_CENTER)

#define TAB_STARTPOS    2

// take care of GetTextOffset when doing changes
void SvTreeListBox::SetTabs()
{
    // Moved to SvTreeListBox::Paint to make inplace editing work for X11 in the enhancement patch
    // tdf#139663 Rename objects from tree view in navigator.
    // if( IsEditingActive() )
    //   EndEditing( true );
    nTreeFlags &= ~SvTreeFlags::RECALCTABS;
    nFocusWidth = -1;
    const WinBits nStyle( GetStyle() );
    bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0;
    bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT |
                                              WB_HASBUTTONSATROOT))!=0;
    tools::Long nStartPos = TAB_STARTPOS;
    tools::Long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width();

    // pCheckButtonData->Width() knows nothing about the native checkbox width,
    // so we have mnCheckboxItemWidth which becomes valid when something is added.
    tools::Long nCheckWidth = 0;
    if( nTreeFlags & SvTreeFlags::CHKBTN )
        nCheckWidth = mnCheckboxItemWidth;
    tools::Long nCheckWidthDIV2 = nCheckWidth / 2;

    tools::Long nContextWidth = nContextBmpWidthMax;
    tools::Long nContextWidthDIV2 = nContextWidth / 2;

    ClearTabList();

    TreeListButtonType eButtonType = TreeListButtonType::NO_BUTTONS;
    if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
    {
        if( bHasButtons )
            eButtonType = TreeListButtonType::NODE_BUTTONS;
    }
    else
    {
        if( bHasButtons )
            eButtonType = TreeListButtonType::NODE_AND_CHECK_BUTTONS;
        else
            eButtonType = TreeListButtonType::CHECK_BUTTONS;
    }

    switch(eButtonType)
    {
        case TreeListButtonType::NO_BUTTONS:
            nStartPos += nContextWidthDIV2;  // because of centering
            AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
            nStartPos += nContextWidthDIV2;  // right edge of context bitmap
            // only set a distance if there are bitmaps
            if( nContextBmpWidthMax )
                nStartPos += 5; // distance context bitmap to text
            AddTab( nStartPos, TABFLAGS_TEXT );
            break;

        case TreeListButtonType::NODE_BUTTONS:
            if( bHasButtonsAtRoot )
                nStartPos += ( nIndent + (nNodeWidthPixel/2) );
            else
                nStartPos += nContextWidthDIV2;
            AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
            // add an indent if the context bitmap can't be centered without touching the expander
            if (nContextBmpWidthMax > nIndent + (nNodeWidthPixel / 2))
                nStartPos += nIndent;
            nStartPos += nContextWidthDIV2;  // right edge of context bitmap
            // only set a distance if there are bitmaps
            if( nContextBmpWidthMax )
                nStartPos += 5; // distance context bitmap to text
            AddTab( nStartPos, TABFLAGS_TEXT );
            break;

        case TreeListButtonType::NODE_AND_CHECK_BUTTONS:
            if( bHasButtonsAtRoot )
                nStartPos += ( nIndent + nNodeWidthPixel );
            else
                nStartPos += nCheckWidthDIV2;
            AddTab( nStartPos, TABFLAGS_CHECKBTN );
            nStartPos += nCheckWidthDIV2;  // right edge of CheckButton
            nStartPos += 3;  // distance CheckButton to context bitmap
            nStartPos += nContextWidthDIV2;  // center of context bitmap
            AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
            nStartPos += nContextWidthDIV2;  // right edge of context bitmap
            // only set a distance if there are bitmaps
            if( nContextBmpWidthMax )
                nStartPos += 5; // distance context bitmap to text
            AddTab( nStartPos, TABFLAGS_TEXT );
            break;

        case TreeListButtonType::CHECK_BUTTONS:
            nStartPos += nCheckWidthDIV2;
            AddTab( nStartPos, TABFLAGS_CHECKBTN );
            nStartPos += nCheckWidthDIV2;  // right edge of CheckButton
            nStartPos += 3;  // distance CheckButton to context bitmap
            nStartPos += nContextWidthDIV2;  // center of context bitmap
            AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
            nStartPos += nContextWidthDIV2;  // right edge of context bitmap
            // only set a distance if there are bitmaps
            if( nContextBmpWidthMax )
                nStartPos += 5; // distance context bitmap to text
            AddTab( nStartPos, TABFLAGS_TEXT );
            break;
    }
    pImpl->NotifyTabsChanged();
}

void SvTreeListBox::InitEntry(SvTreeListEntry* pEntry,
    const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp)
{
    if( nTreeFlags & SvTreeFlags::CHKBTN )
    {
        pEntry->AddItem(std::make_unique<SvLBoxButton>(pCheckButtonData));
    }

    pEntry->AddItem(std::make_unique<SvLBoxContextBmp>( aCollEntryBmp,aExpEntryBmp, mbContextBmpExpanded));

    pEntry->AddItem(std::make_unique<SvLBoxString>(aStr));
}

OUString SvTreeListBox::GetEntryText(SvTreeListEntry* pEntry) const
{
    assert(pEntry);
    SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SvLBoxItemType::String));
    if (pItem) // There may be entries without text items, e.g. in IconView
        return pItem->GetText();
    return {};
}

const Image& SvTreeListBox::GetExpandedEntryBmp(const SvTreeListEntry* pEntry)
{
    assert(pEntry);
    const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
    assert(pItem);
    return pItem->GetBitmap2( );
}

const Image& SvTreeListBox::GetCollapsedEntryBmp( const SvTreeListEntry* pEntry )
{
    assert(pEntry);
    const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
    assert(pItem);
    return pItem->GetBitmap1( );
}

IMPL_LINK( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData, void )
{
    pHdlEntry = pData->GetActEntry();
    CheckButtonHdl();
}

SvTreeListEntry* SvTreeListBox::InsertEntry(
    const OUString& rText,
    SvTreeListEntry* pParent,
    bool bChildrenOnDemand, sal_uInt32 nPos,
    void* pUser
)
{
    nTreeFlags |= SvTreeFlags::MANINS;

    const Image& rDefExpBmp = pImpl->GetDefaultEntryExpBmp( );
    const Image& rDefColBmp = pImpl->GetDefaultEntryColBmp( );

    aCurInsertedExpBmp = rDefExpBmp;
    aCurInsertedColBmp = rDefColBmp;

    SvTreeListEntry* pEntry = new SvTreeListEntry;
    pEntry->SetUserData( pUser );
    InitEntry( pEntry, rText, rDefColBmp, rDefExpBmp );
    pEntry->EnableChildrenOnDemand( bChildrenOnDemand );

    if( !pParent )
        Insert( pEntry, nPos );
    else
        Insert( pEntry, pParent, nPos );

    aPrevInsertedExpBmp = rDefExpBmp;
    aPrevInsertedColBmp = rDefColBmp;

    nTreeFlags &= ~SvTreeFlags::MANINS;

    return pEntry;
}

void SvTreeListBox::SetEntryText(SvTreeListEntry* pEntry, const OUString& rStr)
{
    SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SvLBoxItemType::String));
    assert(pItem);
    pItem->SetText(rStr);
    pItem->InitViewData( this, pEntry );
    GetModel()->InvalidateEntry( pEntry );
}

void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* pEntry, const Image& aBmp )
{
    SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));

    assert(pItem);
    pItem->SetBitmap2( aBmp );

    ModelHasEntryInvalidated(pEntry);
    CalcEntryHeight( pEntry );
    Size aSize = aBmp.GetSizePixel();
    short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, static_cast<short>(aSize.Width()) );
    if( nWidth > nContextBmpWidthMax )
    {
        nContextBmpWidthMax = nWidth;
        SetTabs();
    }
}

void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* pEntry,const Image& aBmp )
{
    SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));

    assert(pItem);
    pItem->SetBitmap1( aBmp );

    ModelHasEntryInvalidated(pEntry);
    CalcEntryHeight( pEntry );
    Size aSize = aBmp.GetSizePixel();
    short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, static_cast<short>(aSize.Width()) );
    if( nWidth > nContextBmpWidthMax )
    {
        nContextBmpWidthMax = nWidth;
        SetTabs();
    }
}

void SvTreeListBox::CheckBoxInserted(SvTreeListEntry* pEntry)
{
    SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
    if( pItem )
    {
        auto nWidth = pItem->GetWidth(this, pEntry);
        if( mnCheckboxItemWidth < nWidth )
        {
            mnCheckboxItemWidth = nWidth;
            nTreeFlags |= SvTreeFlags::RECALCTABS;
        }
    }
}

void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* pEntry )
{

    SvTreeListEntry* pParent = pModel->GetParent( pEntry );
    if( pParent )
    {
        SvTLEntryFlags nFlags = pParent->GetFlags();
        nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
        pParent->SetFlags( nFlags );
    }

    if(!((nTreeFlags & SvTreeFlags::MANINS) &&
         (aPrevInsertedExpBmp == aCurInsertedExpBmp)  &&
         (aPrevInsertedColBmp == aCurInsertedColBmp) ))
    {
        Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel();
        if( aSize.Width() > nContextBmpWidthMax )
        {
            nContextBmpWidthMax = static_cast<short>(aSize.Width());
            nTreeFlags |= SvTreeFlags::RECALCTABS;
        }
        aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel();
        if( aSize.Width() > nContextBmpWidthMax )
        {
            nContextBmpWidthMax = static_cast<short>(aSize.Width());
            nTreeFlags |= SvTreeFlags::RECALCTABS;
        }
    }
    CalcEntryHeight( pEntry );

    if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
        return;

    CheckBoxInserted(pEntry);
}

void SvTreeListBox::SetCheckButtonState( SvTreeListEntry* pEntry, SvButtonState eState)
{
    if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
        return;

    SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
    if(!pItem)
        return ;
    switch( eState )
    {
        case SvButtonState::Checked:
            pItem->SetStateChecked();
            break;

        case SvButtonState::Unchecked:
            pItem->SetStateUnchecked();
            break;

        case SvButtonState::Tristate:
            pItem->SetStateTristate();
            break;
    }
    InvalidateEntry( pEntry );
}

SvButtonState SvTreeListBox::GetCheckButtonState( SvTreeListEntry* pEntry ) const
{
    SvButtonState eState = SvButtonState::Unchecked;
    if( pEntry && ( nTreeFlags & SvTreeFlags::CHKBTN ) )
    {
        SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
        if(!pItem)
            return SvButtonState::Tristate;
        SvItemStateFlags nButtonFlags = pItem->GetButtonFlags();
        eState = SvLBoxButtonData::ConvertToButtonState( nButtonFlags );
    }
    return eState;
}

bool SvTreeListBox::GetCheckButtonEnabled(SvTreeListEntry* pEntry) const
{
    if (pEntry && (nTreeFlags & SvTreeFlags::CHKBTN))
    {
        SvLBoxButton* pItem
            = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
        if (pItem)
            return pItem->isEnable();
    }
    return false;
}

void SvTreeListBox::CheckButtonHdl()
{
    if ( pCheckButtonData )
        pImpl->CallEventListeners( VclEventId::CheckboxToggle, static_cast<void*>(pCheckButtonData->GetActEntry()) );
}


// TODO: Currently all data is cloned so that they conform to the default tree
// view format. Actually, the model should be used as a reference here. This
// leads to us _not_ calling SvTreeListEntry::Clone, but only its base class
// SvTreeListEntry.


SvTreeListEntry* SvTreeListBox::CloneEntry( SvTreeListEntry* pSource )
{
    OUString aStr;
    Image aCollEntryBmp;
    Image aExpEntryBmp;

    SvLBoxString* pStringItem = static_cast<SvLBoxString*>(pSource->GetFirstItem(SvLBoxItemType::String));
    if( pStringItem )
        aStr = pStringItem->GetText();
    SvLBoxContextBmp* pBmpItem = static_cast<SvLBoxContextBmp*>(pSource->GetFirstItem(SvLBoxItemType::ContextBmp));
    if( pBmpItem )
    {
        aCollEntryBmp = pBmpItem->GetBitmap1( );
        aExpEntryBmp  = pBmpItem->GetBitmap2( );
    }
    SvTreeListEntry* pClone = new SvTreeListEntry;
    InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp );
    pClone->SvTreeListEntry::Clone( pSource );
    pClone->EnableChildrenOnDemand( pSource->HasChildrenOnDemand() );
    pClone->SetUserData( pSource->GetUserData() );

    return pClone;
}

const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( ) const
{
    return pImpl->GetDefaultEntryExpBmp( );
}

const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( ) const
{
    return pImpl->GetDefaultEntryColBmp( );
}

void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp )
{
    Size aSize = aBmp.GetSizePixel();
    if( aSize.Width() > nContextBmpWidthMax )
        nContextBmpWidthMax = static_cast<short>(aSize.Width());
    SetTabs();

    pImpl->SetDefaultEntryExpBmp( aBmp );
}

void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp )
{
    Size aSize = aBmp.GetSizePixel();
    if( aSize.Width() > nContextBmpWidthMax )
        nContextBmpWidthMax = static_cast<short>(aSize.Width());
    SetTabs();

    pImpl->SetDefaultEntryColBmp( aBmp );
}

void SvTreeListBox::EnableCheckButton(SvLBoxButtonData& rData)
{
    pCheckButtonData = &rData;
    nTreeFlags |= SvTreeFlags::CHKBTN;
    rData.SetLink( LINK(this, SvTreeListBox, CheckButtonClick));

    SetTabs();
    if( IsUpdateMode() )
        Invalidate();
}

const Image& SvTreeListBox::GetDefaultExpandedNodeImage( )
{
    return SvImpLBox::GetDefaultExpandedNodeImage( );
}

const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( )
{
    return SvImpLBox::GetDefaultCollapsedNodeImage( );
}

void SvTreeListBox::SetNodeDefaultImages()
{
    SetExpandedNodeBmp(GetDefaultExpandedNodeImage());
    SetCollapsedNodeBmp(GetDefaultCollapsedNodeImage());
    SetTabs();
}

bool SvTreeListBox::EditingEntry( SvTreeListEntry* )
{
    return true;
}

bool SvTreeListBox::EditedEntry( SvTreeListEntry* /*pEntry*/,const OUString& /*rNewText*/)
{
    return true;
}

void SvTreeListBox::EnableInplaceEditing( bool bOn )
{
    if (bOn)
        nImpFlags |= SvTreeListBoxFlags::EDT_ENABLED;
    else
        nImpFlags &= ~SvTreeListBoxFlags::EDT_ENABLED;
}

void SvTreeListBox::KeyInput( const KeyEvent& rKEvt )
{
    // under OS/2, we get key up/down even while editing
    if( IsEditingActive() )
        return;

    if( !pImpl->KeyInput( rKEvt ) )
    {
        bool bHandled = HandleKeyInput( rKEvt );
        if ( !bHandled )
            Control::KeyInput( rKEvt );
    }
}

void SvTreeListBox::RequestingChildren( SvTreeListEntry* pParent )
{
    if( !pParent->HasChildren() )
        InsertEntry( u""_ustr, pParent );
}

void SvTreeListBox::GetFocus()
{
    //If there is no item in the tree, draw focus.
    if( !First())
    {
        Invalidate();
    }
    pImpl->GetFocus();
    Control::GetFocus();

    SvTreeListEntry* pEntry = FirstSelected();
    if ( !pEntry )
    {
        pEntry = pImpl->GetCurEntry();
    }
    if (pImpl->m_pCursor)
    {
        if (pEntry != pImpl->m_pCursor)
            pEntry = pImpl->m_pCursor;
    }
    if ( pEntry )
        pImpl->CallEventListeners( VclEventId::ListboxTreeFocus, pEntry );

}

void SvTreeListBox::LoseFocus()
{
    // If there is no item in the tree, delete visual focus.
    if ( !First() )
        Invalidate();
    if ( pImpl )
        pImpl->LoseFocus();
    Control::LoseFocus();
}

void SvTreeListBox::ModelHasCleared()
{
    pImpl->m_pCursor = nullptr; // else we crash in GetFocus when editing in-place
    pTargetEntry = nullptr;
    pEdCtrl.reset();
    pImpl->Clear();
    nFocusWidth = -1;

    nContextBmpWidthMax = 0;
    SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() );
    SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() );

    if( !(nTreeFlags & SvTreeFlags::FIXEDHEIGHT ))
        nEntryHeight = 0;
    AdjustEntryHeight();
    AdjustEntryHeight( GetDefaultExpandedEntryBmp() );
    AdjustEntryHeight( GetDefaultCollapsedEntryBmp() );

    SvListView::ModelHasCleared();
}

bool SvTreeListBox::PosOverBody(const Point& rPos) const
{
    if (rPos.X() < 0 || rPos.Y() < 0)
        return false;
    Size aSize(GetSizePixel());
    if (rPos.X() > aSize.Width() || rPos.Y() > aSize.Height())
        return false;
    if (pImpl->m_aVerSBar->IsVisible())
    {
        tools::Rectangle aRect(pImpl->m_aVerSBar->GetPosPixel(), pImpl->m_aVerSBar->GetSizePixel());
        if (aRect.Contains(rPos))
            return false;
    }
    if (pImpl->m_aHorSBar->IsVisible())
    {
        tools::Rectangle aRect(pImpl->m_aHorSBar->GetPosPixel(), pImpl->m_aHorSBar->GetSizePixel());
        if (aRect.Contains(rPos))
            return false;
    }
    return true;
}

void SvTreeListBox::ScrollOutputArea( short nDeltaEntries )
{
    if( !nDeltaEntries || !pImpl->m_aVerSBar->IsVisible() )
        return;

    tools::Long nThumb = pImpl->m_aVerSBar->GetThumbPos();
    tools::Long nMax = pImpl->m_aVerSBar->GetRange().Max();

    if( nDeltaEntries < 0 )
    {
        // move window up
        nDeltaEntries *= -1;
        tools::Long nVis = pImpl->m_aVerSBar->GetVisibleSize();
        tools::Long nTemp = nThumb + nVis;
        if( nDeltaEntries > (nMax - nTemp) )
            nDeltaEntries = static_cast<short>(nMax - nTemp);
        pImpl->PageDown( static_cast<sal_uInt16>(nDeltaEntries) );
    }
    else
    {
        if( nDeltaEntries > nThumb )
            nDeltaEntries = static_cast<short>(nThumb);
        pImpl->PageUp( static_cast<sal_uInt16>(nDeltaEntries) );
    }
    pImpl->SyncVerThumb();
}

void SvTreeListBox::ScrollToAbsPos( tools::Long nPos )
{
    pImpl->ScrollToAbsPos( nPos );
}

void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode )
{
    eSelMode = eSelectMode;
    pImpl->SetSelectionMode( eSelectMode );
}

void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode )
{
    nDragDropMode = nDDMode;
    pImpl->SetDragDropMode( nDDMode );
}

void SvTreeListBox::CalcEntryHeight( SvTreeListEntry const * pEntry )
{
    short nHeightMax=0;
    sal_uInt16 nCount = pEntry->ItemCount();
    sal_uInt16 nCur = 0;
    SvViewDataEntry* pViewData = GetViewDataEntry( pEntry );
    while( nCur < nCount )
    {
        auto nHeight = SvLBoxItem::GetHeight(pViewData, nCur);
        if( nHeight > nHeightMax )
            nHeightMax = nHeight;
        nCur++;
    }

    if( nHeightMax > nEntryHeight )
    {
        nEntryHeight = nHeightMax;
        Control::SetFont( GetFont() );
        pImpl->SetEntryHeight();
    }
}

void SvTreeListBox::SetEntryHeight( short nHeight )
{
    if( nHeight > nEntryHeight )
    {
        nEntryHeight = nHeight;
        if( nEntryHeight )
            nTreeFlags |= SvTreeFlags::FIXEDHEIGHT;
        else
            nTreeFlags &= ~SvTreeFlags::FIXEDHEIGHT;
        Control::SetFont( GetFont() );
        pImpl->SetEntryHeight();
    }
}

void SvTreeListBox::SetEntryWidth( short nWidth )
{
    nEntryWidth = nWidth;
}

void SvTreeListBox::AdjustEntryHeight( const Image& rBmp )
{
    const Size aSize( rBmp.GetSizePixel() );
    if( aSize.Height() > nEntryHeight )
    {
        nEntryHeight = static_cast<short>(aSize.Height()) + nEntryHeightOffs;
        pImpl->SetEntryHeight();
    }
}

void SvTreeListBox::AdjustEntryHeight()
{
    tools::Long nHeight = GetTextHeight();
    if( nHeight  >  nEntryHeight )
    {
        nEntryHeight = static_cast<short>(nHeight) + nEntryHeightOffs;
        pImpl->SetEntryHeight();
    }
}

bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
{
    pHdlEntry = pParent;
    bool bExpanded = false;
    SvTLEntryFlags nFlags;

    if( pParent->HasChildrenOnDemand() )
        RequestingChildren( pParent );
    bool bExpandAllowed = pParent->HasChildren() && ExpandingHdl();
    // double check if the expander callback ended up removing all children
    if (pParent->HasChildren())
    {
        if (bExpandAllowed)
        {
            bExpanded = true;
            ExpandListEntry( pParent );
            pImpl->EntryExpanded( pParent );
            pHdlEntry = pParent;
            ExpandedHdl();
        }
        nFlags = pParent->GetFlags();
        nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
        nFlags |= SvTLEntryFlags::HAD_CHILDREN;
        pParent->SetFlags( nFlags );
    }
    else
    {
        nFlags = pParent->GetFlags();
        nFlags |= SvTLEntryFlags::NO_NODEBMP;
        pParent->SetFlags( nFlags );
        GetModel()->InvalidateEntry( pParent ); // repaint
    }

    // #i92103#
    if ( bExpanded )
    {
        pImpl->CallEventListeners( VclEventId::ItemExpanded, pParent );
    }

    return bExpanded;
}

bool SvTreeListBox::Collapse( SvTreeListEntry* pParent )
{
    pHdlEntry = pParent;
    bool bCollapsed = false;

    if( ExpandingHdl() )
    {
        bCollapsed = true;
        pImpl->CollapsingEntry( pParent );
        CollapseListEntry( pParent );
        pImpl->EntryCollapsed( pParent );
        pHdlEntry = pParent;
        ExpandedHdl();
    }

    // #i92103#
    if ( bCollapsed )
    {
        pImpl->CallEventListeners( VclEventId::ItemCollapsed, pParent );
    }

    return bCollapsed;
}

bool SvTreeListBox::Select( SvTreeListEntry* pEntry, bool bSelect )
{
    DBG_ASSERT(pEntry,"Select: Null-Ptr");
    bool bRetVal = SelectListEntry( pEntry, bSelect );
    DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed");
    if( bRetVal )
    {
        pImpl->EntrySelected( pEntry, bSelect );
        pHdlEntry = pEntry;
        if( bSelect )
        {
            SelectHdl();
            CallEventListeners( VclEventId::ListboxTreeSelect, pEntry);
        }
        else
            DeselectHdl();
    }
    return bRetVal;
}

sal_uInt32 SvTreeListBox::SelectChildren( SvTreeListEntry* pParent, bool bSelect )
{
    pImpl->DestroyAnchor();
    sal_uInt32 nRet = 0;
    if( !pParent->HasChildren() )
        return 0;
    sal_uInt16 nRefDepth = pModel->GetDepth( pParent );
    SvTreeListEntry* pChild = FirstChild( pParent );
    do {
        nRet++;
        Select( pChild, bSelect );
        pChild = Next( pChild );
    } while( pChild && pModel->GetDepth( pChild ) > nRefDepth );
    return nRet;
}

void SvTreeListBox::SelectAll( bool bSelect )
{
    pImpl->SelAllDestrAnch(
        bSelect,
        true,       // delete anchor,
        true );     // even when using SelectionMode::Single, deselect the cursor
}

void SvTreeListBox::ModelHasInsertedTree( SvTreeListEntry* pEntry )
{
    sal_uInt16 nRefDepth = pModel->GetDepth( pEntry );
    SvTreeListEntry* pTmp = pEntry;
    do
    {
        ImpEntryInserted( pTmp );
        pTmp = Next( pTmp );
    } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) );
    pImpl->TreeInserted( pEntry );
}

void SvTreeListBox::ModelHasInserted( SvTreeListEntry* pEntry )
{
    ImpEntryInserted( pEntry );
    pImpl->EntryInserted( pEntry );
}

void SvTreeListBox::ModelIsMoving(SvTreeListEntry* pSource )
{
    pImpl->MovingEntry( pSource );
}

void SvTreeListBox::ModelHasMoved( SvTreeListEntry* pSource )
{
    pImpl->EntryMoved( pSource );
}

void SvTreeListBox::ModelIsRemoving( SvTreeListEntry* pEntry )
{
    if(pEdEntry == pEntry)
        pEdEntry = nullptr;

    pImpl->RemovingEntry( pEntry );
}

void SvTreeListBox::ModelHasRemoved( SvTreeListEntry* pEntry  )
{
    if (pEntry == pHdlEntry)
        pHdlEntry = nullptr;

    if (pEntry == pTargetEntry)
        pTargetEntry = nullptr;

    pImpl->EntryRemoved();
}

void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp)
{
    AdjustEntryHeight( rBmp );
    pImpl->SetCollapsedNodeBmp( rBmp );
}

void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp )
{
    AdjustEntryHeight( rBmp );
    pImpl->SetExpandedNodeBmp( rBmp );
}


void SvTreeListBox::SetFont( const vcl::Font& rFont )
{
    vcl::Font aTempFont( rFont );
    vcl::Font aOrigFont( GetFont() );
    aTempFont.SetTransparent( true );
    if (aTempFont == aOrigFont)
        return;
    Control::SetFont( aTempFont );

    aTempFont.SetColor(aOrigFont.GetColor());
    aTempFont.SetFillColor(aOrigFont.GetFillColor());
    aTempFont.SetTransparent(aOrigFont.IsTransparent());

    if (aTempFont == aOrigFont)
        return;

    AdjustEntryHeightAndRecalc();
}

void SvTreeListBox::AdjustEntryHeightAndRecalc()
{
    AdjustEntryHeight();
    // always invalidate, else things go wrong in SetEntryHeight
    RecalcViewData();
}

void SvTreeListBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
{
    Control::Paint(rRenderContext, rRect);
    if (nTreeFlags & SvTreeFlags::RECALCTABS)
    {
        if (IsEditingActive())
            EndEditing(true);
        SetTabs();
    }
    pImpl->Paint(rRenderContext, rRect);

    //Add visual focus draw
    if (First())
        return;

    if (HasFocus())
    {
        tools::Long nHeight = rRenderContext.GetTextHeight();
        tools::Rectangle aRect(Point(0, 0), Size(GetSizePixel().Width(), nHeight));
        ShowFocus(aRect);
    }
    else
    {
        HideFocus();
    }
}

void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
{
    // tdf#143114 remember the *correct* starting entry
    pImpl->m_pCursorOld = (rMEvt.IsLeft() && (nTreeFlags & SvTreeFlags::CHKBTN) && mnClicksToToggle > 0)
        ? GetEntry(rMEvt.GetPosPixel())
        : nullptr;

    pImpl->MouseButtonDown( rMEvt );
}

void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt )
{
    // tdf#116675 clicking on an entry should toggle its checkbox
    // tdf#143114 use the already created starting entry and if it exists
    if (nullptr != pImpl->m_pCursorOld)
    {
        const Point aPnt = rMEvt.GetPosPixel();
        SvTreeListEntry* pEntry = GetEntry(aPnt);

        // compare if MouseButtonUp *is* on the same entry, regardless of scrolling
        // or other things
        if (pEntry && pEntry->m_Items.size() > 0 && 1 == mnClicksToToggle && pEntry == pImpl->m_pCursorOld)
        {
            SvLBoxItem* pItem = GetItem(pEntry, aPnt.X());
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=98 G=96

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.