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 94 kB image not shown  

Quelle  svimpbox.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 .
 */


#include <sal/config.h>

#include <o3tl/safeint.hxx>
#include <vcl/svapp.hxx>
#include <vcl/salnativewidgets.hxx>
#include <vcl/help.hxx>
#include <vcl/settings.hxx>
#include <vcl/commandevent.hxx>

#include <cstdlib>
#include <memory>
#include <stack>

#include <vcl/toolkit/treelistbox.hxx>
#include <vcl/toolkit/svlbitm.hxx>
#include <vcl/wintypes.hxx>
#include <bitmaps.hlst>
#include <svimpbox.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <tools/debug.hxx>

#include <vcl/toolkit/treelistentry.hxx>
#include <vcl/toolkit/viewdataentry.hxx>

// #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors
Image*  SvImpLBox::s_pDefCollapsed      = nullptr;
Image*  SvImpLBox::s_pDefExpanded       = nullptr;
oslInterlockedCount SvImpLBox::s_nImageRefCount   = 0;

SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvTreeList* pLBTree, WinBits nWinStyle)
    : m_aScrBarBox(VclPtr<ScrollBarBox>::Create(pLBView))
    , m_aFctSet(this, pLBView)
    , mbForceMakeVisible (false)
    , m_aEditIdle("SvImpLBox m_aEditIdle")
    , m_aHorSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_HSCROLL))
    , m_aVerSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_VSCROLL))
    , m_aOutputSize(0, 0)
    , mbNoAutoCurEntry(false)
    , m_aSelEng(pLBView, nullptr)
    , m_nNextVerVisSize(0)
{
    osl_atomic_increment(&s_nImageRefCount);
    m_pView = pLBView;
    m_pTree = pLBTree;
    m_aSelEng.SetFunctionSet( static_cast<FunctionSet*>(&m_aFctSet) );
    m_aSelEng.ExpandSelectionOnMouseMove( false );
    SetStyle( nWinStyle );
    SetSelectionMode( SelectionMode::Single );
    SetDragDropMode( DragDropMode::NONE );

    m_aVerSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollUpDownHdl ) );
    m_aHorSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollLeftRightHdl ) );
    m_aHorSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) );
    m_aVerSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) );
    m_aVerSBar->SetRange( Range(0,0) );
    m_aVerSBar->Hide();
    m_aHorSBar->SetRange( Range(0,0) );
    m_aHorSBar->SetPageSize( 24 ); // pixels
    m_aHorSBar->SetLineSize( 8 ); // pixels

    m_nHorSBarHeight = static_cast<short>(m_aHorSBar->GetSizePixel().Height());
    m_nVerSBarWidth = static_cast<short>(m_aVerSBar->GetSizePixel().Width());

    m_pStartEntry = nullptr;
    m_pCursor             = nullptr;
    m_pCursorOld          = nullptr;
    m_pAnchor             = nullptr;
    m_nVisibleCount       = 0;    // number of rows of data in control
    m_nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID;
    m_nNodeBmpWidth       = 0;

    // button animation in listbox
    m_pActiveButton = nullptr;
    m_pActiveEntry = nullptr;
    m_pActiveTab = nullptr;

    m_nFlags = LBoxFlags::NONE;

    m_aEditIdle.SetPriority( TaskPriority::LOWEST );
    m_aEditIdle.SetInvokeHandler( LINK(this,SvImpLBox,EditTimerCall) );

    m_nMostRight = -1;
    m_pMostRightEntry = nullptr;
    m_nCurUserEvent = nullptr;

    m_bUpdateMode = true;
    m_bInVScrollHdl = false;
    m_nFlags |= LBoxFlags::Filling;

    m_bSubLstOpLR = false;
}

SvImpLBox::~SvImpLBox()
{
    m_aEditIdle.Stop();
    StopUserEvent();

    if ( osl_atomic_decrement(&s_nImageRefCount) == 0 )
    {
        delete s_pDefCollapsed;
        s_pDefCollapsed = nullptr;
        delete s_pDefExpanded;
        s_pDefExpanded = nullptr;
    }
    m_aVerSBar.disposeAndClear();
    m_aHorSBar.disposeAndClear();
    m_aScrBarBox.disposeAndClear();
}

void SvImpLBox::UpdateStringSorter()
{
    const css::lang::Locale& rNewLocale = Application::GetSettings().GetLanguageTag().getLocale();

    if( m_pStringSorter )
    {
        // different Locale from the older one, drop it and force recreate
        const css::lang::Locale &aLocale = m_pStringSorter->getLocale();
        if( aLocale.Language != rNewLocale.Language ||
            aLocale.Country != rNewLocale.Country ||
            aLocale.Variant != rNewLocale.Variant )
            m_pStringSorter.reset();
    }

    if( !m_pStringSorter )
    {
        m_pStringSorter.reset(new comphelper::string::NaturalStringSorter(
                              ::comphelper::getProcessComponentContext(),
                              rNewLocale));
    }
}

short SvImpLBox::UpdateContextBmpWidthVector( SvTreeListEntry const * pEntry, short nWidth )
{
    DBG_ASSERT( m_pView->pModel, "View and Model aren't valid!" );

    sal_uInt16 nDepth = m_pView->pModel->GetDepth( pEntry );
    // initialize vector if necessary
    std::vector< short >::size_type nSize = m_aContextBmpWidthVector.size();
    while ( nDepth > nSize )
    {
        m_aContextBmpWidthVector.resize( nSize + 1 );
        m_aContextBmpWidthVector.at( nSize ) = nWidth;
        ++nSize;
    }
    if( m_aContextBmpWidthVector.size() == nDepth )
    {
        m_aContextBmpWidthVector.resize( nDepth + 1 );
        m_aContextBmpWidthVector.at( nDepth ) = 0;
    }
    short nContextBmpWidth = m_aContextBmpWidthVector[ nDepth ];
    if( nContextBmpWidth < nWidth )
    {
        m_aContextBmpWidthVector.at( nDepth ) = nWidth;
        return nWidth;
    }
    else
        return nContextBmpWidth;
}

void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry* pEntry )
{
    assert(pEntry && "Moved Entry is invalid!");

    SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem(SvLBoxItemType::ContextBmp) );
    short nExpWidth = static_cast<short>(pBmpItem->GetBitmap1().GetSizePixel().Width());
    short nColWidth = static_cast<short>(pBmpItem->GetBitmap2().GetSizePixel().Width());
    short nMax = std::max(nExpWidth, nColWidth);
    UpdateContextBmpWidthVector( pEntry, nMax );

    if( pEntry->HasChildren() ) // recursive call, whether expanded or not
    {
        SvTreeListEntry* pChild = m_pView->FirstChild( pEntry );
        DBG_ASSERT( pChild, "The first child is invalid!" );
        do
        {
            UpdateContextBmpWidthVectorFromMovedEntry( pChild );
            pChild = m_pView->Next( pChild );
        } while ( pChild );
    }
}

void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry const * pEntry )
{
    sal_uInt16 nDepth = m_pView->pModel->GetDepth( pEntry );
    if( m_aContextBmpWidthVector.empty() )
        return;
    short nWidth = m_aContextBmpWidthVector[ nDepth ];
    if( nWidth != m_pView->nContextBmpWidthMax ) {
        m_pView->nContextBmpWidthMax = nWidth;
        m_nFlags |= LBoxFlags::IgnoreChangedTabs;
        m_pView->SetTabs();
        m_nFlags &= ~LBoxFlags::IgnoreChangedTabs;
    }
}

void SvImpLBox::SetStyle( WinBits i_nWinStyle )
{
    m_nStyle = i_nWinStyle;
    if ( ( m_nStyle & WB_SIMPLEMODE) && ( m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) )
        m_aSelEng.AddAlways( true );
}

void SvImpLBox::SetNoAutoCurEntry( bool b )
{
    mbNoAutoCurEntry = b;
}

// don't touch the model any more
void SvImpLBox::Clear()
{
    StopUserEvent();
    m_pStartEntry = nullptr;
    m_pAnchor = nullptr;

    m_pActiveButton = nullptr;
    m_pActiveEntry = nullptr;
    m_pActiveTab = nullptr;

    m_nMostRight = -1;
    m_pMostRightEntry = nullptr;

    // don't touch the cursor any more
    if( m_pCursor )
    {
        if( m_pView->HasFocus() )
            m_pView->HideFocus();
        m_pCursor = nullptr;
    }
    m_pCursorOld = nullptr;
    m_aVerSBar->Hide();
    m_aVerSBar->SetThumbPos( 0 );
    Range aRange( 0, 0 );
    m_aVerSBar->SetRange( aRange );
    m_aOutputSize = m_pView->Control::GetOutputSizePixel();
    m_aHorSBar->Hide();
    m_aHorSBar->SetThumbPos( 0 );
    MapMode aMapMode( m_pView->GetMapMode());
    aMapMode.SetOrigin( Point(0,0) );
    m_pView->Control::SetMapMode( aMapMode );
    m_aHorSBar->SetRange( aRange );
    m_aHorSBar->SetSizePixel(Size(m_aOutputSize.Width(),m_nHorSBarHeight));
    m_pView->GetOutDev()->SetClipRegion();
    if( GetUpdateMode() )
        m_pView->Invalidate( GetVisibleArea() );
    m_nFlags |= LBoxFlags::Filling;
    if( !m_aHorSBar->IsVisible() && !m_aVerSBar->IsVisible() )
        m_aScrBarBox->Hide();

    m_aContextBmpWidthVector.clear();

    CallEventListeners( VclEventId::ListboxItemRemoved );
}

// *********************************************************************
// Paint, navigate, scroll
// *********************************************************************

IMPL_LINK_NOARG(SvImpLBox, EndScrollHdl, ScrollBar*, void)
{
    if( m_nFlags & LBoxFlags::EndScrollSetVisSize )
    {
        m_aVerSBar->SetVisibleSize( m_nNextVerVisSize );
        m_nFlags &= ~LBoxFlags::EndScrollSetVisSize;
    }
}

// handler for vertical scrollbar

IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar, void )
{
    DBG_ASSERT(!m_bInVScrollHdl,"Scroll handler out-paces itself!");
    tools::Long nDelta = pScrollBar->GetDelta();
    if( !nDelta )
        return;

    // when only one row don't skip lines
    if (pScrollBar->GetPageSize() == 1)
        nDelta = nDelta > 0 ? 1 : -1;

    m_nFlags &= ~LBoxFlags::Filling;

    m_bInVScrollHdl = true;

    if( m_pView->IsEditingActive() )
    {
        m_pView->EndEditing( true ); // Cancel
        m_pView->PaintImmediately();
    }

    if( nDelta > 0 )
    {
        if( nDelta == 1 && pScrollBar->GetPageSize() > 1)
            CursorDown();
        else
            PageDown( static_cast<sal_uInt16>(nDelta) );
    }
    else
    {
        nDelta *= -1;
        if( nDelta == 1 && pScrollBar->GetPageSize() > 1)
            CursorUp();
        else
            PageUp( static_cast<sal_uInt16>(nDelta) );
    }
    m_bInVScrollHdl = false;
}


void SvImpLBox::CursorDown()
{
    if (!m_pStartEntry)
        return;

    SvTreeListEntry* pNextFirstToDraw = m_pView->NextVisible(m_pStartEntry);
    if( pNextFirstToDraw )
    {
        m_nFlags &= ~LBoxFlags::Filling;
        ShowCursor( false );
        m_pView->PaintImmediately();
        m_pStartEntry = pNextFirstToDraw;
        tools::Rectangle aArea( GetVisibleArea() );
        m_pView->Scroll( 0, -(m_pView->GetEntryHeight()), aArea, ScrollFlags::NoChildren );
        m_pView->PaintImmediately();
        ShowCursor( true );
        m_pView->NotifyScrolled();
    }
}

void SvImpLBox::CursorUp()
{
    if (!m_pStartEntry)
        return;

    SvTreeListEntry* pPrevFirstToDraw = m_pView->PrevVisible(m_pStartEntry);
    if( !pPrevFirstToDraw )
        return;

    m_nFlags &= ~LBoxFlags::Filling;
    tools::Long nEntryHeight = m_pView->GetEntryHeight();
    ShowCursor( false );
    m_pView->PaintImmediately();
    m_pStartEntry = pPrevFirstToDraw;
    tools::Rectangle aArea( GetVisibleArea() );
    if (aArea.GetHeight() > nEntryHeight)
        aArea.AdjustBottom(-nEntryHeight);
    m_pView->Scroll( 0, nEntryHeight, aArea, ScrollFlags::NoChildren );
    m_pView->PaintImmediately();
    ShowCursor( true );
    m_pView->NotifyScrolled();
}

void SvImpLBox::PageDown( sal_uInt16 nDelta )
{
    sal_uInt16 nRealDelta = nDelta;

    if( !nDelta )
        return;

    if (!m_pStartEntry)
        return;

    SvTreeListEntry* pNext = m_pView->NextVisible(m_pStartEntry, nRealDelta);
    if( pNext == m_pStartEntry )
        return;

    ShowCursor( false );

    m_nFlags &= ~LBoxFlags::Filling;
    m_pView->PaintImmediately();
    m_pStartEntry = pNext;

    if( nRealDelta >= m_nVisibleCount )
    {
        m_pView->Invalidate( GetVisibleArea() );
        m_pView->PaintImmediately();
    }
    else
    {
        tools::Rectangle aArea( GetVisibleArea() );
        tools::Long nScroll = m_pView->GetEntryHeight() * static_cast<tools::Long>(nRealDelta);
        nScroll = -nScroll;
        m_pView->PaintImmediately();
        m_pView->Scroll( 0, nScroll, aArea, ScrollFlags::NoChildren );
        m_pView->PaintImmediately();
    }

    ShowCursor( true );
    m_pView->NotifyScrolled();
}

void SvImpLBox::PageUp( sal_uInt16 nDelta )
{
    sal_uInt16 nRealDelta = nDelta;
    if( !nDelta )
        return;

    if (!m_pStartEntry)
        return;

    SvTreeListEntry* pPrev = m_pView->PrevVisible(m_pStartEntry, nRealDelta);
    if( pPrev == m_pStartEntry )
        return;

    m_nFlags &= ~LBoxFlags::Filling;
    ShowCursor( false );

    m_pView->PaintImmediately();
    m_pStartEntry = pPrev;
    if( nRealDelta >= m_nVisibleCount )
    {
        m_pView->Invalidate( GetVisibleArea() );
        m_pView->PaintImmediately();
    }
    else
    {
        tools::Long nEntryHeight = m_pView->GetEntryHeight();
        tools::Rectangle aArea( GetVisibleArea() );
        m_pView->PaintImmediately();
        m_pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, ScrollFlags::NoChildren );
        m_pView->PaintImmediately();
    }

    ShowCursor( true );
    m_pView->NotifyScrolled();
}

void SvImpLBox::KeyUp( bool bPageUp )
{
    if( !m_aVerSBar->IsVisible() )
        return;

    tools::Long nDelta;
    if( bPageUp )
        nDelta = m_aVerSBar->GetPageSize();
    else
        nDelta = 1;

    tools::Long nThumbPos = m_aVerSBar->GetThumbPos();

    if( nThumbPos < nDelta )
        nDelta = nThumbPos;

    if( nDelta <= 0 )
        return;

    m_nFlags &= ~LBoxFlags::Filling;

    m_aVerSBar->SetThumbPos( nThumbPos - nDelta );
    if( bPageUp )
        PageUp( static_cast<short>(nDelta) );
    else
        CursorUp();
}


void SvImpLBox::KeyDown( bool bPageDown )
{
    if( !m_aVerSBar->IsVisible() )
        return;

    tools::Long nDelta;
    if( bPageDown )
        nDelta = m_aVerSBar->GetPageSize();
    else
        nDelta = 1;

    tools::Long nThumbPos = m_aVerSBar->GetThumbPos();
    tools::Long nVisibleSize = m_aVerSBar->GetVisibleSize();
    tools::Long nRange = m_aVerSBar->GetRange().Len();

    tools::Long nTmp = nThumbPos+nVisibleSize;
    while( (nDelta > 0) && (nTmp+nDelta) >= nRange )
        nDelta--;

    if( nDelta <= 0 )
        return;

    m_nFlags &= ~LBoxFlags::Filling;

    m_aVerSBar->SetThumbPos( nThumbPos+nDelta );
    if( bPageDown )
        PageDown( static_cast<short>(nDelta) );
    else
        CursorDown();
}


void SvImpLBox::InvalidateEntriesFrom( tools::Long nY ) const
{
    if( !(m_nFlags & LBoxFlags::InPaint ))
    {
        tools::Rectangle aRect( GetVisibleArea() );
        aRect.SetTop( nY );
        m_pView->Invalidate( aRect );
    }
}

void SvImpLBox::InvalidateEntry( tools::Long nY ) const
{
    if( m_nFlags & LBoxFlags::InPaint )
        return;

    tools::Rectangle aRect( GetVisibleArea() );
    tools::Long nMaxBottom = aRect.Bottom();
    aRect.SetTop( nY );
    aRect.SetBottom( nY ); aRect.AdjustBottom(m_pView->GetEntryHeight() );
    if( aRect.Top() > nMaxBottom )
        return;
    if( aRect.Bottom() > nMaxBottom )
        aRect.SetBottom( nMaxBottom );
    if (m_pView->SupportsDoubleBuffering())
        // Perform full paint when flicker is to be avoided explicitly.
        m_pView->Invalidate();
    else
        m_pView->Invalidate(aRect);
}

void SvImpLBox::InvalidateEntry( SvTreeListEntry* pEntry )
{
    if( GetUpdateMode() )
    {
        tools::Long nPrev = m_nMostRight;
        SetMostRight( pEntry );
        if( nPrev < m_nMostRight )
            ShowVerSBar();
    }
    if( !(m_nFlags & LBoxFlags::InPaint ))
    {
        bool bHasFocusRect = false;
        if( pEntry==m_pCursor && m_pView->HasFocus() )
        {
            bHasFocusRect = true;
            ShowCursor( false );
        }
        InvalidateEntry( GetEntryLine( pEntry ) );
        if( bHasFocusRect )
            ShowCursor( true );
    }
}


void SvImpLBox::RecalcFocusRect()
{
    if( m_pView->HasFocus() && m_pCursor )
    {
        m_pView->HideFocus();
        tools::Long nY = GetEntryLine( m_pCursor );
        tools::Rectangle aRect = m_pView->GetFocusRect( m_pCursor, nY );
        vcl::Region aOldClip( m_pView->GetOutDev()->GetClipRegion());
        vcl::Region aClipRegion( GetClipRegionRect() );
        m_pView->GetOutDev()->SetClipRegion( aClipRegion );
        m_pView->ShowFocus( aRect );
        m_pView->GetOutDev()->SetClipRegion( aOldClip );
    }
}


//  Sets cursor. When using SingleSelection, the selection is adjusted.
void SvImpLBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect )
{
    SvViewDataEntry* pViewDataNewCur = nullptr;
    if( pEntry )
        pViewDataNewCur= m_pView->GetViewDataEntry(pEntry);
    if( pEntry &&
        pEntry == m_pCursor &&
        pViewDataNewCur &&
        pViewDataNewCur->HasFocus() &&
        pViewDataNewCur->IsSelected())
    {
        return;
    }

    // if this cursor is not selectable, find first visible that is and use it
    while( pEntry && pViewDataNewCur && !pViewDataNewCur->IsSelectable() )
    {
        pEntry = m_pView->NextVisible(pEntry);
        pViewDataNewCur = pEntry ? m_pView->GetViewDataEntry(pEntry) : nullptr;
    }

    SvTreeListEntry* pOldCursor = m_pCursor;
    if( m_pCursor && pEntry != m_pCursor )
    {
        m_pView->SetEntryFocus( m_pCursor, false );
        if( m_bSimpleTravel )
            m_pView->Select( m_pCursor, false );
        m_pView->HideFocus();
    }
    m_pCursor = pEntry;
    if( m_pCursor )
    {
        if (pViewDataNewCur)
            pViewDataNewCur->SetFocus( true );
        if(!bForceNoSelect && m_bSimpleTravel && !(m_nFlags & LBoxFlags::DeselectAll) && GetUpdateMode())
        {
            m_pView->Select( m_pCursor );
            CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor );
        }
        // multiple selection: select in cursor move if we're not in
        // Add mode (Ctrl-F8)
        else if( GetUpdateMode() &&
                 m_pView->GetSelectionMode() == SelectionMode::Multiple &&
                 !(m_nFlags & LBoxFlags::DeselectAll) && !m_aSelEng.IsAddMode() &&
                 !bForceNoSelect )
        {
            m_pView->Select( m_pCursor );
            CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor );
        }
        else
        {
            ShowCursor( true );
            if (bForceNoSelect && GetUpdateMode())
            {
                CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor);
            }
        }

        if( m_pAnchor )
        {
            DBG_ASSERT(m_aSelEng.GetSelectionMode() != SelectionMode::Single,"Mode?");
            SetAnchorSelection( pOldCursor, m_pCursor );
        }
    }
    m_nFlags &= ~LBoxFlags::DeselectAll;

    m_pView->OnCurrentEntryChanged();
}

void SvImpLBox::ShowCursor( bool bShow )
{
    if( !bShow || !m_pCursor || !m_pView->HasFocus() )
    {
        vcl::Region aOldClip( m_pView->GetOutDev()->GetClipRegion());
        vcl::Region aClipRegion( GetClipRegionRect() );
        m_pView->GetOutDev()->SetClipRegion( aClipRegion );
        m_pView->HideFocus();
        m_pView->GetOutDev()->SetClipRegion( aOldClip );
    }
    else
    {
        tools::Long nY = GetEntryLine( m_pCursor );
        tools::Rectangle aRect = m_pView->GetFocusRect( m_pCursor, nY );
        vcl::Region aOldClip( m_pView->GetOutDev()->GetClipRegion());
        vcl::Region aClipRegion( GetClipRegionRect() );
        m_pView->GetOutDev()->SetClipRegion( aClipRegion );
        m_pView->ShowFocus( aRect );
        m_pView->GetOutDev()->SetClipRegion( aOldClip );
    }
}


void SvImpLBox::UpdateAll()
{
    FindMostRight();
    m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) );
    SyncVerThumb();
    FillView();
    ShowVerSBar();
    if( m_bSimpleTravel && m_pCursor && m_pView->HasFocus() )
        m_pView->Select( m_pCursor );
    ShowCursor( true );
    m_pView->Invalidate( GetVisibleArea() );
}

IMPL_LINK( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar, void )
{
    tools::Long nDelta = pScrollBar->GetDelta();
    if( nDelta )
    {
        if( m_pView->IsEditingActive() )
        {
            m_pView->EndEditing( true ); // Cancel
            m_pView->PaintImmediately();
        }
        m_pView->nFocusWidth = -1;
        KeyLeftRight( nDelta );
    }
}

void SvImpLBox::KeyLeftRight( tools::Long nDelta )
{
    if( !(m_nFlags & LBoxFlags::InResize) )
        m_pView->PaintImmediately();
    m_nFlags &= ~LBoxFlags::Filling;
    ShowCursor( false );

    // calculate new origin
    tools::Long nPos = m_aHorSBar->GetThumbPos();
    Point aOrigin( -nPos, 0 );

    MapMode aMapMode( m_pView->GetMapMode() );
    aMapMode.SetOrigin( aOrigin );
    m_pView->SetMapMode( aMapMode );

    if( !(m_nFlags & LBoxFlags::InResize) )
    {
        tools::Rectangle aRect( GetVisibleArea() );
        m_pView->Scroll( -nDelta, 0, aRect, ScrollFlags::NoChildren );
    }
    else
        m_pView->Invalidate();
    RecalcFocusRect();
    ShowCursor( true );
    m_pView->NotifyScrolled();
}


// returns the last entry if position is just past the last entry
SvTreeListEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const
{
    DBG_ASSERT( m_pView->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" );
    if ( !m_pView->GetModel() )
        // this is quite impossible. Nevertheless, stack traces from the crash reporter
        // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it
        // reliably :-\ ...
        // #122359# / 2005-05-23 / frank.schoenheit@sun.com
        return nullptr;
    if( m_pView->GetEntryCount() == 0 || !m_pStartEntry || !m_pView->GetEntryHeight())
        return nullptr;

    sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() );
    sal_uInt16 nTemp = nClickedEntry;
    SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
    return pEntry;
}


//  checks if the entry was hit "the right way"
//  (Focusrect+ ContextBitmap at TreeListBox)

bool SvImpLBox::EntryReallyHit(SvTreeListEntry* pEntry, const Point& rPosPixel, tools::Long nLine)
{
    bool bRet;
    // we are not too exact when it comes to "special" entries
    // (with CheckButtons etc.)
    if( pEntry->ItemCount() >= 3 )
        return true;

    tools::Rectangle aRect( m_pView->GetFocusRect( pEntry, nLine ));
    aRect.SetRight( GetOutputSize().Width() - m_pView->GetMapMode().GetOrigin().X() );

    SvLBoxContextBmp* pBmp = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
    aRect.AdjustLeft( -pBmp->GetWidth(m_pView,pEntry) );
    aRect.AdjustLeft( -4 ); // a little tolerance

    Point aPos( rPosPixel );
    aPos -= m_pView->GetMapMode().GetOrigin();
    bRet = aRect.Contains( aPos );
    return bRet;
}


// returns 0 if position is just past the last entry
SvTreeListEntry* SvImpLBox::GetEntry( const Point& rPoint ) const
{
    if( (m_pView->GetEntryCount() == 0) || !m_pStartEntry ||
        (rPoint.Y() > m_aOutputSize.Height())
        || !m_pView->GetEntryHeight())
        return nullptr;

    sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() );
    sal_uInt16 nTemp = nClickedEntry;
    SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
    if( nTemp != nClickedEntry )
        pEntry = nullptr;
    return pEntry;
}


SvTreeListEntry* SvImpLBox::MakePointVisible(const Point& rPoint)
{
    if( !m_pCursor )
        return nullptr;
    tools::Long nY = rPoint.Y();
    SvTreeListEntry* pEntry = nullptr;
    tools::Long nMax = m_aOutputSize.Height();
    if( nY < 0 || nY >= nMax ) // aOutputSize.Height() )
    {
        if( nY < 0 )
            pEntry = m_pView->PrevVisible(m_pCursor);
        else
            pEntry = m_pView->NextVisible(m_pCursor);

        if( pEntry && pEntry != m_pCursor )
            m_pView->SetEntryFocus( m_pCursor, false );

        if( nY < 0 )
            KeyUp( false );
        else
            KeyDown( false );
    }
    else
    {
        pEntry = GetClickedEntry( rPoint );
        if( !pEntry )
        {
            sal_uInt16 nSteps = 0xFFFF;
            // TODO: LastVisible is not yet implemented!
            pEntry = m_pView->NextVisible(m_pStartEntry, nSteps);
        }
        if( pEntry )
        {
            if( pEntry != m_pCursor &&
                 m_aSelEng.GetSelectionMode() == SelectionMode::Single
            )
                m_pView->Select( m_pCursor, false );
        }
    }
    return pEntry;
}

