office-gobmx/svtools/source/contnr/treelist.cxx
2011-11-27 13:24:31 -06:00

1879 lines
50 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* 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.
*
************************************************************************/
#include <svtools/treelist.hxx>
DBG_NAME(SvListEntry);
SvListEntry::SvListEntry()
{
DBG_CTOR(SvListEntry,0);
pChilds = 0;
pParent = 0;
nListPos = 0;
nAbsPos = 0;
}
SvListEntry::SvListEntry( const SvListEntry& rEntry )
{
DBG_CTOR(SvListEntry,0);
pChilds = 0;
pParent = 0;
nListPos &= 0x80000000;
nListPos |= ( rEntry.nListPos & 0x7fffffff);
nAbsPos = rEntry.nAbsPos;
}
SvListEntry::~SvListEntry()
{
DBG_DTOR(SvListEntry,0);
if ( pChilds )
{
pChilds->DestroyAll();
delete pChilds;
}
#ifdef DBG_UTIL
pChilds = 0;
pParent = 0;
#endif
}
void SvListEntry::Clone( SvListEntry* pSource)
{
DBG_CHKTHIS(SvListEntry,0);
nListPos &= 0x80000000;
nListPos |= ( pSource->nListPos & 0x7fffffff);
nAbsPos = pSource->nAbsPos;
}
void SvListEntry::SetListPositions()
{
if( pChilds )
{
SvListEntry *pEntry = (SvListEntry*)pChilds->First();
sal_uLong nCur = 0;
while ( pEntry )
{
pEntry->nListPos &= 0x80000000;
pEntry->nListPos |= nCur;
nCur++;
pEntry = (SvListEntry*)pChilds->Next();
}
}
nListPos &= (~0x80000000);
}
DBG_NAME(SvViewData);
SvViewData::SvViewData()
{
DBG_CTOR(SvViewData,0);
nFlags = 0;
nVisPos = 0;
}
SvViewData::SvViewData( const SvViewData& rData )
{
DBG_CTOR(SvViewData,0);
nFlags = rData.nFlags;
nFlags &= ~( SVLISTENTRYFLAG_SELECTED | SVLISTENTRYFLAG_FOCUSED );
nVisPos = rData.nVisPos;
}
SvViewData::~SvViewData()
{
DBG_DTOR(SvViewData,0);
#ifdef DBG_UTIL
nVisPos = 0x12345678;
nFlags = 0x1234;
#endif
}
//=============================================================================
// SvTreeEntryList
//=============================================================================
void SvTreeEntryList::DestroyAll()
{
SvListEntry* pPtr = (SvListEntry*)First();
while( pPtr )
{
delete pPtr;
pPtr = (SvListEntry*)Next();
}
}
SvTreeEntryList::SvTreeEntryList(SvTreeEntryList& rList)
{
maEntryList.clear();
maCurrent = 0;
for ( size_t i = 0, n = rList.size(); i < n; ++i ) {
maEntryList.push_back( rList[ i ] );
}
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvTreeList::SvTreeList()
{
nEntryCount = 0;
bAbsPositionsValid = sal_False;
nRefCount = 1;
pRootItem = new SvListEntry;
eSortMode = SortNone;
}
/*************************************************************************
|*
|* SvTreeList::~SvTreeList
|*
*************************************************************************/
SvTreeList::~SvTreeList()
{
Clear();
delete pRootItem;
#ifdef DBG_UTIL
pRootItem = 0;
#endif
}
/*************************************************************************
|*
|* SvTreeList::Broadcast
|*
*************************************************************************/
void SvTreeList::Broadcast(
sal_uInt16 nActionId,
SvListEntry* pEntry1,
SvListEntry* pEntry2,
sal_uLong nPos
) {
sal_uLong nViewCount = aViewList.size();
for( sal_uLong nCurView = 0; nCurView < nViewCount; nCurView++ )
{
SvListView* pView = aViewList[ nCurView ];
if( pView )
pView->ModelNotification( nActionId, pEntry1, pEntry2, nPos );
}
}
void SvTreeList::InsertView( SvListView* pView )
{
for ( sal_uLong i = 0, n = aViewList.size(); i < n; ++i ) {
if ( aViewList[ i ] == pView ) {
return;
}
}
aViewList.push_back( pView );
nRefCount++;
}
void SvTreeList::RemoveView( SvListView* pView )
{
for ( SvListView_impl::iterator it = aViewList.begin(); it < aViewList.end(); ++it ) {
if ( *it == pView ) {
aViewList.erase( it );
nRefCount--;
break;
}
}
}
// Ein Entry ist sichtbar, wenn alle Parents expandiert sind
sal_Bool SvTreeList::IsEntryVisible( const SvListView* pView, SvListEntry* pEntry ) const
{
DBG_ASSERT(pView&&pEntry,"IsVisible:Invalid Params");
sal_Bool bRetVal=sal_False;
do
{
if ( pEntry == pRootItem )
{
bRetVal=sal_True;
break;
}
pEntry = pEntry->pParent;
} while( pView->IsExpanded( pEntry ) );
return bRetVal;
}
sal_uInt16 SvTreeList::GetDepth( SvListEntry* pEntry ) const
{
DBG_ASSERT(pEntry&&pEntry!=pRootItem,"GetDepth:Bad Entry");
sal_uInt16 nDepth = 0;
while( pEntry->pParent != pRootItem )
{
nDepth++;
pEntry = pEntry->pParent;
}
return nDepth;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
void SvTreeList::Clear()
{
Broadcast( LISTACTION_CLEARING );
SvTreeEntryList* pRootList = pRootItem->pChilds;
if ( pRootList )
{
SvListEntry* pEntry = (SvListEntry*)(pRootList->First());
while( pEntry )
{
delete pEntry;
pEntry = (SvListEntry*)(pRootList->Next());
}
delete pRootItem->pChilds;
pRootItem->pChilds = 0;
}
nEntryCount = 0;
Broadcast( LISTACTION_CLEARED );
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
sal_Bool SvTreeList::IsChild( SvListEntry* pParent, SvListEntry* pChild ) const
{
if ( !pParent )
pParent = pRootItem;
sal_Bool bIsChild = sal_False;
SvTreeEntryList* pList = pParent->pChilds;
if ( !pList )
return sal_False;
SvListEntry* pActualChild = (SvListEntry*)(pList->First());
while( !bIsChild && pActualChild )
{
if ( pActualChild == pChild )
bIsChild = sal_True;
else
{
if ( pActualChild->pChilds )
bIsChild = IsChild( pActualChild, pChild );
pActualChild = (SvListEntry*)(pList->Next());
}
}
return bIsChild;
}
sal_uLong SvTreeList::Move(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,sal_uLong nListPos)
{
// pDest darf Null sein!
DBG_ASSERT(pSrcEntry,"Entry?");
if ( !pTargetParent )
pTargetParent = pRootItem;
DBG_ASSERT(pSrcEntry!=pTargetParent,"Move:Source=Target");
Broadcast( LISTACTION_MOVING, pSrcEntry, pTargetParent, nListPos );
if ( !pTargetParent->pChilds )
pTargetParent->pChilds = new SvTreeEntryList;
if ( pSrcEntry == pTargetParent )
return pSrcEntry->GetChildListPos();
bAbsPositionsValid = sal_False;
SvTreeEntryList* pDstList = pTargetParent->pChilds;
SvTreeEntryList* pSrcList = pSrcEntry->pParent->pChilds;
// Dummy-Ptr einfuegen, weil nListPos durch das
// folgende Remove ungueltig werden koennte
SvListEntry* pDummy = 0;
pDstList->insert( pDummy, nListPos );
// loeschen
pSrcList->remove( pSrcEntry );
// Hat Parent noch Childs ?
if ( pSrcList->empty() )
{
// Keine Childs, deshalb Child-List loeschen
SvListEntry* pParent = pSrcEntry->pParent;
pParent->pChilds = 0;
delete pSrcList;
pSrcList = 0;
}
// Parent umsetzen (erst hier, weil wir zum Loeschen
// der ChildList den alten Parent noch benoetigen!)
pSrcEntry->pParent = pTargetParent;
pDstList->replace( pSrcEntry, pDummy );
// Listenpositionen in Zielliste korrigieren
SetListPositions( pDstList );
if ( pSrcList && (sal_uLong)pSrcList != (sal_uLong)pDstList )
SetListPositions( pSrcList );
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
sal_uLong nRetVal = pDstList->GetPos( pSrcEntry );
DBG_ASSERT(nRetVal==pSrcEntry->GetChildListPos(),"ListPos not valid");
Broadcast( LISTACTION_MOVED,pSrcEntry,pTargetParent,nRetVal);
return nRetVal;
}
sal_uLong SvTreeList::Copy(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,sal_uLong nListPos)
{
// pDest darf Null sein!
DBG_ASSERT(pSrcEntry,"Entry?");
if ( !pTargetParent )
pTargetParent = pRootItem;
if ( !pTargetParent->pChilds )
pTargetParent->pChilds = new SvTreeEntryList;
bAbsPositionsValid = sal_False;
sal_uLong nCloneCount = 0;
SvListEntry* pClonedEntry = Clone( pSrcEntry, nCloneCount );
nEntryCount += nCloneCount;
SvTreeEntryList* pDstList = pTargetParent->pChilds;
pClonedEntry->pParent = pTargetParent; // Parent umsetzen
pDstList->insert( pClonedEntry, nListPos ); // Einfuegen
SetListPositions( pDstList ); // Listenpositionen in Zielliste korrigieren
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
Broadcast( LISTACTION_INSERTED_TREE, pClonedEntry );
sal_uLong nRetVal = pDstList->GetPos( pClonedEntry );
return nRetVal;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
void SvTreeList::Move( SvListEntry* pSrcEntry, SvListEntry* pDstEntry )
{
SvListEntry* pParent;
sal_uLong nPos;
if ( !pDstEntry )
{
pParent = pRootItem;
nPos = 0UL;
}
else
{
pParent = pDstEntry->pParent;
nPos = pDstEntry->GetChildListPos();
nPos++; // UNTER (Bildschirm) pDstEntry einfuegen
}
Move( pSrcEntry, pParent, nPos );
}
void SvTreeList::InsertTree(SvListEntry* pSrcEntry,
SvListEntry* pTargetParent,sal_uLong nListPos)
{
DBG_ASSERT(pSrcEntry,"InsertTree:Entry?");
if ( !pSrcEntry )
return;
if ( !pTargetParent )
pTargetParent = pRootItem;
if ( !pTargetParent->pChilds )
pTargetParent->pChilds = new SvTreeEntryList;
// Sortierung beruecksichtigen
GetInsertionPos( pSrcEntry, pTargetParent, nListPos );
bAbsPositionsValid = sal_False;
pSrcEntry->pParent = pTargetParent; // Parent umsetzen
SvTreeEntryList* pDstList = pTargetParent->pChilds;
pDstList->insert( pSrcEntry, nListPos ); // einfuegen
SetListPositions(pDstList); // Listenpositionen in Zielliste korrigieren
nEntryCount += GetChildCount( pSrcEntry );
nEntryCount++; // der Parent ist ja auch neu
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
Broadcast(LISTACTION_INSERTED_TREE, pSrcEntry );
}
SvListEntry* SvTreeList::CloneEntry( SvListEntry* pSource ) const
{
if( aCloneLink.IsSet() )
return (SvListEntry*)aCloneLink.Call( pSource );
SvListEntry* pEntry = CreateEntry();
pSource->Clone( pEntry );
return pSource;
}
SvListEntry* SvTreeList::CreateEntry() const
{
return new SvListEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::Clone( SvListEntry* pEntry, sal_uLong& nCloneCount ) const
{
SvListEntry* pClonedEntry = CloneEntry( pEntry );
nCloneCount = 1;
SvTreeEntryList* pChilds = pEntry->pChilds;
if ( pChilds )
pClonedEntry->pChilds=CloneChilds(pChilds,pClonedEntry,nCloneCount);
return pClonedEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvTreeEntryList* SvTreeList::CloneChilds( SvTreeEntryList* pChilds,
SvListEntry* pNewParent,
sal_uLong& nCloneCount ) const
{
DBG_ASSERT(!pChilds->empty(),"Childs?");
SvTreeEntryList* pClonedChilds = new SvTreeEntryList;
SvListEntry* pChild = (SvListEntry*)pChilds->First();
while ( pChild )
{
SvListEntry* pNewChild = CloneEntry( pChild );
nCloneCount++;
pNewChild->pParent = pNewParent;
SvTreeEntryList* pSubChilds = pChild->pChilds;
if ( pSubChilds )
{
pSubChilds = CloneChilds( pSubChilds, pNewChild, nCloneCount );
pNewChild->pChilds = pSubChilds;
}
pClonedChilds->push_back( pNewChild );
pChild = (SvListEntry*)pChilds->Next();
}
return pClonedChilds;
}
/*************************************************************************
|*
|* SvTreeList::GetChildCount
|*
*************************************************************************/
sal_uLong SvTreeList::GetChildCount( SvListEntry* pParent ) const
{
if ( !pParent )
return GetEntryCount();
if ( !pParent || !pParent->pChilds)
return 0;
sal_uLong nCount = 0;
sal_uInt16 nRefDepth = GetDepth( pParent );
sal_uInt16 nActDepth = nRefDepth;
do
{
pParent = Next( pParent, &nActDepth );
nCount++;
} while( pParent && nRefDepth < nActDepth );
nCount--;
return nCount;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
sal_uLong SvTreeList::GetVisibleChildCount(const SvListView* pView, SvListEntry* pParent) const
{
DBG_ASSERT(pView,"GetVisChildCount:No View");
if ( !pParent )
pParent = pRootItem;
if ( !pParent || !pView->IsExpanded(pParent) || !pParent->pChilds )
return 0;
sal_uLong nCount = 0;
sal_uInt16 nRefDepth = GetDepth( pParent );
sal_uInt16 nActDepth = nRefDepth;
do
{
pParent = NextVisible( pView, pParent, &nActDepth );
nCount++;
} while( pParent && nRefDepth < nActDepth );
nCount--;
return nCount;
}
sal_uLong SvTreeList::GetChildSelectionCount(const SvListView* pView,SvListEntry* pParent) const
{
DBG_ASSERT(pView,"GetChildSelCount:No View");
if ( !pParent )
pParent = pRootItem;
if ( !pParent || !pParent->pChilds)
return 0;
sal_uLong nCount = 0;
sal_uInt16 nRefDepth = GetDepth( pParent );
sal_uInt16 nActDepth = nRefDepth;
do
{
pParent = Next( pParent, &nActDepth );
if( pParent && pView->IsSelected( pParent ) && nRefDepth < nActDepth)
nCount++;
} while( pParent && nRefDepth < nActDepth );
// nCount--;
return nCount;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::First() const
{
if ( nEntryCount )
return (SvListEntry*)(*pRootItem->pChilds)[ 0 ];
else
return 0;
}
/*************************************************************************
|*
|* SvTreeList::Next
|*
*************************************************************************/
SvListEntry* SvTreeList::Next( SvListEntry* pActEntry, sal_uInt16* pDepth ) const
{
DBG_ASSERT( pActEntry && pActEntry->pParent, "SvTreeList::Next: invalid entry/parent!" );
if ( !pActEntry || !pActEntry->pParent )
return NULL;
sal_uInt16 nDepth = 0;
int bWithDepth = sal_False;
if ( pDepth )
{
nDepth = *pDepth;
bWithDepth = sal_True;
}
SvTreeEntryList* pActualList = pActEntry->pParent->pChilds;
sal_uLong nActualPos = pActEntry->GetChildListPos();
if ( pActEntry->pChilds /* && pActEntry->pChilds->Count() */ )
{
nDepth++;
pActEntry = (SvListEntry*)(*pActEntry->pChilds)[ 0 ];
if ( bWithDepth )
*pDepth = nDepth;
return pActEntry;
}
if ( pActualList->size() > ( nActualPos + 1 ) )
{
pActEntry = (SvListEntry*)(*pActualList)[ nActualPos + 1 ];
if ( bWithDepth )
*pDepth = nDepth;
return pActEntry;
}
SvListEntry* pParent = pActEntry->pParent;
nDepth--;
while( pParent != pRootItem && pParent != 0 )
{
DBG_ASSERT(pParent!=0,"TreeData corrupt!");
pActualList = pParent->pParent->pChilds;
DBG_ASSERT(pActualList,"TreeData corrupt!");
nActualPos = pParent->GetChildListPos();
if ( pActualList->size() > ( nActualPos + 1 ) )
{
pActEntry = (SvListEntry*)(*pActualList)[ nActualPos + 1 ];
if ( bWithDepth )
*pDepth = nDepth;
return pActEntry;
}
pParent = pParent->pParent;
nDepth--;
}
return 0;
}
/*************************************************************************
|*
|* SvTreeList::Prev
|*
*************************************************************************/
SvListEntry* SvTreeList::Prev( SvListEntry* pActEntry, sal_uInt16* pDepth ) const
{
DBG_ASSERT(pActEntry!=0,"Entry?");
sal_uInt16 nDepth = 0;
int bWithDepth = sal_False;
if ( pDepth )
{
nDepth = *pDepth;
bWithDepth = sal_True;
}
SvTreeEntryList* pActualList = pActEntry->pParent->pChilds;
sal_uLong nActualPos = pActEntry->GetChildListPos();
if ( nActualPos > 0 )
{
pActEntry = (SvListEntry*)(*pActualList)[ nActualPos - 1 ];
while( pActEntry->pChilds )
{
pActualList = pActEntry->pChilds;
nDepth++;
pActEntry = (SvListEntry*)(pActualList->last());
}
if ( bWithDepth )
*pDepth = nDepth;
return pActEntry;
}
if ( pActEntry->pParent == pRootItem )
return 0;
pActEntry = pActEntry->pParent;
if ( pActEntry )
{
nDepth--;
if ( bWithDepth )
*pDepth = nDepth;
return pActEntry;
}
return 0;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::Last() const
{
SvTreeEntryList* pActList = pRootItem->pChilds;
// if ( pActList->Count() == 0 )
// return 0;
SvListEntry* pEntry = 0;
while( pActList )
{
pEntry = (SvListEntry*)(pActList->last());
pActList = pEntry->pChilds;
// if ( pActList->Count() == 0 )
// pActList = 0;
}
return pEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
sal_uLong SvTreeList::GetVisiblePos( const SvListView* pView, SvListEntry* pEntry ) const
{
DBG_ASSERT(pView&&pEntry,"View/Entry?");
if ( !pView->bVisPositionsValid )
{
// damit GetVisibleCount die Positionen aktualisiert
((SvListView*)pView)->nVisibleCount = 0;
GetVisibleCount( pView );
}
SvViewData* pViewData = pView->GetViewData( pEntry );
return pViewData->nVisPos;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
sal_uLong SvTreeList::GetVisibleCount( const SvListView* pView ) const
{
DBG_ASSERT(pView,"GetVisCount:No View");
if( !pView->HasViewData() )
return 0;
if ( pView->nVisibleCount )
return pView->nVisibleCount;
sal_uLong nPos = 0;
SvListEntry* pEntry = First(); // erster Eintrag immer sichtbar
while ( pEntry )
{
SvViewData* pViewData = pView->GetViewData( pEntry );
pViewData->nVisPos = nPos;
nPos++;
pEntry = NextVisible( pView, pEntry );
}
#ifdef DBG_UTIL
if( nPos > 10000000 )
{
OSL_FAIL("nVisibleCount bad");
}
#endif
((SvListView*)pView)->nVisibleCount = nPos;
((SvListView*)pView)->bVisPositionsValid = sal_True;
return nPos;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
// Funktion geht aus Geschwindigkeitsgruenden davon aus,
// das der uebergebene Eintrag bereits sichtbar ist
SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pActEntry,sal_uInt16* pActDepth) const
{
DBG_ASSERT(pView,"NextVisible:No View");
if ( !pActEntry )
return 0;
sal_uInt16 nDepth = 0;
int bWithDepth = sal_False;
if ( pActDepth )
{
nDepth = *pActDepth;
bWithDepth = sal_True;
}
SvTreeEntryList* pActualList = pActEntry->pParent->pChilds;
sal_uLong nActualPos = pActEntry->GetChildListPos();
if ( pView->IsExpanded(pActEntry) )
{
DBG_ASSERT(pActEntry->pChilds,"Childs?");
nDepth++;
pActEntry = (SvListEntry*)(*pActEntry->pChilds)[ 0 ];
if ( bWithDepth )
*pActDepth = nDepth;
return pActEntry;
}
nActualPos++;
if ( pActualList->size() > nActualPos )
{
pActEntry = (SvListEntry*)(*pActualList)[ nActualPos ];
if ( bWithDepth )
*pActDepth = nDepth;
return pActEntry;
}
SvListEntry* pParent = pActEntry->pParent;
nDepth--;
while( pParent != pRootItem )
{
pActualList = pParent->pParent->pChilds;
nActualPos = pParent->GetChildListPos();
nActualPos++;
if ( pActualList->size() > nActualPos )
{
pActEntry = (SvListEntry*)(*pActualList)[ nActualPos ];
if ( bWithDepth )
*pActDepth = nDepth;
return pActEntry;
}
pParent = pParent->pParent;
nDepth--;
}
return 0;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
// Funktion geht aus Geschwindigkeitsgruenden davon aus,
// das der uebergebene Eintrag bereits sichtbar ist
SvListEntry* SvTreeList::PrevVisible(const SvListView* pView, SvListEntry* pActEntry, sal_uInt16* pActDepth) const
{
DBG_ASSERT(pView&&pActEntry,"PrevVis:View/Entry?");
sal_uInt16 nDepth = 0;
int bWithDepth = sal_False;
if ( pActDepth )
{
nDepth = *pActDepth;
bWithDepth = sal_True;
}
SvTreeEntryList* pActualList = pActEntry->pParent->pChilds;
sal_uLong nActualPos = pActEntry->GetChildListPos();
if ( nActualPos > 0 )
{
pActEntry = (SvListEntry*)(*pActualList)[ nActualPos - 1 ];
while( pView->IsExpanded(pActEntry) )
{
pActualList = pActEntry->pChilds;
nDepth++;
pActEntry = (SvListEntry*)(pActualList->last());
}
if ( bWithDepth )
*pActDepth = nDepth;
return pActEntry;
}
if ( pActEntry->pParent == pRootItem )
return 0;
pActEntry = pActEntry->pParent;
if ( pActEntry )
{
nDepth--;
if ( bWithDepth )
*pActDepth = nDepth;
return pActEntry;
}
return 0;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::LastVisible( const SvListView* pView, sal_uInt16* pDepth) const
{
DBG_ASSERT(pView,"LastVis:No View");
SvListEntry* pEntry = Last();
while( pEntry && !IsEntryVisible( pView, pEntry ) )
pEntry = PrevVisible( pView, pEntry );
if ( pEntry && pDepth )
*pDepth = GetDepth( pEntry );
return pEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pEntry,sal_uInt16& nDelta) const
{
DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"NextVis:Wrong Prms/!Vis");
sal_uLong nVisPos = GetVisiblePos( pView, pEntry );
// nDelta Eintraege vorhanden ?
// Beispiel: 0,1,2,3,4,5,6,7,8,9 nVisPos=5 nDelta=7
// nNewDelta = 10-nVisPos-1 == 4
if ( nVisPos+nDelta >= pView->nVisibleCount )
{
nDelta = (sal_uInt16)(pView->nVisibleCount-nVisPos);
nDelta--;
}
sal_uInt16 nDeltaTmp = nDelta;
while( nDeltaTmp )
{
pEntry = NextVisible( pView, pEntry );
nDeltaTmp--;
DBG_ASSERT(pEntry,"Entry?");
}
return pEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::PrevVisible( const SvListView* pView, SvListEntry* pEntry, sal_uInt16& nDelta ) const
{
DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"PrevVis:Parms/!Vis");
sal_uLong nVisPos = GetVisiblePos( pView, pEntry );
// nDelta Eintraege vorhanden ?
// Beispiel: 0,1,2,3,4,5,6,7,8,9 nVisPos=8 nDelta=20
// nNewDelta = nNewVisPos
if ( nDelta > nVisPos )
nDelta = (sal_uInt16)nVisPos;
sal_uInt16 nDeltaTmp = nDelta;
while( nDeltaTmp )
{
pEntry = PrevVisible( pView, pEntry );
nDeltaTmp--;
DBG_ASSERT(pEntry,"Entry?");
}
return pEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::FirstSelected( const SvListView* pView) const
{
DBG_ASSERT(pView,"FirstSel:No View");
if( !pView )
return 0;
SvListEntry* pActSelEntry = First();
while( pActSelEntry && !pView->IsSelected(pActSelEntry) )
pActSelEntry = NextVisible( pView, pActSelEntry );
return pActSelEntry;
}
SvListEntry* SvTreeList::FirstChild( SvListEntry* pParent ) const
{
if ( !pParent )
pParent = pRootItem;
SvListEntry* pResult;
if ( pParent->pChilds )
pResult = (SvListEntry*)(*pParent->pChilds)[ 0 ];
else
pResult = 0;
return pResult;
}
SvListEntry* SvTreeList::NextSibling( SvListEntry* pEntry ) const
{
DBG_ASSERT(pEntry,"Entry?");
if( !pEntry )
return 0;
SvTreeEntryList* pList = pEntry->pParent->pChilds;
sal_uLong nPos = pEntry->GetChildListPos();
nPos++;
pEntry = (SvListEntry*)(*pList)[ nPos ];
return pEntry;
}
SvListEntry* SvTreeList::PrevSibling( SvListEntry* pEntry ) const
{
DBG_ASSERT(pEntry,"Entry?");
if( !pEntry )
return 0;
SvTreeEntryList* pList = pEntry->pParent->pChilds;
sal_uLong nPos = pEntry->GetChildListPos();
if ( nPos == 0 )
return 0;
nPos--;
pEntry = (SvListEntry*)(*pList)[ nPos ];
return pEntry;
}
SvListEntry* SvTreeList::LastSibling( SvListEntry* pEntry ) const
{
DBG_ASSERT(pEntry,"LastSibling:Entry?");
if( !pEntry )
return 0;
SvListEntry* pSib = 0;
SvTreeEntryList* pSibs = pEntry->pParent->pChilds;
if ( pSibs )
pSib = (SvListEntry*)(pSibs->last());
return pSib;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::NextSelected( const SvListView* pView, SvListEntry* pEntry ) const
{
DBG_ASSERT(pView&&pEntry,"NextSel:View/Entry?");
pEntry = Next( pEntry );
while( pEntry && !pView->IsSelected(pEntry) )
pEntry = Next( pEntry );
return pEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::PrevSelected( const SvListView* pView, SvListEntry* pEntry) const
{
DBG_ASSERT(pView&&pEntry,"PrevSel:View/Entry?");
pEntry = Prev( pEntry );
while( pEntry && !pView->IsSelected(pEntry) )
pEntry = Prev( pEntry );
return pEntry;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
SvListEntry* SvTreeList::LastSelected( const SvListView* pView ) const
{
DBG_ASSERT(pView,"LastSel:No View");
SvListEntry* pEntry = Last();
while( pEntry && !pView->IsSelected(pEntry) )
pEntry = Prev( pEntry );
return pEntry;
}
/*************************************************************************
|*
|* SvTreeList::Insert
|*
*************************************************************************/
sal_uLong SvTreeList::Insert( SvListEntry* pEntry,SvListEntry* pParent,sal_uLong nPos )
{
DBG_ASSERT( pEntry,"Entry?");
if ( !pParent )
pParent = pRootItem;
SvTreeEntryList* pList = pParent->pChilds;
if ( !pList )
{
// Parent bekommt zum erstenmal ein Kind
pList = new SvTreeEntryList;
pParent->pChilds = pList;
}
// Sortierung beruecksichtigen
GetInsertionPos( pEntry, pParent, nPos );
bAbsPositionsValid = sal_False;
pEntry->pParent = pParent;
pList->insert( pEntry, nPos );
nEntryCount++;
if( nPos != ULONG_MAX && (nPos != (pList->size()-1)) )
SetListPositions( pList );
else
pEntry->nListPos = pList->size()-1;
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
Broadcast( LISTACTION_INSERTED, pEntry );
return nPos; // pEntry->nListPos;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
sal_uLong SvTreeList::GetAbsPos( SvListEntry* pEntry) const
{
if ( !bAbsPositionsValid )
((SvTreeList*)this)->SetAbsolutePositions();
return pEntry->nAbsPos;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
void SvTreeList::SetAbsolutePositions()
{
sal_uLong nPos = 0;
SvListEntry* pEntry = First();
while ( pEntry )
{
pEntry->nAbsPos = nPos;
nPos++;
pEntry = Next( pEntry );
}
bAbsPositionsValid = sal_True;
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
}
/*************************************************************************
|*
|* SvTreeList::Expand
|*
*************************************************************************/
void SvTreeList::Expand( SvListView* pView, SvListEntry* pEntry )
{
DBG_ASSERT(pEntry&&pView,"Expand:View/Entry?");
if ( pView->IsExpanded(pEntry) )
return;
DBG_ASSERT(pEntry->pChilds,"Expand:No Childs!");
SvViewData* pViewData = pView->GetViewData(pEntry);
pViewData->nFlags |= SVLISTENTRYFLAG_EXPANDED;
SvListEntry* pParent = pEntry->pParent;
// wenn Parent sichtbar dann Statusdaten invalidieren
if ( pView->IsExpanded( pParent ) )
{
pView->bVisPositionsValid = sal_False;
pView->nVisibleCount = 0;
}
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
}
/*************************************************************************
|*
|* SvTreeList::Collapse
|*
*************************************************************************/
void SvTreeList::Collapse( SvListView* pView, SvListEntry* pEntry )
{
DBG_ASSERT(pView&&pEntry,"Collapse:View/Entry?");
if ( !pView->IsExpanded(pEntry) )
return;
DBG_ASSERT(pEntry->pChilds,"Collapse:No Childs!");
SvViewData* pViewData = pView->GetViewData( pEntry );
pViewData->nFlags &=(~SVLISTENTRYFLAG_EXPANDED);
SvListEntry* pParent = pEntry->pParent;
if ( pView->IsExpanded(pParent) )
{
pView->nVisibleCount = 0;
pView->bVisPositionsValid = sal_False;
}
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
sal_Bool SvTreeList::Select( SvListView* pView, SvListEntry* pEntry, sal_Bool bSelect )
{
DBG_ASSERT(pView&&pEntry,"Select:View/Entry?");
SvViewData* pViewData = pView->GetViewData( pEntry );
if ( bSelect )
{
if ( pViewData->IsSelected() || !pViewData->IsSelectable() )
return sal_False;
else
{
pViewData->nFlags |= SVLISTENTRYFLAG_SELECTED;
pView->nSelectionCount++;
}
}
else
{
if ( !pViewData->IsSelected() )
return sal_False;
else
{
pViewData->nFlags &= ~( SVLISTENTRYFLAG_SELECTED );
pView->nSelectionCount--;
}
}
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
return sal_True;
}
/*************************************************************************
|*
|* SvTreeList::Remove
|*
*************************************************************************/
sal_Bool SvTreeList::Remove( SvListEntry* pEntry )
{
DBG_ASSERT(pEntry,"Cannot remove root, use clear");
if( !pEntry->pParent )
{
OSL_FAIL("Removing entry not in model!");
// unter gewissen Umstaenden (welche?) loescht der
// Explorer aus der View Eintraege, die er nicht in die View
// eingefuegt hat. Da sich der Kunde fuer ein platzendes
// Office nichts kaufen kann, fange ich diesen Fall ab.
return sal_False;
}
Broadcast( LISTACTION_REMOVING, pEntry );
sal_uLong nRemoved = 1 + GetChildCount(pEntry);
bAbsPositionsValid = sal_False;
SvListEntry* pParent = pEntry->pParent;
SvTreeEntryList* pList = pParent->pChilds;
DBG_ASSERT(pList,"Remove:No Childlist");
sal_Bool bLastEntry = sal_False;
if ( pEntry->HasChildListPos() )
{
size_t nListPos = pEntry->GetChildListPos();
bLastEntry = (nListPos == (pList->size()-1) ) ? sal_True : sal_False;
pList->remove( nListPos );
}
else
{
pList->remove( pEntry );
}
// moved to end of method because it is used later with Broadcast
// delete pEntry; // loescht auch alle Childs
if ( pList->empty() )
{
pParent->pChilds = 0;
delete pList;
}
else
{
if( !bLastEntry )
SetListPositions( pList );
}
nEntryCount -= nRemoved;
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
Broadcast( LISTACTION_REMOVED, pEntry );
delete pEntry; // loescht auch alle Childs
return sal_True;
}
/*************************************************************************
|*
|* SvTreeList::
|*
*************************************************************************/
void SvTreeList::SelectAll( SvListView* pView, sal_Bool bSelect )
{
DBG_ASSERT(pView,"SelectAll:NoView");
SvListEntry* pEntry = First();
while ( pEntry )
{
SvViewData* pViewData = pView->GetViewData( pEntry );
if ( bSelect )
pViewData->nFlags |= SVLISTENTRYFLAG_SELECTED;
else
pViewData->nFlags &= (~SVLISTENTRYFLAG_SELECTED);
pEntry = Next( pEntry );
}
if ( bSelect )
pView->nSelectionCount = nEntryCount;
else
pView->nSelectionCount = 0;
#ifdef CHECK_INTEGRITY
CheckIntegrity();
#endif
}
SvListEntry* SvTreeList::GetEntryAtAbsPos( sal_uLong nAbsPos ) const
{
SvListEntry* pEntry = First();
while ( nAbsPos && pEntry )
{
pEntry = Next( pEntry );
nAbsPos--;
}
return pEntry;
}
SvListEntry* SvTreeList::GetEntryAtVisPos( const SvListView* pView, sal_uLong nVisPos ) const
{
DBG_ASSERT(pView,"GetEntryAtVisPos:No View");
SvListEntry* pEntry = First();
while ( nVisPos && pEntry )
{
pEntry = NextVisible( pView, pEntry );
nVisPos--;
}
return pEntry;
}
void SvTreeList::SetListPositions( SvTreeEntryList* pList )
{
if( !pList->empty() )
{
SvListEntry* pEntry = (SvListEntry*)(*pList)[ 0 ];
if( pEntry->pParent )
pEntry->pParent->InvalidateChildrensListPositions();
}
}
void SvTreeList::InvalidateEntry( SvListEntry* pEntry )
{
Broadcast( LISTACTION_INVALIDATE_ENTRY, pEntry );
}
sal_Bool SvTreeList::IsInChildList( SvListEntry* pParent, SvListEntry* pChild) const
{
if ( !pParent )
pParent = pRootItem;
sal_Bool bIsChild = sal_False;
if ( pParent->pChilds )
bIsChild = (sal_Bool)(pParent->pChilds->GetPos(pChild) != ULONG_MAX);
return bIsChild;
}
void lcl_CheckList( SvTreeEntryList* pList )
{
SvListEntry* pEntry = (SvListEntry*)(pList->First());
sal_uLong nPos = 0;
while ( pEntry )
{
DBG_ASSERT(pEntry->GetChildListPos()==nPos,"Wrong ListPos");
pEntry = (SvListEntry*)(pList->Next());
nPos++;
}
}
SvListEntry* SvTreeList::GetRootLevelParent( SvListEntry* pEntry ) const
{
DBG_ASSERT(pEntry,"GetRootLevelParent:No Entry");
SvListEntry* pCurParent = 0;
if ( pEntry )
{
pCurParent = pEntry->pParent;
if ( pCurParent == pRootItem )
return pEntry; // ist sein eigener Parent
while( pCurParent && pCurParent->pParent != pRootItem )
pCurParent = pCurParent->pParent;
}
return pCurParent;
}
//*************************************************************************
//*************************************************************************
//*************************************************************************
//*************************************************************************
//*************************************************************************
//*************************************************************************
//*************************************************************************
//*************************************************************************
DBG_NAME(SvListView);
SvListView::SvListView( SvTreeList* pModell )
{
DBG_CTOR(SvListView,0);
pModel = 0;
nSelectionCount = 0;
nVisibleCount = 0;
bVisPositionsValid = sal_False;
SetModel( pModell );
}
SvListView::SvListView()
{
DBG_CTOR(SvListView,0);
pModel = 0;
nSelectionCount = 0;
nVisibleCount = 0;
bVisPositionsValid = sal_False;
}
SvListView::~SvListView()
{
DBG_DTOR(SvListView,0);
ClearTable();
}
void SvListView::InitTable()
{
DBG_CHKTHIS(SvListView,0);
DBG_ASSERT(pModel,"InitTable:No Model");
DBG_ASSERT(!nSelectionCount&&!nVisibleCount&&!bVisPositionsValid,"InitTable: Not cleared!");
if( aDataTable.Count() )
{
DBG_ASSERT(aDataTable.Count()==1,"InitTable: TableCount != 1");
// die im Clear fuer die Root allozierten View-Daten loeschen
// Achtung: Das zu dem RootEntry (und damit auch der Entry)
// gehoerende Model kann bereits geloescht sein!
SvViewData* pViewData = (SvViewData*)aDataTable.GetObject( 0 );
delete pViewData;
aDataTable.Clear();
}
SvListEntry* pEntry;
SvViewData* pViewData;
// RootEntry einfuegen
pEntry = pModel->pRootItem;
pViewData = new SvViewData;
pViewData->nFlags = SVLISTENTRYFLAG_EXPANDED;
aDataTable.Insert( (sal_uLong)pEntry, pViewData );
// Jetzt alle anderen Entries
pEntry = pModel->First();
while( pEntry )
{
pViewData = CreateViewData( pEntry );
DBG_ASSERT(pViewData,"InitTable:No ViewData");
InitViewData( pViewData, pEntry );
aDataTable.Insert( (sal_uLong)pEntry, pViewData );
pEntry = pModel->Next( pEntry );
}
}
SvViewData* SvListView::CreateViewData( SvListEntry* )
{
DBG_CHKTHIS(SvListView,0);
return new SvViewData;
}
void SvListView::ClearTable()
{
DBG_CHKTHIS(SvListView,0);
SvViewData* pViewData = (SvViewData*)aDataTable.First();
while( pViewData )
{
delete pViewData;
pViewData = (SvViewData*)aDataTable.Next();
}
aDataTable.Clear();
}
void SvListView::Clear()
{
ClearTable();
nSelectionCount = 0;
nVisibleCount = 0;
bVisPositionsValid = sal_False;
if( pModel )
{
// RootEntry einfuegen
SvListEntry* pEntry = pModel->pRootItem;
SvViewData* pViewData = new SvViewData;
pViewData->nFlags = SVLISTENTRYFLAG_EXPANDED;
aDataTable.Insert( (sal_uLong)pEntry, pViewData );
}
}
void SvListView::SetModel( SvTreeList* pNewModel )
{
DBG_CHKTHIS(SvListView,0);
sal_Bool bBroadcastCleared = sal_False;
if ( pModel )
{
pModel->RemoveView( this );
bBroadcastCleared = sal_True;
ModelNotification( LISTACTION_CLEARING,0,0,0 );
if ( pModel->GetRefCount() == 0 )
delete pModel;
}
pModel = pNewModel;
InitTable();
pNewModel->InsertView( this );
if( bBroadcastCleared )
ModelNotification( LISTACTION_CLEARED,0,0,0 );
}
void SvListView::ModelHasCleared()
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ModelHasInserted( SvListEntry* )
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ModelHasInsertedTree( SvListEntry* )
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ModelIsMoving( SvListEntry* /* pSource */ ,
SvListEntry* /* pTargetParent */ , sal_uLong /* nPos */ )
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ModelHasMoved( SvListEntry* )
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ModelIsRemoving( SvListEntry* )
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ModelHasRemoved( SvListEntry* )
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ModelHasEntryInvalidated( SvListEntry*)
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ActionMoving( SvListEntry* pEntry,SvListEntry*,sal_uLong)
{
DBG_CHKTHIS(SvListView,0);
SvListEntry* pParent = pEntry->pParent;
DBG_ASSERT(pParent,"Model not consistent");
if( pParent != pModel->pRootItem && pParent->pChilds->size() == 1 )
{
SvViewData* pViewData = (SvViewData*)aDataTable.Get( (sal_uLong)pParent );
pViewData->nFlags &= (~SVLISTENTRYFLAG_EXPANDED);
}
// vorlaeufig
nVisibleCount = 0;
bVisPositionsValid = sal_False;
}
void SvListView::ActionMoved( SvListEntry* /* pEntry */ ,
SvListEntry* /* pTargetPrnt */ ,
sal_uLong /* nChildPos */ )
{
DBG_CHKTHIS(SvListView,0);
nVisibleCount = 0;
bVisPositionsValid = sal_False;
}
void SvListView::ActionInserted( SvListEntry* pEntry )
{
DBG_CHKTHIS(SvListView,0);
DBG_ASSERT(pEntry,"Insert:No Entry");
SvViewData* pData = CreateViewData( pEntry );
InitViewData( pData, pEntry );
#ifdef DBG_UTIL
sal_Bool bSuccess =
#endif
aDataTable.Insert( (sal_uLong)pEntry, pData );
DBG_ASSERT(bSuccess,"Entry already in View");
if ( nVisibleCount && pModel->IsEntryVisible( this, pEntry ))
{
nVisibleCount = 0;
bVisPositionsValid = sal_False;
}
}
void SvListView::ActionInsertedTree( SvListEntry* pEntry )
{
DBG_CHKTHIS(SvListView,0);
if ( pModel->IsEntryVisible( this, pEntry ))
{
nVisibleCount = 0;
bVisPositionsValid = sal_False;
}
// ueber Entry und seine Childs iterieren
SvListEntry* pCurEntry = pEntry;
sal_uInt16 nRefDepth = pModel->GetDepth( pCurEntry );
while( pCurEntry )
{
DBG_ASSERT(aDataTable.Get((sal_uLong)pCurEntry)==0,"Entry already in Table");
SvViewData* pViewData = CreateViewData( pCurEntry );
DBG_ASSERT(pViewData,"No ViewData");
InitViewData( pViewData, pEntry );
aDataTable.Insert( (sal_uLong)pCurEntry, pViewData );
pCurEntry = pModel->Next( pCurEntry );
if ( pCurEntry && pModel->GetDepth(pCurEntry) <= nRefDepth)
pCurEntry = 0;
}
}
void SvListView::RemoveViewData( SvListEntry* pParent )
{
SvTreeEntryList* pChilds = pParent->pChilds;
if( pChilds )
{
SvListEntry* pCur = (SvListEntry*)pChilds->First();
while( pCur )
{
SvViewData* pViewData = (SvViewData*)aDataTable.Get((sal_uLong)pCur);
delete pViewData;
aDataTable.Remove( (sal_uLong)pCur );
if( pCur->HasChilds())
RemoveViewData( pCur );
pCur = (SvListEntry*)pChilds->Next();
}
}
}
void SvListView::ActionRemoving( SvListEntry* pEntry )
{
DBG_CHKTHIS(SvListView,0);
DBG_ASSERT(pEntry,"Remove:No Entry");
SvViewData* pViewData = (SvViewData*)aDataTable.Get( (sal_uLong)pEntry );
sal_uLong nSelRemoved = 0;
if ( pViewData->IsSelected() )
nSelRemoved = 1 + pModel->GetChildSelectionCount( this, pEntry );
nSelectionCount -= nSelRemoved;
sal_uLong nVisibleRemoved = 0;
if ( pModel->IsEntryVisible( this, pEntry ) )
nVisibleRemoved = 1 + pModel->GetVisibleChildCount( this, pEntry );
if( nVisibleCount )
{
#ifdef DBG_UTIL
if( nVisibleCount < nVisibleRemoved )
{
OSL_FAIL("nVisibleRemoved bad");
}
#endif
nVisibleCount -= nVisibleRemoved;
}
bVisPositionsValid = sal_False;
pViewData = (SvViewData*)aDataTable.Get((sal_uLong)pEntry);
delete pViewData;
aDataTable.Remove( (sal_uLong)pEntry );
RemoveViewData( pEntry );
SvListEntry* pCurEntry = pEntry->pParent;
if ( pCurEntry && pCurEntry != pModel->pRootItem &&
pCurEntry->pChilds->size() == 1 )
{
pViewData = (SvViewData*)aDataTable.Get((sal_uLong)pCurEntry);
pViewData->nFlags &= (~SVLISTENTRYFLAG_EXPANDED);
}
}
void SvListView::ActionRemoved( SvListEntry* /* pEntry */ )
{
DBG_CHKTHIS(SvListView,0);
}
void SvListView::ActionClear()
{
DBG_CHKTHIS(SvListView,0);
Clear();
}
void SvListView::ModelNotification( sal_uInt16 nActionId, SvListEntry* pEntry1,
SvListEntry* pEntry2, sal_uLong nPos )
{
DBG_CHKTHIS(SvListView,0);
switch( nActionId )
{
case LISTACTION_INSERTED:
ActionInserted( pEntry1 );
ModelHasInserted( pEntry1 );
break;
case LISTACTION_INSERTED_TREE:
ActionInsertedTree( pEntry1 );
ModelHasInsertedTree( pEntry1 );
break;
case LISTACTION_REMOVING:
ModelIsRemoving( pEntry1 );
ActionRemoving( pEntry1 );
break;
case LISTACTION_REMOVED:
ActionRemoved( pEntry1 );
ModelHasRemoved( pEntry1 );
break;
case LISTACTION_MOVING:
ModelIsMoving( pEntry1, pEntry2, nPos );
ActionMoving( pEntry1, pEntry2, nPos );
break;
case LISTACTION_MOVED:
ActionMoved( pEntry1, pEntry2, nPos );
ModelHasMoved( pEntry1 );
break;
case LISTACTION_CLEARING:
ActionClear();
ModelHasCleared(); //sic! wg. Kompatibilitaet!
break;
case LISTACTION_CLEARED:
break;
case LISTACTION_INVALIDATE_ENTRY:
// keine Action fuer die Basisklasse
ModelHasEntryInvalidated( pEntry1 );
break;
case LISTACTION_RESORTED:
bVisPositionsValid = sal_False;
break;
case LISTACTION_RESORTING:
break;
default:
OSL_FAIL("unknown ActionId");
}
}
void SvListView::InitViewData( SvViewData*, SvListEntry* )
{
}
StringCompare SvTreeList::Compare( SvListEntry* pLeft, SvListEntry* pRight) const
{
if( aCompareLink.IsSet())
{
SvSortData aSortData;
aSortData.pLeft = pLeft;
aSortData.pRight = pRight;
return (StringCompare)aCompareLink.Call( &aSortData );
}
return COMPARE_EQUAL;
}
void SvTreeList::Resort()
{
Broadcast( LISTACTION_RESORTING );
bAbsPositionsValid = sal_False;
ResortChilds( pRootItem );
Broadcast( LISTACTION_RESORTED );
}
void SvTreeList::ResortChilds( SvListEntry* pParent )
{
DBG_ASSERT(pParent,"Parent not set");
SvTreeEntryList* pChildList = pParent->pChilds;
if( !pChildList )
return;
SvTreeEntryList aList( *pChildList );
pChildList->clear();
size_t nCount = aList.size();
for( size_t nCur = 0; nCur < nCount; nCur++ )
{
SvListEntry* pCurEntry = (SvListEntry*)aList[ nCur ];
sal_uLong nListPos = ULONG_MAX;
GetInsertionPos( pCurEntry, pParent, nListPos );
pChildList->insert( pCurEntry, nListPos );
if( pCurEntry->pChilds )
ResortChilds( pCurEntry );
}
SetListPositions( (SvTreeEntryList*)pChildList );
}
void SvTreeList::GetInsertionPos( SvListEntry* pEntry, SvListEntry* pParent,
sal_uLong& rPos )
{
DBG_ASSERT(pEntry,"No Entry");
if( eSortMode == SortNone )
return;
rPos = ULONG_MAX;
SvTreeEntryList* pChildList = GetChildList( pParent );
if( pChildList && !pChildList->empty() )
{
long i = 0;
long j = pChildList->size()-1;
long k;
StringCompare eCompare = COMPARE_GREATER;
do
{
k = (i+j)/2;
SvListEntry* pTempEntry = (SvListEntry*)(*pChildList)[ k ];
eCompare = Compare( pEntry, pTempEntry );
if( eSortMode == SortDescending && eCompare != COMPARE_EQUAL )
{
if( eCompare == COMPARE_LESS )
eCompare = COMPARE_GREATER;
else
eCompare = COMPARE_LESS;
}
if( eCompare == COMPARE_GREATER )
i = k + 1;
else
j = k - 1;
} while( (eCompare != COMPARE_EQUAL) && (i <= j) );
if( eCompare != COMPARE_EQUAL )
{
if(i > ((long)pChildList->size() - 1)) // nicht gefunden, Ende der Liste
rPos = ULONG_MAX;
else
rPos = i; // nicht gefunden, Mitte
}
else
rPos = k;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */