diff options
Diffstat (limited to 'svtools/source/contnr/treelist.cxx')
-rw-r--r-- | svtools/source/contnr/treelist.cxx | 2129 |
1 files changed, 2129 insertions, 0 deletions
diff --git a/svtools/source/contnr/treelist.cxx b/svtools/source/contnr/treelist.cxx new file mode 100644 index 000000000000..c1491571dd1c --- /dev/null +++ b/svtools/source/contnr/treelist.cxx @@ -0,0 +1,2129 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: treelist.cxx,v $ + * $Revision: 1.13 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#define _TREELIST_CXX + +#ifndef GCC +#endif + +#include <svtools/treelist.hxx> + +#ifdef DBG_UTIL +// Prueft Integritaet der Liste nach jeder Operation +//#define CHECK_INTEGRITY +#endif + + +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(); + 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 +} + +void SvTreeEntryList::DestroyAll() +{ + SvListEntry* pPtr = (SvListEntry*)First(); + while( pPtr ) + { + delete pPtr; + pPtr = (SvListEntry*)Next(); + } +} + + + + +#if defined (WIN) && defined (MSC) +// siehe BugId 42896: Die Funktionen Prev, PrevVisible, Next, NextVisible +// (andere?) funktionieren nicht mit Optimierung. +#pragma optimize ("", off) +#endif + + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeList::SvTreeList() +{ + nEntryCount = 0; + bAbsPositionsValid = FALSE; + nRefCount = 1; + pRootItem = new SvListEntry; + eSortMode = SortNone; +} + + +/************************************************************************* +|* +|* SvTreeList::~SvTreeList +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeList::~SvTreeList() +{ + Clear(); + delete pRootItem; +#ifdef DBG_UTIL + pRootItem = 0; +#endif +} + +/************************************************************************* +|* +|* SvTreeList::Broadcast +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Broadcast( USHORT nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, ULONG nPos ) +{ + ULONG nViewCount = aViewList.Count(); + for( ULONG nCurView = 0; nCurView < nViewCount; nCurView++ ) + { + SvListView* pView = (SvListView*)aViewList.GetObject( nCurView ); + if( pView ) + pView->ModelNotification( nActionId, pEntry1, pEntry2, nPos ); + } +} + +void SvTreeList::InsertView( SvListView* pView) +{ + ULONG nPos = aViewList.GetPos( pView ); + if ( nPos == LIST_ENTRY_NOTFOUND ) + { + aViewList.Insert( pView, LIST_APPEND ); + nRefCount++; + } +} + +void SvTreeList::RemoveView( SvListView* pView ) +{ + ULONG nPos = aViewList.GetPos( pView ); + if ( nPos != LIST_ENTRY_NOTFOUND ) + { + aViewList.Remove( pView ); + nRefCount--; + } +} + + +// Ein Entry ist sichtbar, wenn alle Parents expandiert sind +BOOL SvTreeList::IsEntryVisible( const SvListView* pView, SvListEntry* pEntry ) const +{ + DBG_ASSERT(pView&&pEntry,"IsVisible:Invalid Params"); + BOOL bRetVal=FALSE; + do + { + if ( pEntry == pRootItem ) + { + bRetVal=TRUE; + break; + } + pEntry = pEntry->pParent; + } while( pView->IsExpanded( pEntry ) ); + return bRetVal; +} + +USHORT SvTreeList::GetDepth( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry&&pEntry!=pRootItem,"GetDepth:Bad Entry"); + USHORT nDepth = 0; + while( pEntry->pParent != pRootItem ) + { + nDepth++; + pEntry = pEntry->pParent; + } + return nDepth; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +BOOL SvTreeList::IsChild( SvListEntry* pParent, SvListEntry* pChild ) const +{ + if ( !pParent ) + pParent = pRootItem; + + BOOL bIsChild = FALSE; + SvTreeEntryList* pList = pParent->pChilds; + if ( !pList ) + return FALSE; + SvListEntry* pActualChild = (SvListEntry*)(pList->First()); + while( !bIsChild && pActualChild ) + { + if ( pActualChild == pChild ) + bIsChild = TRUE; + else + { + if ( pActualChild->pChilds ) + bIsChild = IsChild( pActualChild, pChild ); + pActualChild = (SvListEntry*)(pList->Next()); + } + } + return bIsChild; +} + +ULONG SvTreeList::Move(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,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 = 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->Count() == 0 ) + { + // 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 && (ULONG)pSrcList != (ULONG)pDstList ) + SetListPositions( pSrcList ); + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + + ULONG nRetVal = pDstList->GetPos( pSrcEntry ); + DBG_ASSERT(nRetVal==pSrcEntry->GetChildListPos(),"ListPos not valid"); + Broadcast( LISTACTION_MOVED,pSrcEntry,pTargetParent,nRetVal); + return nRetVal; +} + +ULONG SvTreeList::Copy(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,ULONG nListPos) +{ + // pDest darf Null sein! + DBG_ASSERT(pSrcEntry,"Entry?"); + if ( !pTargetParent ) + pTargetParent = pRootItem; + if ( !pTargetParent->pChilds ) + pTargetParent->pChilds = new SvTreeEntryList; + + bAbsPositionsValid = FALSE; + + 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 ); + ULONG nRetVal = pDstList->GetPos( pClonedEntry ); + return nRetVal; +} + + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Move( SvListEntry* pSrcEntry, SvListEntry* pDstEntry ) +{ + SvListEntry* pParent; + ULONG nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos(); + nPos++; // UNTER (Bildschirm) pDstEntry einfuegen + } + Move( pSrcEntry, pParent, nPos ); +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Copy( SvListEntry* pSrcEntry, SvListEntry* pDstEntry ) +{ + SvListEntry* pParent; + ULONG nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos()+1; + } + Copy( pSrcEntry, pParent, nPos ); +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +void SvTreeList::InsertTree( SvListEntry* pSrcEntry, SvListEntry* pDstEntry) +{ + SvListEntry* pParent; + ULONG nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos()+1; + } + InsertTree( pSrcEntry, pParent, nPos ); +} + + +void SvTreeList::InsertTree(SvListEntry* pSrcEntry, + SvListEntry* pTargetParent,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 = 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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::Clone( SvListEntry* pEntry, ULONG& nCloneCount ) const +{ + SvListEntry* pClonedEntry = CloneEntry( pEntry ); + nCloneCount = 1; + SvTreeEntryList* pChilds = pEntry->pChilds; + if ( pChilds ) + pClonedEntry->pChilds=CloneChilds(pChilds,pClonedEntry,nCloneCount); + return pClonedEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeEntryList* SvTreeList::CloneChilds( SvTreeEntryList* pChilds, + SvListEntry* pNewParent, + ULONG& nCloneCount ) const +{ + DBG_ASSERT(pChilds->Count(),"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->Insert( pNewChild, LIST_APPEND ); + pChild = (SvListEntry*)pChilds->Next(); + } + return pClonedChilds; +} + + +/************************************************************************* +|* +|* SvTreeList::GetChildCount +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetChildCount( SvListEntry* pParent ) const +{ + if ( !pParent ) + return GetEntryCount(); + + if ( !pParent || !pParent->pChilds) + return 0; + ULONG nCount = 0; + USHORT nRefDepth = GetDepth( pParent ); + USHORT nActDepth = nRefDepth; + do + { + pParent = Next( pParent, &nActDepth ); + nCount++; + } while( pParent && nRefDepth < nActDepth ); + nCount--; + return nCount; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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; + ULONG nCount = 0; + USHORT nRefDepth = GetDepth( pParent ); + USHORT nActDepth = nRefDepth; + do + { + pParent = NextVisible( pView, pParent, &nActDepth ); + nCount++; + } while( pParent && nRefDepth < nActDepth ); + nCount--; + return nCount; +} + +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; + ULONG nCount = 0; + USHORT nRefDepth = GetDepth( pParent ); + USHORT nActDepth = nRefDepth; + do + { + pParent = Next( pParent, &nActDepth ); + if( pParent && pView->IsSelected( pParent ) && nRefDepth < nActDepth) + nCount++; + } while( pParent && nRefDepth < nActDepth ); +// nCount--; + return nCount; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::First() const +{ + if ( nEntryCount ) + return (SvListEntry*)(pRootItem->pChilds->GetObject(0)); + else + return 0; +} + +/************************************************************************* +|* +|* SvTreeList::Next +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +SvListEntry* SvTreeList::Next( SvListEntry* pActEntry, USHORT* pDepth ) const +{ + DBG_ASSERT( pActEntry && pActEntry->pParent, "SvTreeList::Next: invalid entry/parent!" ); + if ( !pActEntry || !pActEntry->pParent ) + return NULL; + + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pDepth ) + { + nDepth = *pDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( pActEntry->pChilds /* && pActEntry->pChilds->Count() */ ) + { + nDepth++; + pActEntry = (SvListEntry*)(pActEntry->pChilds->GetObject(0)); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + + if ( pActualList->Count() > ( nActualPos + 1 ) ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( 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->Count() > ( nActualPos + 1 ) ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos + 1 )); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + pParent = pParent->pParent; + nDepth--; + } + return 0; +} + +/************************************************************************* +|* +|* SvTreeList::Prev +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +SvListEntry* SvTreeList::Prev( SvListEntry* pActEntry, USHORT* pDepth ) const +{ + DBG_ASSERT(pActEntry!=0,"Entry?"); + + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pDepth ) + { + nDepth = *pDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( nActualPos > 0 ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos - 1 )); + while( pActEntry->pChilds /* && pActEntry->pChilds->Count() */ ) + { + 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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::Last( USHORT* /* nDepth */ ) 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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetVisibleCount( const SvListView* pView ) const +{ + DBG_ASSERT(pView,"GetVisCount:No View"); + if( !pView->HasViewData() ) + return 0; + if ( pView->nVisibleCount ) + return pView->nVisibleCount; + + 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 ) + { + DBG_ERROR("nVisibleCount bad"); + } +#endif + ((SvListView*)pView)->nVisibleCount = nPos; + ((SvListView*)pView)->bVisPositionsValid = TRUE; + return nPos; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +// Funktion geht aus Geschwindigkeitsgruenden davon aus, +// das der uebergebene Eintrag bereits sichtbar ist + +SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pActEntry,USHORT* pActDepth) const +{ + DBG_ASSERT(pView,"NextVisible:No View"); + if ( !pActEntry ) + return 0; + + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pActDepth ) + { + nDepth = *pActDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( pView->IsExpanded(pActEntry) ) + { + DBG_ASSERT(pActEntry->pChilds,"Childs?"); + nDepth++; + pActEntry = (SvListEntry*)(pActEntry->pChilds->GetObject(0)); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + + nActualPos++; + if ( pActualList->Count() > nActualPos ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( 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->Count() > nActualPos ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos )); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + pParent = pParent->pParent; + nDepth--; + } + return 0; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +// Funktion geht aus Geschwindigkeitsgruenden davon aus, +// das der uebergebene Eintrag bereits sichtbar ist + +SvListEntry* SvTreeList::PrevVisible(const SvListView* pView, SvListEntry* pActEntry, USHORT* pActDepth) const +{ + DBG_ASSERT(pView&&pActEntry,"PrevVis:View/Entry?"); + + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pActDepth ) + { + nDepth = *pActDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( nActualPos > 0 ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( 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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::LastVisible( const SvListView* pView, USHORT* 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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pEntry,USHORT& nDelta) const +{ + DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"NextVis:Wrong Prms/!Vis"); + + 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 = (USHORT)(pView->nVisibleCount-nVisPos); + nDelta--; + } + USHORT nDeltaTmp = nDelta; + while( nDeltaTmp ) + { + pEntry = NextVisible( pView, pEntry ); + nDeltaTmp--; + DBG_ASSERT(pEntry,"Entry?"); + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::PrevVisible( const SvListView* pView, SvListEntry* pEntry, USHORT& nDelta ) const +{ + DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"PrevVis:Parms/!Vis"); + + 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 = (USHORT)nVisPos; + USHORT nDeltaTmp = nDelta; + while( nDeltaTmp ) + { + pEntry = PrevVisible( pView, pEntry ); + nDeltaTmp--; + DBG_ASSERT(pEntry,"Entry?"); + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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->GetObject( 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; +// ULONG nPos = pList->GetPos( pEntry ); + ULONG nPos = pEntry->GetChildListPos(); + nPos++; + pEntry = (SvListEntry*)(pList->GetObject( nPos )); + return pEntry; +} + +SvListEntry* SvTreeList::PrevSibling( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"Entry?"); + if( !pEntry ) + return 0; + + SvTreeEntryList* pList = pEntry->pParent->pChilds; + // ULONG nPos = pList->GetPos( pEntry ); + ULONG nPos = pEntry->GetChildListPos(); + if ( nPos == 0 ) + return 0; + nPos--; + pEntry = (SvListEntry*)(pList->GetObject( 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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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 +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +ULONG SvTreeList::Insert( SvListEntry* pEntry,SvListEntry* pParent,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 = FALSE; + pEntry->pParent = pParent; + + pList->Insert( pEntry, nPos ); + nEntryCount++; + if( nPos != LIST_APPEND && (nPos != (pList->Count()-1)) ) + SetListPositions( pList ); + else + pEntry->nListPos = pList->Count()-1; + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast( LISTACTION_INSERTED, pEntry ); + return nPos; // pEntry->nListPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetAbsPos( SvListEntry* pEntry) const +{ + if ( !bAbsPositionsValid ) + ((SvTreeList*)this)->SetAbsolutePositions(); + return pEntry->nAbsPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::SetAbsolutePositions() +{ + ULONG nPos = 0; + SvListEntry* pEntry = First(); + while ( pEntry ) + { + pEntry->nAbsPos = nPos; + nPos++; + pEntry = Next( pEntry ); + } + bAbsPositionsValid = TRUE; +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +/************************************************************************* +|* +|* SvTreeList::Expand +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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 = FALSE; + pView->nVisibleCount = 0; + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + +/************************************************************************* +|* +|* SvTreeList::Collapse +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +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 = FALSE; + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +BOOL SvTreeList::Select( SvListView* pView, SvListEntry* pEntry, BOOL bSelect ) +{ + DBG_ASSERT(pView&&pEntry,"Select:View/Entry?"); + SvViewData* pViewData = pView->GetViewData( pEntry ); + if ( bSelect ) + { + if ( pViewData->IsSelected() || !pViewData->IsSelectable() ) + return FALSE; + else + { + pViewData->nFlags |= SVLISTENTRYFLAG_SELECTED; + pView->nSelectionCount++; + } + } + else + { + if ( !pViewData->IsSelected() ) + return FALSE; + else + { + pViewData->nFlags &= ~( SVLISTENTRYFLAG_SELECTED ); + pView->nSelectionCount--; + } + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + return TRUE; +} + +/************************************************************************* +|* +|* SvTreeList::Remove +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 05.04.01 +|* +*************************************************************************/ +BOOL SvTreeList::Remove( SvListEntry* pEntry ) +{ + DBG_ASSERT(pEntry,"Cannot remove root, use clear"); + + if( !pEntry->pParent ) + { + DBG_ERROR("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 FALSE; + } + + Broadcast( LISTACTION_REMOVING, pEntry ); + ULONG nRemoved = 1 + GetChildCount(pEntry); + bAbsPositionsValid = FALSE; + + SvListEntry* pParent = pEntry->pParent; + SvTreeEntryList* pList = pParent->pChilds; + DBG_ASSERT(pList,"Remove:No Childlist"); + BOOL bLastEntry = FALSE; + + if ( pEntry->HasChildListPos() ) + { + ULONG nListPos = pEntry->GetChildListPos(); + bLastEntry = (nListPos == (pList->Count()-1) ) ? TRUE : FALSE; + pList->Remove( nListPos ); + } + else + { + pList->Remove( (void*) pEntry ); + } + + + // moved to end of method because it is used later with Broadcast + // delete pEntry; // loescht auch alle Childs + + if ( pList->Count() == 0 ) + { + 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 TRUE; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::SelectChilds(SvListView* pView, SvListEntry* pParent,BOOL bSelect ) +{ + DBG_ASSERT(pView&&pParent,"SelChilds:View/Parent?"); + if ( !pParent->pChilds ) + return 0; + if ( pParent->pChilds->Count() == 0 ) + return 0; + + USHORT nRefDepth = GetDepth( pParent ); + USHORT nDepth = nRefDepth; + ULONG nCount = 0; + pParent = Next( pParent ); + do + { + if ( Select( pView, pParent, bSelect ) ) + nCount++; // nur die tatsaechlichen Selektierungen zaehlen + pParent = Next( pParent, &nDepth ); + } + while( pParent && nDepth > nRefDepth ); +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + return nCount; +} + +void SvTreeList::SelectAll( SvListView* pView, 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( ULONG nAbsPos ) const +{ + SvListEntry* pEntry = First(); + while ( nAbsPos && pEntry ) + { + pEntry = Next( pEntry ); + nAbsPos--; + } + return pEntry; +} + +SvListEntry* SvTreeList::GetEntryAtVisPos( const SvListView* pView, 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->Count() ) + { + SvListEntry* pEntry = (SvListEntry*)(pList->GetObject(0)); + if( pEntry->pParent ) + pEntry->pParent->InvalidateChildrensListPositions(); + } + /* + ULONG nListPos = 0; + SvListEntry* pEntry = (SvListEntry*)(pList->First()); + while( pEntry ) + { + pEntry->nListPos = nListPos; + nListPos++; + pEntry = (SvListEntry*)(pList->Next()); + } + */ +} + + +void SvTreeList::InvalidateEntry( SvListEntry* pEntry ) +{ + Broadcast( LISTACTION_INVALIDATE_ENTRY, pEntry ); +} + +BOOL SvTreeList::IsInChildList( SvListEntry* pParent, SvListEntry* pChild) const +{ + if ( !pParent ) + pParent = pRootItem; + BOOL bIsChild = FALSE; + if ( pParent->pChilds ) + bIsChild = (BOOL)(pParent->pChilds->GetPos(pChild) != LIST_ENTRY_NOTFOUND); + return bIsChild; +} + + +void lcl_CheckList( SvTreeEntryList* pList ) +{ + SvListEntry* pEntry = (SvListEntry*)(pList->First()); + ULONG nPos = 0; + while ( pEntry ) + { + DBG_ASSERT(pEntry->GetChildListPos()==nPos,"Wrong ListPos"); + pEntry = (SvListEntry*)(pList->Next()); + nPos++; + } +} + +void SvTreeList::CheckIntegrity() const +{ + ULONG nMyEntryCount = 0; + if ( pRootItem->pChilds ) + { + lcl_CheckList( pRootItem->pChilds ); + SvListEntry* pEntry = First(); + while( pEntry ) + { + nMyEntryCount++; + if ( pEntry->pChilds ) + lcl_CheckList( pEntry->pChilds ); + pEntry = Next( pEntry ); + } + } + DBG_ASSERT(nMyEntryCount==GetEntryCount(),"Entry count invalid"); +} + +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 = FALSE; + SetModel( pModell ); +} + +SvListView::SvListView() +{ + DBG_CTOR(SvListView,0); + pModel = 0; + nSelectionCount = 0; + nVisibleCount = 0; + bVisPositionsValid = 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( (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( (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 = FALSE; + if( pModel ) + { + // RootEntry einfuegen + SvListEntry* pEntry = pModel->pRootItem; + SvViewData* pViewData = new SvViewData; + pViewData->nFlags = SVLISTENTRYFLAG_EXPANDED; + aDataTable.Insert( (ULONG)pEntry, pViewData ); + } +} + +void SvListView::SetModel( SvTreeList* pNewModel ) +{ + DBG_CHKTHIS(SvListView,0); + BOOL bBroadcastCleared = FALSE; + if ( pModel ) + { + pModel->RemoveView( this ); + bBroadcastCleared = 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 */ , 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*,ULONG) +{ + DBG_CHKTHIS(SvListView,0); + SvListEntry* pParent = pEntry->pParent; + DBG_ASSERT(pParent,"Model not consistent"); + if( pParent != pModel->pRootItem && pParent->pChilds->Count() == 1 ) + { + SvViewData* pViewData = (SvViewData*)aDataTable.Get( (ULONG)pParent ); + pViewData->nFlags &= (~SVLISTENTRYFLAG_EXPANDED); + } + // vorlaeufig + nVisibleCount = 0; + bVisPositionsValid = FALSE; +} + +void SvListView::ActionMoved( SvListEntry* /* pEntry */ , + SvListEntry* /* pTargetPrnt */ , + ULONG /* nChildPos */ ) +{ + DBG_CHKTHIS(SvListView,0); + nVisibleCount = 0; + bVisPositionsValid = 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 + BOOL bSuccess = + #endif + aDataTable.Insert( (ULONG)pEntry, pData ); + DBG_ASSERT(bSuccess,"Entry already in View"); + if ( nVisibleCount && pModel->IsEntryVisible( this, pEntry )) + { + nVisibleCount = 0; + bVisPositionsValid = FALSE; + } +} + +void SvListView::ActionInsertedTree( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvListView,0); + if ( pModel->IsEntryVisible( this, pEntry )) + { + nVisibleCount = 0; + bVisPositionsValid = FALSE; + } + // ueber Entry und seine Childs iterieren + SvListEntry* pCurEntry = pEntry; + USHORT nRefDepth = pModel->GetDepth( pCurEntry ); + while( pCurEntry ) + { + DBG_ASSERT(aDataTable.Get((ULONG)pCurEntry)==0,"Entry already in Table"); + SvViewData* pViewData = CreateViewData( pCurEntry ); + DBG_ASSERT(pViewData,"No ViewData"); + InitViewData( pViewData, pEntry ); + aDataTable.Insert( (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((ULONG)pCur); + delete pViewData; + aDataTable.Remove( (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( (ULONG)pEntry ); + ULONG nSelRemoved = 0; + if ( pViewData->IsSelected() ) + nSelRemoved = 1 + pModel->GetChildSelectionCount( this, pEntry ); + nSelectionCount -= nSelRemoved; + ULONG nVisibleRemoved = 0; + if ( pModel->IsEntryVisible( this, pEntry ) ) + nVisibleRemoved = 1 + pModel->GetVisibleChildCount( this, pEntry ); + if( nVisibleCount ) + { +#ifdef DBG_UTIL + if( nVisibleCount < nVisibleRemoved ) + { + DBG_ERROR("nVisibleRemoved bad"); + } +#endif + nVisibleCount -= nVisibleRemoved; + } + bVisPositionsValid = FALSE; + + pViewData = (SvViewData*)aDataTable.Get((ULONG)pEntry); + delete pViewData; + aDataTable.Remove( (ULONG)pEntry ); + RemoveViewData( pEntry ); + + SvListEntry* pCurEntry = pEntry->pParent; + if ( pCurEntry && pCurEntry != pModel->pRootItem && + pCurEntry->pChilds->Count() == 1 ) + { + pViewData = (SvViewData*)aDataTable.Get((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( USHORT nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, 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 = FALSE; + break; + case LISTACTION_RESORTING: + break; + default: + DBG_ERROR("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 = FALSE; + ResortChilds( pRootItem ); + Broadcast( LISTACTION_RESORTED ); +} + +void SvTreeList::ResortChilds( SvListEntry* pParent ) +{ + DBG_ASSERT(pParent,"Parent not set"); + List* pChildList = pParent->pChilds; + if( !pChildList ) + return; + List aList( *pChildList ); + pChildList->Clear(); + + ULONG nCount = aList.Count(); + for( ULONG nCur = 0; nCur < nCount; nCur++ ) + { + SvListEntry* pCurEntry = (SvListEntry*)aList.GetObject( nCur ); + ULONG nListPos = LIST_APPEND; + GetInsertionPos( pCurEntry, pParent, nListPos ); + pChildList->Insert( pCurEntry, nListPos ); + if( pCurEntry->pChilds ) + ResortChilds( pCurEntry ); + } + SetListPositions( (SvTreeEntryList*)pChildList ); +} + +void SvTreeList::GetInsertionPos( SvListEntry* pEntry, SvListEntry* pParent, + ULONG& rPos ) +{ + DBG_ASSERT(pEntry,"No Entry"); + + if( eSortMode == SortNone ) + return; + + rPos = LIST_APPEND; + SvTreeEntryList* pChildList = GetChildList( pParent ); + + if( pChildList && pChildList->Count() ) + { + long i = 0; + long j = pChildList->Count()-1; + long k; + StringCompare eCompare = COMPARE_GREATER; + + do + { + k = (i+j)/2; + SvListEntry* pTempEntry = (SvListEntry*)(pChildList->GetObject(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->Count() - 1)) // nicht gefunden, Ende der Liste + rPos = LIST_APPEND; + else + rPos = i; // nicht gefunden, Mitte + } + else + rPos = k; + } +} + + |