tools::Rectangle SvImpLBox::GetClipRegionRect() const
{
    Point aOrigin( m_pView->GetMapMode().GetOrigin() );
    aOrigin.setX( aOrigin.X() * -1 ); // conversion document coordinates
    tools::Rectangle aClipRect( aOrigin, m_aOutputSize );
    aClipRect.AdjustBottom( 1 );
    return aClipRect;
}


void SvImpLBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&&nbsp;rRect)
{
    if (!m_pView->GetVisibleCount())
        return;

    m_nFlags |= LBoxFlags::InPaint;

    if (m_nFlags & LBoxFlags::Filling)
    {
        SvTreeListEntry* pFirst = m_pView->First();
        if (pFirst != m_pStartEntry)
        {
            ShowCursor(false);
            m_pStartEntry = m_pView->First();
            m_aVerSBar->SetThumbPos( 0 );
            StopUserEvent();
            ShowCursor(true);
            m_nCurUserEvent = Application::PostUserEvent(LINK(this, SvImpLBox, MyUserEvent),
                                                       reinterpret_cast<void*>(1));
            return;
        }
    }

    if (!m_pStartEntry)
    {
        m_pStartEntry = m_pView->First();
    }

    if (m_nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID)
        SetNodeBmpTabDistance();

    tools::Long nRectHeight = rRect.GetHeight();
    tools::Long nEntryHeight = m_pView->GetEntryHeight();

    // calculate area for the entries we want to draw
    sal_uInt16 nStartLine = static_cast<sal_uInt16>(rRect.Top() / nEntryHeight);
    sal_uInt16 nCount = static_cast<sal_uInt16>(nRectHeight / nEntryHeight);
    nCount += 2; // don't miss a row

    tools::Long nY = nStartLine * nEntryHeight;
    SvTreeListEntry* pEntry = m_pStartEntry;
    while (nStartLine && pEntry)
    {
        pEntry = m_pView->NextVisible(pEntry);
        nStartLine--;
    }

    if (!m_pCursor && !mbNoAutoCurEntry)
    {
        // do not select if multiselection or explicit set
        bool bNotSelect = (m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) || ((m_nStyle & WB_NOINITIALSELECTION) == WB_NOINITIALSELECTION);
        SetCursor(m_pStartEntry, bNotSelect);
    }

    for(sal_uInt16 n=0; n< nCount && pEntry; n++)
    {
        /*long nMaxRight=*/
        m_pView->PaintEntry1(*pEntry, nY, rRenderContext );
        nY += nEntryHeight;
        pEntry = m_pView->NextVisible(pEntry);
    }

    if (m_nStyle & (WB_HASLINES | WB_HASLINESATROOT))
        DrawNet(rRenderContext);

    m_nFlags &= ~LBoxFlags::DeselectAll;
    m_nFlags &= ~LBoxFlags::InPaint;
}

void SvImpLBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop )
{
    if( !pEntry )
        return;

    bool bInView = IsEntryInView( pEntry );

    if( bInView && (!bMoveToTop || m_pStartEntry == pEntry) )
        return;  // is already visible

    if( m_pStartEntry || mbForceMakeVisible )
        m_nFlags &= ~LBoxFlags::Filling;
    if( !bInView )
    {
        if( !m_pView->IsEntryVisible(pEntry) )  // Parent(s) collapsed?
        {
            SvTreeListEntry* pParent = m_pView->GetParent( pEntry );
            while( pParent )
            {
                if( !m_pView->IsExpanded( pParent ) )
                {
                    bool bRet = m_pView->Expand( pParent );
                    DBG_ASSERT(bRet,"Not expanded!");
                }
                pParent = m_pView->GetParent( pParent );
            }
            // do the parent's children fit into the view or do we have to scroll?
            if( IsEntryInView( pEntry ) && !bMoveToTop )
                return;  // no need to scroll
        }
    }

    m_pStartEntry = pEntry;
    ShowCursor( false );
    FillView();
    m_aVerSBar->SetThumbPos( static_cast<tools::Long>(m_pView->GetVisiblePos( m_pStartEntry )) );
    ShowCursor( true );
    m_pView->NotifyScrolled();
    m_pView->Invalidate();
}

void SvImpLBox::ScrollToAbsPos( tools::Long nPos )
{
    if( m_pView->GetVisibleCount() == 0 )
        return;
    tools::Long nLastEntryPos = m_pView->GetAbsPos( m_pView->Last() );

    if( nPos < 0 )
        nPos = 0;
    else if( nPos > nLastEntryPos )
        nPos = nLastEntryPos;

    SvTreeListEntry* pEntry = m_pView->GetEntryAtAbsPos( nPos );
    if( !pEntry || pEntry == m_pStartEntry )
        return;

    if( m_pStartEntry || mbForceMakeVisible )
        m_nFlags &= ~LBoxFlags::Filling;

    if( m_pView->IsEntryVisible(pEntry) )
    {
        m_pStartEntry = pEntry;
        ShowCursor( false );
        m_aVerSBar->SetThumbPos( nPos );
        ShowCursor( true );
        if (GetUpdateMode())
            m_pView->Invalidate();
    }
}

void SvImpLBox::DrawNet(vcl::RenderContext& rRenderContext)
{
    if (m_pView->GetVisibleCount() < 2 && !m_pStartEntry->HasChildrenOnDemand() &&
        !m_pStartEntry->HasChildren())
    {
        return;
    }

    // for platforms that don't have nets, DrawNativeControl does nothing and returns true
    // so that SvImpLBox::DrawNet() doesn't draw anything either
    if (rRenderContext.IsNativeControlSupported(ControlType::ListNet, ControlPart::Entire))
    {
        ImplControlValue aControlValue;
        if (rRenderContext.DrawNativeControl(ControlType::ListNet, ControlPart::Entire,
                                             tools::Rectangle(), ControlState::ENABLED, aControlValue, OUString()))
        {
            return;
        }
    }

    tools::Long nEntryHeight = m_pView->GetEntryHeight();
    tools::Long nEntryHeightDIV2 = nEntryHeight / 2;
    if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001))
        nEntryHeightDIV2--;

    SvTreeListEntry* pChild;
    SvTreeListEntry* pEntry = m_pStartEntry;

    SvLBoxTab* pFirstDynamicTab = m_pView->GetFirstDynamicTab();
    while (m_pTree->GetDepth( pEntry ) > 0)
    {
        pEntry = m_pView->GetParent(pEntry);
    }
    sal_uInt16 nOffs = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pStartEntry) - m_pView->GetVisiblePos(pEntry));
    tools::Long nY = 0;
    nY -= (nOffs * nEntryHeight);

    DBG_ASSERT(pFirstDynamicTab,"No Tree!");

    rRenderContext.Push(vcl::PushFlags::LINECOLOR);

    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();

    // Set color to draw the vertical and horizontal lines
    rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());

    Point aPos1, aPos2;
    sal_uInt16 nDistance;
    sal_uLong nMax = m_nVisibleCount + nOffs + 1;

    const Image& rExpandedNodeBitmap = GetExpandedNodeBmp();

    for (sal_uLong n=0; n< nMax && pEntry; n++)
    {
        if (m_pView->IsExpanded(pEntry))
        {
            // draw vertical line
            aPos1.setX(m_pView->GetTabPos(pEntry, pFirstDynamicTab) + m_nNodeBmpTabDistance +
                       rExpandedNodeBitmap.GetSizePixel().Width() / 2);
            aPos1.setY(nY + nEntryHeight);
            pChild = m_pView->FirstChild(pEntry);
            assert(pChild && "Child?");
            pChild = pChild->LastSibling();
            nDistance = static_cast<sal_uInt16>(m_pView->GetVisiblePos(pChild) -
                                                m_pView->GetVisiblePos(pEntry));
            aPos2 = aPos1;
            aPos2.AdjustY((nDistance * nEntryHeight) - (nEntryHeightDIV2 + 2));
            rRenderContext.DrawLine(aPos1, aPos2);
        }
        // visible in control?
        if (n >= nOffs && !m_pTree->IsAtRootDepth(pEntry))
        {
            // draw horizontal line
            aPos1.setX(m_pView->GetTabPos(m_pView->GetParent(pEntry), pFirstDynamicTab)
                       + m_nNodeBmpTabDistance
                       + rExpandedNodeBitmap.GetSizePixel().Width() / 2);
            aPos1.setY(nY + nEntryHeightDIV2);
            aPos2 = aPos1;
            aPos2.AdjustX(m_pView->GetIndent() / 2);
            rRenderContext.DrawLine(aPos1, aPos2);
        }
        nY += nEntryHeight;
        pEntry = m_pView->NextVisible(pEntry);
    }

    rRenderContext.Pop();
}

