blob: c271a1f487b49111c8dd7603c50fbe79fb717be4 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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( sal_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 = sal_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 = sal_True;
bInVScrollHdl = sal_False;
nFlags |= F_FILLING;
bSubLstOpRet = bSubLstOpLR = bContextMenuHandling = bIsCellFocusEnabled = sal_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!" );
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( 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 )
{
sal_uInt16 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( sal_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();
CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED, NULL );
}
// *********************************************************************
// 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 = sal_True;
if( pView->IsEditingActive() )
{
pView->EndEditing( sal_True ); // Cancel
pView->Update();
}
BeginScroll();
if( nDelta > 0 )
{
if( nDelta == 1 )
CursorDown();
else
PageDown( (sal_uInt16) nDelta );
}
else
{
nDelta *= (-1);
if( nDelta == 1 )
CursorUp();
else
PageUp( (sal_uInt16) nDelta );
}
bInVScrollHdl = sal_False;
return 0;
}
void SvImpLBox::CursorDown()
{
SvLBoxEntry* pNextFirstToDraw = (SvLBoxEntry*)(pView->NextVisible( pStartEntry));
if( pNextFirstToDraw )
{
nFlags &= (~F_FILLING);
pView->NotifyScrolling( -1 );
ShowCursor( sal_False );
pView->Update();
pStartEntry = pNextFirstToDraw;
Rectangle aArea( GetVisibleArea() );
pView->Scroll( 0, -(pView->GetEntryHeight()), aArea, SCROLL_NOCHILDREN );
pView->Update();
ShowCursor( sal_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( sal_False );
pView->Update();
pStartEntry = pPrevFirstToDraw;
Rectangle aArea( GetVisibleArea() );
aArea.Bottom() -= nEntryHeight;
pView->Scroll( 0, nEntryHeight, aArea, SCROLL_NOCHILDREN );
pView->Update();
ShowCursor( sal_True );
pView->NotifyScrolled();
}
}
void SvImpLBox::PageDown( sal_uInt16 nDelta )
{
sal_uInt16 nRealDelta = nDelta;
if( !nDelta )
return;
SvLBoxEntry* pNext;
pNext = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nRealDelta ));
if( (sal_uLong)pNext == (sal_uLong)pStartEntry )
return;
ShowCursor( sal_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( sal_True );
}
void SvImpLBox::PageUp( sal_uInt16 nDelta )
{
sal_uInt16 nRealDelta = nDelta;
if( !nDelta )
return;
SvLBoxEntry* pPrev = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry, nRealDelta ));
if( (sal_uLong)pPrev == (sal_uLong)pStartEntry )
return;
nFlags &= (~F_FILLING);
ShowCursor( sal_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( sal_True );
}
void SvImpLBox::KeyUp( sal_Bool bPageUp, sal_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( sal_Bool bPageDown, sal_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 ))
{
sal_Bool bHasFocusRect = sal_False;
if( pEntry==pCursor && pView->HasFocus() )
{
bHasFocusRect = sal_True;
ShowCursor( sal_False );
}
InvalidateEntry( GetEntryLine( pEntry ) );
if( bHasFocusRect )
ShowCursor( sal_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, sal_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, sal_False );
if( bSimpleTravel )
pView->Select( pCursor, sal_False );
pView->HideFocus();
}
pCursor = pEntry;
if( pCursor )
{
pViewDataNewCur->SetFocus( sal_True );
if(!bForceNoSelect && bSimpleTravel && !(nFlags & F_DESEL_ALL) && GetUpdateMode())
{
pView->Select( pCursor, sal_True );
CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS, pCursor );
}
// 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, sal_True );
CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS, pCursor );
}
else
{
ShowCursor( sal_True );
if (bForceNoSelect && GetUpdateMode())
{
CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS, pCursor);
}
}
if( pAnchor )
{
DBG_ASSERT(aSelEng.GetSelectionMode() != SINGLE_SELECTION,"Mode?");
SetAnchorSelection( pOldCursor, pCursor );
}
}
nFlags &= (~F_DESEL_ALL);
pView->OnCurrentEntryChanged();
}
void SvImpLBox::ShowCursor( sal_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( sal_Bool bInvalidateCompleteView,
sal_Bool bUpdateVerScrollBar )
{
if( bUpdateVerScrollBar )
FindMostRight(0);
aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) );
SyncVerThumb();
FillView();
ShowVerSBar();
if( bSimpleTravel && pCursor && pView->HasFocus() )
pView->Select( pCursor, sal_True );
ShowCursor( sal_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( sal_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( sal_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( sal_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;
sal_uInt16 nClickedEntry = (sal_uInt16)(rPoint.Y() / pView->GetEntryHeight() );
sal_uInt16 nTemp = nClickedEntry;
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp ));
return pEntry;
}
//
// prueft, ob der Eintrag "richtig" getroffen wurde
// (Focusrect+ ContextBitmap bei TreeListBox)
//
sal_Bool SvImpLBox::EntryReallyHit(SvLBoxEntry* pEntry,const Point& rPosPixel,long nLine)
{
sal_Bool bRet;
// bei "besonderen" Entries (mit CheckButtons usw.) sind wir
// nicht so pingelig
if( pEntry->ItemCount() >= 3 )
return sal_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 = sal_True;
else
bRet = sal_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;
sal_uInt16 nClickedEntry = (sal_uInt16)(rPoint.Y() / pView->GetEntryHeight() );
sal_uInt16 nTemp = nClickedEntry;
SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp ));
if( nTemp != nClickedEntry )
pEntry = 0;
return pEntry;
}
SvLBoxEntry* SvImpLBox::MakePointVisible(const Point& rPoint,sal_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, sal_False );
if( nY < 0 )
KeyUp( sal_False, bNotifyScroll );
else
KeyDown( sal_False, bNotifyScroll );
}
else
{
pEntry = GetClickedEntry( rPoint );
if( !pEntry )
{
sal_uInt16 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, sal_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( sal_False );
pStartEntry = pView->First();
aVerSBar.SetThumbPos( 0 );
StopUserEvent();
ShowCursor( sal_True );
nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)1);
return;
}
}
if( !pStartEntry )
{
pStartEntry = pView->First();
}
#ifdef XX_OV
sal_uLong nXAbsPos = (sal_uInt16)pTree->GetAbsPos( pStartEntry );
sal_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
sal_uInt16 nStartLine = (sal_uInt16)( rRect.Top() / nEntryHeight );
sal_uInt16 nCount = (sal_uInt16)( 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( sal_uInt16 n=0; n< nCount && pEntry; n++ )
{
/*long nMaxRight=*/
pView->PaintEntry1( pEntry, nY, 0xffff, sal_True );
nY += nEntryHeight;
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if ( !pCursor && ( ( nExtendedWinBits & EWB_NO_AUTO_CURENTRY ) == 0 ) )
{
// do not select if multiselection or explicit set
sal_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, sal_Bool bMoveToTop )
{
if( !pEntry )
return;
sal_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
sal_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( sal_False );
FillView();
aVerSBar.SetThumbPos( (long)(pView->GetVisiblePos( pStartEntry )) );
ShowCursor( sal_True );
pView->Invalidate();
}
void SvImpLBox::RepaintSelectionItems()
{
if( !pView->GetVisibleCount() )
return;
if( !pStartEntry )
pStartEntry = pView->First();
if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID )
SetNodeBmpTabDistance();
ShowCursor( sal_False );
long nEntryHeight = pView->GetEntryHeight();
sal_uLong nCount = nVisibleCount;
long nY = 0;
SvLBoxEntry* pEntry = pStartEntry;
for( sal_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( sal_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 );
sal_uInt16 nOffs = (sal_uInt16)(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;
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.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 = (sal_uInt16)(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, sal_uInt16 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
sal_uInt16 SvImpLBox::AdjustScrollBars( Size& rSize )
{
long nEntryHeight = pView->GetEntryHeight();
if( !nEntryHeight )
return 0;
sal_uInt16 nResult = 0;
Size aOSize( pView->Control::GetOutputSizePixel() );
const WinBits nWindowStyle = pView->GetStyle();
sal_Bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
sal_Bool bHorBar = sal_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 = sal_True;
// Anzahl aller nicht eingeklappten Eintraege
sal_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 = sal_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( sal_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 )
{
sal_uInt16 nVisibleViewCount = (sal_uInt16)(pView->GetVisibleCount());
sal_uInt16 nTempThumb = (sal_uInt16)aVerSBar.GetThumbPos();
if( nTempThumb >= nVisibleViewCount )
nTempThumb = nVisibleViewCount - 1;
pStartEntry = (SvLBoxEntry*)(pView->GetEntryAtVisPos(nTempThumb));
}
if( pStartEntry )
{
sal_uInt16 nLast = (sal_uInt16)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible())));
sal_uInt16 nThumb = (sal_uInt16)(pView->GetVisiblePos( pStartEntry ));
sal_uInt16 nCurDispEntries = nLast-nThumb+1;
if( nCurDispEntries < nVisibleCount )
{
ShowCursor( sal_False );
// Fenster fuellen, indem der Thumb schrittweise
// nach oben bewegt wird
sal_Bool bFound = sal_False;
SvLBoxEntry* pTemp = pStartEntry;
while( nCurDispEntries < nVisibleCount && pTemp )
{
pTemp = (SvLBoxEntry*)(pView->PrevVisible(pStartEntry));
if( pTemp )
{
nThumb--;
pStartEntry = pTemp;
nCurDispEntries++;
bFound = sal_True;
}
}
if( bFound )
{
aVerSBar.SetThumbPos( nThumb );
ShowCursor( sal_True ); // Focusrect neu berechnen
pView->Invalidate();
}
}
}
}
void SvImpLBox::ShowVerSBar()
{
sal_Bool bVerBar = ( pView->GetStyle() & WB_VSCROLL ) != 0;
sal_uLong nVis = 0;
if( !bVerBar )
nVis = pView->GetVisibleCount();
if( bVerBar || (nVisibleCount && nVis > (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.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 );
}
sal_Bool SvImpLBox::IsEntryInView( SvLBoxEntry* pEntry ) const
{
// Parent eingeklappt
if( !pView->IsEntryVisible(pEntry) )
return sal_False;
long nY = GetEntryLine( pEntry );
if( nY < 0 )
return sal_False;
long nMax = nVisibleCount * pView->GetEntryHeight();
if( nY >= nMax )
return sal_False;
return sal_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( sal_False, sal_True ); //DeselectAll();
if( GetUpdateMode() )
{
ShowCursor( sal_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( sal_True );
}
}
void SvImpLBox::EntryCollapsed( SvLBoxEntry* pEntry )
{
if( !pView->IsEntryVisible( pEntry ) )
return;
ShowCursor( sal_False );
if( !pMostRightEntry || pTree->IsChild( pEntry,pMostRightEntry ) )
{
FindMostRight(0);
}
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 = (sal_uInt16)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( sal_True );
if( GetUpdateMode() && pCursor )
pView->Select( pCursor, sal_True );
}
void SvImpLBox::CollapsingEntry( SvLBoxEntry* pEntry )
{
if( !pView->IsEntryVisible( pEntry ) || !pStartEntry )
return;
SelAllDestrAnch( sal_False, sal_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, sal_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( sal_False );
pView->PaintEntry1( pEntry, nY, 0xffff ); // wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION );
ShowCursor( sal_True );
}
}
}
void SvImpLBox::RemovingEntry( SvLBoxEntry* pEntry )
{
CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED , 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, sal_False );
ShowCursor( sal_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, sal_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, sal_True );
if( pCursor && (bSimpleTravel || !pView->GetSelectionCount() ))
pView->Select( pCursor, sal_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, sal_True );
}
ShowCursor( sal_True );
}
nFlags &= (~F_REMOVED_RECALC_MOST_RIGHT);
}
void SvImpLBox::MovingEntry( SvLBoxEntry* pEntry )
{
int bDeselAll = nFlags & F_DESEL_ALL;
SelAllDestrAnch( sal_False, sal_True ); // DeselectAll();
if( !bDeselAll )
nFlags &= (~F_DESEL_ALL);
if( pEntry == pCursor )
ShowCursor( sal_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));
sal_uInt16 nFirstPos = (sal_uInt16)pTree->GetAbsPos( pStartEntry );
sal_uInt16 nNewPos = (sal_uInt16)pTree->GetAbsPos( pEntry );
FindMostRight(0);
if( nNewPos < nFirstPos ) //!!!Notloesung
pStartEntry = pEntry;
// #97702# ---------------
SyncVerThumb();
if( pEntry == pCursor )
{
if( pView->IsEntryVisible( pCursor ) )
ShowCursor( sal_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( sal_False, sal_True );
else
DestroyAnchor();
// nFlags &= (~F_DESEL_ALL);
// ShowCursor( sal_False ); // falls sich Cursor nach unten verschiebt
long nY = GetEntryLine( pEntry );
sal_Bool bEntryVisible = IsLineVisible( nY );
if( bEntryVisible )
{
ShowCursor( sal_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)
sal_uInt16 nLast = (sal_uInt16)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible())));
sal_uInt16 nThumb = (sal_uInt16)(pView->GetVisiblePos( pStartEntry ));
sal_uInt16 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( sal_True );
if( pStartEntry != pView->First() && (nFlags & F_FILLING) )
pView->Update();
}
}
// ********************************************************************
// Eventhandler
// ********************************************************************
// ****** Steuerung der Controlanimation
sal_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( sal_True );
pView->PaintEntry1( pActiveEntry, nY,
SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER |
SV_LBOXTAB_ADJUST_RIGHT );
return sal_True;
}
else
pActiveButton = 0;
return sal_False;
}
sal_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(sal_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(sal_False );
nY = GetEntryLine( pActiveEntry );
pView->PaintEntry1( pActiveEntry, nY, SV_LBOXTAB_PUSHABLE );
}
}
return sal_True;
}
return sal_False;
}
sal_Bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt )
{
if( pActiveButton )
{
pView->ReleaseMouse();
SvLBoxEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() );
long nY = GetEntryLine( pActiveEntry );
pActiveButton->SetStateHilighted( sal_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( sal_True );
pActiveButton = 0;
pActiveEntry = 0;
pActiveTab = 0;
return sal_True;
}
return sal_False;
}
// ******* Steuerung Plus/Minus-Button zum Expandieren/Kollabieren
// sal_False == kein Expand/Collapse-Button getroffen
sal_Bool SvImpLBox::IsNodeButton( const Point& rPosPixel, SvLBoxEntry* pEntry ) const
{
if( !pEntry->HasChilds() && !pEntry->HasChildsOnDemand() )
return sal_False;
SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab();
if( !pFirstDynamicTab )
return sal_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 sal_False;
nX += nNodeBmpWidth;
if( nMouseX > nX )
return sal_False;
return sal_True;
}
// sal_False == hit no node button
sal_Bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, SvLBoxEntry* pEntry, long /* nY */ )
{
sal_Bool bRet = sal_False;
if ( pView->IsEditingActive() && pEntry == pView->pEdEntry )
// inplace editing -> nothing to do
bRet = sal_True;
else if ( IsNodeButton( rMEvt.GetPosPixel(), pEntry ) )
{
if ( pView->IsExpanded( pEntry ) )
{
pView->EndEditing( sal_True );
pView->Collapse( pEntry );
}
else
{
// you can expand an entry, which is in editing
pView->Expand( pEntry );
}
bRet = sal_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( sal_False, sal_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, sal_True );
return;
}
}
}
else
{
// CheckButton? (TreeListBox: Check + Info)
if( ButtonDownCheckCtrl(rMEvt, pEntry, nY) == sal_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;
}
sal_Bool SvImpLBox::KeyInput( const KeyEvent& rKEvt)
{
aEditTimer.Stop();
const KeyCode& rKeyCode = rKEvt.GetKeyCode();
if( rKeyCode.IsMod2() )
return sal_False; // Alt-Taste nicht auswerten
nFlags &= (~F_FILLING);
if( !pCursor )
pCursor = pStartEntry;
if( !pCursor )
return sal_False;
sal_Bool bKeyUsed = sal_True;
sal_uInt16 nDelta = (sal_uInt16)aVerSBar.GetPageSize();
sal_uInt16 aCode = rKeyCode.GetCode();
sal_Bool bShift = rKeyCode.IsShift();
sal_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( sal_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, sal_False );
KeyDown( sal_False );
SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
}
}
else
KeyDown( sal_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( sal_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 = sal_False;
break;
}
case KEY_LEFT:
{
// if ( bIsCellFocusEnabled )
if ( bIsCellFocusEnabled && pCursor )
{
if ( nCurTabPos > FIRST_ENTRY_TAB )
{
--nCurTabPos;
ShowCursor( sal_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 = sal_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&&(sal_uLong)pNewCursor!=(sal_uLong)pCursor,"Cursor?");
aSelEng.CursorPosChanging( bShift, bMod1 );
if( IsEntryInView( pNewCursor ) )
SetCursor( pNewCursor );
else
{
SetCursor( pNewCursor );
KeyUp( sal_True );
}
}
}
else
bKeyUsed = sal_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&&(sal_uLong)pNewCursor!=(sal_uLong)pCursor,"Cursor?");
aSelEng.CursorPosChanging( bShift, bMod1 );
if( IsEntryInView( pNewCursor ) )
SetCursor( pNewCursor );
else
{
SetCursor( pNewCursor );
KeyDown( sal_True );
}
}
else
KeyDown( sal_False ); // siehe KEY_DOWN
}
else
bKeyUsed = sal_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( sal_False );
pView->Select( pCursor, sal_True );
}
else
bKeyUsed = sal_False;
}
else
bKeyUsed = sal_False;
}
else
bKeyUsed = sal_False;
break;
case KEY_RETURN:
if( bSubLstOpRet && IsExpandable() )
{
if( pView->IsExpanded( pCursor ) )
pView->Collapse( pCursor );
else
pView->Expand( pCursor );
}
else
bKeyUsed = sal_False;
break;
case KEY_F2:
if( !bShift && !bMod1 )
{
aEditClickPos = Point( -1, -1 );
EditTimerCall( 0 );
}
else
bKeyUsed = sal_False;
break;
case KEY_F8:
if( bShift && pView->GetSelectionMode()==MULTIPLE_SELECTION &&
!(m_nStyle & WB_SIMPLEMODE))
{
if( aSelEng.IsAlwaysAdding() )
aSelEng.AddAlways( sal_False );
else
aSelEng.AddAlways( sal_True );
}
else
bKeyUsed = sal_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 )
{
sal_uInt16 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 = sal_False;
break;
case KEY_A:
if( bMod1 )
SelAllDestrAnch( sal_True );
else
bKeyUsed = sal_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 )
{
sal_uInt16 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 = sal_False;
break;
case KEY_DIVIDE :
if( bMod1 )
SelAllDestrAnch( sal_True );
else
bKeyUsed = sal_False;
break;
case KEY_COMMA :
if( bMod1 )
SelAllDestrAnch( sal_False );
else
bKeyUsed = sal_False;
break;
case KEY_HOME :
pNewCursor = pView->GetModel()->First();
while( pNewCursor && !IsSelectable(pNewCursor) )
{
pNewCursor = (SvLBoxEntry*)(pView->NextVisible( pNewCursor ));
}
if( pNewCursor && pNewCursor != pCursor )
{
// SelAllDestrAnch( sal_False );
aSelEng.CursorPosChanging( bShift, bMod1 );
SetCursor( pNewCursor );
if( !IsEntryInView( pNewCursor ) )
MakeVisible( pNewCursor );
}
else
bKeyUsed = sal_False;
break;
case KEY_END :
pNewCursor = pView->GetModel()->Last();
while( pNewCursor && !IsSelectable(pNewCursor) )
{
pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pNewCursor ));
}
if( pNewCursor && pNewCursor != pCursor)
{
// SelAllDestrAnch( sal_False );
aSelEng.CursorPosChanging( bShift, bMod1 );
SetCursor( pNewCursor );
if( !IsEntryInView( pNewCursor ) )
MakeVisible( pNewCursor );
}
else
bKeyUsed = sal_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 = sal_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 sal_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 = sal_False;
break;
}
return bKeyUsed;
}
void __EXPORT SvImpLBox::GetFocus()
{
if( pCursor )
{
pView->SetEntryFocus( pCursor, sal_True );
ShowCursor( sal_True );
// auskommentiert wg. deselectall
// if( bSimpleTravel && !pView->IsSelected(pCursor) )
// pView->Select( pCursor, sal_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( sal_False );
InvalidateEntry( pEntry );
}
pEntry = pView->GetModel()->Next( pEntry );
}
*/
}
}
void __EXPORT SvImpLBox::LoseFocus()
{
aEditTimer.Stop();
if( pCursor )
pView->SetEntryFocus( pCursor,sal_False );
ShowCursor( sal_False );
if( m_nStyle & WB_HIDESELECTION )
{
SvLBoxEntry* pEntry = pView->FirstSelected();
while( pEntry )
{
//SvViewData* pViewData = pView->GetViewData( pEntry );
//pViewData->SetCursored( sal_True );
InvalidateEntry( pEntry );
pEntry = pView->NextSelected( pEntry );
}
}
}
// ********************************************************************
// SelectionEngine
// ********************************************************************
inline void SvImpLBox::SelectEntry( SvLBoxEntry* pEntry, sal_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;
}
*/
sal_Bool __EXPORT ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, sal_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, sal_True );
pImp->SetCursor( pNewCursor, bDontSelectAtCursor );
return sal_True;
}
return sal_False;
}
sal_Bool __EXPORT ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint )
{
SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint );
if( pEntry )
return pView->IsSelected(pEntry);
return sal_False;
}
void __EXPORT ImpLBSelEng::DeselectAtPoint( const Point& rPoint )
{
SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint );
if( !pEntry )
return;
pImp->SelectEntry( pEntry, sal_False );
}
/*
void __EXPORT ImpLBSelEng::SelectAtPoint( const Point& rPoint )
{
SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint );
if( !pEntry )
return;
pImp->SelectEntry( pEntry, sal_True );
}
*/
void __EXPORT ImpLBSelEng::DeselectAll()
{
pImp->SelAllDestrAnch( sal_False, sal_False ); // SelectionEngine nicht resetten!
pImp->nFlags &= (~F_DESEL_ALL);
}
// ***********************************************************************
// Selektion
// ***********************************************************************
void SvImpLBox::SetAnchorSelection(SvLBoxEntry* pOldCursor,SvLBoxEntry* pNewCursor)
{
SvLBoxEntry* 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, sal_True );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if( pEntry )
pView->Select( pEntry, sal_True );
return;
}
if( nNewVisPos < nAnchorVisPos )
{
pEntry = pAnchor;
while( pEntry && pEntry != pOldCursor )
{
pView->Select( pEntry, sal_False );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if( pEntry )
pView->Select( pEntry, sal_False );
pEntry = pNewCursor;
while( pEntry && pEntry != pAnchor )
{
pView->Select( pEntry, sal_True );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if( pEntry )
pView->Select( pEntry, sal_True );
return;
}
if( nNewVisPos < nOldVisPos )
{
pEntry = pNewCursor;
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
while( pEntry && pEntry != pOldCursor )
{
pView->Select( pEntry, sal_False );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if( pEntry )
pView->Select( pEntry, sal_False );
return;
}
}
else
{
if( nNewVisPos < nOldVisPos ) // Vergroessern der Selektion
{
pEntry = pNewCursor;
while( pEntry && pEntry != pOldCursor )
{
pView->Select( pEntry, sal_True );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if( pEntry )
pView->Select( pEntry, sal_True );
return;
}
if( nNewVisPos > nAnchorVisPos )
{
pEntry = pOldCursor;
while( pEntry && pEntry != pAnchor )
{
pView->Select( pEntry, sal_False );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if( pEntry )
pView->Select( pEntry, sal_False );
pEntry = pAnchor;
while( pEntry && pEntry != pNewCursor )
{
pView->Select( pEntry, sal_True );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
if( pEntry )
pView->Select( pEntry, sal_True );
return;
}
if( nNewVisPos > nOldVisPos )
{
pEntry = pOldCursor;
while( pEntry && pEntry != pNewCursor )
{
pView->Select( pEntry, sal_False );
pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry ));
}
return;
}
}
}
void SvImpLBox::SelAllDestrAnch( sal_Bool bSelect, sal_Bool bDestroyAnchor,
sal_Bool bSingleSelToo )
{
SvLBoxEntry* pEntry;
nFlags &= (~F_DESEL_ALL);
if( bSelect && bSimpleTravel )
{
if( pCursor && !pView->IsSelected( pCursor ))
{
pView->Select( pCursor, sal_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, sal_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( sal_False );
sal_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( sal_True );
}
void SvImpLBox::SetSelectionMode( SelectionMode eSelMode )
{
aSelEng.SetSelectionMode( eSelMode);
if( eSelMode == SINGLE_SELECTION )
bSimpleTravel = sal_True;
else
bSimpleTravel = sal_False;
if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == MULTIPLE_SELECTION) )
aSelEng.AddAlways( sal_True );
}
// ***********************************************************************
// Drag & Drop
// ***********************************************************************
void SvImpLBox::SetDragDropMode( DragDropMode eDDMode )
{
if( eDDMode && eDDMode != SV_DRAGDROP_APP_DROP )
{
aSelEng.ExpandSelectionOnMouseMove( sal_False );
aSelEng.EnableDrag( sal_True );
}
else
{
aSelEng.ExpandSelectionOnMouseMove( sal_True );
aSelEng.EnableDrag( sal_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(sal_uInt16 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 )
{
sal_uInt16 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;
sal_Bool bClickedIsFreePlace = sal_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
sal_Bool bClickedIsSelected = sal_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( sal_False );
pView->SetCursor( pClickedEntry );
}
}
else if( aSelEng.GetSelectionMode() == SINGLE_SELECTION )
{//modified by BerryJia for fixing Bug102739 2002-9-9 17:00(Beijing Time)
bClickedIsFreePlace = sal_True;
sal_Int32 nSelectedEntries = pView->GetSelectionCount();
SvLBoxEntry* pSelected = pView->FirstSelected();
for(sal_uInt16 nSel = 0; nSel < nSelectedEntries; nSel++ )
{
aSelRestore.push(pSelected);
pSelected = pView->NextSelected( pSelected );
}
pView->SelectAll( sal_False );
}
else
{ // deselect all
pView->SelectAll( sal_False );
}
}
else
{ // key event (or at least no mouse event)
sal_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
sal_uInt16 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(sal_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( sal_False, sal_True, sal_False );
if ( pEntry )
MakeVisible( pEntry );
SetCursor( pEntry );
if ( pEntry && ( aSelEng.GetSelectionMode() != NO_SELECTION ) )
pView->Select( pEntry, sal_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( sal_False );
pView->ImplEditEntry( pEntry );
ShowCursor( sal_True );
}
}
return 0;
}
sal_Bool SvImpLBox::RequestHelp( const HelpEvent& rHEvt )
{
if( rHEvt.GetMode() & HELPMODE_QUICK )
{
Point aPos( pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() ));
if( !GetVisibleArea().IsInside( aPos ))
return sal_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 sal_False;
aPos = GetEntryPosition( pEntry );
aPos.X() = pView->GetTabPos( pEntry, pTab ); //pTab->GetPos();
Size aSize( pItem->GetSize( pView, pEntry ) );
SvLBoxTab* pNextTab = NextTab( pTab );
sal_Bool bItemClipped = sal_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 = sal_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 sal_True;
}
}
}
return sal_False;
}
SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab* pTab )
{
sal_uInt16 nTabCount = pView->TabCount();
if( nTabCount <= 1 )
return 0;
for( sal_uInt16 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( sal_Bool bMode )
{
if( bUpdateMode != bMode )
{
bUpdateMode = bMode;
if( bUpdateMode )
UpdateAll( sal_False );
}
}
void SvImpLBox::SetUpdateModeFast( sal_Bool bMode )
{
if( bUpdateMode != bMode )
{
bUpdateMode = bMode;
if( bUpdateMode )
UpdateAll( sal_False, sal_False );
}
}
sal_Bool SvImpLBox::SetMostRight( SvLBoxEntry* pEntry )
{
if( pView->nTreeFlags & TREEFLAG_RECALCTABS )
{
nFlags |= F_IGNORE_CHANGED_TABS;
pView->SetTabs();
nFlags &= ~F_IGNORE_CHANGED_TABS;
}
sal_uInt16 nLastTab = pView->aTabs.Count() - 1;
sal_uInt16 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 sal_True;
}
}
return sal_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;
sal_uLong nCount = pList->Count();
for( sal_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( sal_uLong 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( sal_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;
}
}