diff options
Diffstat (limited to 'svtools/source/contnr/svimpbox.cxx')
-rw-r--r-- | svtools/source/contnr/svimpbox.cxx | 3630 |
1 files changed, 3630 insertions, 0 deletions
diff --git a/svtools/source/contnr/svimpbox.cxx b/svtools/source/contnr/svimpbox.cxx new file mode 100644 index 000000000000..74c6bb163797 --- /dev/null +++ b/svtools/source/contnr/svimpbox.cxx @@ -0,0 +1,3630 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" +#include <vcl/svapp.hxx> +#include <vcl/salnativewidgets.hxx> +#include <vcl/help.hxx> +#include <svtools/tabbar.hxx> + +#include <stack> + +#define _SVTREEBX_CXX +#include <svtools/svtreebx.hxx> +#include <svtools/svlbox.hxx> +#include <svimpbox.hxx> +#include <rtl/instance.hxx> +#include <svtools/svtdata.hxx> +#include <tools/wintypes.hxx> +#include <svtools/svtools.hrc> +#include <comphelper/processfactory.hxx> + +#define NODE_BMP_TABDIST_NOTVALID -2000000 +#define FIRST_ENTRY_TAB 1 + +// #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors +Image* SvImpLBox::s_pDefCollapsed = NULL; +Image* SvImpLBox::s_pDefExpanded = NULL; +Image* SvImpLBox::s_pDefCollapsedHC = NULL; +Image* SvImpLBox::s_pDefExpandedHC = NULL; +sal_Int32 SvImpLBox::s_nImageRefCount = 0; + +SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvLBoxTreeList* pLBTree, WinBits nWinStyle) : + + pTabBar( NULL ), + aVerSBar( pLBView, WB_DRAG | WB_VSCROLL ), + aHorSBar( pLBView, WB_DRAG | WB_HSCROLL ), + aScrBarBox( pLBView ), + aOutputSize( 0, 0 ), + aSelEng( pLBView, (FunctionSet*)0 ), + aFctSet( this, &aSelEng, pLBView ), + nExtendedWinBits( 0 ), + bAreChildrenTransient( sal_True ), + pIntlWrapper( NULL ) // #102891# ----------------------- +{ + osl_incrementInterlockedCount(&s_nImageRefCount); + pView = pLBView; + pTree = pLBTree; + aSelEng.SetFunctionSet( (FunctionSet*)&aFctSet ); + aSelEng.ExpandSelectionOnMouseMove( FALSE ); + SetStyle( nWinStyle ); + SetSelectionMode( SINGLE_SELECTION ); + SetDragDropMode( 0 ); + + 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 ); // Pixel + aHorSBar.SetLineSize( 8 ); // Pixel + + nHorSBarHeight = (short)aHorSBar.GetSizePixel().Height(); + nVerSBarWidth = (short)aVerSBar.GetSizePixel().Width(); + + pStartEntry = 0; + pCursor = 0; + pAnchor = 0; + nVisibleCount = 0; // Anzahl Daten-Zeilen im Control + nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID; + nYoffsNodeBmp = 0; + nNodeBmpWidth = 0; + + bAsyncBeginDrag = FALSE; + aAsyncBeginDragTimer.SetTimeout( 0 ); + aAsyncBeginDragTimer.SetTimeoutHdl( LINK(this,SvImpLBox,BeginDragHdl)); + // Button-Animation in Listbox + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + + nFlags = 0; + nCurTabPos = FIRST_ENTRY_TAB; + + aEditTimer.SetTimeout( 800 ); + aEditTimer.SetTimeoutHdl( LINK(this,SvImpLBox,EditTimerCall) ); + + nMostRight = -1; + pMostRightEntry = 0; + nCurUserEvent = 0xffffffff; + + bUpdateMode = TRUE; + bInVScrollHdl = FALSE; + nFlags |= F_FILLING; + + bSubLstOpRet = bSubLstOpLR = bContextMenuHandling = bIsCellFocusEnabled = FALSE; +} + +SvImpLBox::~SvImpLBox() +{ + aEditTimer.Stop(); + StopUserEvent(); + + // #102891# --------------------- + if( pIntlWrapper ) + delete pIntlWrapper; + if ( osl_decrementInterlockedCount(&s_nImageRefCount) == 0 ) + { + DELETEZ(s_pDefCollapsed); + DELETEZ(s_pDefExpanded); + DELETEZ(s_pDefCollapsedHC); + DELETEZ(s_pDefExpandedHC); + } +} + +// #102891# -------------------- +void SvImpLBox::UpdateIntlWrapper() +{ + const ::com::sun::star::lang::Locale & aNewLocale = Application::GetSettings().GetLocale(); + if( !pIntlWrapper ) + pIntlWrapper = new IntlWrapper( ::comphelper::getProcessServiceFactory(), aNewLocale ); + else + { + const ::com::sun::star::lang::Locale &aLocale = pIntlWrapper->getLocale(); + if( aLocale.Language != aNewLocale.Language || // different Locale from the older one + aLocale.Country != aNewLocale.Country || + aLocale.Variant != aNewLocale.Variant ) + { + delete pIntlWrapper; + pIntlWrapper = new IntlWrapper( ::comphelper::getProcessServiceFactory(), aNewLocale ); + } + } +} + +// #97680# ---------------------- +short SvImpLBox::UpdateContextBmpWidthVector( SvLBoxEntry* pEntry, short nWidth ) +{ + DBG_ASSERT( pView->pModel, "View and Model aren't valid!" ); + + USHORT 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( SvLBoxEntry* pEntry ) +{ + DBG_ASSERT( pEntry, "Moved Entry is invalid!" ); + + SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) ); + short nExpWidth = (short)pBmpItem->GetBitmap1().GetSizePixel().Width(); + short nColWidth = (short)pBmpItem->GetBitmap2().GetSizePixel().Width(); + short nMax = Max(nExpWidth, nColWidth); + UpdateContextBmpWidthVector( pEntry, nMax ); + + if( pEntry->HasChilds() ) // recursive call, whether expanded or not + { + SvLBoxEntry* pChild = pView->FirstChild( pEntry ); + DBG_ASSERT( pChild, "The first child is invalid!" ); + do + { + UpdateContextBmpWidthVectorFromMovedEntry( pChild ); + pChild = pView->Next( pChild ); + } while ( pChild ); + } +} + +void SvImpLBox::UpdateContextBmpWidthMax( SvLBoxEntry* pEntry ) +{ + USHORT nDepth = pView->pModel->GetDepth( pEntry ); + if( aContextBmpWidthVector.size() < 1 ) + return; + short nWidth = aContextBmpWidthVector[ nDepth ]; + if( nWidth != pView->nContextBmpWidthMax ) { + pView->nContextBmpWidthMax = nWidth; + nFlags |= F_IGNORE_CHANGED_TABS; + pView->SetTabs(); + nFlags &= ~F_IGNORE_CHANGED_TABS; + } +} + +void SvImpLBox::CalcCellFocusRect( SvLBoxEntry* pEntry, Rectangle& rRect ) +{ + if ( pEntry && bIsCellFocusEnabled ) + { + if ( nCurTabPos > FIRST_ENTRY_TAB ) + { + SvLBoxItem* pItem = pCursor->GetItem( nCurTabPos ); + rRect.Left() = pView->GetTab( pCursor, pItem )->GetPos(); + } + if ( pCursor->ItemCount() > ( nCurTabPos + 1 ) ) + { + SvLBoxItem* pNextItem = pCursor->GetItem( nCurTabPos + 1 ); + long nRight = pView->GetTab( pCursor, pNextItem )->GetPos() - 1; + if ( nRight < rRect.Right() ) + rRect.Right() = nRight; + } + } +} + +void SvImpLBox::SetStyle( WinBits i_nWinStyle ) +{ + m_nStyle = i_nWinStyle; + if ( ( m_nStyle & WB_SIMPLEMODE) && ( aSelEng.GetSelectionMode() == MULTIPLE_SELECTION ) ) + aSelEng.AddAlways( TRUE ); +} + +void SvImpLBox::SetExtendedWindowBits( ExtendedWinBits _nBits ) +{ + nExtendedWinBits = _nBits; +} + +// Das Model darf hier nicht mehr angefasst werden +void SvImpLBox::Clear() +{ + StopUserEvent(); + pStartEntry = 0; + pAnchor = 0; + + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + + nMostRight = -1; + pMostRightEntry = 0; + + // Der Cursor darf hier nicht mehr angefasst werden! + if( pCursor ) + { + if( pView->HasFocus() ) + pView->HideFocus(); + pCursor = 0; + } + aVerSBar.Hide(); + aVerSBar.SetThumbPos( 0 ); + Range aRange( 0, 0 ); + aVerSBar.SetRange( aRange ); + aOutputSize = pView->Control::GetOutputSizePixel(); + nFlags &= ~(F_VER_SBARSIZE_WITH_HBAR | F_HOR_SBARSIZE_WITH_VBAR ); + if( pTabBar ) + { + aOutputSize.Height() -= nHorSBarHeight; + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + if( !pTabBar ) + 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 |= F_FILLING; + if( !aHorSBar.IsVisible() && !aVerSBar.IsVisible() ) + aScrBarBox.Hide(); + + // #97680# --------- + aContextBmpWidthVector.clear(); +} + +// ********************************************************************* +// Painten, Navigieren, Scrollen +// ********************************************************************* + +IMPL_LINK_INLINE_START( SvImpLBox, EndScrollHdl, ScrollBar *, EMPTYARG ) +{ + if( nFlags & F_ENDSCROLL_SET_VIS_SIZE ) + { + aVerSBar.SetVisibleSize( nNextVerVisSize ); + nFlags &= ~F_ENDSCROLL_SET_VIS_SIZE; + } + EndScroll(); + return 0; +} +IMPL_LINK_INLINE_END( SvImpLBox, EndScrollHdl, ScrollBar *, pScrollBar ) + + +// Handler vertikale ScrollBar + +IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar ) +{ + DBG_ASSERT(!bInVScrollHdl,"Scroll-Handler ueberholt sich!"); + long nDelta = pScrollBar->GetDelta(); + if( !nDelta ) + return 0; + + nFlags &= (~F_FILLING); + + bInVScrollHdl = TRUE; + + if( pView->IsEditingActive() ) + { + pView->EndEditing( TRUE ); // Cancel + pView->Update(); + } + BeginScroll(); + + if( nDelta > 0 ) + { + if( nDelta == 1 ) + CursorDown(); + else + PageDown( (USHORT) nDelta ); + } + else + { + nDelta *= (-1); + if( nDelta == 1 ) + CursorUp(); + else + PageUp( (USHORT) nDelta ); + } + bInVScrollHdl = FALSE; + return 0; +} + + +void SvImpLBox::CursorDown() +{ + SvLBoxEntry* pNextFirstToDraw = (SvLBoxEntry*)(pView->NextVisible( pStartEntry)); + if( pNextFirstToDraw ) + { + nFlags &= (~F_FILLING); + pView->NotifyScrolling( -1 ); + ShowCursor( FALSE ); + pView->Update(); + pStartEntry = pNextFirstToDraw; + Rectangle aArea( GetVisibleArea() ); + pView->Scroll( 0, -(pView->GetEntryHeight()), aArea, SCROLL_NOCHILDREN ); + pView->Update(); + ShowCursor( TRUE ); + pView->NotifyScrolled(); + } +} + +void SvImpLBox::CursorUp() +{ + SvLBoxEntry* pPrevFirstToDraw = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry)); + if( pPrevFirstToDraw ) + { + nFlags &= (~F_FILLING); + long nEntryHeight = pView->GetEntryHeight(); + pView->NotifyScrolling( 1 ); + ShowCursor( FALSE ); + pView->Update(); + pStartEntry = pPrevFirstToDraw; + Rectangle aArea( GetVisibleArea() ); + aArea.Bottom() -= nEntryHeight; + pView->Scroll( 0, nEntryHeight, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + ShowCursor( TRUE ); + pView->NotifyScrolled(); + } +} + +void SvImpLBox::PageDown( USHORT nDelta ) +{ + USHORT nRealDelta = nDelta; + + if( !nDelta ) + return; + + SvLBoxEntry* pNext; + pNext = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nRealDelta )); + if( (ULONG)pNext == (ULONG)pStartEntry ) + return; + + ShowCursor( FALSE ); + + nFlags &= (~F_FILLING); + pView->Update(); + pStartEntry = pNext; + + if( nRealDelta >= nVisibleCount ) + { + pView->Invalidate( GetVisibleArea() ); + pView->Update(); + } + else + { + long nScroll = nRealDelta * (-1); + pView->NotifyScrolling( nScroll ); + Rectangle aArea( GetVisibleArea() ); + nScroll = pView->GetEntryHeight()*nRealDelta; + nScroll = -nScroll; + pView->Update(); + pView->Scroll( 0, nScroll, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + pView->NotifyScrolled(); + } + + ShowCursor( TRUE ); +} + +void SvImpLBox::PageUp( USHORT nDelta ) +{ + USHORT nRealDelta = nDelta; + if( !nDelta ) + return; + + SvLBoxEntry* pPrev = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry, nRealDelta )); + if( (ULONG)pPrev == (ULONG)pStartEntry ) + return; + + nFlags &= (~F_FILLING); + ShowCursor( FALSE ); + + pView->Update(); + pStartEntry = pPrev; + if( nRealDelta >= nVisibleCount ) + { + pView->Invalidate( GetVisibleArea() ); + pView->Update(); + } + else + { + long nEntryHeight = pView->GetEntryHeight(); + pView->NotifyScrolling( (long)nRealDelta ); + Rectangle aArea( GetVisibleArea() ); + pView->Update(); + pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + pView->NotifyScrolled(); + } + + ShowCursor( TRUE ); +} + +void SvImpLBox::KeyUp( BOOL bPageUp, BOOL bNotifyScroll ) +{ + 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 &= (~F_FILLING); + if( bNotifyScroll ) + BeginScroll(); + + aVerSBar.SetThumbPos( nThumbPos - nDelta ); + if( bPageUp ) + PageUp( (short)nDelta ); + else + CursorUp(); + + if( bNotifyScroll ) + EndScroll(); +} + + +void SvImpLBox::KeyDown( BOOL bPageDown, BOOL bNotifyScroll ) +{ + 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 &= (~F_FILLING); + if( bNotifyScroll ) + BeginScroll(); + + aVerSBar.SetThumbPos( nThumbPos+nDelta ); + if( bPageDown ) + PageDown( (short)nDelta ); + else + CursorDown(); + + if( bNotifyScroll ) + EndScroll(); +} + + + +void SvImpLBox::InvalidateEntriesFrom( long nY ) const +{ + if( !(nFlags & F_IN_PAINT )) + { + Rectangle aRect( GetVisibleArea() ); + aRect.Top() = nY; + pView->Invalidate( aRect ); + } +} + +void SvImpLBox::InvalidateEntry( long nY ) const +{ + if( !(nFlags & F_IN_PAINT )) + { + Rectangle aRect( GetVisibleArea() ); + long nMaxBottom = aRect.Bottom(); + aRect.Top() = nY; + aRect.Bottom() = nY; aRect.Bottom() += pView->GetEntryHeight(); + if( aRect.Top() > nMaxBottom ) + return; + if( aRect.Bottom() > nMaxBottom ) + aRect.Bottom() = nMaxBottom; + pView->Invalidate( aRect ); + } +} + +void SvImpLBox::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + if( GetUpdateMode() ) + { + long nPrev = nMostRight; + SetMostRight( pEntry ); + if( nPrev < nMostRight ) + ShowVerSBar(); + } + if( !(nFlags & F_IN_PAINT )) + { + 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 ); + Rectangle aRect = pView->GetFocusRect( pCursor, nY ); + CalcCellFocusRect( pCursor, aRect ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + } +} + +// +// Setzt Cursor. Passt bei SingleSelection die Selektion an +// + +void SvImpLBox::SetCursor( SvLBoxEntry* pEntry, BOOL bForceNoSelect ) +{ + SvViewDataEntry* pViewDataNewCur = 0; + if( pEntry ) + pViewDataNewCur= pView->GetViewDataEntry(pEntry); + if( pEntry && + pEntry == pCursor && + 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 = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + pViewDataNewCur = pEntry ? pView->GetViewDataEntry(pEntry) : 0; + } + + SvLBoxEntry* pOldCursor = pCursor; + if( pCursor && pEntry != pCursor ) + { + pView->SetEntryFocus( pCursor, FALSE ); + if( bSimpleTravel ) + pView->Select( pCursor, FALSE ); + pView->HideFocus(); + } + pCursor = pEntry; + if( pCursor ) + { + pViewDataNewCur->SetFocus( TRUE ); + if(!bForceNoSelect && bSimpleTravel && !(nFlags & F_DESEL_ALL) && GetUpdateMode()) + { + pView->Select( pCursor, TRUE ); + } + // Mehrfachselektion: Im Cursor-Move selektieren, wenn + // nicht im Add-Mode (Ctrl-F8) + else if( GetUpdateMode() && + pView->GetSelectionMode() == MULTIPLE_SELECTION && + !(nFlags & F_DESEL_ALL) && !aSelEng.IsAddMode() && + !bForceNoSelect ) + { + pView->Select( pCursor, TRUE ); + } + else + { + ShowCursor( TRUE ); + } + + if( pAnchor ) + { + DBG_ASSERT(aSelEng.GetSelectionMode() != SINGLE_SELECTION,"Mode?"); + SetAnchorSelection( pOldCursor, pCursor ); + } + } + nFlags &= (~F_DESEL_ALL); + + pView->OnCurrentEntryChanged(); +} + +void SvImpLBox::ShowCursor( BOOL bShow ) +{ + if( !bShow || !pCursor || !pView->HasFocus() ) + { + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->HideFocus(); + pView->SetClipRegion( aOldClip ); + } + else + { + long nY = GetEntryLine( pCursor ); + Rectangle aRect = pView->GetFocusRect( pCursor, nY ); + CalcCellFocusRect( pCursor, aRect ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + } +} + + + +void SvImpLBox::UpdateAll( BOOL bInvalidateCompleteView, + BOOL bUpdateVerScrollBar ) +{ + if( bUpdateVerScrollBar ) + FindMostRight(0); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + SyncVerThumb(); + FillView(); + ShowVerSBar(); + if( bSimpleTravel && pCursor && pView->HasFocus() ) + pView->Select( pCursor, TRUE ); + ShowCursor( TRUE ); + if( bInvalidateCompleteView ) + pView->Invalidate(); + else + pView->Invalidate( GetVisibleArea() ); +} + +IMPL_LINK_INLINE_START( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) +{ + long nDelta = pScrollBar->GetDelta(); + if( nDelta ) + { + if( pView->IsEditingActive() ) + { + pView->EndEditing( TRUE ); // Cancel + pView->Update(); + } + pView->nFocusWidth = -1; + KeyLeftRight( nDelta ); + } + return 0; +} +IMPL_LINK_INLINE_END( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) + +void SvImpLBox::KeyLeftRight( long nDelta ) +{ + if( !(nFlags & F_IN_RESIZE) ) + pView->Update(); + BeginScroll(); + nFlags &= (~F_FILLING); + pView->NotifyScrolling( 0 ); // 0 == horizontales Scrolling + ShowCursor( FALSE ); + + // neuen Origin berechnen + long nPos = aHorSBar.GetThumbPos(); + Point aOrigin( -nPos, 0 ); + + MapMode aMapMode( pView->GetMapMode() ); + aMapMode.SetOrigin( aOrigin ); + pView->SetMapMode( aMapMode ); + + if( !(nFlags & F_IN_RESIZE) ) + { + Rectangle aRect( GetVisibleArea() ); + pView->Scroll( -nDelta, 0, aRect, SCROLL_NOCHILDREN ); + } + else + pView->Invalidate(); + RecalcFocusRect(); + ShowCursor( TRUE ); + pView->NotifyScrolled(); +} + + +// gibt letzten Eintrag zurueck, wenn Position unter +// dem letzten Eintrag ist +SvLBoxEntry* 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 NULL; + if( pView->GetEntryCount() == 0 || !pStartEntry || !pView->GetEntryHeight()) + return 0; + + USHORT nClickedEntry = (USHORT)(rPoint.Y() / pView->GetEntryHeight() ); + USHORT nTemp = nClickedEntry; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp )); + return pEntry; +} + +// +// prueft, ob der Eintrag "richtig" getroffen wurde +// (Focusrect+ ContextBitmap bei TreeListBox) +// +BOOL SvImpLBox::EntryReallyHit(SvLBoxEntry* pEntry,const Point& rPosPixel,long nLine) +{ + BOOL bRet; + // bei "besonderen" Entries (mit CheckButtons usw.) sind wir + // nicht so pingelig + if( pEntry->ItemCount() >= 3 ) + return TRUE; + + Rectangle aRect( pView->GetFocusRect( pEntry, nLine )); + aRect.Right() = GetOutputSize().Width() - pView->GetMapMode().GetOrigin().X(); + if( pView->IsA() == SV_LISTBOX_ID_TREEBOX ) + { + SvLBoxContextBmp* pBmp = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + aRect.Left() -= pBmp->GetSize(pView,pEntry).Width(); + aRect.Left() -= 4; // etwas Speilraum lassen + } + Point aPos( rPosPixel ); + aPos -= pView->GetMapMode().GetOrigin(); + if( aRect.IsInside( aPos ) ) + bRet = TRUE; + else + bRet = FALSE; + return bRet; +} + + +// gibt 0 zurueck, wenn Position unter dem letzten Eintrag ist +SvLBoxEntry* SvImpLBox::GetEntry( const Point& rPoint ) const +{ + if( (pView->GetEntryCount() == 0) || !pStartEntry || + (rPoint.Y() > aOutputSize.Height()) + || !pView->GetEntryHeight()) + return 0; + + USHORT nClickedEntry = (USHORT)(rPoint.Y() / pView->GetEntryHeight() ); + USHORT nTemp = nClickedEntry; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp )); + if( nTemp != nClickedEntry ) + pEntry = 0; + return pEntry; +} + + +SvLBoxEntry* SvImpLBox::MakePointVisible(const Point& rPoint,BOOL bNotifyScroll) +{ + if( !pCursor ) + return 0; + long nY = rPoint.Y(); + SvLBoxEntry* pEntry = 0; + long nMax = aOutputSize.Height(); + if( nY < 0 || nY >= nMax ) // aOutputSize.Height() ) + { + if( nY < 0 ) + pEntry = (SvLBoxEntry*)(pView->PrevVisible( pCursor )); + else + pEntry = (SvLBoxEntry*)(pView->NextVisible( pCursor )); + + if( pEntry && pEntry != pCursor ) + pView->SetEntryFocus( pCursor, FALSE ); + + if( nY < 0 ) + KeyUp( FALSE, bNotifyScroll ); + else + KeyDown( FALSE, bNotifyScroll ); + } + else + { + pEntry = GetClickedEntry( rPoint ); + if( !pEntry ) + { + USHORT nSteps = 0xFFFF; + // LastVisible ist noch nicht implementiert! + pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nSteps )); + } + if( pEntry ) + { + if( pEntry != pCursor && + aSelEng.GetSelectionMode() == SINGLE_SELECTION + ) + pView->Select( pCursor, FALSE ); + } + } + return pEntry; +} + +Rectangle SvImpLBox::GetClipRegionRect() const +{ + Point aOrigin( pView->GetMapMode().GetOrigin() ); + aOrigin.X() *= -1; // Umrechnung Dokumentkoord. + Rectangle aClipRect( aOrigin, aOutputSize ); + aClipRect.Bottom()++; + return aClipRect; +} + + +void SvImpLBox::Paint( const Rectangle& rRect ) +{ + if( !pView->GetVisibleCount() ) + return; + + nFlags |= F_IN_PAINT; + + if( nFlags & F_FILLING ) + { + SvLBoxEntry* pFirst = pView->First(); + if( pFirst != pStartEntry ) + { + ShowCursor( FALSE ); + pStartEntry = pView->First(); + aVerSBar.SetThumbPos( 0 ); + StopUserEvent(); + ShowCursor( TRUE ); + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)1); + return; + } + } + + if( !pStartEntry ) + { + pStartEntry = pView->First(); + } + +#ifdef XX_OV + ULONG nXAbsPos = (USHORT)pTree->GetAbsPos( pStartEntry ); + ULONG nXVisPos = pView->GetVisiblePos( pStartEntry ); + SvLBoxString* pXStr = (SvLBoxString*)pStartEntry->GetFirstItem( SV_ITEM_ID_LBOXSTRING); +#endif + + + + if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID ) + SetNodeBmpTabDistance(); + + long nRectHeight = rRect.GetHeight(); + long nEntryHeight = pView->GetEntryHeight(); + + // Bereich der zu zeichnenden Entries berechnen + USHORT nStartLine = (USHORT)( rRect.Top() / nEntryHeight ); + USHORT nCount = (USHORT)( nRectHeight / nEntryHeight ); + nCount += 2; // keine Zeile vergessen + + long nY = nStartLine * nEntryHeight; + SvLBoxEntry* pEntry = pStartEntry; + while( nStartLine && pEntry ) + { + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + nStartLine--; + } + + Region aClipRegion( GetClipRegionRect() ); + + // erst die Linien Zeichnen, dann clippen! + pView->SetClipRegion(); + if( m_nStyle & ( WB_HASLINES | WB_HASLINESATROOT ) ) + DrawNet(); + + pView->SetClipRegion( aClipRegion ); + + for( USHORT n=0; n< nCount && pEntry; n++ ) + { + /*long nMaxRight=*/ + pView->PaintEntry1( pEntry, nY, 0xffff, TRUE ); + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + + if ( !pCursor && ( ( nExtendedWinBits & EWB_NO_AUTO_CURENTRY ) == 0 ) ) + { + // do not select if multiselection or explicit set + BOOL bNotSelect = ( aSelEng.GetSelectionMode() == MULTIPLE_SELECTION ) + || ( ( m_nStyle & WB_NOINITIALSELECTION ) == WB_NOINITIALSELECTION ); + SetCursor( pStartEntry, bNotSelect ); + } + + nFlags &= (~F_DESEL_ALL); + pView->SetClipRegion(); + Rectangle aRect; + if( !(nFlags & F_PAINTED) ) + { + nFlags |= F_PAINTED; + RepaintScrollBars(); + } + nFlags &= (~F_IN_PAINT); +} + +void SvImpLBox::MakeVisible( SvLBoxEntry* pEntry, BOOL bMoveToTop ) +{ + if( !pEntry ) + return; + + BOOL bInView = IsEntryInView( pEntry ); + + if( bInView && (!bMoveToTop || pStartEntry == pEntry) ) + return; // ist schon sichtbar + + if( pStartEntry || (m_nStyle & WB_FORCE_MAKEVISIBLE) ) + nFlags &= (~F_FILLING); + if( !bInView ) + { + if( !pView->IsEntryVisible(pEntry) ) // Parent(s) zugeklappt ? + { + SvLBoxEntry* pParent = pView->GetParent( pEntry ); + while( pParent ) + { + if( !pView->IsExpanded( pParent ) ) + { + #ifdef DBG_UTIL + BOOL bRet = + #endif + pView->Expand( pParent ); + DBG_ASSERT(bRet,"Not expanded!"); + } + pParent = pView->GetParent( pParent ); + } + // Passen Childs der Parents in View oder muessen wir scrollen ? + if( IsEntryInView( pEntry ) && !bMoveToTop ) + return; // Scrollen nicht noetig -> tschuess + } + } + + pStartEntry = pEntry; + ShowCursor( FALSE ); + FillView(); + aVerSBar.SetThumbPos( (long)(pView->GetVisiblePos( pStartEntry )) ); + ShowCursor( TRUE ); + pView->Invalidate(); +} + + +void SvImpLBox::RepaintSelectionItems() +{ + if( !pView->GetVisibleCount() ) + return; + + if( !pStartEntry ) + pStartEntry = pView->First(); + + if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID ) + SetNodeBmpTabDistance(); + + ShowCursor( FALSE ); + + long nEntryHeight = pView->GetEntryHeight(); + + ULONG nCount = nVisibleCount; + long nY = 0; + SvLBoxEntry* pEntry = pStartEntry; + for( ULONG n=0; n< nCount && pEntry; n++ ) + { + pView->PaintEntry1( pEntry, nY, 0xffff ); //wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + + ShowCursor( TRUE ); +} + + +void SvImpLBox::DrawNet() +{ + if( pView->GetVisibleCount() < 2 && !pStartEntry->HasChildsOnDemand() && + !pStartEntry->HasChilds() ) + return; + + //for platforms who don't have nets, DrawNativeControl does nothing and return true + //so that SvImpLBox::DrawNet() doesn't draw anything too + if(pView->IsNativeControlSupported( CTRL_LISTNET, PART_ENTIRE_CONTROL)) { + ImplControlValue aControlValue; + Point aTemp(0,0); // temporary needed for g++ 3.3.5 + Rectangle aCtrlRegion( aTemp, Size( 0, 0 ) ); + ControlState nState = CTRL_STATE_ENABLED; + if( pView->DrawNativeControl( CTRL_LISTNET, PART_ENTIRE_CONTROL, + aCtrlRegion, nState, aControlValue, rtl::OUString() ) ) + { + return; + } + + } + + long nEntryHeight = pView->GetEntryHeight(); + long nEntryHeightDIV2 = nEntryHeight / 2; + if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001)) + nEntryHeightDIV2--; + + SvLBoxEntry* pChild; + SvLBoxEntry* pEntry = pStartEntry; + + SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab(); + while( pTree->GetDepth( pEntry ) > 0 ) + pEntry = pView->GetParent( pEntry ); + USHORT nOffs = (USHORT)(pView->GetVisiblePos( pStartEntry ) - + pView->GetVisiblePos( pEntry )); + long nY = 0; + nY -= ( nOffs * nEntryHeight ); + + DBG_ASSERT(pFirstDynamicTab,"No Tree!"); + + Color aOldLineColor = pView->GetLineColor(); + const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings(); + Color aCol= rStyleSettings.GetFaceColor(); + + if( aCol.IsRGBEqual( pView->GetBackground().GetColor()) ) + aCol = rStyleSettings.GetShadowColor(); + pView->SetLineColor( aCol ); + Point aPos1, aPos2; + USHORT nDistance; + ULONG nMax = nVisibleCount + nOffs + 1; + + const Image& rExpandedNodeBitmap = GetExpandedNodeBmp(); + + for( ULONG n=0; n< nMax && pEntry; n++ ) + { + if( pView->IsExpanded(pEntry) ) + { + aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2; + + aPos1.Y() = nY; + aPos1.Y() += nEntryHeightDIV2; + + pChild = pView->FirstChild( pEntry ); + DBG_ASSERT(pChild,"Child?"); + pChild = pTree->LastSibling( pChild ); + nDistance = (USHORT)(pView->GetVisiblePos(pChild) - + pView->GetVisiblePos(pEntry)); + aPos2 = aPos1; + aPos2.Y() += nDistance * nEntryHeight; + pView->DrawLine( aPos1, aPos2 ); + } + // Sichtbar im Control ? + if( n>= nOffs && ((m_nStyle & WB_HASLINESATROOT) || !pTree->IsAtRootDepth(pEntry))) + { + // kann aPos1 recyclet werden ? + if( !pView->IsExpanded(pEntry) ) + { + // njet + aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2; + aPos1.Y() = nY; + aPos1.Y() += nEntryHeightDIV2; + aPos2.X() = aPos1.X(); + } + aPos2.Y() = aPos1.Y(); + aPos2.X() -= pView->GetIndent(); + pView->DrawLine( aPos1, aPos2 ); + } + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( m_nStyle & WB_HASLINESATROOT ) + { + pEntry = pView->First(); + aPos1.X() = pView->GetTabPos( pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2; + aPos1.X() -= pView->GetIndent(); + aPos1.Y() = GetEntryLine( pEntry ); + aPos1.Y() += nEntryHeightDIV2; + pChild = pTree->LastSibling( pEntry ); + aPos2.X() = aPos1.X(); + aPos2.Y() = GetEntryLine( pChild ); + aPos2.Y() += nEntryHeightDIV2; + pView->DrawLine( aPos1, aPos2 ); + } + pView->SetLineColor( aOldLineColor ); +} + + +static long GetOptSize( TabBar* pTabBar ) +{ + return pTabBar->CalcWindowSizePixel().Width(); +} + +void SvImpLBox::PositionScrollBars( Size& rSize, USHORT nMask ) +{ + long nOverlap = 0; + + Size aVerSize( nVerSBarWidth, rSize.Height() ); + Size aHorSize( rSize.Width(), nHorSBarHeight ); + long nTabBarWidth = 0; + if( pTabBar ) + { + nTabBarWidth = GetOptSize( pTabBar ); + long nMaxWidth = (rSize.Width() * 700) / 1000; + if( nTabBarWidth > nMaxWidth ) + { + nTabBarWidth = nMaxWidth; + pTabBar->SetStyle( pTabBar->GetStyle() | WB_MINSCROLL ); + } + else + { + WinBits nStyle = pTabBar->GetStyle(); + nStyle &= ~(WB_MINSCROLL); + pTabBar->SetStyle( nStyle ); + } + aHorSize.Width() -= nTabBarWidth; + Size aTabSize( pTabBar->GetSizePixel() ); + aTabSize.Width() = nTabBarWidth; + pTabBar->SetSizePixel( aTabSize ); + } + if( nMask & 0x0001 ) + aHorSize.Width() -= nVerSBarWidth; + if( nMask & 0x0002 ) + aVerSize.Height() -= nHorSBarHeight; + + aVerSize.Height() += 2 * nOverlap; + Point aVerPos( rSize.Width() - aVerSize.Width() + nOverlap, -nOverlap ); + aVerSBar.SetPosSizePixel( aVerPos, aVerSize ); + + aHorSize.Width() += 2 * nOverlap; + Point aHorPos( -nOverlap, rSize.Height() - aHorSize.Height() + nOverlap ); + if( pTabBar ) + pTabBar->SetPosPixel( aHorPos ); + aHorPos.X() += nTabBarWidth; + aHorSBar.SetPosSizePixel( aHorPos, aHorSize ); + + if( nMask & 0x0001 ) + rSize.Width() = aVerPos.X(); + if( nMask & 0x0002 ) + rSize.Height() = aHorPos.Y(); + if( pTabBar ) + pTabBar->Show(); + + if( (nMask & (0x0001|0x0002)) == (0x0001|0x0002) ) + aScrBarBox.Show(); + else + aScrBarBox.Hide(); + +} + +// nResult: Bit0 == VerSBar Bit1 == HorSBar +USHORT SvImpLBox::AdjustScrollBars( Size& rSize ) +{ + long nEntryHeight = pView->GetEntryHeight(); + if( !nEntryHeight ) + return 0; + + USHORT 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.X() *= -1; + nMaxRight += aOrigin.X() - 1; + long nVis = nMostRight - aOrigin.X(); + if( pTabBar || ( + (nWindowStyle & WB_HSCROLL) && + (nVis < nMostRight || nMaxRight < nMostRight) )) + bHorBar = TRUE; + + // Anzahl aller nicht eingeklappten Eintraege + ULONG nTotalCount = pView->GetVisibleCount(); + + // Anzahl in der View sichtbarer Eintraege + nVisibleCount = aOSize.Height() / nEntryHeight; + + // muessen wir eine vertikale Scrollbar einblenden? + if( bVerSBar || nTotalCount > nVisibleCount ) + { + nResult = 1; + nFlags |= F_HOR_SBARSIZE_WITH_VBAR; + nMaxRight -= nVerSBarWidth; + if( !bHorBar ) + { + if( (nWindowStyle & WB_HSCROLL) && + (nVis < nMostRight || nMaxRight < nMostRight) ) + bHorBar = TRUE; + } + } + + // muessen wir eine horizontale Scrollbar einblenden? + if( bHorBar ) + { + nResult |= 0x0002; + // die Anzahl der in der View sichtbaren Eintraege + // muss neu berechnet werden, da die horizontale + // ScrollBar eingeblendet wird + nVisibleCount = (aOSize.Height() - nHorSBarHeight) / nEntryHeight; + // eventuell brauchen wir jetzt doch eine vertikale ScrollBar + if( !(nResult & 0x0001) && + ((nTotalCount > nVisibleCount) || bVerSBar) ) + { + nResult = 3; + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + } + + PositionScrollBars( aOSize, nResult ); + + // Range, VisibleRange usw. anpassen + + // Output-Size aktualisieren, falls wir scrollen muessen + Rectangle aRect; + aRect.SetSize( aOSize ); + aSelEng.SetVisibleArea( aRect ); + + // Vertikale ScrollBar + long nTemp = (long)nVisibleCount; + nTemp--; + if( nTemp != aVerSBar.GetVisibleSize() ) + { + if( !bInVScrollHdl ) + { + aVerSBar.SetPageSize( nTemp - 1 ); + aVerSBar.SetVisibleSize( nTemp ); + } + else + { + nFlags |= F_ENDSCROLL_SET_VIS_SIZE; + nNextVerVisSize = nTemp; + } + } + + // Horizontale 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 + { + if( !pTabBar ) + aHorSBar.Hide(); + } + rSize = aOSize; + return nResult; +} + +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() +{ + Size aSize( pView->Control::GetOutputSizePixel()); + if( aSize.Width() <= 0 || aSize.Height() <= 0 ) + return; + nFlags |= F_IN_RESIZE; + InitScrollBarBox(); + + if( pView->GetEntryHeight()) + { + AdjustScrollBars( aOutputSize ); + FillView(); + } + // !!!HACK, da in Floating- & Docking-Windows nach Resizes + // die Scrollbars nicht richtig, bzw. ueberhaupt nicht gezeichnet werden + if( aHorSBar.IsVisible()) + aHorSBar.Invalidate(); + if( aVerSBar.IsVisible()) + aVerSBar.Invalidate(); + nFlags &= (~(F_IN_RESIZE | F_PAINTED)); +} + +void SvImpLBox::FillView() +{ + if( !pStartEntry ) + { + USHORT nVisibleViewCount = (USHORT)(pView->GetVisibleCount()); + USHORT nTempThumb = (USHORT)aVerSBar.GetThumbPos(); + if( nTempThumb >= nVisibleViewCount ) + nTempThumb = nVisibleViewCount - 1; + pStartEntry = (SvLBoxEntry*)(pView->GetEntryAtVisPos(nTempThumb)); + } + if( pStartEntry ) + { + USHORT nLast = (USHORT)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible()))); + USHORT nThumb = (USHORT)(pView->GetVisiblePos( pStartEntry )); + USHORT nCurDispEntries = nLast-nThumb+1; + if( nCurDispEntries < nVisibleCount ) + { + ShowCursor( FALSE ); + // Fenster fuellen, indem der Thumb schrittweise + // nach oben bewegt wird + BOOL bFound = FALSE; + SvLBoxEntry* pTemp = pStartEntry; + while( nCurDispEntries < nVisibleCount && pTemp ) + { + pTemp = (SvLBoxEntry*)(pView->PrevVisible(pStartEntry)); + if( pTemp ) + { + nThumb--; + pStartEntry = pTemp; + nCurDispEntries++; + bFound = TRUE; + } + } + if( bFound ) + { + aVerSBar.SetThumbPos( nThumb ); + ShowCursor( TRUE ); // Focusrect neu berechnen + pView->Invalidate(); + } + } + } +} + + + + +void SvImpLBox::ShowVerSBar() +{ + BOOL bVerBar = ( pView->GetStyle() & WB_VSCROLL ) != 0; + ULONG nVis = 0; + if( !bVerBar ) + nVis = pView->GetVisibleCount(); + if( bVerBar || (nVisibleCount && nVis > (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.X() *= -1; // Umrechnung Dokumentkoord. + 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( SvLBoxEntry* pEntry ) const +{ + // Parent eingeklappt + if( !pView->IsEntryVisible(pEntry) ) + return FALSE; + long nY = GetEntryLine( pEntry ); + if( nY < 0 ) + return FALSE; + long nMax = nVisibleCount * pView->GetEntryHeight(); + if( nY >= nMax ) + return FALSE; + return TRUE; +} + + +long SvImpLBox::GetEntryLine( SvLBoxEntry* pEntry ) const +{ + if(!pStartEntry ) + return -1; // unsichtbare Position + + long nFirstVisPos = pView->GetVisiblePos( pStartEntry ); + long nEntryVisPos = pView->GetVisiblePos( pEntry ); + nFirstVisPos = nEntryVisPos - nFirstVisPos; + nFirstVisPos *= pView->GetEntryHeight(); + return nFirstVisPos; +} + +void SvImpLBox::SetEntryHeight( short /* nHeight */ ) +{ + SetNodeBmpYOffset( GetExpandedNodeBmp() ); + SetNodeBmpYOffset( GetCollapsedNodeBmp() ); + if(!pView->HasViewData()) // stehen wir im Clear? + { + Size aSize = pView->Control::GetOutputSizePixel(); + AdjustScrollBars( aSize ); + } + else + { + Resize(); + if( GetUpdateMode() ) + pView->Invalidate(); + } +} + + + +// *********************************************************************** +// Callback-Functions +// *********************************************************************** + +void SvImpLBox::IndentChanged( short /* nIndentPixel */ ) {} + +void SvImpLBox::EntryExpanded( SvLBoxEntry* pEntry ) +{ + // SelAllDestrAnch( FALSE, TRUE ); //DeselectAll(); + if( GetUpdateMode() ) + { + ShowCursor( FALSE ); + long nY = GetEntryLine( pEntry ); + if( IsLineVisible(nY) ) + { + InvalidateEntriesFrom( nY ); + FindMostRight( pEntry, 0 ); + } + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + // falls vor dem Thumb expandiert wurde, muss + // die Thumb-Position korrigiert werden. + SyncVerThumb(); + ShowVerSBar(); + ShowCursor( TRUE ); + } +} + +void SvImpLBox::EntryCollapsed( SvLBoxEntry* pEntry ) +{ + if( !pView->IsEntryVisible( pEntry ) ) + return; + + ShowCursor( FALSE ); + + if( !pMostRightEntry || pTree->IsChild( pEntry,pMostRightEntry ) ) + { + FindMostRight(0); + } + + if( pStartEntry ) + { + long nOldThumbPos = aVerSBar.GetThumbPos(); + ULONG nVisList = pView->GetVisibleCount(); + aVerSBar.SetRange( Range(0, nVisList-1) ); + long nNewThumbPos = aVerSBar.GetThumbPos(); + if( nNewThumbPos != nOldThumbPos ) + { + pStartEntry = pView->First(); + USHORT nDistance = (USHORT)nNewThumbPos; + if( nDistance ) + pStartEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, + nDistance)); + if( GetUpdateMode() ) + pView->Invalidate(); + } + else + SyncVerThumb(); + ShowVerSBar(); + } + // wurde Cursor eingeklappt ? + if( pTree->IsChild( pEntry, pCursor ) ) + SetCursor( pEntry ); + if( GetUpdateMode() ) + ShowVerSBar(); + ShowCursor( TRUE ); + if( GetUpdateMode() && pCursor ) + pView->Select( pCursor, TRUE ); +} + +void SvImpLBox::CollapsingEntry( SvLBoxEntry* pEntry ) +{ + if( !pView->IsEntryVisible( pEntry ) || !pStartEntry ) + return; + + SelAllDestrAnch( FALSE, TRUE ); // deselectall + + // ist der eingeklappte Parent sichtbar ? + 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::SetNodeBmpYOffset( const Image& rBmp ) +{ + Size aSize; + nYoffsNodeBmp = pView->GetHeightOffset( rBmp, aSize ); + nNodeBmpWidth = aSize.Width(); +} + +void SvImpLBox::SetNodeBmpTabDistance() +{ + nNodeBmpTabDistance = -pView->GetIndent(); + if( pView->nContextBmpWidthMax ) + { + // nur, wenn der erste dynamische Tab zentriert ist + // (setze ich momentan voraus) + Size aSize = GetExpandedNodeBmp().GetSizePixel(); + nNodeBmpTabDistance -= aSize.Width() / 2; + } +} + +// +// korrigiert bei SingleSelection den Cursor +// +void SvImpLBox::EntrySelected( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + if( nFlags & F_IGNORE_SELECT ) + return; + + /* + if( (m_nStyle & WB_HIDESELECTION) && pEntry && !pView->HasFocus() ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + pViewData->SetCursored( bSelect ); + } + */ + + nFlags &= (~F_DESEL_ALL); + if( bSelect && + aSelEng.GetSelectionMode() == SINGLE_SELECTION && + 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 ); + pView->PaintEntry1( pEntry, nY, 0xffff ); // wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + ShowCursor( TRUE ); + } + } +} + + +void SvImpLBox::RemovingEntry( SvLBoxEntry* pEntry ) +{ + DestroyAnchor(); + + if( !pView->IsEntryVisible( pEntry ) ) + { + // wenn Parent eingeklappt, dann tschuess + nFlags |= F_REMOVED_ENTRY_INVISIBLE; + return; + } + + if( pEntry == pMostRightEntry || ( + pEntry->HasChilds() && pView->IsExpanded(pEntry) && + pTree->IsChild(pEntry, pMostRightEntry))) + { + nFlags |= F_REMOVED_RECALC_MOST_RIGHT; + } + + SvLBoxEntry* pOldStartEntry = pStartEntry; + + SvLBoxEntry* pParent = (SvLBoxEntry*)(pView->GetModel()->GetParent(pEntry)); + + if( pParent && pView->GetModel()->GetChildList(pParent)->Count() == 1 ) + { + DBG_ASSERT( pView->IsExpanded( pParent ), "Parent not expanded"); + pParent->SetFlags( pParent->GetFlags() | SV_ENTRYFLAG_NO_NODEBMP); + InvalidateEntry( pParent ); + } + + if( pCursor && pTree->IsChild( pEntry, pCursor) ) + pCursor = pEntry; + if( pStartEntry && pTree->IsChild(pEntry,pStartEntry) ) + pStartEntry = pEntry; + + SvLBoxEntry* pTemp; + if( pCursor && pCursor == pEntry ) + { + if( bSimpleTravel ) + pView->Select( pCursor, FALSE ); + ShowCursor( FALSE ); // Focus-Rect weg + // NextSibling, weil auch Childs des Cursors geloescht werden + pTemp = pView->NextSibling( pCursor ); + if( !pTemp ) + pTemp = (SvLBoxEntry*)(pView->PrevVisible( pCursor )); + + SetCursor( pTemp, TRUE ); + } + if( pStartEntry && pStartEntry == pEntry ) + { + pTemp = pView->NextSibling( pStartEntry ); + if( !pTemp ) + pTemp = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry )); + pStartEntry = pTemp; + } + if( GetUpdateMode()) + { + // wenns der letzte ist, muss invalidiert werden, damit die Linien + // richtig gezeichnet (in diesem Fall geloescht) werden. + if( pStartEntry && (pStartEntry != pOldStartEntry || pEntry == (SvLBoxEntry*)pView->GetModel()->Last()) ) + { + aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry )); + pView->Invalidate( GetVisibleArea() ); + } + else + InvalidateEntriesFrom( GetEntryLine( pEntry ) ); + } +} + +void SvImpLBox::EntryRemoved() +{ + if( nFlags & F_REMOVED_ENTRY_INVISIBLE ) + { + nFlags &= (~F_REMOVED_ENTRY_INVISIBLE); + return; + } + if( !pStartEntry ) + pStartEntry = pTree->First(); + if( !pCursor ) + SetCursor( pStartEntry, TRUE ); + + if( pCursor && (bSimpleTravel || !pView->GetSelectionCount() )) + pView->Select( pCursor, TRUE ); + + if( GetUpdateMode()) + { + if( nFlags & F_REMOVED_RECALC_MOST_RIGHT ) + FindMostRight(0); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + FillView(); + if( pStartEntry ) + // falls ueber dem Thumb geloescht wurde + aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry) ); + + ShowVerSBar(); + if( pCursor && pView->HasFocus() && !pView->IsSelected(pCursor) ) + { + if( pView->GetSelectionCount() ) + { + // ist ein benachbarter Eintrag selektiert? + SvLBoxEntry* pNextCursor = (SvLBoxEntry*)pView->PrevVisible( pCursor ); + if( !pNextCursor || !pView->IsSelected( pNextCursor )) + pNextCursor = (SvLBoxEntry*)pView->NextVisible( pCursor ); + if( !pNextCursor || !pView->IsSelected( pNextCursor )) + // kein Nachbar selektiert: Ersten selektierten nehmen + pNextCursor = pView->FirstSelected(); + SetCursor( pNextCursor ); + MakeVisible( pCursor ); + } + else + pView->Select( pCursor, TRUE ); + } + ShowCursor( TRUE ); + } + nFlags &= (~F_REMOVED_RECALC_MOST_RIGHT); +} + + +void SvImpLBox::MovingEntry( SvLBoxEntry* pEntry ) +{ + int bDeselAll = nFlags & F_DESEL_ALL; + SelAllDestrAnch( FALSE, TRUE ); // DeselectAll(); + if( !bDeselAll ) + nFlags &= (~F_DESEL_ALL); + + if( pEntry == pCursor ) + ShowCursor( FALSE ); + if( IsEntryInView( pEntry ) ) + pView->Invalidate(); + if( pEntry == pStartEntry ) + { + SvLBoxEntry* pNew = 0; + if( !pEntry->HasChilds() ) + { + pNew = (SvLBoxEntry*)(pView->NextVisible( pStartEntry )); + if( !pNew ) + pNew = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry )); + } + else + { + pNew = pTree->NextSibling( pEntry ); + if( !pNew ) + pNew = pTree->PrevSibling( pEntry ); + } + pStartEntry = pNew; + } +} + +void SvImpLBox::EntryMoved( SvLBoxEntry* pEntry ) +{ + // #97680# -------------- + 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)); + USHORT nFirstPos = (USHORT)pTree->GetAbsPos( pStartEntry ); + USHORT nNewPos = (USHORT)pTree->GetAbsPos( pEntry ); + FindMostRight(0); + if( nNewPos < nFirstPos ) //!!!Notloesung + pStartEntry = pEntry; + // #97702# --------------- + SyncVerThumb(); + if( pEntry == pCursor ) + { + if( pView->IsEntryVisible( pCursor ) ) + ShowCursor( TRUE ); + else + { + SvLBoxEntry* pParent = pEntry; + do { + pParent = pTree->GetParent( pParent ); + } + while( !pView->IsEntryVisible( pParent ) ); + SetCursor( pParent ); + } + } + if( IsEntryInView( pEntry ) ) + pView->Invalidate(); +} + + + +void SvImpLBox::EntryInserted( SvLBoxEntry* pEntry ) +{ + if( GetUpdateMode() ) + { + SvLBoxEntry* pParent = (SvLBoxEntry*)pTree->GetParent(pEntry); + if( pParent && pTree->GetChildList(pParent)->Count() == 1 ) + // Pluszeichen zeichnen + pTree->InvalidateEntry( pParent ); + + if( !pView->IsEntryVisible( pEntry ) ) + return; + int bDeselAll = nFlags & F_DESEL_ALL; + if( bDeselAll ) + SelAllDestrAnch( FALSE, TRUE ); + else + DestroyAnchor(); + // nFlags &= (~F_DESEL_ALL); +// ShowCursor( FALSE ); // falls sich Cursor nach unten verschiebt + long nY = GetEntryLine( pEntry ); + BOOL bEntryVisible = IsLineVisible( nY ); + if( bEntryVisible ) + { + ShowCursor( FALSE ); // falls sich Cursor nach unten verschiebt + nY -= pView->GetEntryHeight(); // wg. Linien + InvalidateEntriesFrom( nY ); + } + else if( pStartEntry && nY < GetEntryLine(pStartEntry) ) + { + // pruefen, ob die View komplett gefuellt ist. Wenn + // nicht, dann pStartEntry und den Cursor anpassen + // (automatisches scrollen) + USHORT nLast = (USHORT)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible()))); + USHORT nThumb = (USHORT)(pView->GetVisiblePos( pStartEntry )); + USHORT nCurDispEntries = nLast-nThumb+1; + if( nCurDispEntries < nVisibleCount ) + { + // beim naechsten Paint-Event setzen + pStartEntry = 0; + SetCursor( 0 ); + pView->Invalidate(); + } + } + else if( !pStartEntry ) + pView->Invalidate(); + + // die Linien invalidieren + /* + if( (bEntryVisible || bPrevEntryVisible) && + (m_nStyle & ( WB_HASLINES | WB_HASLINESATROOT )) ) + { + SvLBoxTab* pTab = pView->GetFirstDynamicTab(); + if( pTab ) + { + long nDX = pView->GetTabPos( pEntry, pTab ); + Point aTmpPoint; + Size aSize( nDX, nY ); + Rectangle aRect( aTmpPoint, aSize ); + pView->Invalidate( aRect ); + } + } + */ + + SetMostRight( pEntry ); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1)); + SyncVerThumb(); // falls vor Thumb eingefuegt wurde + ShowVerSBar(); + ShowCursor( TRUE ); + if( pStartEntry != pView->First() && (nFlags & F_FILLING) ) + pView->Update(); + } +} + + + +// ******************************************************************** +// Eventhandler +// ******************************************************************** + + +// ****** Steuerung der Controlanimation + +BOOL SvImpLBox::ButtonDownCheckCtrl(const MouseEvent& rMEvt, SvLBoxEntry* pEntry, + long nY ) +{ + SvLBoxItem* pItem = pView->GetItem(pEntry,rMEvt.GetPosPixel().X(),&pActiveTab); + if( pItem && (pItem->IsA()==SV_ITEM_ID_LBOXBUTTON)) + { + pActiveButton = (SvLBoxButton*)pItem; + pActiveEntry = pEntry; + if( pCursor == pActiveEntry ) + pView->HideFocus(); + pView->CaptureMouse(); + pActiveButton->SetStateHilighted( TRUE ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + return TRUE; + } + else + pActiveButton = 0; + return FALSE; +} + +BOOL SvImpLBox::MouseMoveCheckCtrl( const MouseEvent& rMEvt, SvLBoxEntry* pEntry) +{ + if( pActiveButton ) + { + long nY; + long nMouseX = rMEvt.GetPosPixel().X(); + if( pEntry == pActiveEntry && + pView->GetItem(pActiveEntry, nMouseX) == pActiveButton ) + { + if( !pActiveButton->IsStateHilighted() ) + { + pActiveButton->SetStateHilighted(TRUE ); + nY = GetEntryLine( pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + } + } + else + { + if( pActiveButton->IsStateHilighted() ) + { + pActiveButton->SetStateHilighted(FALSE ); + nY = GetEntryLine( pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, SV_LBOXTAB_PUSHABLE ); + } + } + return TRUE; + } + return FALSE; +} + +BOOL SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt ) +{ + if( pActiveButton ) + { + pView->ReleaseMouse(); + SvLBoxEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() ); + long nY = GetEntryLine( pActiveEntry ); + pActiveButton->SetStateHilighted( FALSE ); + long nMouseX = rMEvt.GetPosPixel().X(); + if( pEntry == pActiveEntry && + pView->GetItem( pActiveEntry, nMouseX ) == pActiveButton ) + pActiveButton->ClickHdl( pView, pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + if( pCursor == pActiveEntry ) + ShowCursor( TRUE ); + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + return TRUE; + } + return FALSE; +} + +// ******* Steuerung Plus/Minus-Button zum Expandieren/Kollabieren + +// FALSE == kein Expand/Collapse-Button getroffen +BOOL SvImpLBox::IsNodeButton( const Point& rPosPixel, SvLBoxEntry* pEntry ) const +{ + if( !pEntry->HasChilds() && !pEntry->HasChildsOnDemand() ) + return FALSE; + + SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab(); + if( !pFirstDynamicTab ) + return FALSE; + + long nMouseX = rPosPixel.X(); + // in Doc-Koords umrechnen + Point aOrigin( pView->GetMapMode().GetOrigin() ); + nMouseX -= aOrigin.X(); + + long nX = pView->GetTabPos( pEntry, pFirstDynamicTab); + nX += nNodeBmpTabDistance; + if( nMouseX < nX ) + return FALSE; + nX += nNodeBmpWidth; + if( nMouseX > nX ) + return FALSE; + return TRUE; +} + +// FALSE == hit no node button +BOOL SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, SvLBoxEntry* pEntry, long /* nY */ ) +{ + 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; + +#ifdef OS2 + // unter OS/2 kommt zwischen MouseButtonDown und + // MouseButtonUp ein MouseMove + nFlags |= F_IGNORE_NEXT_MOUSEMOVE; +#endif + aEditTimer.Stop(); + Point aPos( rMEvt.GetPosPixel()); + + if( aPos.X() > aOutputSize.Width() || aPos.Y() > aOutputSize.Height() ) + return; + + SvLBoxEntry* pEntry = GetEntry( aPos ); + if ( pEntry != pCursor ) + // new entry selected -> reset current tab position to first tab + nCurTabPos = FIRST_ENTRY_TAB; + nFlags &= (~F_FILLING); + pView->GrabFocus(); + // #120417# the entry can still be invalid! + if( !pEntry || !pView->GetViewData( pEntry )) + return; + + long nY = GetEntryLine( pEntry ); + // Node-Button? + if( ButtonDownCheckExpand( rMEvt, pEntry, nY ) ) + 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() && NULL == pView->NextSelected( pEntry ) ) + // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected + nFlags |= F_START_EDITTIMER; + if ( !pView->IsSelected( pEntry ) ) + nFlags &= ~F_START_EDITTIMER; + } + + + if( (rMEvt.GetClicks() % 2) == 0 ) + { + nFlags &= (~F_START_EDITTIMER); + pView->pHdlEntry = pEntry; + if( pView->DoubleClickHdl() ) + { + // falls im Handler der Eintrag geloescht wurde + pEntry = GetClickedEntry( aPos ); + if( !pEntry ) + return; + if( pEntry != pView->pHdlEntry ) + { + // neu selektieren & tschuess + if( !bSimpleTravel && !aSelEng.IsAlwaysAdding()) + SelAllDestrAnch( FALSE, TRUE ); // DeselectAll(); + SetCursor( pEntry ); + + return; + } + if( pEntry->HasChilds() || pEntry->HasChildsOnDemand() ) + { + if( pView->IsExpanded(pEntry) ) + pView->Collapse( pEntry ); + else + pView->Expand( pEntry ); + if( pEntry == pCursor ) // nur wenn Entryitem angeklickt wurde + // (Nodebutton ist kein Entryitem!) + pView->Select( pCursor, TRUE ); + return; + } + } + } + else + { + // CheckButton? (TreeListBox: Check + Info) + if( ButtonDownCheckCtrl(rMEvt, pEntry, nY) == TRUE) + return; + // Inplace-Editing? +#if 0 + if( rMEvt.IsMod2() && pView->IsInplaceEditingEnabled() ) + { + SvLBoxItem* pItem = pView->GetItem( pEntry, aPos.X() ); + if( pItem ) + pView->EditingRequest( pEntry, pItem, aPos ); + return; + } +#endif + } + if ( aSelEng.GetSelectionMode() != NO_SELECTION ) + aSelEng.SelMouseButtonDown( rMEvt ); +} + +void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt) +{ +#ifdef OS2 + nFlags &= (~F_IGNORE_NEXT_MOUSEMOVE); +#endif + if ( !ButtonUpCheckCtrl( rMEvt ) && ( aSelEng.GetSelectionMode() != NO_SELECTION ) ) + aSelEng.SelMouseButtonUp( rMEvt ); + EndScroll(); + if( nFlags & F_START_EDITTIMER ) + { + nFlags &= (~F_START_EDITTIMER); + aEditClickPos = rMEvt.GetPosPixel(); + aEditTimer.Start(); + } + + return; +} + +void SvImpLBox::MouseMove( const MouseEvent& rMEvt) +{ +#ifdef OS2 + if( nFlags & F_IGNORE_NEXT_MOUSEMOVE ) + { + nFlags &= (~F_IGNORE_NEXT_MOUSEMOVE); + return; + } +#endif + SvLBoxEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() ); + if ( !MouseMoveCheckCtrl( rMEvt, pEntry ) && ( aSelEng.GetSelectionMode() != NO_SELECTION ) ) + aSelEng.SelMouseMove( rMEvt ); + return; +} + +BOOL SvImpLBox::KeyInput( const KeyEvent& rKEvt) +{ + aEditTimer.Stop(); + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + + if( rKeyCode.IsMod2() ) + return FALSE; // Alt-Taste nicht auswerten + + nFlags &= (~F_FILLING); + + if( !pCursor ) + pCursor = pStartEntry; + if( !pCursor ) + return FALSE; + + BOOL bKeyUsed = TRUE; + + USHORT nDelta = (USHORT)aVerSBar.GetPageSize(); + USHORT aCode = rKeyCode.GetCode(); + + BOOL bShift = rKeyCode.IsShift(); + BOOL bMod1 = rKeyCode.IsMod1(); + + SvLBoxEntry* pNewCursor; + + const WinBits nWindowStyle = pView->GetStyle(); + switch( aCode ) + { + case KEY_UP: + if( !IsEntryInView( pCursor ) ) + MakeVisible( pCursor ); + + pNewCursor = pCursor; + do + { + pNewCursor = (SvLBoxEntry*)(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 + // 06.09.20001 - 83416 - fs@openoffice.org + if ( !pNewCursor && pCursor ) + pNewCursor = pCursor; + + if( pNewCursor ) + { + 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 = (SvLBoxEntry*)(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 ); // weil ScrollBar-Range evtl. noch + // scrollen erlaubt + break; + + case KEY_RIGHT: + { + if( bSubLstOpLR && IsNowExpandable() ) + pView->Expand( pCursor ); + else if ( bIsCellFocusEnabled && pCursor ) + { + if ( nCurTabPos < ( pView->TabCount() - 1 /*!2*/ ) ) + { + ++nCurTabPos; + ShowCursor( TRUE ); + CallEventListeners( VCLEVENT_LISTBOX_SELECT, 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 ) + { + if ( nCurTabPos > FIRST_ENTRY_TAB ) + { + --nCurTabPos; + ShowCursor( TRUE ); + CallEventListeners( VCLEVENT_LISTBOX_SELECT, 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 && IsExpandable() ) + pView->Collapse( pCursor ); + else + bKeyUsed = FALSE; + break; + } + + case KEY_PAGEUP: + if( !bMod1 ) + { + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pCursor, nDelta )); + + while( nDelta && pNewCursor && !IsSelectable(pNewCursor) ) + { + pNewCursor = (SvLBoxEntry*)(pView->NextVisible( pNewCursor )); + nDelta--; + } + + if( nDelta ) + { + DBG_ASSERT(pNewCursor&&(ULONG)pNewCursor!=(ULONG)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= (SvLBoxEntry*)(pView->NextVisible( pCursor, nDelta )); + + while( nDelta && pNewCursor && !IsSelectable(pNewCursor) ) + { + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pNewCursor )); + nDelta--; + } + + if( nDelta ) + { + DBG_ASSERT(pNewCursor&&(ULONG)pNewCursor!=(ULONG)pCursor,"Cursor?"); + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor ); + else + { + SetCursor( pNewCursor ); + KeyDown( TRUE ); + } + } + else + KeyDown( FALSE ); // siehe KEY_DOWN + } + else + bKeyUsed = FALSE; + break; + + case KEY_SPACE: + if ( pView->GetSelectionMode() != NO_SELECTION ) + { + if ( bMod1 ) + { + if ( pView->GetSelectionMode() == MULTIPLE_SELECTION && !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, TRUE ); + } + 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( 0 ); + } + else + bKeyUsed = FALSE; + break; + + case KEY_F8: + if( bShift && pView->GetSelectionMode()==MULTIPLE_SELECTION && + !(m_nStyle & WB_SIMPLEMODE)) + { + if( aSelEng.IsAlwaysAdding() ) + aSelEng.AddAlways( FALSE ); + else + aSelEng.AddAlways( TRUE ); + } + else + bKeyUsed = FALSE; + break; + + +#ifdef OV_DEBUG + case KEY_F9: + MakeVisible( pCursor ); + break; + case KEY_F10: + pView->RemoveSelection(); + break; + case KEY_DELETE: + pView->RemoveEntry( pCursor ); + break; +#endif + + case KEY_ADD: + if( pCursor ) + { + if( !pView->IsExpanded(pCursor)) + pView->Expand( pCursor ); + if( bMod1 ) + { + USHORT nRefDepth = pTree->GetDepth( pCursor ); + SvLBoxEntry* pCur = pTree->Next( pCursor ); + while( pCur && pTree->GetDepth(pCur) > nRefDepth ) + { + if( pCur->HasChilds() && !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 ) + { + // bis zur Root alle Parents einklappen + SvLBoxEntry* pParentToCollapse = (SvLBoxEntry*)pTree->GetRootLevelParent(pCursor); + if( pParentToCollapse ) + { + USHORT nRefDepth; + // Sonderbehandlung Explorer: Befindet sich auf der + // Root nur ein Eintrag,dann den Root-Entry nicht + // einklappen + if( pTree->GetChildList(0)->Count() < 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 ); + SvLBoxEntry* pCur = pTree->Next( pParentToCollapse ); + while( pCur && pTree->GetDepth(pCur) > nRefDepth ) + { + if( pCur->HasChilds() && 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 = (SvLBoxEntry*)(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 = (SvLBoxEntry*)(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: + // #105907# 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 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 __EXPORT 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 ) + { + SvLBoxEntry* pEntry = pView->FirstSelected(); + while( pEntry ) + { + InvalidateEntry( pEntry ); + pEntry = pView->NextSelected( pEntry ); + } + /* + SvLBoxEntry* pEntry = pView->GetModel()->First(); + while( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + if( pViewData->IsCursored() ) + { + pViewData->SetCursored( FALSE ); + InvalidateEntry( pEntry ); + } + pEntry = pView->GetModel()->Next( pEntry ); + } + */ + + + } +} + +void __EXPORT SvImpLBox::LoseFocus() +{ + aEditTimer.Stop(); + if( pCursor ) + pView->SetEntryFocus( pCursor,FALSE ); + ShowCursor( FALSE ); + + if( m_nStyle & WB_HIDESELECTION ) + { + SvLBoxEntry* pEntry = pView->FirstSelected(); + while( pEntry ) + { + //SvViewData* pViewData = pView->GetViewData( pEntry ); + //pViewData->SetCursored( TRUE ); + InvalidateEntry( pEntry ); + pEntry = pView->NextSelected( pEntry ); + } + } +} + + +// ******************************************************************** +// SelectionEngine +// ******************************************************************** + +inline void SvImpLBox::SelectEntry( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + pView->Select( pEntry, bSelect ); +} + +__EXPORT ImpLBSelEng::ImpLBSelEng( SvImpLBox* pImpl, SelectionEngine* pSEng, + SvTreeListBox* pV ) +{ + pImp = pImpl; + pSelEng = pSEng; + pView = pV; +} + +__EXPORT ImpLBSelEng::~ImpLBSelEng() +{ +} + +void __EXPORT ImpLBSelEng::BeginDrag() +{ + pImp->BeginDrag(); +} + +/* +void __EXPORT ImpLBSelEng::EndDrag( const Point& ) +{ +} +*/ + +void __EXPORT ImpLBSelEng::CreateAnchor() +{ + pImp->pAnchor = pImp->pCursor; +} + +void __EXPORT ImpLBSelEng::DestroyAnchor() +{ + pImp->pAnchor = 0; +} + +/* +void __EXPORT ImpLBSelEng::CreateCursor() +{ + pImp->pAnchor = 0; +} +*/ + + +BOOL __EXPORT ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, BOOL bDontSelectAtCursor) +{ + SvLBoxEntry* pNewCursor = pImp->MakePointVisible( rPoint ); + if( pNewCursor != pImp->pCursor ) + pImp->BeginScroll(); + + if( pNewCursor ) + { + // bei SimpleTravel wird in SetCursor selektiert und + // der Select-Handler gerufen + //if( !bDontSelectAtCursor && !pImp->bSimpleTravel ) + // pImp->SelectEntry( pNewCursor, TRUE ); + pImp->SetCursor( pNewCursor, bDontSelectAtCursor ); + return TRUE; + } + return FALSE; +} + +BOOL __EXPORT ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( pEntry ) + return pView->IsSelected(pEntry); + return FALSE; +} + +void __EXPORT ImpLBSelEng::DeselectAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( !pEntry ) + return; + pImp->SelectEntry( pEntry, FALSE ); +} + +/* +void __EXPORT ImpLBSelEng::SelectAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( !pEntry ) + return; + pImp->SelectEntry( pEntry, TRUE ); +} +*/ + +void __EXPORT ImpLBSelEng::DeselectAll() +{ + pImp->SelAllDestrAnch( FALSE, FALSE ); // SelectionEngine nicht resetten! + pImp->nFlags &= (~F_DESEL_ALL); +} + +// *********************************************************************** +// Selektion +// *********************************************************************** + +void SvImpLBox::SetAnchorSelection(SvLBoxEntry* pOldCursor,SvLBoxEntry* pNewCursor) +{ + SvLBoxEntry* pEntry; + ULONG nAnchorVisPos = pView->GetVisiblePos( pAnchor ); + ULONG nOldVisPos = pView->GetVisiblePos( pOldCursor ); + ULONG nNewVisPos = pView->GetVisiblePos( pNewCursor ); + + if( nOldVisPos > nAnchorVisPos || + ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) ) + { + if( nNewVisPos > nOldVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos < nAnchorVisPos ) + { + pEntry = pAnchor; + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, FALSE ); + + pEntry = pNewCursor; + while( pEntry && pEntry != pAnchor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos < nOldVisPos ) + { + pEntry = pNewCursor; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, FALSE ); + return; + } + } + else + { + if( nNewVisPos < nOldVisPos ) // Vergroessern der Selektion + { + pEntry = pNewCursor; + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos > nAnchorVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pAnchor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, FALSE ); + pEntry = pAnchor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos > nOldVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + return; + } + } +} + +void SvImpLBox::SelAllDestrAnch( BOOL bSelect, BOOL bDestroyAnchor, + BOOL bSingleSelToo ) +{ + SvLBoxEntry* pEntry; + nFlags &= (~F_DESEL_ALL); + if( bSelect && bSimpleTravel ) + { + if( pCursor && !pView->IsSelected( pCursor )) + { + pView->Select( pCursor, TRUE ); + } + return; + } + if( !bSelect && pView->GetSelectionCount() == 0 ) + { + if( bSimpleTravel && ( !GetUpdateMode() || !pCursor) ) + nFlags |= F_DESEL_ALL; + 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(); // Anker loeschen & SelectionEngine zuruecksetzen + else + pAnchor = 0; // internen Anker immer loeschen + return; + } + + if( bSimpleTravel && !pCursor && !GetUpdateMode() ) + nFlags |= F_DESEL_ALL; + + ShowCursor( FALSE ); + BOOL bUpdate = GetUpdateMode(); + + nFlags |= F_IGNORE_SELECT; // EntryInserted soll nix tun + pEntry = pTree->First(); + while( pEntry ) + { + if( pView->Select( pEntry, bSelect ) ) + { + if( bUpdate && pView->IsEntryVisible(pEntry) ) + { + long nY = GetEntryLine( pEntry ); + if( IsLineVisible( nY ) ) + pView->PaintEntry1( pEntry, nY, 0xffff ); // wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + } + } + pEntry = pTree->Next( pEntry ); + } + nFlags &= ~F_IGNORE_SELECT; + + if( bDestroyAnchor ) + DestroyAnchor(); // Anker loeschen & SelectionEngine zuruecksetzen + else + pAnchor = 0; // internen Anker immer loeschen + ShowCursor( TRUE ); +} + +void SvImpLBox::SetSelectionMode( SelectionMode eSelMode ) +{ + aSelEng.SetSelectionMode( eSelMode); + if( eSelMode == SINGLE_SELECTION ) + bSimpleTravel = TRUE; + else + bSimpleTravel = FALSE; + if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == MULTIPLE_SELECTION) ) + aSelEng.AddAlways( TRUE ); +} + +// *********************************************************************** +// Drag & Drop +// *********************************************************************** + +void SvImpLBox::SetDragDropMode( DragDropMode eDDMode ) +{ + if( eDDMode && eDDMode != SV_DRAGDROP_APP_DROP ) + { + aSelEng.ExpandSelectionOnMouseMove( FALSE ); + aSelEng.EnableDrag( TRUE ); + } + else + { + aSelEng.ExpandSelectionOnMouseMove( TRUE ); + aSelEng.EnableDrag( FALSE ); + } +} + +void SvImpLBox::BeginDrag() +{ + nFlags &= (~F_FILLING); + if( !bAsyncBeginDrag ) + { + BeginScroll(); + pView->StartDrag( 0, aSelEng.GetMousePosPixel() ); + EndScroll(); + } + else + { + aAsyncBeginDragPos = aSelEng.GetMousePosPixel(); + aAsyncBeginDragTimer.Start(); + } +} + +IMPL_LINK( SvImpLBox, BeginDragHdl, void*, EMPTYARG ) +{ + pView->StartDrag( 0, aAsyncBeginDragPos ); + return 0; +} + +void SvImpLBox::PaintDDCursor( SvLBoxEntry* pInsertionPos ) +{ + long nY; + if( pInsertionPos ) + { + nY = GetEntryLine( pInsertionPos ); + nY += pView->GetEntryHeight(); + } + else + nY = 1; + RasterOp eOldOp = pView->GetRasterOp(); + pView->SetRasterOp( ROP_INVERT ); + Color aOldLineColor = pView->GetLineColor(); + pView->SetLineColor( Color( COL_BLACK ) ); + pView->DrawLine( Point( 0, nY ), Point( aOutputSize.Width(), nY ) ); + pView->SetLineColor( aOldLineColor ); + pView->SetRasterOp( eOldOp ); +} +/* -----------------26.08.2003 12:52----------------- + Delete all sub menues of a PopupMenu, recursively + --------------------------------------------------*/ +void lcl_DeleteSubPopups(PopupMenu* pPopup) +{ + for(USHORT i = 0; i < pPopup->GetItemCount(); i++) + { + PopupMenu* pSubPopup = pPopup->GetPopupMenu( pPopup->GetItemId( i )); + if(pSubPopup) + { + lcl_DeleteSubPopups(pSubPopup); + delete pSubPopup; + } + } +} + +void SvImpLBox::Command( const CommandEvent& rCEvt ) +{ + USHORT nCommand = rCEvt.GetCommand(); + + if( nCommand == COMMAND_CONTEXTMENU ) + aEditTimer.Stop(); + + // Rollmaus-Event? + if( ( ( nCommand == COMMAND_WHEEL ) || ( nCommand == COMMAND_STARTAUTOSCROLL ) || ( nCommand == COMMAND_AUTOSCROLL ) ) + && pView->HandleScrollCommand( rCEvt, &aHorSBar, &aVerSBar ) ) + return; + + if( bContextMenuHandling && nCommand == COMMAND_CONTEXTMENU ) + { + Point aPopupPos; + BOOL bClickedIsFreePlace = FALSE; + std::stack<SvLBoxEntry*> aSelRestore; + + if( rCEvt.IsMouseEvent() ) + { // change selection, if mouse pos doesn't fit to selection + + aPopupPos = rCEvt.GetMousePosPixel(); + + SvLBoxEntry* pClickedEntry = GetEntry( aPopupPos ); + if( pClickedEntry ) + { // mouse in non empty area + BOOL bClickedIsSelected = FALSE; + + // collect the currently selected entries + SvLBoxEntry* 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() == SINGLE_SELECTION ) + {//modified by BerryJia for fixing Bug102739 2002-9-9 17:00(Beijing Time) + bClickedIsFreePlace = TRUE; + INT32 nSelectedEntries = pView->GetSelectionCount(); + SvLBoxEntry* pSelected = pView->FirstSelected(); + for(USHORT 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) + INT32 nSelectionCount = pView->GetSelectionCount(); + + if( nSelectionCount ) + { // now allways take first visible as base for positioning the menu + SvLBoxEntry* 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 ); + } + + PopupMenu* pPopup = pView->CreateContextMenu(); + + if( pPopup ) + { + // do action for selected entry in popup menu + USHORT nMenuAction = pPopup->Execute( pView, aPopupPos ); + if ( nMenuAction ) + pView->ExcecuteContextMenuAction( nMenuAction ); + lcl_DeleteSubPopups(pPopup); + delete pPopup; + } + //added by BerryJia for fixing Bug102739 2002-9-9 17:00(Beijing Time) + if( bClickedIsFreePlace ) + { + while(!aSelRestore.empty()) + { + SvLBoxEntry* pEntry = aSelRestore.top(); + //#i19717# the entry is maybe already deleted + bool bFound = false; + for(ULONG nEntry = 0; nEntry < pView->GetEntryCount(); nEntry++) + if(pEntry == pView->GetEntry(nEntry)) + { + bFound = true; + break; + } + if(bFound) + SetCurEntry( pEntry ); + aSelRestore.pop(); + } + } + } +#ifndef NOCOMMAND + else + { + const Point& rPos = rCEvt.GetMousePosPixel(); + if( rPos.X() < aOutputSize.Width() && rPos.Y() < aOutputSize.Height() ) + aSelEng.Command( rCEvt ); + } +#endif +} + +void SvImpLBox::BeginScroll() +{ + if( !(nFlags & F_IN_SCROLLING)) + { + pView->NotifyBeginScroll(); + nFlags |= F_IN_SCROLLING; + } +} + +void SvImpLBox::EndScroll() +{ + if( nFlags & F_IN_SCROLLING) + { + pView->NotifyEndScroll(); + nFlags &= (~F_IN_SCROLLING); + } +} + + +Rectangle SvImpLBox::GetVisibleArea() const +{ + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; + Rectangle aRect( aPos, aOutputSize ); + return aRect; +} + +void SvImpLBox::Invalidate() +{ + pView->SetClipRegion(); +} + +void SvImpLBox::SetCurEntry( SvLBoxEntry* pEntry ) +{ + if ( ( aSelEng.GetSelectionMode() != SINGLE_SELECTION ) + && ( aSelEng.GetSelectionMode() != NO_SELECTION ) + ) + SelAllDestrAnch( FALSE, TRUE, FALSE ); + if ( pEntry ) + MakeVisible( pEntry ); + SetCursor( pEntry ); + if ( pEntry && ( aSelEng.GetSelectionMode() != NO_SELECTION ) ) + pView->Select( pEntry, TRUE ); +} + +IMPL_LINK( SvImpLBox, EditTimerCall, Timer *, EMPTYARG ) +{ + if( pView->IsInplaceEditingEnabled() ) + { + sal_Bool bIsMouseTriggered = aEditClickPos.X() >= 0; + if ( bIsMouseTriggered ) + { + Point aCurrentMousePos = pView->GetPointerPosPixel(); + if ( ( abs( aCurrentMousePos.X() - aEditClickPos.X() ) > 5 ) + || ( abs( aCurrentMousePos.Y() - aEditClickPos.Y() ) > 5 ) + ) + { + return 0L; + } + } + + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + { + ShowCursor( FALSE ); + pView->ImplEditEntry( pEntry ); + ShowCursor( TRUE ); + } + } + return 0; +} + +BOOL SvImpLBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if( rHEvt.GetMode() & HELPMODE_QUICK ) + { + Point aPos( pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() )); + if( !GetVisibleArea().IsInside( aPos )) + return FALSE; + + SvLBoxEntry* pEntry = GetEntry( aPos ); + if( pEntry ) + { + // Rechteck des Textes berechnen + SvLBoxTab* pTab; + SvLBoxString* pItem = (SvLBoxString*)(pView->GetItem( pEntry, aPos.X(), &pTab )); + if( !pItem || pItem->IsA() != SV_ITEM_ID_LBOXSTRING ) + return FALSE; + + aPos = GetEntryPosition( pEntry ); + aPos.X() = pView->GetTabPos( pEntry, pTab ); //pTab->GetPos(); + Size aSize( pItem->GetSize( pView, pEntry ) ); + SvLBoxTab* pNextTab = NextTab( pTab ); + BOOL bItemClipped = FALSE; + // wurde das Item von seinem rechten Nachbarn abgeschnitten? + if( pNextTab && pView->GetTabPos(pEntry,pNextTab) < aPos.X()+aSize.Width() ) + { + aSize.Width() = pNextTab->GetPos() - pTab->GetPos(); + bItemClipped = TRUE; + } + Rectangle aItemRect( aPos, aSize ); + + Rectangle aViewRect( GetVisibleArea() ); + + if( bItemClipped || !aViewRect.IsInside( aItemRect ) ) + { + // rechten Item-Rand am View-Rand clippen + //if( aItemRect.Right() > aViewRect.Right() ) + // aItemRect.Right() = aViewRect.Right(); + + Point aPt = pView->OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = pView->OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + + Help::ShowQuickHelp( pView, aItemRect, + pItem->GetText(), QUICKHELP_LEFT | QUICKHELP_VCENTER ); + return TRUE; + } + } + } + return FALSE; +} + +SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab* pTab ) +{ + USHORT nTabCount = pView->TabCount(); + if( nTabCount <= 1 ) + return 0; + for( USHORT nTab=0; nTab < (nTabCount-1); nTab++) + { + if( pView->aTabs[nTab]==pTab ) + return (SvLBoxTab*)(pView->aTabs[nTab+1]); + } + return 0; +} + +void SvImpLBox::EndSelection() +{ + DestroyAnchor(); + nFlags &= ~F_START_EDITTIMER; +} + +void SvImpLBox::RepaintScrollBars() +{ +} + +void SvImpLBox::SetUpdateMode( BOOL bMode ) +{ + if( bUpdateMode != bMode ) + { + bUpdateMode = bMode; + if( bUpdateMode ) + UpdateAll( FALSE ); + } +} + +void SvImpLBox::SetUpdateModeFast( BOOL bMode ) +{ + if( bUpdateMode != bMode ) + { + bUpdateMode = bMode; + if( bUpdateMode ) + UpdateAll( FALSE, FALSE ); + } +} + + +BOOL SvImpLBox::SetMostRight( SvLBoxEntry* pEntry ) +{ + if( pView->nTreeFlags & TREEFLAG_RECALCTABS ) + { + nFlags |= F_IGNORE_CHANGED_TABS; + pView->SetTabs(); + nFlags &= ~F_IGNORE_CHANGED_TABS; + } + + USHORT nLastTab = pView->aTabs.Count() - 1; + USHORT nLastItem = pEntry->ItemCount() - 1; + if( nLastTab != USHRT_MAX && nLastItem != USHRT_MAX ) + { + if( nLastItem < nLastTab ) + nLastTab = nLastItem; + + SvLBoxTab* pTab = (SvLBoxTab*)pView->aTabs[ nLastTab ]; + SvLBoxItem* pItem = pEntry->GetItem( nLastTab ); + + long nTabPos = pView->GetTabPos( pEntry, pTab ); + + long nMaxRight = GetOutputSize().Width(); + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; // Umrechnung Dokumentkoord. + nMaxRight = nMaxRight + aPos.X() - 1; + + long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50; + long nTabWidth = nNextTab - nTabPos + 1; + long nItemSize = pItem->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( SvLBoxEntry* pEntryToIgnore ) +{ + nMostRight = -1; + pMostRightEntry = 0; + if( !pView->GetModel() ) + return; + + SvLBoxEntry* pEntry = (SvLBoxEntry*)pView->FirstVisible(); + while( pEntry ) + { + if( pEntry != pEntryToIgnore ) + SetMostRight( pEntry ); + pEntry = (SvLBoxEntry*)pView->NextVisible( pEntry ); + } +} + +void SvImpLBox::FindMostRight( SvLBoxEntry* pParent, SvLBoxEntry* pEntryToIgnore ) +{ + if( !pParent ) + FindMostRight( pEntryToIgnore ); + else + FindMostRight_Impl( pParent, pEntryToIgnore ); +} + +void SvImpLBox::FindMostRight_Impl( SvLBoxEntry* pParent, SvLBoxEntry* pEntryToIgnore ) +{ + SvTreeEntryList* pList = pTree->GetChildList( pParent ); + + if( !pList ) + return; + + ULONG nCount = pList->Count(); + for( ULONG nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pChild = (SvLBoxEntry*)pList->GetObject( nCur ); + if( pChild != pEntryToIgnore ) + { + SetMostRight( pChild ); + if( pChild->HasChilds() && pView->IsExpanded( pChild )) + FindMostRight_Impl( pChild, pEntryToIgnore ); + } + } +} + +void SvImpLBox::NotifyTabsChanged() +{ + if( GetUpdateMode() && !(nFlags & F_IGNORE_CHANGED_TABS ) && + nCurUserEvent == 0xffffffff ) + { + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)0); + } +} + +IMPL_LINK(SvImpLBox,MyUserEvent,void*, pArg ) +{ + nCurUserEvent = 0xffffffff; + if( !pArg ) + { + pView->Invalidate(); + pView->Update(); + } + else + { + FindMostRight( 0 ); + ShowVerSBar(); + pView->Invalidate( GetVisibleArea() ); + } + return 0; +} + + +void SvImpLBox::StopUserEvent() +{ + if( nCurUserEvent != 0xffffffff ) + { + Application::RemoveUserEvent( nCurUserEvent ); + nCurUserEvent = 0xffffffff; + } +} + +void SvImpLBox::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + if( pEntry ) + { + long nY = GetEntryLine( (SvLBoxEntry*)pEntry ); + Rectangle aRect = pView->GetFocusRect( (SvLBoxEntry*)pEntry, nY ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + + } + else + { + pView->HideFocus(); + } +} + +void SvImpLBox::SetTabBar( TabBar* _pTabBar ) +{ + pTabBar = _pTabBar; +} + +void SvImpLBox::CancelPendingEdit() +{ + if( aEditTimer.IsActive() ) + aEditTimer.Stop(); + nFlags &= ~F_START_EDITTIMER; +} + +// ----------------------------------------------------------------------- +void SvImpLBox::implInitDefaultNodeImages() +{ + if ( s_pDefCollapsed ) + // assume that all or nothing is initialized + return; + + s_pDefCollapsed = new Image( SvtResId( RID_IMG_TREENODE_COLLAPSED ) ); + s_pDefCollapsedHC = new Image( SvtResId( RID_IMG_TREENODE_COLLAPSED_HC ) ); + s_pDefExpanded = new Image( SvtResId( RID_IMG_TREENODE_EXPANDED ) ); + s_pDefExpandedHC = new Image( SvtResId( RID_IMG_TREENODE_EXPANDED_HC ) ); +} + +// ----------------------------------------------------------------------- +const Image& SvImpLBox::GetDefaultExpandedNodeImage( BmpColorMode _eMode ) +{ + implInitDefaultNodeImages(); + return ( BMP_COLOR_NORMAL == _eMode ) ? *s_pDefExpanded : *s_pDefExpandedHC; +} + +// ----------------------------------------------------------------------- +const Image& SvImpLBox::GetDefaultCollapsedNodeImage( BmpColorMode _eMode ) +{ + implInitDefaultNodeImages(); + return ( BMP_COLOR_NORMAL == _eMode ) ? *s_pDefCollapsed : *s_pDefCollapsedHC; +} + +// ----------------------------------------------------------------------- +void SvImpLBox::CallEventListeners( ULONG nEvent, void* pData ) +{ + if ( pView ) + pView->CallImplEventListeners( nEvent, pData); +} + +// ----------------------------------------------------------------------- + +bool SvImpLBox::SetCurrentTabPos( USHORT _nNewPos ) +{ + bool bRet = false; + + if ( pView && _nNewPos < ( pView->TabCount() - 2 ) ) + { + nCurTabPos = _nNewPos; + ShowCursor( TRUE ); + bRet = true; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +bool SvImpLBox::IsSelectable( const SvLBoxEntry* pEntry ) +{ + if( pEntry ) + { + SvViewDataEntry* pViewDataNewCur = pView->GetViewDataEntry(const_cast<SvLBoxEntry*>(pEntry)); + return (pViewDataNewCur == 0) || pViewDataNewCur->IsSelectable(); + } + else + { + return false; + } +} + |