void SvImpLBox::PositionScrollBars( Size& rSize, sal_uInt16 nMask )
{
    tools::Long nOverlap = 0;

    Size aVerSize( m_nVerSBarWidth, rSize.Height() );
    Size aHorSize( rSize.Width(), m_nHorSBarHeight );

    if( nMask & 0x0001 )
        aHorSize.AdjustWidth( -m_nVerSBarWidth );
    if( nMask & 0x0002 )
        aVerSize.AdjustHeight( -m_nHorSBarHeight );

    aVerSize.AdjustHeight(2 * nOverlap );
    Point aVerPos( rSize.Width() - aVerSize.Width() + nOverlap, -nOverlap );
    m_aVerSBar->SetPosSizePixel( aVerPos, aVerSize );

    aHorSize.AdjustWidth(2 * nOverlap );
    Point aHorPos( -nOverlap, rSize.Height() - aHorSize.Height() + nOverlap );

    m_aHorSBar->SetPosSizePixel( aHorPos, aHorSize );

    if( nMask & 0x0001 )
        rSize.setWidth( aVerPos.X() );
    if( nMask & 0x0002 )
        rSize.setHeight( aHorPos.Y() );

    if( (nMask & (0x0001|0x0002)) == (0x0001|0x0002) )
        m_aScrBarBox->Show();
    else
        m_aScrBarBox->Hide();
}

void SvImpLBox::AdjustScrollBars( Size& rSize )
{
    tools::Long nEntryHeight = m_pView->GetEntryHeight();
    if( !nEntryHeight )
        return;

    sal_uInt16 nResult = 0;

    Size aOSize( m_pView->Control::GetOutputSizePixel() );

    const WinBits nWindowStyle = m_pView->GetStyle();
    bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
    bool bHorBar = false;
    tools::Long nMaxRight = aOSize.Width(); //GetOutputSize().Width();
    Point aOrigin( m_pView->GetMapMode().GetOrigin() );
    aOrigin.setX( aOrigin.X() * -1 );
    nMaxRight += aOrigin.X() - 1;
    tools::Long nVis = m_nMostRight - aOrigin.X();
    if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) &&
        (nVis < m_nMostRight || nMaxRight < m_nMostRight) )
    {
        bHorBar = true;
    }

    // number of entries that are not collapsed
    sal_uLong nTotalCount = m_pView->GetVisibleCount();

    // number of entries visible within the view
    m_nVisibleCount = o3tl::make_unsigned(aOSize.Height() / nEntryHeight);

    // do we need a vertical scrollbar?
    if( bVerSBar || nTotalCount > m_nVisibleCount )
    {
        nResult = 1;
        nMaxRight -= m_nVerSBarWidth;
        if( !bHorBar )
        {
            if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) &&
                (nVis < m_nMostRight || nMaxRight < m_nMostRight) )
                bHorBar = true;
        }
    }

    // do we need a horizontal scrollbar?
    if( bHorBar )
    {
        nResult |= 0x0002;
        // the number of entries visible within the view has to be recalculated
        // because the horizontal scrollbar is now visible.
        m_nVisibleCount = o3tl::make_unsigned(std::max<tools::Long>(0, aOSize.Height() - m_nHorSBarHeight) / nEntryHeight);
        // we might actually need a vertical scrollbar now
        if( !(nResult & 0x0001) &&
            ((nTotalCount > m_nVisibleCount) || bVerSBar) )
        {
            nResult = 3;
        }
    }

    PositionScrollBars( aOSize, nResult );

    // adapt Range, VisibleRange etc.

    // refresh output size, in case we have to scroll
    tools::Rectangle aRect;
    aRect.SetSize( aOSize );
    m_aSelEng.SetVisibleArea( aRect );

    // vertical scrollbar
    tools::Long nTemp = static_cast<tools::Long>(m_nVisibleCount);
    nTemp--;
    if( nTemp != m_aVerSBar->GetVisibleSize() )
    {
        if( !m_bInVScrollHdl )
        {
            m_aVerSBar->SetPageSize( nTemp - 1 );
            m_aVerSBar->SetVisibleSize( nTemp );
        }
        else
        {
            m_nFlags |= LBoxFlags::EndScrollSetVisSize;
            m_nNextVerVisSize = nTemp;
        }
    }

    // horizontal scrollbar
    nTemp = m_aHorSBar->GetThumbPos();
    m_aHorSBar->SetVisibleSize( aOSize.Width() );
    tools::Long nNewThumbPos = m_aHorSBar->GetThumbPos();
    Range aRange( m_aHorSBar->GetRange() );
    if( aRange.Max() < m_nMostRight+25 )
    {
        aRange.Max() = m_nMostRight+25;
        m_aHorSBar->SetRange( aRange );
    }

    if( nTemp != nNewThumbPos )
    {
        nTemp = nNewThumbPos - nTemp;
        if( m_pView->IsEditingActive() )
        {
            m_pView->EndEditing( true ); // Cancel
            m_pView->PaintImmediately();
        }
        m_pView->nFocusWidth = -1;
        KeyLeftRight( nTemp );
    }

    if( nResult & 0x0001 )
        m_aVerSBar->Show();
    else
        m_aVerSBar->Hide();

    if( nResult & 0x0002 )
        m_aHorSBar->Show();
    else
    {
        m_aHorSBar->Hide();
    }
    rSize = aOSize;
}

void SvImpLBox::InitScrollBarBox()
{
    m_aScrBarBox->SetSizePixel( Size(m_nVerSBarWidth, m_nHorSBarHeight) );
    Size aSize( m_pView->Control::GetOutputSizePixel() );
    m_aScrBarBox->SetPosPixel( Point(aSize.Width()-m_nVerSBarWidth, aSize.Height()-m_nHorSBarHeight));
}

void SvImpLBox::Resize()
{
    m_aOutputSize = m_pView->Control::GetOutputSizePixel();
    if( m_aOutputSize.IsEmpty() )
        return;
    m_nFlags |= LBoxFlags::InResize;
    InitScrollBarBox();

    if( m_pView->GetEntryHeight())
    {
        AdjustScrollBars( m_aOutputSize );
        UpdateAll();
    }
    // HACK, as in floating and docked windows the scrollbars might not be drawn
    // correctly/not be drawn at all after resizing!
    if( m_aHorSBar->IsVisible())
        m_aHorSBar->Invalidate();
    if( m_aVerSBar->IsVisible())
        m_aVerSBar->Invalidate();
    m_nFlags &= ~LBoxFlags::InResize;
}

void SvImpLBox::FillView()
{
    if( !m_pStartEntry )
    {
        sal_uLong nVisibleViewCount = m_pView->GetVisibleCount();
        tools::Long nTempThumb = m_aVerSBar->GetThumbPos();
        if( nTempThumb < 0 )
            nTempThumb = 0;
        else if( o3tl::make_unsigned(nTempThumb) >= nVisibleViewCount )
            nTempThumb = nVisibleViewCount == 0 ? 0 : nVisibleViewCount - 1;
        m_pStartEntry = m_pView->GetEntryAtVisPos(nTempThumb);
    }
    if( !m_pStartEntry )
        return;

    sal_uInt16 nLast = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pView->LastVisible()));
    sal_uInt16 nThumb = static_cast<sal_uInt16>(m_pView->GetVisiblePos( m_pStartEntry ));
    sal_uLong nCurDispEntries = nLast-nThumb+1;
    if( nCurDispEntries >=  m_nVisibleCount )
        return;

    ShowCursor( false );
    // fill window by moving the thumb up incrementally
    bool bFound = false;
    SvTreeListEntry* pTemp = m_pStartEntry;
    while( nCurDispEntries < m_nVisibleCount && pTemp )
    {
        pTemp = m_pView->PrevVisible(m_pStartEntry);
        if( pTemp )
        {
            nThumb--;
            m_pStartEntry = pTemp;
            nCurDispEntries++;
            bFound = true;
        }
    }
    if( bFound )
    {
        m_aVerSBar->SetThumbPos( nThumb );
        ShowCursor( true ); // recalculate focus rectangle
        m_pView->Invalidate();
    }
}


void SvImpLBox::ShowVerSBar()
{
    bool bVerBar = ( m_pView->GetStyle() & WB_VSCROLL ) != 0;
    sal_uLong nVis = 0;
    if( !bVerBar )
        nVis = m_pView->GetVisibleCount();
    if( bVerBar || (m_nVisibleCount && nVis > static_cast<sal_uLong>(m_nVisibleCount-1)) )
    {
        if( !m_aVerSBar->IsVisible() )
        {
            m_pView->nFocusWidth = -1;
            AdjustScrollBars( m_aOutputSize );
            if( GetUpdateMode() )
                m_aVerSBar->Invalidate();
        }
    }
    else
    {
        if( m_aVerSBar->IsVisible() )
        {
            m_pView->nFocusWidth = -1;
            AdjustScrollBars( m_aOutputSize );
        }
    }

    tools::Long nMaxRight = GetOutputSize().Width();
    Point aPos( m_pView->GetMapMode().GetOrigin() );
    aPos.setX( aPos.X() * -1 ); // convert document coordinates
    nMaxRight = nMaxRight + aPos.X() - 1;
    if( nMaxRight < m_nMostRight  )
    {
        if( !m_aHorSBar->IsVisible() )
        {
            m_pView->nFocusWidth = -1;
            AdjustScrollBars( m_aOutputSize );
            if( GetUpdateMode() )
                m_aHorSBar->Invalidate();
        }
        else
        {
            Range aRange( m_aHorSBar->GetRange() );
            if( aRange.Max() < m_nMostRight+25 )
            {
                aRange.Max() = m_nMostRight+25;
                m_aHorSBar->SetRange( aRange );
            }
            else
            {
                m_pView->nFocusWidth = -1;
                AdjustScrollBars( m_aOutputSize );
            }
        }
    }
    else
    {
        if( m_aHorSBar->IsVisible() )
        {
            m_pView->nFocusWidth = -1;
            AdjustScrollBars( m_aOutputSize );
        }
    }
}


