    /* -*- 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 <vcl/svapp.hxx>
    #include <vcl/salnativewidgets.hxx>
    #include <vcl/help.hxx>
    #include <vcl/settings.hxx>

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

    #include <svtools/treelistbox.hxx>
    #include <svtools/iconview.hxx>
    #include <svtools/svlbitm.hxx>
    #include <svimpbox.hxx>
    #include <iconviewimpl.hxx>
    #include <rtl/instance.hxx>
    #include <tools/wintypes.hxx>
    #include <bitmaps.hlst>
    #include <comphelper/processfactory.hxx>
    #include <comphelper/string.hxx>

    #include <svtools/treelistentry.hxx>
    #include <svtools/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)
        : aHorSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_HSCROLL))
        , aScrBarBox(VclPtr<ScrollBarBox>::Create(pLBView))
        , aFctSet(this, pLBView)
        , bAreChildrenTransient(true)
        , mbForceMakeVisible (false)
        , aVerSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_VSCROLL))
        , aOutputSize(0, 0)
        , mbNoAutoCurEntry(false)
        , aSelEng(pLBView, nullptr)
        , nNextVerVisSize(0)
    {
        osl_atomic_increment(&s_nImageRefCount);
        pView = pLBView;
        pTree = pLBTree;
        aSelEng.SetFunctionSet( static_cast<FunctionSet*>(&aFctSet) );
        aSelEng.ExpandSelectionOnMouseMove( false );
        SetStyle( nWinStyle );
        SetSelectionMode( SelectionMode::Single );
        SetDragDropMode( DragDropMode::NONE );

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

        nHorSBarHeight = static_cast<short>(aHorSBar->GetSizePixel().Height());
        nVerSBarWidth = static_cast<short>(aVerSBar->GetSizePixel().Width());

        pStartEntry = nullptr;
        pCursor             = nullptr;
        pAnchor             = nullptr;
        nVisibleCount       = 0;    // number of rows of data in control
        nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID;
        nNodeBmpWidth       = 0;

        bAsyncBeginDrag     = false;
        aAsyncBeginDragIdle.SetPriority( TaskPriority::HIGHEST );
        aAsyncBeginDragIdle.SetInvokeHandler( LINK(this,SvImpLBox,BeginDragHdl));
        // button animation in listbox
        pActiveButton = nullptr;
        pActiveEntry = nullptr;
        pActiveTab = nullptr;

        nFlags = LBoxFlags::NONE;
        nCurTabPos = FIRST_ENTRY_TAB;

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

        nMostRight = -1;
        pMostRightEntry = nullptr;
        nCurUserEvent = nullptr;

        bUpdateMode = true;
        bInVScrollHdl = false;
        nFlags |= LBoxFlags::Filling;

        bSubLstOpRet = bSubLstOpLR = bContextMenuHandling = bIsCellFocusEnabled = false;
        bSubLstOpDblClick = true;
    }

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

        if ( osl_atomic_decrement(&s_nImageRefCount) == 0 )
        {
            DELETEZ(s_pDefCollapsed);
            DELETEZ(s_pDefExpanded);
        }
        aVerSBar.disposeAndClear();
        aHorSBar.disposeAndClear();
        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( pView->pModel, "View and Model aren't valid!" );

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

    void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry* pEntry )
    {
        DBG_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 = pView->FirstChild( pEntry );
            DBG_ASSERT( pChild, "The first child is invalid!" );
            do
            {
                UpdateContextBmpWidthVectorFromMovedEntry( pChild );
                pChild = pView->Next( pChild );
            } while ( pChild );
        }
    }

    void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry const * pEntry )
    {
        sal_uInt16 nDepth = pView->pModel->GetDepth( pEntry );
        if( aContextBmpWidthVector.size() < 1 )
            return;
        short nWidth = aContextBmpWidthVector[ nDepth ];
        if( nWidth != pView->nContextBmpWidthMax ) {
            pView->nContextBmpWidthMax = nWidth;
            nFlags |= LBoxFlags::IgnoreChangedTabs;
            pView->SetTabs();
            nFlags &= ~LBoxFlags::IgnoreChangedTabs;
        }
    }

    void SvImpLBox::CalcCellFocusRect( SvTreeListEntry const * pEntry, tools::Rectangle& rRect )
    {
        if ( !(pEntry && bIsCellFocusEnabled) )
            return;

        if ( nCurTabPos > FIRST_ENTRY_TAB )
        {
            SvLBoxItem& rItem = pCursor->GetItem( nCurTabPos );
            rRect.SetLeft( pView->GetTab( pCursor, &rItem )->GetPos() );
        }
        if (pCursor->ItemCount() > static_cast<size_t>(nCurTabPos+1))
        {
            SvLBoxItem& rNextItem = pCursor->GetItem( nCurTabPos + 1 );
            long nRight = pView->GetTab( pCursor, &rNextItem )->GetPos() - 1;
            if ( nRight < rRect.Right() )
                rRect.SetRight( nRight );
        }
    }

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

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

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

        pActiveButton = nullptr;
        pActiveEntry = nullptr;
        pActiveTab = nullptr;

        nMostRight = -1;
        pMostRightEntry = nullptr;

        // don't touch the cursor any more
        if( pCursor )
        {
            if( pView->HasFocus() )
                pView->HideFocus();
            pCursor = nullptr;
        }
        aVerSBar->Hide();
        aVerSBar->SetThumbPos( 0 );
        Range aRange( 0, 0 );
        aVerSBar->SetRange( aRange );
        aOutputSize = pView->Control::GetOutputSizePixel();
        aHorSBar->Hide();
        aHorSBar->SetThumbPos( 0 );
        MapMode aMapMode( pView->GetMapMode());
        aMapMode.SetOrigin( Point(0,0) );
        pView->Control::SetMapMode( aMapMode );
        aHorSBar->SetRange( aRange );
        aHorSBar->SetSizePixel(Size(aOutputSize.Width(),nHorSBarHeight));
        pView->SetClipRegion();
        if( GetUpdateMode() )
            pView->Invalidate( GetVisibleArea() );
        nFlags |= LBoxFlags::Filling;
        if( !aHorSBar->IsVisible() && !aVerSBar->IsVisible() )
            aScrBarBox->Hide();

        aContextBmpWidthVector.clear();

        CallEventListeners( VclEventId::ListboxItemRemoved );
    }

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

    IMPL_LINK_NOARG(SvImpLBox, EndScrollHdl, ScrollBar*, void)
    {
        if( nFlags & LBoxFlags::EndScrollSetVisSize )
        {
            aVerSBar->SetVisibleSize( nNextVerVisSize );
            nFlags &= ~LBoxFlags::EndScrollSetVisSize;
        }
        EndScroll();
    }

    // handler for vertical scrollbar

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

        nFlags &= (~LBoxFlags::Filling);

        bInVScrollHdl = true;

        if( pView->IsEditingActive() )
        {
            pView->EndEditing( true ); // Cancel
            pView->Update();
        }
        BeginScroll();

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

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

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

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

        SvTreeListEntry* pPrevFirstToDraw = pView->PrevVisible(pStartEntry);
        if( !pPrevFirstToDraw )
            return;

        nFlags &= (~LBoxFlags::Filling);
        long nEntryHeight = pView->GetEntryHeight();
        ShowCursor( false );
        pView->Update();
        pStartEntry = pPrevFirstToDraw;
        tools::Rectangle aArea( GetVisibleArea() );
        aArea.AdjustBottom( -nEntryHeight );
        pView->Scroll( 0, nEntryHeight, aArea, ScrollFlags::NoChildren );
        pView->Update();
        ShowCursor( true );
        pView->NotifyScrolled();
    }

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

        if( !nDelta )
            return;

        if (!pStartEntry)
            return;

        SvTreeListEntry* pNext = pView->NextVisible(pStartEntry, nRealDelta);
        if( pNext == pStartEntry )
            return;

        ShowCursor( false );

        nFlags &= (~LBoxFlags::Filling);
        pView->Update();
        pStartEntry = pNext;

        if( nRealDelta >= nVisibleCount )
        {
            pView->Invalidate( GetVisibleArea() );
            pView->Update();
        }
        else
        {
            tools::Rectangle aArea( GetVisibleArea() );
            long nScroll = pView->GetEntryHeight() * static_cast<long>(nRealDelta);
            nScroll = -nScroll;
            pView->Update();
            pView->Scroll( 0, nScroll, aArea, ScrollFlags::NoChildren );
            pView->Update();
            pView->NotifyScrolled();
        }

        ShowCursor( true );
    }

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

        if (!pStartEntry)
            return;

        SvTreeListEntry* pPrev = pView->PrevVisible(pStartEntry, nRealDelta);
        if( pPrev == pStartEntry )
            return;

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

        pView->Update();
        pStartEntry = pPrev;
        if( nRealDelta >= nVisibleCount )
        {
            pView->Invalidate( GetVisibleArea() );
            pView->Update();
        }
        else
        {
            long nEntryHeight = pView->GetEntryHeight();
            tools::Rectangle aArea( GetVisibleArea() );
            pView->Update();
            pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, ScrollFlags::NoChildren );
            pView->Update();
            pView->NotifyScrolled();
        }

        ShowCursor( true );
    }

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

        long nDelta;
        if( bPageUp )
            nDelta = aVerSBar->GetPageSize();
        else
            nDelta = 1;

        long nThumbPos = aVerSBar->GetThumbPos();

        if( nThumbPos < nDelta )
            nDelta = nThumbPos;

        if( nDelta <= 0 )
            return;

        nFlags &= (~LBoxFlags::Filling);
        BeginScroll();

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

        EndScroll();
    }

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

        long nDelta;
        if( bPageDown )
            nDelta = aVerSBar->GetPageSize();
        else
            nDelta = 1;

        long nThumbPos = aVerSBar->GetThumbPos();
        long nVisibleSize = aVerSBar->GetVisibleSize();
        long nRange = aVerSBar->GetRange().Len();

        long nTmp = nThumbPos+nVisibleSize;
        while( (nDelta > 0) && (nTmp+nDelta) >= nRange )
            nDelta--;

        if( nDelta <= 0 )
            return;

        nFlags &= (~LBoxFlags::Filling);
        BeginScroll();

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

        EndScroll();
    }

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

    void SvImpLBox::InvalidateEntry( long nY ) const
    {
        if( !(nFlags & LBoxFlags::InPaint ))
        {
            tools::Rectangle aRect( GetVisibleArea() );
            long nMaxBottom = aRect.Bottom();
            aRect.SetTop( nY );
            aRect.SetBottom( nY ); aRect.AdjustBottom(pView->GetEntryHeight() );
            if( aRect.Top() > nMaxBottom )
                return;
            if( aRect.Bottom() > nMaxBottom )
                aRect.SetBottom( nMaxBottom );
            pView->Invalidate( aRect );
        }
    }

    void SvImpLBox::InvalidateEntry( SvTreeListEntry* pEntry )
    {
        if( GetUpdateMode() )
        {
            long nPrev = nMostRight;
            SetMostRight( pEntry );
            if( nPrev < nMostRight )
                ShowVerSBar();
        }
        if( !(nFlags & LBoxFlags::InPaint ))
        {
            bool bHasFocusRect = false;
            if( pEntry==pCursor && pView->HasFocus() )
            {
                bHasFocusRect = true;
                ShowCursor( false );
            }
            InvalidateEntry( GetEntryLine( pEntry ) );
            if( bHasFocusRect )
                ShowCursor( true );
        }
    }

    void SvImpLBox::RecalcFocusRect()
    {
        if( pView->HasFocus() && pCursor )
        {
            pView->HideFocus();
            long nY = GetEntryLine( pCursor );
            tools::Rectangle aRect = pView->GetFocusRect( pCursor, nY );
            CalcCellFocusRect( pCursor, aRect );
            vcl::Region aOldClip( pView->GetClipRegion());
            vcl::Region aClipRegion( GetClipRegionRect() );
            pView->SetClipRegion( aClipRegion );
            pView->ShowFocus( aRect );
            pView->SetClipRegion( aOldClip );
        }
    }

    //  Sets cursor. When using SingleSelection, the selection is adjusted.

    void SvImpLBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect )
    {
        SvViewDataEntry* pViewDataNewCur = nullptr;
        if( pEntry )
            pViewDataNewCur= pView->GetViewDataEntry(pEntry);
        if( pEntry &&
            pEntry == 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 = pView->NextVisible(pEntry);
            pViewDataNewCur = pEntry ? pView->GetViewDataEntry(pEntry) : nullptr;
        }

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

            if( pAnchor )
            {
                DBG_ASSERT(aSelEng.GetSelectionMode() != SelectionMode::Single,"Mode?");
                SetAnchorSelection( pOldCursor, pCursor );
            }
        }
        nFlags &= (~LBoxFlags::DeselectAll);

        pView->OnCurrentEntryChanged();
    }

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

    void SvImpLBox::UpdateAll( bool bInvalidateCompleteView )
    {
        FindMostRight(nullptr);
        aVerSBar->SetRange( Range(0, pView->GetVisibleCount()-1 ) );
        SyncVerThumb();
        FillView();
        ShowVerSBar();
        if( bSimpleTravel && pCursor && pView->HasFocus() )
            pView->Select( pCursor );
        ShowCursor( true );
        if( bInvalidateCompleteView )
            pView->Invalidate();
        else
            pView->Invalidate( GetVisibleArea() );
    }

    IMPL_LINK( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar, void )
    {
        long nDelta = pScrollBar->GetDelta();
        if( nDelta )
        {
            if( pView->IsEditingActive() )
            {
                pView->EndEditing( true ); // Cancel
                pView->Update();
            }
            pView->nFocusWidth = -1;
            KeyLeftRight( nDelta );
        }
    }

    void SvImpLBox::KeyLeftRight( long nDelta )
    {
        if( !(nFlags & LBoxFlags::InResize) )
            pView->Update();
        BeginScroll();
        nFlags &= (~LBoxFlags::Filling);
        ShowCursor( false );

        // calculate new origin
        long nPos = aHorSBar->GetThumbPos();
        Point aOrigin( -nPos, 0 );

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

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

    // returns the last entry if position is just past the last entry
    SvTreeListEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const
    {
        DBG_ASSERT( pView->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" );
        if ( !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( pView->GetEntryCount() == 0 || !pStartEntry || !pView->GetEntryHeight())
            return nullptr;

        sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / pView->GetEntryHeight() );
        sal_uInt16 nTemp = nClickedEntry;
        SvTreeListEntry* pEntry = pView->NextVisible(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, 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( pView->GetFocusRect( pEntry, nLine ));
        aRect.SetRight( GetOutputSize().Width() - pView->GetMapMode().GetOrigin().X() );

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

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

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

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

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

            if( pEntry && pEntry != pCursor )
                pView->SetEntryFocus( 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 = pView->NextVisible(pStartEntry, nSteps);
            }
            if( pEntry )
            {
                if( pEntry != pCursor &&
                     aSelEng.GetSelectionMode() == SelectionMode::Single
                )
                    pView->Select( pCursor, false );
            }
        }
        return pEntry;
    }

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

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

        nFlags |= LBoxFlags::InPaint;

        if (nFlags & LBoxFlags::Filling)
        {
            SvTreeListEntry* pFirst = pView->First();
            if (pFirst != pStartEntry)
            {
                ShowCursor(false);
                pStartEntry = pView->First();
                aVerSBar->SetThumbPos( 0 );
                StopUserEvent();
                ShowCursor(true);
                nCurUserEvent = Application::PostUserEvent(LINK(this, SvImpLBox, MyUserEvent),
                                                           reinterpret_cast<void*>(1));
                return;
            }
        }

        if (!pStartEntry)
        {
            pStartEntry = pView->First();
        }

        if (nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID)
            SetNodeBmpTabDistance();

        long nRectHeight = rRect.GetHeight();
        long nEntryHeight = 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

        long nY = nStartLine * nEntryHeight;
        SvTreeListEntry* pEntry = pStartEntry;
        while (nStartLine && pEntry)
        {
            pEntry = pView->NextVisible(pEntry);
            nStartLine--;
        }

        vcl::Region aClipRegion(GetClipRegionRect());

        // first draw the lines, then clip them!
        rRenderContext.SetClipRegion();
        if (m_nStyle & (WB_HASLINES | WB_HASLINESATROOT))
            DrawNet(rRenderContext);

        rRenderContext.SetClipRegion(aClipRegion);

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

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

        nFlags &= (~LBoxFlags::DeselectAll);
        rRenderContext.SetClipRegion();
        nFlags &= (~LBoxFlags::InPaint);
    }

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

        bool bInView = IsEntryInView( pEntry );

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

        if( pStartEntry || mbForceMakeVisible )
            nFlags &= (~LBoxFlags::Filling);
        if( !bInView )
        {
            if( !pView->IsEntryVisible(pEntry) )  // Parent(s) collapsed?
            {
                SvTreeListEntry* pParent = pView->GetParent( pEntry );
                while( pParent )
                {
                    if( !pView->IsExpanded( pParent ) )
                    {
                        bool bRet = pView->Expand( pParent );
                        DBG_ASSERT(bRet,"Not expanded!");
                    }
                    pParent = 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
            }
        }

        pStartEntry = pEntry;
        ShowCursor( false );
        FillView();
        aVerSBar->SetThumbPos( static_cast<long>(pView->GetVisiblePos( pStartEntry )) );
        ShowCursor( true );
        pView->Invalidate();
    }

    void SvImpLBox::ScrollToAbsPos( long nPos )
    {
        if( pView->GetVisibleCount() == 0 )
            return;
        long nLastEntryPos = pView->GetAbsPos( pView->Last() );

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

        SvTreeListEntry* pEntry = pView->GetEntryAtAbsPos( nPos );
        if( !pEntry || pEntry == pStartEntry )
            return;

        if( pStartEntry || mbForceMakeVisible )
            nFlags &= (~LBoxFlags::Filling);

        if( pView->IsEntryVisible(pEntry) )
        {
            pStartEntry = pEntry;
            ShowCursor( false );
            aVerSBar->SetThumbPos( nPos );
            ShowCursor( true );
            if (GetUpdateMode())
                pView->Invalidate();
        }
    }

    void SvImpLBox::DrawNet(vcl::RenderContext& rRenderContext)
    {
        if (pView->GetVisibleCount() < 2 && !pStartEntry->HasChildrenOnDemand() &&
            !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;
            }
        }

        long nEntryHeight = pView->GetEntryHeight();
        long nEntryHeightDIV2 = nEntryHeight / 2;
        if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001))
            nEntryHeightDIV2--;

        SvTreeListEntry* pChild;
        SvTreeListEntry* pEntry = pStartEntry;

        SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab();
        while (pTree->GetDepth( pEntry ) > 0)
        {
            pEntry = pView->GetParent(pEntry);
        }
        sal_uInt16 nOffs = static_cast<sal_uInt16>(pView->GetVisiblePos(pStartEntry) - pView->GetVisiblePos(pEntry));
        long nY = 0;
        nY -= (nOffs * nEntryHeight);

        DBG_ASSERT(pFirstDynamicTab,"No Tree!");

        rRenderContext.Push(PushFlags::LINECOLOR);

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

        if (aCol.IsRGBEqual(rRenderContext.GetBackground().GetColor()))
            aCol = rStyleSettings.GetShadowColor();
        rRenderContext.SetLineColor(aCol);
        Point aPos1, aPos2;
        sal_uInt16 nDistance;
        sal_uLong nMax = nVisibleCount + nOffs + 1;

        const Image& rExpandedNodeBitmap = GetExpandedNodeBmp();

        for (sal_uLong n=0; n< nMax && pEntry; n++)
        {
            if (pView->IsExpanded(pEntry))
            {
                aPos1.setX( pView->GetTabPos(pEntry, pFirstDynamicTab) );
                // if it is not a context bitmap, go a little to the right below the
                // first text (node bitmap, too)
                if (!pView->nContextBmpWidthMax)
                    aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 );

                aPos1.setY( nY );
                aPos1.AdjustY(nEntryHeightDIV2 );

                pChild = pView->FirstChild( pEntry );
                assert(pChild && "Child?");
                pChild = pChild->LastSibling();
                nDistance = static_cast<sal_uInt16>(pView->GetVisiblePos(pChild) - pView->GetVisiblePos(pEntry));
                aPos2 = aPos1;
                aPos2.AdjustY(nDistance * nEntryHeight );
                rRenderContext.DrawLine(aPos1, aPos2);
            }
            // visible in control?
            if (n >= nOffs && ((m_nStyle & WB_HASLINESATROOT) || !pTree->IsAtRootDepth(pEntry)))
            {
                // can we recycle aPos1?
                if (!pView->IsExpanded(pEntry))
                {
                    // nope
                    aPos1.setX( pView->GetTabPos(pEntry, pFirstDynamicTab) );
                    // if it is not a context bitmap, go a little to the right below
                    // the first text (node bitmap, too)
                    if (!pView->nContextBmpWidthMax)
                        aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 );
                    aPos1.setY( nY );
                    aPos1.AdjustY(nEntryHeightDIV2 );
                    aPos2.setX( aPos1.X() );
                }
                aPos2.setY( aPos1.Y() );
                aPos2.AdjustX( -(pView->GetIndent()) );
                rRenderContext.DrawLine(aPos1, aPos2);
            }
            nY += nEntryHeight;
            pEntry = pView->NextVisible(pEntry);
        }
        if (m_nStyle & WB_HASLINESATROOT)
        {
            pEntry = pView->First();
            aPos1.setX( pView->GetTabPos(pEntry, pFirstDynamicTab) );
            // if it is not a context bitmap, go a little to the right below the
            // first text (node bitmap, too)
            if (!pView->nContextBmpWidthMax)
                aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 );
            aPos1.AdjustX( -(pView->GetIndent()) );
            aPos1.setY( GetEntryLine( pEntry ) );
            aPos1.AdjustY(nEntryHeightDIV2 );
            pChild = pEntry->LastSibling();
            aPos2.setX( aPos1.X() );
            aPos2.setY( GetEntryLine( pChild ) );
            aPos2.AdjustY(nEntryHeightDIV2 );
            rRenderContext.DrawLine(aPos1, aPos2);
        }
        rRenderContext.Pop();
    }

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

        Size aVerSize( nVerSBarWidth, rSize.Height() );
        Size aHorSize( rSize.Width(), nHorSBarHeight );

        if( nMask & 0x0001 )
            aHorSize.AdjustWidth( -(nVerSBarWidth) );
        if( nMask & 0x0002 )
            aVerSize.AdjustHeight( -(nHorSBarHeight) );

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

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

        aHorSBar->SetPosSizePixel( aHorPos, aHorSize );

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

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

    void SvImpLBox::AdjustScrollBars( Size& rSize )
    {
        long nEntryHeight = pView->GetEntryHeight();
        if( !nEntryHeight )
            return;

        sal_uInt16 nResult = 0;

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

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

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

        // number of entries visible within the view
        nVisibleCount = aOSize.Height() / nEntryHeight;

        // do we need a vertical scrollbar?
        if( bVerSBar || nTotalCount > nVisibleCount )
        {
            nResult = 1;
            nMaxRight -= nVerSBarWidth;
            if( !bHorBar )
            {
                if( (nWindowStyle & WB_HSCROLL) &&
                    (nVis < nMostRight || nMaxRight < 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.
            nVisibleCount =  (aOSize.Height() - nHorSBarHeight) / nEntryHeight;
            // we might actually need a vertical scrollbar now
            if( !(nResult & 0x0001) &&
                ((nTotalCount > 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 );
        aSelEng.SetVisibleArea( aRect );

        // vertical scrollbar
        long nTemp = static_cast<long>(nVisibleCount);
        nTemp--;
        if( nTemp != aVerSBar->GetVisibleSize() )
        {
            if( !bInVScrollHdl )
            {
                aVerSBar->SetPageSize( nTemp - 1 );
                aVerSBar->SetVisibleSize( nTemp );
            }
            else
            {
                nFlags |= LBoxFlags::EndScrollSetVisSize;
                nNextVerVisSize = nTemp;
            }
        }

        // horizontal scrollbar
        nTemp = aHorSBar->GetThumbPos();
        aHorSBar->SetVisibleSize( aOSize.Width() );
        long nNewThumbPos = aHorSBar->GetThumbPos();
        Range aRange( aHorSBar->GetRange() );
        if( aRange.Max() < nMostRight+25 )
        {
            aRange.Max() = nMostRight+25;
            aHorSBar->SetRange( aRange );
        }

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

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

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

    void SvImpLBox::InitScrollBarBox()
    {
        aScrBarBox->SetSizePixel( Size(nVerSBarWidth, nHorSBarHeight) );
        Size aSize( pView->Control::GetOutputSizePixel() );
        aScrBarBox->SetPosPixel( Point(aSize.Width()-nVerSBarWidth, aSize.Height()-nHorSBarHeight));
    }

    void SvImpLBox::Resize()
    {
        aOutputSize = pView->Control::GetOutputSizePixel();
        if( aOutputSize.Width() <= 0 || aOutputSize.Height() <= 0 )
            return;
        nFlags |= LBoxFlags::InResize;
        InitScrollBarBox();

        if( pView->GetEntryHeight())
        {
            AdjustScrollBars( aOutputSize );
            UpdateAll(false);
        }
        // HACK, as in floating and docked windows the scrollbars might not be drawn
        // correctly/not be drawn at all after resizing!
        if( aHorSBar->IsVisible())
            aHorSBar->Invalidate();
        if( aVerSBar->IsVisible())
            aVerSBar->Invalidate();
        nFlags &= ~LBoxFlags::InResize;
    }

    void SvImpLBox::FillView()
    {
        if( !pStartEntry )
        {
            sal_uLong nVisibleViewCount = pView->GetVisibleCount();
            long nTempThumb = aVerSBar->GetThumbPos();
            if( nTempThumb < 0 )
                nTempThumb = 0;
            else if( static_cast<unsigned long>(nTempThumb) >= nVisibleViewCount )
                nTempThumb = nVisibleViewCount == 0 ? 0 : nVisibleViewCount - 1;
            pStartEntry = pView->GetEntryAtVisPos(nTempThumb);
        }
        if( !pStartEntry )
            return;

        sal_uInt16 nLast = static_cast<sal_uInt16>(pView->GetVisiblePos(pView->LastVisible()));
        sal_uInt16 nThumb = static_cast<sal_uInt16>(pView->GetVisiblePos( pStartEntry ));
        sal_uLong nCurDispEntries = nLast-nThumb+1;
        if( nCurDispEntries >=  nVisibleCount )
            return;

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

    void SvImpLBox::ShowVerSBar()
    {
        bool bVerBar = ( pView->GetStyle() & WB_VSCROLL ) != 0;
        sal_uLong nVis = 0;
        if( !bVerBar )
            nVis = pView->GetVisibleCount();
        if( bVerBar || (nVisibleCount && nVis > static_cast<sal_uLong>(nVisibleCount-1)) )
        {
            if( !aVerSBar->IsVisible() )
            {
                pView->nFocusWidth = -1;
                AdjustScrollBars( aOutputSize );
                if( GetUpdateMode() )
                    aVerSBar->Update();
            }
        }
        else
        {
            if( aVerSBar->IsVisible() )
            {
                pView->nFocusWidth = -1;
                AdjustScrollBars( aOutputSize );
            }
        }

        long nMaxRight = GetOutputSize().Width();
        Point aPos( pView->GetMapMode().GetOrigin() );
        aPos.setX( aPos.X() * -1 ); // convert document coordinates
        nMaxRight = nMaxRight + aPos.X() - 1;
        if( nMaxRight < nMostRight  )
        {
            if( !aHorSBar->IsVisible() )
            {
                pView->nFocusWidth = -1;
                AdjustScrollBars( aOutputSize );
                if( GetUpdateMode() )
                    aHorSBar->Update();
            }
            else
            {
                Range aRange( aHorSBar->GetRange() );
                if( aRange.Max() < nMostRight+25 )
                {
                    aRange.Max() = nMostRight+25;
                    aHorSBar->SetRange( aRange );
                }
                else
                {
                    pView->nFocusWidth = -1;
                    AdjustScrollBars( aOutputSize );
                }
            }
        }
        else
        {
            if( aHorSBar->IsVisible() )
            {
                pView->nFocusWidth = -1;
                AdjustScrollBars( aOutputSize );
            }
        }
    }

    void SvImpLBox::SyncVerThumb()
    {
        if( pStartEntry )
        {
            long nEntryPos = pView->GetVisiblePos( pStartEntry );
            aVerSBar->SetThumbPos( nEntryPos );
        }
        else
            aVerSBar->SetThumbPos( 0 );
    }

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

    long SvImpLBox::GetEntryLine( SvTreeListEntry* pEntry ) const
    {
        if(!pStartEntry )
            return -1; // invisible position

        long nFirstVisPos = pView->GetVisiblePos( pStartEntry );
        long nEntryVisPos = pView->GetVisiblePos( pEntry );
        nFirstVisPos = nEntryVisPos - nFirstVisPos;
        nFirstVisPos *= pView->GetEntryHeight();
        return nFirstVisPos;
    }

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

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

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

        ShowCursor( false );
        long nY = GetEntryLine( pEntry );
        if( IsLineVisible(nY) )
        {
            InvalidateEntriesFrom( nY );
            FindMostRight( pEntry, nullptr  );
        }
        aVerSBar->SetRange( Range(0, 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( !pView->IsEntryVisible( pEntry ) )
            return;

        ShowCursor( false );

        if( !pMostRightEntry || pTree->IsChild( pEntry,pMostRightEntry ) )
        {
            FindMostRight(nullptr);
        }

        if( pStartEntry )
        {
            long nOldThumbPos   = aVerSBar->GetThumbPos();
            sal_uLong nVisList      = pView->GetVisibleCount();
            aVerSBar->SetRange( Range(0, nVisList-1) );
            long nNewThumbPos   = aVerSBar->GetThumbPos();
            if( nNewThumbPos != nOldThumbPos  )
            {
                pStartEntry = pView->First();
                sal_uInt16 nDistance = static_cast<sal_uInt16>(nNewThumbPos);
                if( nDistance )
                    pStartEntry = pView->NextVisible(pStartEntry, nDistance);
                if( GetUpdateMode() )
                    pView->Invalidate();
            }
            else
                SyncVerThumb();
            ShowVerSBar();
        }
        // has the cursor been collapsed?
        if( pTree->IsChild( pEntry, pCursor ) )
            SetCursor( pEntry );
        if( GetUpdateMode() )
            ShowVerSBar();
        ShowCursor( true );
        if( GetUpdateMode() && pCursor )
            pView->Select( pCursor );
    }

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

        SelAllDestrAnch( false ); // deselect all

        // is the collapsed cursor visible?
        long nY = GetEntryLine( pEntry );
        if( IsLineVisible(nY) )
        {
            if( GetUpdateMode() )
                InvalidateEntriesFrom( nY );
        }
        else
        {
            if( pTree->IsChild(pEntry, pStartEntry) )
            {
                pStartEntry = pEntry;
                if( GetUpdateMode() )
                    pView->Invalidate();
            }
        }
    }

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

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

    // corrects the cursor when using SingleSelection

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

        nFlags &= (~LBoxFlags::DeselectAll);
        if( bSelect &&
            aSelEng.GetSelectionMode() == SelectionMode::Single &&
            pEntry != pCursor )
        {
            SetCursor( pEntry );
            DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?");
        }

        if( GetUpdateMode() && pView->IsEntryVisible(pEntry) )
        {
            long nY = GetEntryLine( pEntry );
            if( IsLineVisible( nY ) )
            {
                ShowCursor(false);
                InvalidateEntry(pEntry);
                ShowCursor(true);
            }
        }
    }

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

        DestroyAnchor();

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

        if( pEntry == pMostRightEntry || (
            pEntry->HasChildren() && pView->IsExpanded(pEntry) &&
            pTree->IsChild(pEntry, pMostRightEntry)))
        {
            nFlags |= LBoxFlags::RemovedRecalcMostRight;
        }

        SvTreeListEntry* pOldStartEntry = pStartEntry;

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

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

        if( pCursor && pTree->IsChild( pEntry, pCursor) )
            pCursor = pEntry;
        if( pStartEntry && pTree->IsChild(pEntry,pStartEntry) )
            pStartEntry = pEntry;

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

            SetCursor( pTemp, true );
        }
        if( pStartEntry && pStartEntry == pEntry )
        {
            pTemp = pStartEntry->NextSibling();
            if( !pTemp )
                pTemp = pView->PrevVisible(pStartEntry);
            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( pStartEntry && (pStartEntry != pOldStartEntry || pEntry == pView->GetModel()->Last()) )
            {
                aVerSBar->SetThumbPos( pView->GetVisiblePos( pStartEntry ));
                pView->Invalidate( GetVisibleArea() );
            }
            else
                InvalidateEntriesFrom( GetEntryLine( pEntry ) );
        }
    }

    void SvImpLBox::EntryRemoved()
    {
        if( nFlags & LBoxFlags::RemovedEntryInvisible )
        {
            nFlags &= (~LBoxFlags::RemovedEntryInvisible);
            return;
        }
        if( !pStartEntry )
            pStartEntry = pTree->First();
        if( !pCursor )
            SetCursor( pStartEntry, true );

        if( pCursor && (bSimpleTravel || !pView->GetSelectionCount() ))
            pView->Select( pCursor );

        if( GetUpdateMode())
        {
            if( nFlags & LBoxFlags::RemovedRecalcMostRight )
                FindMostRight(nullptr);
            aVerSBar->SetRange( Range(0, pView->GetVisibleCount()-1 ) );
            FillView();
            if( pStartEntry )
                // if something above the thumb was deleted
                aVerSBar->SetThumbPos( pView->GetVisiblePos( pStartEntry) );

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

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

        if( pEntry == pCursor )
            ShowCursor( false );
        if( IsEntryInView( pEntry ) )
            pView->Invalidate();
        if( pEntry != pStartEntry )
            return;

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

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

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

        aVerSBar->SetRange( Range(0, pView->GetVisibleCount()-1));
        sal_uInt16 nFirstPos = static_cast<sal_uInt16>(pTree->GetAbsPos( pStartEntry ));
        sal_uInt16 nNewPos = static_cast<sal_uInt16>(pTree->GetAbsPos( pEntry ));
        FindMostRight(nullptr);
        if( nNewPos < nFirstPos ) // HACK!
            pStartEntry = pEntry;
        SyncVerThumb();
        if( pEntry == pCursor )
        {
            if( pView->IsEntryVisible( pCursor ) )
                ShowCursor( true );
            else
            {
                SvTreeListEntry* pParent = pEntry;
                do {
                    pParent = pTree->GetParent( pParent );
                }
                while( !pView->IsEntryVisible( pParent ) );
                SetCursor( pParent );
            }
        }
        if( IsEntryInView( pEntry ) )
            pView->Invalidate();
    }

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

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

        if( !pView->IsEntryVisible( pEntry ) )
            return;
        bool bDeselAll(nFlags & LBoxFlags::DeselectAll);
        if( bDeselAll )
            SelAllDestrAnch( false );
        else
            DestroyAnchor();
        //  nFlags &= (~LBoxFlags::DeselectAll);
    //      ShowCursor( false ); // if cursor is moved lower
        long nY = GetEntryLine( pEntry );
        bool bEntryVisible = IsLineVisible( nY );
        if( bEntryVisible )
        {
            ShowCursor( false ); // if cursor is moved lower
            nY -= pView->GetEntryHeight(); // because of lines
            InvalidateEntriesFrom( nY );
        }
        else if( pStartEntry && nY < GetEntryLine(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>(pView->GetVisiblePos(pView->LastVisible()));
            sal_uInt16 nThumb = static_cast<sal_uInt16>(pView->GetVisiblePos( pStartEntry ));
            sal_uInt16 nCurDispEntries = nLast-nThumb+1;
            if( nCurDispEntries < nVisibleCount )
            {
                // set at the next paint event
                pStartEntry = nullptr;
                SetCursor( nullptr );
                pView->Invalidate();
            }
        }
        else if( !pStartEntry )
            pView->Invalidate();

        SetMostRight( pEntry );
        aVerSBar->SetRange( Range(0, pView->GetVisibleCount()-1));
        SyncVerThumb(); // if something was inserted before the thumb
        ShowVerSBar();
        ShowCursor( true );
        if( pStartEntry != pView->First() && (nFlags & LBoxFlags::Filling) )
            pView->Update();
    }

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

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

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

    bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry const * pEntry)
    {
        if( pActiveButton )
        {
            long nMouseX = rMEvt.GetPosPixel().X();
            if( pEntry == pActiveEntry &&
                 pView->GetItem(pActiveEntry, nMouseX) == pActiveButton )
            {
                if( !pActiveButton->IsStateHilighted() )
                {
                    pActiveButton->SetStateHilighted(true );
                    InvalidateEntry(pActiveEntry);
                }
            }
            else
            {
                if( pActiveButton->IsStateHilighted() )
                {
                    pActiveButton->SetStateHilighted(false );
                    InvalidateEntry(pActiveEntry);
                }
            }
            return true;
        }
        return false;
    }

    bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt )
    {
        if( pActiveButton )
        {
            pView->ReleaseMouse();
            SvTreeListEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() );
            pActiveButton->SetStateHilighted( false );
            long nMouseX = rMEvt.GetPosPixel().X();
            if (pEntry == pActiveEntry && pView->GetItem(pActiveEntry, nMouseX) == pActiveButton)
                pActiveButton->ClickHdl(pActiveEntry);
            InvalidateEntry(pActiveEntry);
            if (pCursor == pActiveEntry)
                ShowCursor(true);
            pActiveButton = nullptr;
            pActiveEntry = nullptr;
            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, SvTreeListEntry* pEntry ) const
    {
        if( !pEntry->HasChildren() && !pEntry->HasChildrenOnDemand() )
            return false;

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

        long nMouseX = rPosPixel.X();
        // convert to document coordinates
        Point aOrigin( pView->GetMapMode().GetOrigin() );
        nMouseX -= aOrigin.X();

        long nX = pView->GetTabPos( pEntry, pFirstDynamicTab);
        nX += nNodeBmpTabDistance;
        if( nMouseX < nX )
            return false;
        nX += nNodeBmpWidth;
        return nMouseX <= nX;
    }

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

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

        return bRet;
    }

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

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

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

        SvTreeListEntry* pEntry = GetEntry( aPos );
        if ( pEntry != pCursor )
            // new entry selected -> reset current tab position to first tab
            nCurTabPos = FIRST_ENTRY_TAB;
        nFlags &= (~LBoxFlags::Filling);
        pView->GrabFocus();
        //fdo#82270 Grabbing focus can invalidate the entries, re-fetch
        pEntry = GetEntry(aPos);
        // the entry can still be invalid!
        if( !pEntry || !pView->GetViewData( pEntry ))
            return;

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

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

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

        if( (rMEvt.GetClicks() % 2) == 0 )
        {
            nFlags &= (~LBoxFlags::StartEditTimer);
            pView->pHdlEntry = pEntry;
            if( !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 != pView->pHdlEntry )
                {
                    // select anew & bye
                    if( !bSimpleTravel && !aSelEng.IsAlwaysAdding())
                        SelAllDestrAnch( false ); // DeselectAll();
                    SetCursor( pEntry );

                    return;
                }
                if( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() )
                {
                    if( bSubLstOpDblClick )
                    {
                        if( pView->IsExpanded(pEntry) )
                            pView->Collapse( pEntry );
                        else
                            pView->Expand( pEntry );
                    }
                    if( pEntry == pCursor )  // only if Entryitem was clicked
                                              // (Nodebutton is not an Entryitem!)
                        pView->Select( pCursor );
                    return;
                }
            }
        }
        else
        {
            // CheckButton? (TreeListBox: Check + Info)
            if( ButtonDownCheckCtrl(rMEvt, pEntry) )
                return;
            // Inplace-Editing?
        }
        if ( aSelEng.GetSelectionMode() != SelectionMode::NONE )
            aSelEng.SelMouseButtonDown( rMEvt );
    }

    void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt)
    {
        if ( !ButtonUpCheckCtrl( rMEvt ) && ( aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
            aSelEng.SelMouseButtonUp( rMEvt );
        EndScroll();
        if( nFlags & LBoxFlags::StartEditTimer )
        {
            nFlags &= (~LBoxFlags::StartEditTimer);
            aEditClickPos = rMEvt.GetPosPixel();
            aEditIdle.Start();
        }
    }

    void SvImpLBox::MouseMove( const MouseEvent& rMEvt)
    {
        SvTreeListEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() );
        if ( !MouseMoveCheckCtrl( rMEvt, pEntry ) && ( aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
            aSelEng.SelMouseMove( rMEvt );
    }

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

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

        nFlags &= (~LBoxFlags::Filling);

        if( !pCursor )
            pCursor = pStartEntry;
        if( !pCursor )
            return false;

        bool bKeyUsed = true;

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

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

        SvTreeListEntry* pNewCursor;

        const WinBits nWindowStyle = pView->GetStyle();
        switch( aCode )
        {
            case KEY_UP:
                if( !IsEntryInView( pCursor ) )
                    MakeVisible( pCursor );

                pNewCursor = pCursor;
                do
                {
                    pNewCursor = pView->PrevVisible(pNewCursor);
                } while( pNewCursor && !IsSelectable(pNewCursor) );

                if ( pNewCursor )
                    // new entry selected -> reset current tab position to first tab
                    nCurTabPos = FIRST_ENTRY_TAB;
                // if there is no next entry, take the current one
                // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
                // the cursor key
                if (!pNewCursor)
                    pNewCursor = pCursor;

                aSelEng.CursorPosChanging( bShift, bMod1 );
                SetCursor( pNewCursor, bMod1 );     // no selection, when Ctrl is on
                if( !IsEntryInView( pNewCursor ) )
                    KeyUp( false );
                break;

            case KEY_DOWN:
                if( !IsEntryInView( pCursor ) )
                    MakeVisible( pCursor );

                pNewCursor = pCursor;
                do
                {
                    pNewCursor = pView->NextVisible(pNewCursor);
                } while( pNewCursor && !IsSelectable(pNewCursor) );

                if ( pNewCursor )
                    // new entry selected -> reset current tab position to first tab
                    nCurTabPos = FIRST_ENTRY_TAB;

                // if there is no next entry, take the current one
                // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
                // the cursor key
                // 06.09.20001 - 83416 - frank.schoenheit@sun.com
                if ( !pNewCursor && pCursor )
                    pNewCursor = pCursor;

                if( pNewCursor )
                {
                    aSelEng.CursorPosChanging( bShift, bMod1 );
                    if( IsEntryInView( pNewCursor ) )
                        SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
                    else
                    {
                        if( pCursor )
                            pView->Select( pCursor, false );
                        KeyDown( false );
                        SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
                    }
                }
                else
                    KeyDown( false );   // because scrollbar range might still
                                            // allow scrolling
                break;

            case KEY_RIGHT:
            {
                if( bSubLstOpLR )
                {
                    // only try to expand if sublist is expandable,
                    // otherwise ignore the key press
                    if( IsExpandable() && !pView->IsExpanded( pCursor ) )
                        pView->Expand( pCursor );
                }
                else if ( bIsCellFocusEnabled && pCursor )
                {
                    if ( nCurTabPos < ( pView->TabCount() - 1 /*!2*/ ) )
                    {
                        ++nCurTabPos;
                        ShowCursor( true );
                        CallEventListeners( VclEventId::ListboxSelect, pCursor );
                    }
                }
                else if( nWindowStyle & WB_HSCROLL )
                {
                    long    nThumb = aHorSBar->GetThumbPos();
                    nThumb += aHorSBar->GetLineSize();
                    long    nOldThumb = aHorSBar->GetThumbPos();
                    aHorSBar->SetThumbPos( nThumb );
                    nThumb = nOldThumb;
                    nThumb -= aHorSBar->GetThumbPos();
                    nThumb *= -1;
                    if( nThumb )
                    {
                        KeyLeftRight( nThumb );
                        EndScroll();
                    }
                }
                else
                    bKeyUsed = false;
                break;
            }

            case KEY_LEFT:
            {
                if ( bIsCellFocusEnabled && pCursor )
                {
                    if ( nCurTabPos > FIRST_ENTRY_TAB )
                    {
                        --nCurTabPos;
                        ShowCursor( true );
                        CallEventListeners( VclEventId::ListboxSelect, pCursor );
                    }
                }
                else if ( nWindowStyle & WB_HSCROLL )
                {
                    long    nThumb = aHorSBar->GetThumbPos();
                    nThumb -= aHorSBar->GetLineSize();
                    long    nOldThumb = aHorSBar->GetThumbPos();
                    aHorSBar->SetThumbPos( nThumb );
                    nThumb = nOldThumb;
                    nThumb -= aHorSBar->GetThumbPos();
                    if( nThumb )
                    {
                        KeyLeftRight( -nThumb );
                        EndScroll();
                    }
                    else if( bSubLstOpLR )
                    {
                        if( IsExpandable() && pView->IsExpanded( pCursor ) )
                            pView->Collapse( pCursor );
                        else
                        {
                            pNewCursor = pView->GetParent( pCursor );
                            if( pNewCursor )
                                SetCursor( pNewCursor );
                        }
                    }
                }
                else if( bSubLstOpLR )
                {
                    if( IsExpandable() && pView->IsExpanded( pCursor ) )
                        pView->Collapse( pCursor );
                    else
                    {
                        pNewCursor = pView->GetParent( pCursor );
                        if( pNewCursor )
                            SetCursor( pNewCursor );
                    }
                }
                else
                    bKeyUsed = false;
                break;
            }

            case KEY_PAGEUP:
                if( !bMod1 )
                {
                    pNewCursor = pView->PrevVisible(pCursor, nDelta);

                    while( nDelta && pNewCursor && !IsSelectable(pNewCursor) )
                    {
                        pNewCursor = pView->NextVisible(pNewCursor);
                        nDelta--;
                    }

                    if( nDelta )
                    {
                        DBG_ASSERT(pNewCursor && pNewCursor!=pCursor, "Cursor?");
                        aSelEng.CursorPosChanging( bShift, bMod1 );
                        if( IsEntryInView( pNewCursor ) )
                            SetCursor( pNewCursor );
                        else
                        {
                            SetCursor( pNewCursor );
                            KeyUp( true );
                        }
                    }
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_PAGEDOWN:
                if( !bMod1 )
                {
                    pNewCursor= pView->NextVisible(pCursor, nDelta);

                    while( nDelta && pNewCursor && !IsSelectable(pNewCursor) )
                    {
                        pNewCursor = pView->PrevVisible(pNewCursor);
                        nDelta--;
                    }

                    if( nDelta && pNewCursor )
                    {
                        DBG_ASSERT(pNewCursor && pNewCursor!=pCursor, "Cursor?");
                        aSelEng.CursorPosChanging( bShift, bMod1 );
                        if( IsEntryInView( pNewCursor ) )
                            SetCursor( pNewCursor );
                        else
                        {
                            SetCursor( pNewCursor );
                            KeyDown( true );
                        }
                    }
                    else
                        KeyDown( false ); // see also: KEY_DOWN
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_SPACE:
                if ( pView->GetSelectionMode() != SelectionMode::NONE )
                {
                    if ( bMod1 )
                    {
                        if ( pView->GetSelectionMode() == SelectionMode::Multiple && !bShift )
                            // toggle selection
                            pView->Select( pCursor, !pView->IsSelected( pCursor ) );
                    }
                    else if ( !bShift /*&& !bMod1*/ )
                    {
                        if ( aSelEng.IsAddMode() )
                        {
                            // toggle selection
                            pView->Select( pCursor, !pView->IsSelected( pCursor ) );
                        }
                        else if ( !pView->IsSelected( pCursor ) )
                        {
                            SelAllDestrAnch( false );
                            pView->Select( pCursor );
                        }
                        else
                            bKeyUsed = false;
                    }
                    else
                        bKeyUsed = false;
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_RETURN:
                if( bSubLstOpRet && IsExpandable() )
                {
                    if( pView->IsExpanded( pCursor ) )
                        pView->Collapse( pCursor );
                    else
                        pView->Expand( pCursor );
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_F2:
                if( !bShift && !bMod1 )
                {
                    aEditClickPos = Point( -1, -1 );
                    EditTimerCall( nullptr );
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_F8:
                if( bShift && pView->GetSelectionMode()==SelectionMode::Multiple &&
                    !(m_nStyle & WB_SIMPLEMODE))
                {
                    if( aSelEng.IsAlwaysAdding() )
                        aSelEng.AddAlways( false );
                    else
                        aSelEng.AddAlways( true );
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_ADD:
                if( pCursor )
                {
                    if( !pView->IsExpanded(pCursor))
                        pView->Expand( pCursor );
                    if( bMod1 )
                    {
                        sal_uInt16 nRefDepth = pTree->GetDepth( pCursor );
                        SvTreeListEntry* pCur = pTree->Next( pCursor );
                        while( pCur && pTree->GetDepth(pCur) > nRefDepth )
                        {
                            if( pCur->HasChildren() && !pView->IsExpanded(pCur))
                                pView->Expand( pCur );
                            pCur = pTree->Next( pCur );
                        }
                    }
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_A:
                if( bMod1 )
                    SelAllDestrAnch( true );
                else
                    bKeyUsed = false;
                break;

            case KEY_SUBTRACT:
                if( pCursor )
                {
                    if( pView->IsExpanded(pCursor))
                        pView->Collapse( pCursor );
                    if( bMod1 )
                    {
                        // collapse all parents until we get to the root
                        SvTreeListEntry* pParentToCollapse = pTree->GetRootLevelParent(pCursor);
                        if( pParentToCollapse )
                        {
                            sal_uInt16 nRefDepth;
                            // special case explorer: if the root only has a single
                            // entry, don't collapse the root entry
                            if (pTree->GetChildList(nullptr).size() < 2)
                            {
                                nRefDepth = 1;
                                pParentToCollapse = pCursor;
                                while( pTree->GetParent(pParentToCollapse) &&
                                       pTree->GetDepth( pTree->GetParent(pParentToCollapse)) > 0)
                                {
                                    pParentToCollapse = pTree->GetParent(pParentToCollapse);
                                }
                            }
                            else
                                nRefDepth = 0;

                            if( pView->IsExpanded(pParentToCollapse) )
                                pView->Collapse( pParentToCollapse );
                            SvTreeListEntry* pCur = pTree->Next( pParentToCollapse );
                            while( pCur && pTree->GetDepth(pCur) > nRefDepth )
                            {
                                if( pCur->HasChildren() && pView->IsExpanded(pCur) )
                                    pView->Collapse( pCur );
                                pCur = pTree->Next( pCur );
                            }
                        }
                    }
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_DIVIDE :
                if( bMod1 )
                    SelAllDestrAnch( true );
                else
                    bKeyUsed = false;
                break;

            case KEY_COMMA :
                if( bMod1 )
                    SelAllDestrAnch( false );
                else
                    bKeyUsed = false;
                break;

            case KEY_HOME :
                pNewCursor = pView->GetModel()->First();

                while( pNewCursor && !IsSelectable(pNewCursor) )
                {
                    pNewCursor = pView->NextVisible(pNewCursor);
                }

                if( pNewCursor && pNewCursor != pCursor )
                {
    //              SelAllDestrAnch( false );
                    aSelEng.CursorPosChanging( bShift, bMod1 );
                    SetCursor( pNewCursor );
                    if( !IsEntryInView( pNewCursor ) )
                        MakeVisible( pNewCursor );
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_END :
                pNewCursor = pView->GetModel()->Last();

                while( pNewCursor && !IsSelectable(pNewCursor) )
                {
                    pNewCursor = pView->PrevVisible(pNewCursor);
                }

                if( pNewCursor && pNewCursor != pCursor)
                {
    //              SelAllDestrAnch( false );
                    aSelEng.CursorPosChanging( bShift, bMod1 );
                    SetCursor( pNewCursor );
                    if( !IsEntryInView( pNewCursor ) )
                        MakeVisible( pNewCursor );
                }
                else
                    bKeyUsed = false;
                break;

            case KEY_ESCAPE:
            case KEY_TAB:
            case KEY_DELETE:
            case KEY_BACKSPACE:
                // must not be handled because this quits dialogs and does other magic things...
                // if there are other single keys which should not be handled, they can be added here
                bKeyUsed = false;
                break;

            default:
                // is there any reason why we should eat the events here? The only place where this is called
                // is from SvTreeListBox::KeyInput. If we set bKeyUsed to true here, then the key input
                // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection
                // handling.
                // (The old code here which intentionally set bKeyUsed to sal_True said this was because of "quick search"
                // handling, but actually there was no quick search handling anymore. We just re-implemented it.)
                // #i31275# / 2009-06-16 / frank.schoenheit@sun.com
                bKeyUsed = false;
                break;
        }
        return bKeyUsed;
    }

    void SvImpLBox::GetFocus()
    {
        if( pCursor )
        {
            pView->SetEntryFocus( pCursor, true );
            ShowCursor( true );
    // auskommentiert wg. deselectall
    //      if( bSimpleTravel && !pView->IsSelected(pCursor) )
    //          pView->Select( pCursor, true );
        }
        if( m_nStyle & WB_HIDESELECTION )
        {
            SvTreeListEntry* pEntry = pView->FirstSelected();
            while( pEntry )
            {
                InvalidateEntry( pEntry );
                pEntry = pView->NextSelected( pEntry );
            }
        }
    }

    void SvImpLBox::LoseFocus()
    {
        aEditIdle.Stop();
        if( pCursor )
            pView->SetEntryFocus( pCursor,false );
        ShowCursor( false );

        if( m_nStyle & WB_HIDESELECTION )
        {
            SvTreeListEntry* pEntry = pView ?  pView->FirstSelected() : nullptr;
            while( pEntry )
            {
                InvalidateEntry( pEntry );
                pEntry = pView->NextSelected( pEntry );
            }
        }
    }

    // ********************************************************************
    // SelectionEngine
    // ********************************************************************

    void SvImpLBox::SelectEntry( SvTreeListEntry* pEntry, bool bSelect )
    {
        pView->Select( pEntry, bSelect );
    }

    ImpLBSelEng::ImpLBSelEng( SvImpLBox* pImpl, SvTreeListBox* pV )
    {
        pImp = pImpl;
        pView = pV;
    }

    ImpLBSelEng::~ImpLBSelEng()
    {
    }

    void ImpLBSelEng::BeginDrag()
    {
        pImp->BeginDrag();
    }

    void ImpLBSelEng::CreateAnchor()
    {
        pImp->pAnchor = pImp->pCursor;
    }

    void ImpLBSelEng::DestroyAnchor()
    {
        pImp->pAnchor = nullptr;
    }

    void ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, bool bDontSelectAtCursor)
    {
        SvTreeListEntry* pNewCursor = pImp->MakePointVisible( rPoint );
        if( pNewCursor != pImp->pCursor  )
            pImp->BeginScroll();

        if( pNewCursor )
        {
            // at SimpleTravel, the SetCursor is selected and the select handler is
            // called
            //if( !bDontSelectAtCursor && !pImp->bSimpleTravel )
            //  pImp->SelectEntry( pNewCursor, true );
            pImp->SetCursor( pNewCursor, bDontSelectAtCursor );
        }
    }

    bool ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint )
    {
        SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint );
        if( pEntry )
            return pView->IsSelected(pEntry);
        return false;
    }

    void ImpLBSelEng::DeselectAtPoint( const Point& rPoint )
    {
        SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint );
        if( !pEntry )
            return;
        pImp->SelectEntry( pEntry, false );
    }

    void ImpLBSelEng::DeselectAll()
    {
        pImp->SelAllDestrAnch( false, false ); // don't reset SelectionEngine!
        pImp->nFlags &= (~LBoxFlags::DeselectAll);
    }

    // ***********************************************************************
    // Selection
    // ***********************************************************************

    void SvImpLBox::SetAnchorSelection(SvTreeListEntry* pOldCursor,SvTreeListEntry* pNewCursor)
    {
        SvTreeListEntry* pEntry;
        sal_uLong nAnchorVisPos = pView->GetVisiblePos( pAnchor );
        sal_uLong nOldVisPos = pView->GetVisiblePos( pOldCursor );
        sal_uLong nNewVisPos = pView->GetVisiblePos( pNewCursor );

        if( nOldVisPos > nAnchorVisPos ||
            ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) )
        {
            if( nNewVisPos > nOldVisPos )
            {
                pEntry = pOldCursor;
                while( pEntry && pEntry != pNewCursor )
                {
                    pView->Select( pEntry );
                    pEntry = pView->NextVisible(pEntry);
                }
                if( pEntry )
                    pView->Select( pEntry );
                return;
            }

            if( nNewVisPos < nAnchorVisPos )
            {
                pEntry = pAnchor;
                while( pEntry && pEntry != pOldCursor )
                {
                    pView->Select( pEntry, false );
                    pEntry = pView->NextVisible(pEntry);
                }
                if( pEntry )
                    pView->Select( pEntry, false );

                pEntry = pNewCursor;
                while( pEntry && pEntry != pAnchor )
                {
                    pView->Select( pEntry );
                    pEntry = pView->NextVisible(pEntry);
                }
                if( pEntry )
                    pView->Select( pEntry );
                return;
            }

            if( nNewVisPos < nOldVisPos )
            {
                pEntry = pNewCursor;
                pEntry = pView->NextVisible(pEntry);
                while( pEntry && pEntry != pOldCursor )
                {
                    pView->Select( pEntry, false );
                    pEntry = pView->NextVisible(pEntry);
                }
                if( pEntry )
                    pView->Select( pEntry, false );
                return;
            }
        }
        else
        {
            if( nNewVisPos < nOldVisPos )  // enlarge selection
            {
                pEntry = pNewCursor;
                while( pEntry && pEntry != pOldCursor )
                {
                    pView->Select( pEntry );
                    pEntry = pView->NextVisible(pEntry);
                }
                if( pEntry )
                    pView->Select( pEntry );
                return;
            }

            if( nNewVisPos > nAnchorVisPos )
            {
                pEntry = pOldCursor;
                while( pEntry && pEntry != pAnchor )
                {
                    pView->Select( pEntry, false );
                    pEntry = pView->NextVisible(pEntry);
                }
                if( pEntry )
                    pView->Select( pEntry, false );
                pEntry = pAnchor;
                while( pEntry && pEntry != pNewCursor )
                {
                    pView->Select( pEntry );
                    pEntry = pView->NextVisible(pEntry);
                }
                if( pEntry )
                    pView->Select( pEntry );
                return;
            }

            if( nNewVisPos > nOldVisPos )
            {
                pEntry = pOldCursor;
                while( pEntry && pEntry != pNewCursor )
                {
                    pView->Select( pEntry, false );
                    pEntry = pView->NextVisible(pEntry);
                }
                return;
            }
        }
    }

    void SvImpLBox::SelAllDestrAnch(
        bool bSelect, bool bDestroyAnchor, bool bSingleSelToo )
    {
        SvTreeListEntry* pEntry;
        nFlags &= (~LBoxFlags::DeselectAll);
        if( bSelect && bSimpleTravel )
        {
            if( pCursor && !pView->IsSelected( pCursor ))
            {
                pView->Select( pCursor );
            }
            return;
        }
        if( !bSelect && pView->GetSelectionCount() == 0 )
        {
            if( bSimpleTravel && ( !GetUpdateMode() || !pCursor) )
                nFlags |= LBoxFlags::DeselectAll;
            return;
        }
        if( bSelect && pView->GetSelectionCount() == pView->GetEntryCount())
            return;
        if( !bSingleSelToo && bSimpleTravel )
            return;

        if( !bSelect && pView->GetSelectionCount()==1 && pCursor &&
            pView->IsSelected( pCursor ))
        {
            pView->Select( pCursor, false );
            if( bDestroyAnchor )
                DestroyAnchor(); // delete anchor & reset SelectionEngine
            else
                pAnchor = nullptr; // always delete internal anchor
            return;
        }

        if( bSimpleTravel && !pCursor && !GetUpdateMode() )
            nFlags |= LBoxFlags::DeselectAll;

        ShowCursor( false );
        bool bUpdate = GetUpdateMode();

        nFlags |= LBoxFlags::IgnoreSelect; // EntryInserted should not do anything
        pEntry = pTree->First();
        while( pEntry )
        {
            if( pView->Select( pEntry, bSelect ) )
            {
                if( bUpdate && pView->IsEntryVisible(pEntry) )
                {
                    long nY = GetEntryLine( pEntry );
                    if( IsLineVisible( nY ) )
                        InvalidateEntry(pEntry);
                }
            }
            pEntry = pTree->Next( pEntry );
        }
        nFlags &= ~LBoxFlags::IgnoreSelect;

        if( bDestroyAnchor )
            DestroyAnchor(); // delete anchor & reset SelectionEngine
        else
            pAnchor = nullptr; // always delete internal anchor
        ShowCursor( true );
    }

    void SvImpLBox::SetSelectionMode( SelectionMode eSelMode  )
    {
        aSelEng.SetSelectionMode( eSelMode);
        if( eSelMode == SelectionMode::Single )
            bSimpleTravel = true;
        else
            bSimpleTravel = false;
        if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == SelectionMode::Multiple) )
            aSelEng.AddAlways( true );
    }

    // ***********************************************************************
    // Drag & Drop
    // ***********************************************************************

    void SvImpLBox::SetDragDropMode( DragDropMode eDDMode )
    {
        if( eDDMode != DragDropMode::NONE && eDDMode != DragDropMode::APP_DROP )
        {
            aSelEng.ExpandSelectionOnMouseMove( false );
            aSelEng.EnableDrag( true );
        }
        else
        {
            aSelEng.ExpandSelectionOnMouseMove();
            aSelEng.EnableDrag( false );
        }
    }

    void SvImpLBox::BeginDrag()
    {
        nFlags &= (~LBoxFlags::Filling);
        if( !bAsyncBeginDrag )
        {
            BeginScroll();
            pView->StartDrag( 0, aSelEng.GetMousePosPixel() );
            EndScroll();
        }
        else
        {
            aAsyncBeginDragPos = aSelEng.GetMousePosPixel();
            aAsyncBeginDragIdle.Start();
        }
    }

    IMPL_LINK_NOARG(SvImpLBox, BeginDragHdl, Timer *, void)
    {
        pView->StartDrag( 0, aAsyncBeginDragPos );
    }

    void SvImpLBox::PaintDDCursor( SvTreeListEntry* pInsertionPos )
    {
        long nY;
        if( pInsertionPos )
        {
            nY = GetEntryLine( pInsertionPos );
            nY += pView->GetEntryHeight();
        }
        else
            nY = 1;
        RasterOp eOldOp = pView->GetRasterOp();
        pView->SetRasterOp( RasterOp::Invert );
        Color aOldLineColor = pView->GetLineColor();
        pView->SetLineColor( COL_BLACK );
        pView->DrawLine( Point( 0, nY ), Point( aOutputSize.Width(), nY ) );
        pView->SetLineColor( aOldLineColor );
        pView->SetRasterOp( eOldOp );
    }

    void SvImpLBox::Command( const CommandEvent& rCEvt )
    {
        CommandEventId   nCommand = rCEvt.GetCommand();

        if( nCommand == CommandEventId::ContextMenu )
            aEditIdle.Stop();

        // scroll mouse event?
        if( ( ( nCommand == CommandEventId::Wheel ) || ( nCommand == CommandEventId::StartAutoScroll ) || ( nCommand == CommandEventId::AutoScroll ) )
            && pView->HandleScrollCommand( rCEvt, aHorSBar.get(), aVerSBar.get() ) )
                return;

        if( bContextMenuHandling && nCommand == CommandEventId::ContextMenu )
        {
            Point   aPopupPos;
            bool    bClickedIsFreePlace = false;
            std::stack<SvTreeListEntry*> aSelRestore;

            if( rCEvt.IsMouseEvent() )
            {   // change selection, if mouse position doesn't fit to selection

                aPopupPos = rCEvt.GetMousePosPixel();

                SvTreeListEntry*    pClickedEntry = GetEntry( aPopupPos );
                if( pClickedEntry )
                {   // mouse in non empty area
                    bool                bClickedIsSelected = false;

                    // collect the currently selected entries
                    SvTreeListEntry*        pSelected = pView->FirstSelected();
                    while( pSelected )
                    {
                        bClickedIsSelected |= ( pClickedEntry == pSelected );
                        pSelected = pView->NextSelected( pSelected );
                    }

                    // if the entry which the user clicked at is not selected
                    if( !bClickedIsSelected )
                    {   // deselect all other and select the clicked one
                        pView->SelectAll( false );
                        pView->SetCursor( pClickedEntry );
                    }
                }
                else if( aSelEng.GetSelectionMode() == SelectionMode::Single )
                {
                    bClickedIsFreePlace = true;
                    sal_Int32               nSelectedEntries = pView->GetSelectionCount();
                    SvTreeListEntry*        pSelected = pView->FirstSelected();
                    for(sal_Int32 nSel = 0; nSel < nSelectedEntries; nSel++ )
                    {
                        aSelRestore.push(pSelected);
                        pSelected = pView->NextSelected( pSelected );
                    }
                    pView->SelectAll( false );
                }
                else
                {   // deselect all
                    pView->SelectAll( false );
                }

            }
            else
            {   // key event (or at least no mouse event)
                sal_Int32   nSelectionCount = pView->GetSelectionCount();

                if( nSelectionCount )
                {   // now always take first visible as base for positioning the menu
                    SvTreeListEntry*    pSelected = pView->FirstSelected();
                    while( pSelected )
                    {
                        if( IsEntryInView( pSelected ) )
                            break;

                        pSelected = pView->NextSelected( pSelected );
                    }

                    if( !pSelected )
                    {
                        // no one was visible
                        pSelected = pView->FirstSelected();
                        pView->MakeVisible( pSelected );
                    }

                    aPopupPos = pView->GetFocusRect( pSelected, pView->GetEntryPosition( pSelected ).Y() ).Center();
                }
                else
                    aPopupPos = Point( 0, 0 );
            }

            {
                VclPtr<PopupMenu> pPopup = pView->CreateContextMenu();
                if (pPopup)
                {
                    // do action for selected entry in popup menu
                    sal_uInt16 nMenuAction = pPopup->Execute( pView, aPopupPos );
                    if ( nMenuAction )
                        pView->ExecuteContextMenuAction( nMenuAction );
                    pPopup.disposeAndClear();
                }
            }

            if( bClickedIsFreePlace )
            {
                while(!aSelRestore.empty())
                {
                    SvTreeListEntry* pEntry = aSelRestore.top();
                    //#i19717# the entry is maybe already deleted
                    bool bFound = false;
                    for(sal_uLong nEntry = 0; nEntry < pView->GetEntryCount(); nEntry++)
                        if(pEntry == pView->GetEntry(nEntry))
                        {
                            bFound = true;
                            break;
                        }
                    if(bFound)
                        SetCurEntry( pEntry );
                    aSelRestore.pop();
                }
            }
        }
        else
        {
            const Point& rPos = rCEvt.GetMousePosPixel();
            if( rPos.X() < aOutputSize.Width() && rPos.Y() < aOutputSize.Height() )
                aSelEng.Command( rCEvt );
        }
    }

    void SvImpLBox::BeginScroll()
    {
        if( !(nFlags & LBoxFlags::InScrolling))
        {
            nFlags |= LBoxFlags::InScrolling;
        }
    }

    void SvImpLBox::EndScroll()
    {
        if( nFlags & LBoxFlags::InScrolling)
        {
            pView->NotifyEndScroll();
            nFlags &= (~LBoxFlags::InScrolling);
        }
    }

    tools::Rectangle SvImpLBox::GetVisibleArea() const
    {
        Point aPos( pView->GetMapMode().GetOrigin() );
        aPos.setX( aPos.X() * -1 );
        tools::Rectangle aRect( aPos, aOutputSize );
        return aRect;
    }

    void SvImpLBox::Invalidate()
    {
        pView->SetClipRegion();
    }

    void SvImpLBox::SetCurEntry( SvTreeListEntry* pEntry )
    {
        if  (  ( aSelEng.GetSelectionMode() != SelectionMode::Single )
            && ( aSelEng.GetSelectionMode() != SelectionMode::NONE )
            )
            SelAllDestrAnch( false );
        if ( pEntry )
            MakeVisible( pEntry );
        SetCursor( pEntry );
        if ( pEntry && ( aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
            pView->Select( pEntry );
    }

    IMPL_LINK_NOARG(SvImpLBox, EditTimerCall, Timer *, void)
    {
        if( !pView->IsInplaceEditingEnabled() )
            return;

        bool bIsMouseTriggered = aEditClickPos.X() >= 0;
        if ( bIsMouseTriggered )
        {
            Point aCurrentMousePos = pView->GetPointerPosPixel();
            if  (   ( std::abs( aCurrentMousePos.X() - aEditClickPos.X() ) > 5 )
                ||  ( std::abs( aCurrentMousePos.Y() - aEditClickPos.Y() ) > 5 )
                )
            {
                return;
            }
        }

        SvTreeListEntry* pEntry = GetCurEntry();
        if( pEntry )
        {
            ShowCursor( false );
            pView->ImplEditEntry( pEntry );
            ShowCursor( true );
        }
    }

    bool SvImpLBox::RequestHelp( const HelpEvent& rHEvt )
    {
        if( rHEvt.GetMode() & HelpEventMode::QUICK )
        {
            Point aPos( pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() ));
            if( !GetVisibleArea().IsInside( aPos ))
                return false;

            SvTreeListEntry* pEntry = GetEntry( aPos );
            if( pEntry )
            {
                // recalculate text rectangle
                SvLBoxTab* pTab;
                SvLBoxItem* pItem = pView->GetItem( pEntry, aPos.X(), &pTab );
                if (!pItem || pItem->GetType() != SvLBoxItemType::String)
                    return false;

                aPos = GetEntryPosition( pEntry );
                aPos.setX( pView->GetTabPos( pEntry, pTab ) ); //pTab->GetPos();
                Size aSize( pItem->GetSize( pView, pEntry ) );
                SvLBoxTab* pNextTab = NextTab( pTab );
                bool bItemClipped = false;
                // is the item cut off by its right neighbor?
                if( pNextTab && pView->GetTabPos(pEntry,pNextTab) < aPos.X()+aSize.Width() )
                {
                    aSize.setWidth( pNextTab->GetPos() - pTab->GetPos() );
                    bItemClipped = true;
                }
                tools::Rectangle aItemRect( aPos, aSize );

                tools::Rectangle aViewRect( GetVisibleArea() );

                if( bItemClipped || !aViewRect.IsInside( aItemRect ) )
                {
                    // clip the right edge of the item at the edge of the view
                    //if( aItemRect.Right() > aViewRect.Right() )
                    //  aItemRect.Right() = aViewRect.Right();

                    Point aPt = pView->OutputToScreenPixel( aItemRect.TopLeft() );
                    aItemRect.SetLeft( aPt.X() );
                    aItemRect.SetTop( aPt.Y() );
                    aPt = pView->OutputToScreenPixel( aItemRect.BottomRight() );
                    aItemRect.SetRight( aPt.X() );
                    aItemRect.SetBottom( aPt.Y() );

                    Help::ShowQuickHelp( pView, aItemRect,
                                         static_cast<SvLBoxString*>(pItem)->GetText(), QuickHelpFlags::Left | QuickHelpFlags::VCenter );
                    return true;
                }
            }
        }
        return false;
    }

    SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab const * pTab )
    {
        sal_uInt16 nTabCount = pView->TabCount();
        if( nTabCount <= 1 )
            return nullptr;
        for( int nTab=0; nTab < (nTabCount-1); nTab++)
        {
            if( pView->aTabs[nTab]==pTab )
                return pView->aTabs[nTab+1];
        }
        return nullptr;
    }

    void SvImpLBox::EndSelection()
    {
        DestroyAnchor();
        nFlags &=  ~LBoxFlags::StartEditTimer;
    }

    void SvImpLBox::SetUpdateMode( bool bMode )
    {
        if( bUpdateMode != bMode )
        {
            bUpdateMode = bMode;
            if( bUpdateMode )
                UpdateAll( false );
        }
    }

    bool SvImpLBox::SetMostRight( SvTreeListEntry* pEntry )
    {
        if( pView->nTreeFlags & SvTreeFlags::RECALCTABS )
        {
            nFlags |= LBoxFlags::IgnoreChangedTabs;
            pView->SetTabs();
            nFlags &= ~LBoxFlags::IgnoreChangedTabs;
        }

        sal_uInt16 nLastTab = pView->aTabs.size() - 1;
        sal_uInt16 nLastItem = pEntry->ItemCount() - 1;
        if( !pView->aTabs.empty() && nLastItem != USHRT_MAX )
        {
            if( nLastItem < nLastTab )
                nLastTab = nLastItem;

            SvLBoxTab* pTab = pView->aTabs[ nLastTab ];
            SvLBoxItem& rItem = pEntry->GetItem( nLastTab );

            long nTabPos = pView->GetTabPos( pEntry, pTab );

            long nMaxRight = GetOutputSize().Width();
            Point aPos( pView->GetMapMode().GetOrigin() );
            aPos.setX( aPos.X() * -1 ); // conversion document coordinates
            nMaxRight = nMaxRight + aPos.X() - 1;

            long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50;
            long nTabWidth = nNextTab - nTabPos + 1;
            long nItemSize = rItem.GetSize(pView,pEntry).Width();
            long nOffset = pTab->CalcOffset( nItemSize, nTabWidth );

            long nRight = nTabPos + nOffset + nItemSize;
            if( nRight > nMostRight )
            {
                nMostRight = nRight;
                pMostRightEntry = pEntry;
                return true;
            }
        }
        return false;
    }

    void SvImpLBox::FindMostRight( SvTreeListEntry const * pEntryToIgnore )
    {
        nMostRight = -1;
        pMostRightEntry = nullptr;
        if( !pView->GetModel() )
            return;

        SvTreeListEntry* pEntry = pView->FirstVisible();
        while( pEntry )
        {
            if( pEntry != pEntryToIgnore )
                SetMostRight( pEntry );
            pEntry = pView->NextVisible( pEntry );
        }
    }

    void SvImpLBox::FindMostRight( SvTreeListEntry* pParent, SvTreeListEntry* pEntryToIgnore )
    {
        if( !pParent )
            FindMostRight( pEntryToIgnore );
        else
            FindMostRight_Impl( pParent, pEntryToIgnore  );
    }

    void SvImpLBox::FindMostRight_Impl( SvTreeListEntry* pParent, SvTreeListEntry* pEntryToIgnore )
    {
        SvTreeListEntries& rList = pTree->GetChildList( pParent );

        size_t nCount = rList.size();
        for( size_t nCur = 0; nCur < nCount; nCur++ )
        {
            SvTreeListEntry* pChild = rList[nCur].get();
            if( pChild != pEntryToIgnore )
            {
                SetMostRight( pChild );
                if( pChild->HasChildren() && pView->IsExpanded( pChild ))
                    FindMostRight_Impl( pChild, pEntryToIgnore );
            }
        }
    }

    void SvImpLBox::NotifyTabsChanged()
    {
        if( GetUpdateMode() && !(nFlags & LBoxFlags::IgnoreChangedTabs ) &&
            nCurUserEvent == nullptr )
        {
            nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent));
        }
    }

    bool SvImpLBox::IsExpandable() const
    {
        return pCursor->HasChildren() || pCursor->HasChildrenOnDemand();
    }

    IMPL_LINK(SvImpLBox, MyUserEvent, void*, pArg, void )
    {
        nCurUserEvent = nullptr;
        if( !pArg )
        {
            pView->Invalidate();
            pView->Update();
        }
        else
        {
            FindMostRight( nullptr );
            ShowVerSBar();
            pView->Invalidate( GetVisibleArea() );
        }
    }

    void SvImpLBox::StopUserEvent()
    {
        if( nCurUserEvent != nullptr )
        {
            Application::RemoveUserEvent( nCurUserEvent );
            nCurUserEvent = nullptr;
        }
    }

    void SvImpLBox::ShowFocusRect( const SvTreeListEntry* pEntry )
    {
        if( pEntry )
        {
            long nY = GetEntryLine( const_cast<SvTreeListEntry*>(pEntry) );
            tools::Rectangle aRect = pView->GetFocusRect( const_cast<SvTreeListEntry*>(pEntry), nY );
            vcl::Region aOldClip( pView->GetClipRegion());
            vcl::Region aClipRegion( GetClipRegionRect() );
            pView->SetClipRegion( aClipRegion );
            pView->ShowFocus( aRect );
            pView->SetClipRegion( aOldClip );

        }
        else
        {
            pView->HideFocus();
        }
    }

    void SvImpLBox::implInitDefaultNodeImages()
    {
        if ( s_pDefCollapsed )
            // assume that all or nothing is initialized
            return;

        s_pDefCollapsed = new Image(BitmapEx(RID_BMP_TREENODE_COLLAPSED));
        s_pDefExpanded = new Image(BitmapEx(RID_BMP_TREENODE_EXPANDED));
    }

    const Image& SvImpLBox::GetDefaultExpandedNodeImage( )
    {
        implInitDefaultNodeImages();
        return *s_pDefExpanded;
    }

    const Image& SvImpLBox::GetDefaultCollapsedNodeImage( )
    {
        implInitDefaultNodeImages();
        return *s_pDefCollapsed;
    }

    void SvImpLBox::CallEventListeners( VclEventId nEvent, void* pData )
    {
        if ( pView )
            pView->CallImplEventListeners( nEvent, pData);
    }

    bool SvImpLBox::SetCurrentTabPos( sal_uInt16 _nNewPos )
    {
        bool bRet = false;

        if ( pView && _nNewPos < ( pView->TabCount() - 2 ) )
        {
            nCurTabPos = _nNewPos;
            ShowCursor( true );
            bRet = true;
        }

        return bRet;
    }

    bool SvImpLBox::IsSelectable( const SvTreeListEntry* pEntry )
    {
        if( pEntry )
        {
            SvViewDataEntry* pViewDataNewCur = pView->GetViewDataEntry(pEntry);
            return (pViewDataNewCur == nullptr) || pViewDataNewCur->IsSelectable();
        }
        else
        {
            return false;
        }
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V560 A part of conditional expression is always true: pCursor.

↑ V560 A part of conditional expression is always true: pCursor.

↑ V547 Expression 'pCursor' is always true.

↑ V547 Expression 'pCursor' is always true.