public static bool Add(
     TREENODE parentNode, PositionTracker[] positions, int positionIndex, int relativeRow, int relativeColumn,
     ref NODEPOSITIONTRACKER lastTracker)
 {
     Debug.Assert((lastTracker == null) || (lastTracker.myNext == null));
     Debug.Assert(!parentNode.NoTracking);
     var retVal = false;
     NODEPOSITIONTRACKER newTracker = null;
     if (parentNode.DefaultTracking)
     {
         newTracker = new NODEPOSITIONTRACKER_Default(parentNode, positions, positionIndex, relativeRow, relativeColumn);
     }
     else
     {
         object trackerObject;
         var dummyOptions = 0;
         trackerObject = parentNode.Branch.GetObject(relativeRow, relativeColumn, ObjectStyle.TrackingObject, ref dummyOptions);
         if (trackerObject != null)
         {
             newTracker = new NODEPOSITIONTRACKER_Dynamic(parentNode, positions, positionIndex, trackerObject);
         }
     }
     if (newTracker != null)
     {
         if (lastTracker != null)
         {
             lastTracker.myNext = newTracker;
         }
         lastTracker = newTracker;
         retVal = true;
     }
     return retVal;
 }
 public static void DetachAll(ref NODEPOSITIONTRACKER ntHead)
 {
     var ntCur = ntHead;
     ntHead = null;
     while (ntCur != null)
     {
         if (ntCur.myParentNode != null)
         {
             // Note that this will detach multiple nodes. The sibling
             // chains don't matter as long as they aren't attached to any TREENODE.
             ntCur.myParentNode.FirstPositionTracker = null;
         }
         ntCur = ntCur.myNext;
     }
 }
 private void DoBeforeListShuffle()
 {
     DelayTurnOffRedraw();
     // Begin shuffling list by retrieving PositionTracker arrays from
     // all of our listeners (if any).
     Debug.Assert(myPositionManager == null); // Should be long gone at this point
     // Check after as well, Before is useless without an After listener
     if (ListShuffleBeginning != null
         && ListShuffleEnding != null)
     {
         var positionManager = new PositionManagerEventArgs(this);
         NODEPOSITIONTRACKER ntHead = null;
         NODEPOSITIONTRACKER ntLast = null;
         TREENODE tnParent;
         int relativeRow;
         int relativeColumn;
         try
         {
             ListShuffleBeginning(this, positionManager);
             foreach (PositionTracker[] trackerSet in positionManager)
             {
                 var upper = trackerSet.GetUpperBound(0);
                 for (var i = trackerSet.GetLowerBound(0); i <= upper; ++i)
                 {
                     if (TrackPosition(ref trackerSet[i], out tnParent, out relativeRow, out relativeColumn))
                     {
                         if (ntHead != null)
                         {
                             if (NODEPOSITIONTRACKER.Add(tnParent, trackerSet, i, relativeRow, relativeColumn, ref ntLast))
                             {
                                 continue;
                             }
                         }
                         else if (NODEPOSITIONTRACKER.Add(tnParent, trackerSet, i, relativeRow, relativeColumn, ref ntHead))
                         {
                             ntLast = ntHead;
                             continue;
                         }
                     }
                     ClearPositionTracker(ref trackerSet[i]);
                 }
             }
         }
         catch
         {
             // Errors from the branches are caught during add, so this is a
             // failure on our side. Make sure that all position tracking information
             // is fully detached from the TREENODE objects before continuing. 
             if (ntHead != null)
             {
                 NODEPOSITIONTRACKER.DetachAll(ref ntHead);
             }
             throw;
         }
         finally
         {
             // We made it all the way, go ahead and record the results
             // with this object. Note that we record our results even if
             // the position head is null so that the user gets a ListShuffleEnding
             // event if nothing was tracked successfully. This lets the listener
             // reduce the set of operations they do during other insert and delete
             // notifications while a position manager is active.
             myPositionManager = positionManager;
             myPositionHead = ntHead;
         }
     }
 }
 public static void DetachTrackers(ref NODEPOSITIONTRACKER ntFirst, ref NODEPOSITIONTRACKER_Dynamic ntDetached)
 {
     Debug.Assert(ntFirst != null); // Precondition, check before calling
     var ntHead = (NODEPOSITIONTRACKER_Dynamic)ntFirst;
     var ntNext = ntHead;
     NODEPOSITIONTRACKER_Dynamic ntCur = null;
     while (ntNext != null)
     {
         ntCur = ntNext;
         ntCur.myParentNode = null;
         ntNext = (NODEPOSITIONTRACKER_Dynamic)ntCur.myNextSibling;
     }
     // Link all of the detached objects together
     ntCur.myNextSibling = ntDetached;
     ntDetached = ntHead;
     ntFirst = null;
 }
 public static void UpdateParentNode(NODEPOSITIONTRACKER ntHead, TREENODE newParentNode)
 {
     var ntCur = ntHead;
     while (ntCur != null)
     {
         ntCur.myParentNode = newParentNode;
         ntCur = ntCur.myNextSibling;
     }
 }
 public static void UpdateEndPositions(NODEPOSITIONTRACKER ntHead)
 {
     var ntCur = ntHead;
     while (ntCur != null)
     {
         ntCur.UpdateEndPosition(ref ntCur.myPositions[ntCur.myPositionIndex]);
         ntCur = ntCur.myNext;
     }
 }
 public void TransferPositionTrackerTo(TREENODE tn)
 {
     if (FirstPositionTracker == null)
     {
         return;
     }
     Debug.Assert(tn.FirstPositionTracker == null);
     tn.FirstPositionTracker = FirstPositionTracker;
     FirstPositionTracker = null;
     NODEPOSITIONTRACKER.UpdateParentNode(tn.FirstPositionTracker, tn);
 }