void SvImpLBox::SyncVerThumb()
{
    if( m_pStartEntry )
    {
        tools::Long nEntryPos = m_pView->GetVisiblePos( m_pStartEntry );
        m_aVerSBar->SetThumbPos( nEntryPos );
    }
    else
        m_aVerSBar->SetThumbPos( 0 );
}

bool SvImpLBox::IsEntryInView( SvTreeListEntry* pEntry ) const
{
    // parent collapsed
    if( !m_pView->IsEntryVisible(pEntry) )
        return false;
    tools::Long nY = GetEntryLine( pEntry );
    if( nY < 0 )
        return false;
    tools::Long nMax = m_nVisibleCount * m_pView->GetEntryHeight();
    return nY < nMax;
}


tools::Long SvImpLBox::GetEntryLine(const SvTreeListEntry* pEntry) const
{
    if(!m_pStartEntry )
        return -1; // invisible position

    tools::Long nFirstVisPos = m_pView->GetVisiblePos( m_pStartEntry );
    tools::Long nEntryVisPos = m_pView->GetVisiblePos( pEntry );
    nFirstVisPos = nEntryVisPos - nFirstVisPos;
    nFirstVisPos *= m_pView->GetEntryHeight();
    return nFirstVisPos;
}

void SvImpLBox::SetEntryHeight()
{
    SetNodeBmpWidth( GetExpandedNodeBmp() );
    SetNodeBmpWidth( GetCollapsedNodeBmp() );
    if(!m_pView->HasViewData()) // are we within the Clear?
    {
        Size aSize = m_pView->Control::GetOutputSizePixel();
        AdjustScrollBars( aSize );
    }
    else
    {
        Resize();
        if( GetUpdateMode() )
            m_pView->Invalidate();
    }
}


// ***********************************************************************
// Callback Functions
// ***********************************************************************

void SvImpLBox::EntryExpanded( SvTreeListEntry* pEntry )
{
    // SelAllDestrAnch( false, true ); //DeselectAll();
    if( !GetUpdateMode() )
        return;

    ShowCursor( false );
    tools::Long nY = GetEntryLine( pEntry );
    if( IsLineVisible(nY) )
    {
        InvalidateEntriesFrom( nY );
        FindMostRight( pEntry );
    }
    m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) );
    // if we expanded before the thumb, the thumb's position has to be
    // corrected
    SyncVerThumb();
    ShowVerSBar();
    ShowCursor( true );
}

void SvImpLBox::EntryCollapsed( SvTreeListEntry* pEntry )
{
    if( !m_pView->IsEntryVisible( pEntry ) )
        return;

    ShowCursor( false );

    if( !m_pMostRightEntry || m_pTree->IsChild( pEntry,m_pMostRightEntry ) )
    {
        FindMostRight();
    }

    if( m_pStartEntry )
    {
        tools::Long nOldThumbPos   = m_aVerSBar->GetThumbPos();
        sal_uLong nVisList      = m_pView->GetVisibleCount();
        m_aVerSBar->SetRange( Range(0, nVisList-1) );
        tools::Long nNewThumbPos   = m_aVerSBar->GetThumbPos();
        if( nNewThumbPos != nOldThumbPos  )
        {
            m_pStartEntry = m_pView->First();
            sal_uInt16 nDistance = static_cast<sal_uInt16>(nNewThumbPos);
            if( nDistance )
                m_pStartEntry = m_pView->NextVisible(m_pStartEntry, nDistance);
            if( GetUpdateMode() )
                m_pView->Invalidate();
        }
        else
            SyncVerThumb();
        ShowVerSBar();
    }
    // has the cursor been collapsed?
    if( m_pTree->IsChild( pEntry, m_pCursor ) )
        SetCursor( pEntry );
    if( GetUpdateMode() )
        ShowVerSBar();
    ShowCursor( true );
    if( GetUpdateMode() && m_pCursor )
        m_pView->Select( m_pCursor );
}

void SvImpLBox::CollapsingEntry( SvTreeListEntry* pEntry )
{
    if( !m_pView->IsEntryVisible( pEntry ) || !m_pStartEntry )
        return;

    SelAllDestrAnch( false ); // deselect all

    // is the collapsed cursor visible?
    tools::Long nY = GetEntryLine( pEntry );
    if( IsLineVisible(nY) )
    {
        if( GetUpdateMode() )
            InvalidateEntriesFrom( nY );
    }
    else
    {
        if( m_pTree->IsChild(pEntry, m_pStartEntry) )
        {
            m_pStartEntry = pEntry;
            if( GetUpdateMode() )
                m_pView->Invalidate();
        }
    }
}


void SvImpLBox::SetNodeBmpWidth( const Image& rBmp )
{
    const Size aSize( rBmp.GetSizePixel() );
    m_nNodeBmpWidth = aSize.Width();
}

void SvImpLBox::SetNodeBmpTabDistance()
{
    m_nNodeBmpTabDistance = -m_pView->GetIndent();
    if( m_pView->nContextBmpWidthMax )
    {
        // only if the first dynamic tab is centered (we currently assume that)
        Size aSize = GetExpandedNodeBmp().GetSizePixel();
        m_nNodeBmpTabDistance -= aSize.Width() / 2;
    }
}


// corrects the cursor when using SingleSelection

void SvImpLBox::EntrySelected( SvTreeListEntry* pEntry, bool bSelect )
{
    if( m_nFlags & LBoxFlags::IgnoreSelect )
        return;

    m_nFlags &= ~LBoxFlags::DeselectAll;
    if( bSelect &&
        m_aSelEng.GetSelectionMode() == SelectionMode::Single &&
        pEntry != m_pCursor )
    {
        SetCursor( pEntry );
        DBG_ASSERT(m_pView->GetSelectionCount()==1,"selection count?");
    }

    if( GetUpdateMode() && m_pView->IsEntryVisible(pEntry) )
    {
        tools::Long nY = GetEntryLine( pEntry );
        if( IsLineVisible( nY ) )
        {
            ShowCursor(false);
            InvalidateEntry(pEntry);
            ShowCursor(true);
        }
    }
}


void SvImpLBox::RemovingEntry( SvTreeListEntry* pEntry )
{
    CallEventListeners( VclEventId::ListboxItemRemoved , pEntry );

    DestroyAnchor();

    if( !m_pView->IsEntryVisible( pEntry ) )
    {
        // if parent is collapsed => bye!
        m_nFlags |= LBoxFlags::RemovedEntryInvisible;
        return;
    }

    if( pEntry == m_pMostRightEntry || (
        pEntry->HasChildren() && m_pView->IsExpanded(pEntry) &&
        m_pTree->IsChild(pEntry, m_pMostRightEntry)))
    {
        m_nFlags |= LBoxFlags::RemovedRecalcMostRight;
    }

    SvTreeListEntry* pOldStartEntry = m_pStartEntry;

    SvTreeListEntry* pParent = m_pView->GetModel()->GetParent(pEntry);

    if (pParent && m_pView->GetModel()->GetChildList(pParent).size() == 1)
    {
        DBG_ASSERT( m_pView->IsExpanded( pParent ), "Parent not expanded");
        pParent->SetFlags( pParent->GetFlags() | SvTLEntryFlags::NO_NODEBMP);
        InvalidateEntry( pParent );
    }

    if( m_pCursor && m_pTree->IsChild( pEntry, m_pCursor) )
        m_pCursor = pEntry;
    if( m_pStartEntry && m_pTree->IsChild(pEntry,m_pStartEntry) )
        m_pStartEntry = pEntry;

    SvTreeListEntry* pTemp;
    if( m_pCursor && m_pCursor == pEntry )
    {
        if( m_bSimpleTravel )
            m_pView->Select( m_pCursor, false );
        ShowCursor( false );    // focus rectangle gone
        // NextSibling, because we also delete the children of the cursor
        pTemp = m_pCursor->NextSibling();
        if( !pTemp )
            pTemp = m_pView->PrevVisible(m_pCursor);

        SetCursor( pTemp, true );
    }
    if( m_pStartEntry && m_pStartEntry == pEntry )
    {
        pTemp = m_pStartEntry->NextSibling();
        if( !pTemp )
            pTemp = m_pView->PrevVisible(m_pStartEntry);
        m_pStartEntry = pTemp;
    }
    if( GetUpdateMode())
    {
        // if it is the last one, we have to invalidate it, so the lines are
        // drawn correctly (in this case they're deleted)
        if( m_pStartEntry && (m_pStartEntry != pOldStartEntry || pEntry == m_pView->GetModel()->Last()) )
        {
            m_aVerSBar->SetThumbPos( m_pView->GetVisiblePos( m_pStartEntry ));
            m_pView->Invalidate( GetVisibleArea() );
        }
        else
            InvalidateEntriesFrom( GetEntryLine( pEntry ) );
    }
}

