summaryrefslogtreecommitdiff
path: root/svtools/source/contnr/treelist.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/contnr/treelist.cxx')
-rw-r--r--svtools/source/contnr/treelist.cxx2129
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;
+ }
+}
+
+