void SvImpLBox::EntryRemoved()
{
    if( m_nFlags & LBoxFlags::RemovedEntryInvisible )
    {
        m_nFlags &= ~LBoxFlags::RemovedEntryInvisible;
        return;
    }
    if( !m_pStartEntry )
        m_pStartEntry = m_pTree->First();
    if( !m_pCursor )
        SetCursor( m_pStartEntry, true );

    if( m_pCursor && (m_bSimpleTravel || !m_pView->GetSelectionCount() ))
        m_pView->Select( m_pCursor );

    if( GetUpdateMode())
    {
        if( m_nFlags & LBoxFlags::RemovedRecalcMostRight )
            FindMostRight();
        m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) );
        FillView();
        if( m_pStartEntry )
            // if something above the thumb was deleted
            m_aVerSBar->SetThumbPos( m_pView->GetVisiblePos( m_pStartEntry) );

        ShowVerSBar();
        if( m_pCursor && m_pView->HasFocus() && !m_pView->IsSelected(m_pCursor) )
        {
            if( m_pView->GetSelectionCount() )
            {
                // is a neighboring entry selected?
                SvTreeListEntry* pNextCursor = m_pView->PrevVisible( m_pCursor );
                if( !pNextCursor || !m_pView->IsSelected( pNextCursor ))
                    pNextCursor = m_pView->NextVisible( m_pCursor );
                if( !pNextCursor || !m_pView->IsSelected( pNextCursor ))
                    // no neighbor selected: use first selected
                    pNextCursor = m_pView->FirstSelected();
                SetCursor( pNextCursor );
                MakeVisible( m_pCursor );
            }
            else
                m_pView->Select( m_pCursor );
        }
        ShowCursor( true );
    }
    m_nFlags &= ~LBoxFlags::RemovedRecalcMostRight;
}


void SvImpLBox::MovingEntry( SvTreeListEntry* pEntry )
{
    bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll);
    SelAllDestrAnch( false );  // DeselectAll();
    if( !bDeselAll )
        m_nFlags &= ~LBoxFlags::DeselectAll;

    if( pEntry == m_pCursor )
        ShowCursor( false );
    if( IsEntryInView( pEntry ) )
        m_pView->Invalidate();
    if( pEntry != m_pStartEntry )
        return;

    SvTreeListEntry* pNew = nullptr;
    if( !pEntry->HasChildren() )
    {
        pNew = m_pView->NextVisible(m_pStartEntry);
        if( !pNew )
            pNew = m_pView->PrevVisible(m_pStartEntry);
    }
    else
    {
        pNew = pEntry->NextSibling();
        if( !pNew )
            pNew = pEntry->PrevSibling();
    }
    m_pStartEntry = pNew;
}

void SvImpLBox::EntryMoved( SvTreeListEntry* pEntry )
{
    UpdateContextBmpWidthVectorFromMovedEntry( pEntry );

    if ( !m_pStartEntry )
        // this might happen if the only entry in the view is moved to its very same position
        // #i97346#
        m_pStartEntry = m_pView->First();

    m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1));
    sal_uInt16 nFirstPos = static_cast<sal_uInt16>(m_pTree->GetAbsPos( m_pStartEntry ));
    sal_uInt16 nNewPos = static_cast<sal_uInt16>(m_pTree->GetAbsPos( pEntry ));
    FindMostRight();
    if( nNewPos < nFirstPos ) // HACK!
        m_pStartEntry = pEntry;
    SyncVerThumb();
    if( pEntry == m_pCursor )
    {
        if( m_pView->IsEntryVisible( m_pCursor ) )
            ShowCursor( true );
        else
        {
            SvTreeListEntry* pParent = pEntry;
            do {
                pParent = m_pTree->GetParent( pParent );
            }
            while( !m_pView->IsEntryVisible( pParent ) );
            SetCursor( pParent );
        }
    }
    if( IsEntryInView( pEntry ) )
        m_pView->Invalidate();
}


void SvImpLBox::EntryInserted( SvTreeListEntry* pEntry )
{
    if( !GetUpdateMode() )
        return;

    SvTreeListEntry* pParent = m_pTree->GetParent(pEntry);
    if (pParent && m_pTree->GetChildList(pParent).size() == 1)
        // draw plus sign
        m_pTree->InvalidateEntry( pParent );

    if( !m_pView->IsEntryVisible( pEntry ) )
        return;
    bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll);
    if( bDeselAll )
        SelAllDestrAnch( false );
    else
        DestroyAnchor();
    //  nFlags &= (~LBoxFlags::DeselectAll);
//      ShowCursor( false ); // if cursor is moved lower
    tools::Long nY = GetEntryLine( pEntry );
    bool bEntryVisible = IsLineVisible( nY );
    if( bEntryVisible )
    {
        ShowCursor( false ); // if cursor is moved lower
        nY -= m_pView->GetEntryHeight(); // because of lines
        InvalidateEntriesFrom( nY );
    }
    else if( m_pStartEntry && nY < GetEntryLine(m_pStartEntry) )
    {
        // Check if the view is filled completely. If not, then adjust
        // pStartEntry and the Cursor (automatic scrolling).
        sal_uInt16 nLast = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pView->LastVisible()));
        sal_uInt16 nThumb = static_cast<sal_uInt16>(m_pView->GetVisiblePos( m_pStartEntry ));
        sal_uInt16 nCurDispEntries = nLast-nThumb+1;
        if( nCurDispEntries < m_nVisibleCount )
        {
            // set at the next paint event
            m_pStartEntry = nullptr;
            SetCursor( nullptr );
            m_pView->Invalidate();
        }
    }
    else if( !m_pStartEntry )
        m_pView->Invalidate();

    SetMostRight( pEntry );
    m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1));
    SyncVerThumb(); // if something was inserted before the thumb
    ShowVerSBar();
    ShowCursor( true );
    if( m_pStartEntry != m_pView->First() && (m_nFlags & LBoxFlags::Filling) )
        m_pView->PaintImmediately();
}


// ********************************************************************
// Event handler
// ********************************************************************


// ****** Control the control animation

bool SvImpLBox::ButtonDownCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry* pEntry)
{
    SvLBoxItem* pItem = m_pView->GetItem(pEntry,rMEvt.GetPosPixel().X(),&m_pActiveTab);
    if (pItem && pItem->GetType() == SvLBoxItemType::Button)
    {
        m_pActiveButton = static_cast<SvLBoxButton*>(pItem);
        m_pActiveEntry = pEntry;
        if( m_pCursor == m_pActiveEntry )
            m_pView->HideFocus();
        m_pView->CaptureMouse();
        m_pActiveButton->SetStateHilighted( true );
        InvalidateEntry(m_pActiveEntry);
        return true;
    }
    else
        m_pActiveButton = nullptr;
    return false;
}

bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry const * pEntry)
{
    if( m_pActiveButton )
    {
        tools::Long nMouseX = rMEvt.GetPosPixel().X();
        if( pEntry == m_pActiveEntry &&
             m_pView->GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton )
        {
            if( !m_pActiveButton->IsStateHilighted() )
            {
                m_pActiveButton->SetStateHilighted(true );
                InvalidateEntry(m_pActiveEntry);
            }
        }
        else
        {
            if( m_pActiveButton->IsStateHilighted() )
            {
                m_pActiveButton->SetStateHilighted(false );
                InvalidateEntry(m_pActiveEntry);
            }
        }
        return true;
    }
    return false;
}

bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt )
{
    if( m_pActiveButton && m_pActiveButton->isEnable())
    {
        m_pView->ReleaseMouse();
        SvTreeListEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() );
        m_pActiveButton->SetStateHilighted( false );
        tools::Long nMouseX = rMEvt.GetPosPixel().X();
        if (pEntry == m_pActiveEntry && m_pView->GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton)
        {
            const bool bChecked = m_pActiveButton->IsStateChecked();
            m_pActiveButton->ClickHdl(m_pActiveEntry);
            if (m_pActiveButton->IsStateChecked() != bChecked)
                CallEventListeners(VclEventId::CheckboxToggle, m_pActiveEntry);
        }
        InvalidateEntry(m_pActiveEntry);
        if (m_pCursor == m_pActiveEntry)
            ShowCursor(true);
        m_pActiveButton = nullptr;
        m_pActiveEntry = nullptr;
        m_pActiveTab = nullptr;
        return true;
    }
    return false;
}

// ******* Control plus/minus button for expanding/collapsing

// false == no expand/collapse button hit
bool SvImpLBox::IsNodeButton( const Point& rPosPixel, const SvTreeListEntry* pEntry const
{
    if( !pEntry->HasChildren() && !pEntry->HasChildrenOnDemand() )
        return false;

    SvLBoxTab* pFirstDynamicTab = m_pView->GetFirstDynamicTab();
    if( !pFirstDynamicTab )
        return false;

    tools::Long nMouseX = rPosPixel.X();
    // convert to document coordinates
    Point aOrigin( m_pView->GetMapMode().GetOrigin() );
    nMouseX -= aOrigin.X();

    tools::Long nX = m_pView->GetTabPos( pEntry, pFirstDynamicTab);
    nX += m_nNodeBmpTabDistance;
    if( nMouseX < nX )
        return false;
    nX += m_nNodeBmpWidth;
    return nMouseX <= nX;
}

// false == hit no node button
bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, SvTreeListEntry* pEntry )
{
    bool bRet = false;

    if ( m_pView->IsEditingActive() && pEntry == m_pView->pEdEntry )
        // inplace editing -> nothing to do
        bRet = true;
    else if ( IsNodeButton( rMEvt.GetPosPixel(), pEntry ) )
    {
        if ( m_pView->IsExpanded( pEntry ) )
        {
            m_pView->EndEditing( true );
            m_pView->Collapse( pEntry );
        }
        else
        {
            // you can expand an entry, which is in editing
            m_pView->Expand( pEntry );
        }
        bRet = true;
    }

    return bRet;
}

void SvImpLBox::MouseButtonDown( const MouseEvent& rMEvt )
{
    if ( !rMEvt.IsLeft() && !rMEvt.IsRight())
        return;

    m_aEditIdle.Stop();
    Point aPos( rMEvt.GetPosPixel());

    if( aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height() )
        return;

    if( !m_pCursor )
        m_pCursor = m_pStartEntry;
    m_nFlags &= ~LBoxFlags::Filling;
    m_pView->GrabFocus();
    //fdo#82270 Grabbing focus can invalidate the entries, re-fetch
    SvTreeListEntry* pEntry = GetEntry(aPos);
    // the entry can still be invalid!
    if( !pEntry || !m_pView->GetViewData( pEntry ))
    {
        if (!rMEvt.GetModifier() && rMEvt.IsLeft())
            SelAllDestrAnch(false); // deselect all
        return;
    }

    tools::Long nY = GetEntryLine( pEntry );
    // Node-Button?
    if( ButtonDownCheckExpand( rMEvt, pEntry ) )
        return;

    if( !EntryReallyHit(pEntry,aPos,nY))
        return;

    SvLBoxItem* pXItem = m_pView->GetItem( pEntry, aPos.X() );
    if( pXItem )
    {
        SvLBoxTab* pXTab = m_pView->GetTab( pEntry, pXItem );
        if ( !rMEvt.IsMod1() && !rMEvt.IsMod2() && rMEvt.IsLeft() && pXTab->IsEditable()
            && pEntry == m_pView->FirstSelected() && nullptr == m_pView->NextSelected( pEntry ) )
                // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected
            m_nFlags |= LBoxFlags::StartEditTimer;
        if ( !m_pView->IsSelected( pEntry ) )
            m_nFlags &= ~LBoxFlags::StartEditTimer;
    }


    if( (rMEvt.GetClicks() % 2) == 0)
    {
        m_nFlags &= ~LBoxFlags::StartEditTimer;
        m_pView->pHdlEntry = pEntry;
        if( !m_pView->DoubleClickHdl() )
        {
            // Handler signals nothing to be done anymore, bail out, 'this' may
            // even be dead and destroyed.
            return;
        }
        else
        {
            // if the entry was deleted within the handler
            pEntry = GetClickedEntry( aPos );
            if( !pEntry )
                return;
            if( pEntry != m_pView->pHdlEntry )
            {
                // select anew & bye
                if( !m_bSimpleTravel && !m_aSelEng.IsAlwaysAdding())
                    SelAllDestrAnch( false ); // DeselectAll();
                SetCursor( pEntry );

                return;
            }
            if( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() )
            {
                if( m_pView->IsExpanded(pEntry) )
                    m_pView->Collapse( pEntry );
                else
                    m_pView->Expand( pEntry );
                if( pEntry == m_pCursor )  // only if Entryitem was clicked
                                          // (Nodebutton is not an Entryitem!)
                    m_pView->Select( m_pCursor );
                return;
            }
        }
    }
    else
    {
        // CheckButton? (TreeListBox: Check + Info)
        if( ButtonDownCheckCtrl(rMEvt, pEntry) )
            return;
        // Inplace-Editing?
    }
    if ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE
         && !rMEvt.IsRight() ) // tdf#128824
        m_aSelEng.SelMouseButtonDown( rMEvt );
}

void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt)
{
    if ( !ButtonUpCheckCtrl( rMEvt ) && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
        m_aSelEng.SelMouseButtonUp( rMEvt );
    if( m_nFlags & LBoxFlags::StartEditTimer )
    {
        m_nFlags &= ~LBoxFlags::StartEditTimer;
        m_aEditClickPos = rMEvt.GetPosPixel();
        m_aEditIdle.Start();
    }

    if (m_pView->mbActivateOnSingleClick)
    {
        Point aPos(rMEvt.GetPosPixel());
        SvTreeListEntry* pEntry = GetEntry(aPos);
        // tdf#143245 ActivateOnSingleClick only
        // if the 'up' is at the active entry
        // typically selected by the 'down'
        if (!pEntry || pEntry != m_pCursor)
            return;
        m_pView->DoubleClickHdl();
    }
}

void SvImpLBox::MouseMove( const MouseEvent& rMEvt)
{
    Point aPos = rMEvt.GetPosPixel();
    SvTreeListEntry* pEntry = GetClickedEntry(aPos);
    if ( MouseMoveCheckCtrl( rMEvt, pEntry ) || ( m_aSelEng.GetSelectionMode() == SelectionMode::NONE ) )
        return;

    m_aSelEng.SelMouseMove(rMEvt);
    if (m_pView->mbHoverSelection)
    {
        if (aPos.X() < 0 || aPos.Y() < 0 || aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height())
            pEntry = nullptr;
        else
            pEntry = GetEntry(aPos);
        if (!pEntry)
            m_pView->SelectAll(false);
        else if (!m_pView->IsSelected(pEntry) && IsSelectable(pEntry))
        {
            m_pView->mbSelectingByHover = true;
            m_pView->Select(pEntry);
            m_pView->mbSelectingByHover = false;
        }
    }
}

void SvImpLBox::ExpandAll()
{
    sal_uInt16 nRefDepth = m_pTree->GetDepth(m_pCursor);
    SvTreeListEntry* pCur = m_pTree->Next(m_pCursor);
    while (pCur && m_pTree->GetDepth(pCur) > nRefDepth)
    {
        if (pCur->HasChildren() && !m_pView->IsExpanded(pCur))
            m_pView->Expand(pCur);
        pCur = m_pTree->Next(pCur);
    }
}

void SvImpLBox::CollapseTo(SvTreeListEntry* pParentToCollapse)
{
    // collapse all parents until we get to the given parent to collapse
    if (!pParentToCollapse)
        return;

    sal_uInt16 nRefDepth;
    // special case explorer: if the root only has a single
    // entry, don't collapse the root entry
    if (m_pTree->GetChildList(nullptr).size() < 2)
    {
        nRefDepth = 1;
        pParentToCollapse = m_pCursor;
        while (m_pTree->GetParent(pParentToCollapse)
               && m_pTree->GetDepth(m_pTree->GetParent(pParentToCollapse)) > 0)
        {
            pParentToCollapse = m_pTree->GetParent(pParentToCollapse);
        }
    }
    else
        nRefDepth = m_pTree->GetDepth(pParentToCollapse);

    if (m_pView->IsExpanded(pParentToCollapse))
        m_pView->Collapse(pParentToCollapse);
    SvTreeListEntry* pCur = m_pTree->Next(pParentToCollapse);
    while (pCur && m_pTree->GetDepth(pCur) > nRefDepth)
    {
        if (pCur->HasChildren() && m_pView->IsExpanded(pCur))
            m_pView->Collapse(pCur);
        pCur = m_pTree->Next(pCur);
    }
}

bool SvImpLBox::KeyInput( const KeyEvent& rKEvt)
{
    m_aEditIdle.Stop();
    const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();

    if( rKeyCode.IsMod2() )
        return false// don't evaluate Alt key

    m_nFlags &= ~LBoxFlags::Filling;

    if( !m_pCursor )
        m_pCursor = m_pStartEntry;
    if( !m_pCursor )
        return false;

    bool bKeyUsed = true;

    sal_uInt16  nDelta = static_cast<sal_uInt16>(m_aVerSBar->GetPageSize());
    sal_uInt16  aCode = rKeyCode.GetCode();

    bool    bShift = rKeyCode.IsShift();
    bool    bMod1 = rKeyCode.IsMod1();

    SvTreeListEntry* pNewCursor;

    switch( aCode )
    {
        case KEY_UP:
            if( !IsEntryInView( m_pCursor ) )
                MakeVisible( m_pCursor );

            pNewCursor = m_pCursor;
            do
            {
                pNewCursor = m_pView->PrevVisible(pNewCursor);
--> --------------------

--> maximum size reached

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

Messung V0.5
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© 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.