Example #1
0
 public virtual SUBITEMNODE SubItemAtColumn(int column, out SUBITEMNODE snPrev)
 {
     snPrev = null;
     return null;
 }
Example #2
0
        protected VirtualTreeCoordinate LocateObject(IBranch startingBranch, object target, int locateStyle, int locateOptions)
        {
            // Object location is done in two steps:
            // 1) Track the object below the starting node.
            // 2) Find the offset from the starting node to the child object
            // 3) If the downward search succeeded, then make sure that each of
            //    the branches that lead to the starting node are expanded.
            var targetRow = -1;
            var targetColumn = 0;
            var tn = (startingBranch == null) ? myRootNode : LocateTrackedNode(startingBranch);
            if (tn == null)
            {
                return VirtualTreeCoordinate.Invalid;
            }
            Debug.Assert(tn.NextNode == null); // Branch is in multiple places in the tree. The one we get is undefined. Benign assert.
            var tnStartNode = tn;
            TREENODE tnFirstUnexpanded = null;
            TREENODE tnAttachCache;
            TREENODE tnNext;
            TrackingObjectAction action;
            var firstUnexpandedRow = -1;
            var firstUnexpandedRowSubItemAdjust = 0;
            var firstUnexpandedColumnOffset = 0;
            var totalRowOffset = 0;
            var totalColumnOffset = 0;
            var totalRowOffsetSubItemAdjust = 0;
            int row;
            int rowOffset;
            int rowOffsetSubItemAdjust;
            int column;
            var retVal = false;
            int changeCount;
            int subItemChangeCount;
            int subItemRemainder;
            var totalChangeCount = 0;
            var totalSubItemChangeCount = 0;
            var inSubItemTerritory = false;
            var partialSuccess = false;
            while (tn != null)
            {
                var locateData = tn.Branch.LocateObject(target, (ObjectStyle)locateStyle, locateOptions);
                row = locateData.Row;
                column = locateData.Column;
                action = (TrackingObjectAction)locateData.Options;
                switch (action)
                {
                    case TrackingObjectAction.NotTracked:
                        // Nothing more we can do, just get out.
                        tn = null;
                        break;
                    case TrackingObjectAction.NotTrackedReturnParent:
                        if (partialSuccess)
                        {
                            retVal = true;
                        }
                        tn = null;
                        break;
                    case TrackingObjectAction.ThisLevel:
                    case TrackingObjectAction.NextLevel:
                        partialSuccess = true;
                        rowOffset = tn.GetChildOffset(row, out rowOffsetSubItemAdjust);
                        if (tn.ComplexSubItem)
                        {
                            --rowOffset;
                        }
                        totalRowOffset += rowOffset;
                        totalRowOffsetSubItemAdjust += rowOffsetSubItemAdjust;
                        totalColumnOffset += column;
                        if (!tn.Expanded)
                        {
                            changeCount = tn.FullCount;
                            subItemChangeCount = tn.ExpandedSubItemGain;

                            // Adjust for subsequent ChangeFullCountRecursive call. We
                            // want to make this call on the current node so that any
                            // subitem expansions are picked up and edit correctly, but
                            // we need to avoid the side effects on the current node.
                            tn.FullCount -= changeCount;
                            tn.FullSubItemGain -= subItemChangeCount;
                            if (tnFirstUnexpanded == null)
                            {
                                tnFirstUnexpanded = tn;
                            }
                            Debug.Assert(tn.Branch != null);
                            tn.Expanded = true;
                            ChangeFullCountRecursive(tn, changeCount, subItemChangeCount, tnFirstUnexpanded, out subItemRemainder);
                            totalSubItemChangeCount += subItemRemainder;
                            if (!inSubItemTerritory)
                            {
                                totalChangeCount += changeCount;
                            }
                        }
                        if (tnFirstUnexpanded == null)
                        {
                            firstUnexpandedColumnOffset += column;
                            firstUnexpandedRow += rowOffset;
                            firstUnexpandedRowSubItemAdjust += rowOffsetSubItemAdjust;
                        }
                        if (action == TrackingObjectAction.ThisLevel)
                        {
                            retVal = true;
                            tn = null;
                        }
                        else
                        {
                            // Keep going down the tree
                            tnAttachCache = null;
                            tnNext = FindIndexedNode(row, tn.FirstChild, ref tnAttachCache);

                            // If we have a node with a branch, then it will be expanded if needed
                            // in the next pass through the main loop. We only do expansion here if
                            // that is not the case, meaning that the branch has never been expanded.
                            if (column > 0)
                            {
                                // We're being directed down a subitem column. In this case,
                                // tnNext is a subitem anchor node.
                                if (column < tn.GetColumnCount(row))
                                {
                                    var columnStyle = tn.SubItemStyle(column);
                                    if (0 != (tn.SubItemStyle(column) & SubItemCellStyles.Mixed))
                                    {
                                        SUBITEMNODE snPrev = null;
                                        var sn = (tnNext != null) ? tnNext.SubItemAtColumn(column, out snPrev) : null;
                                        if (sn == null)
                                        {
                                            if (0 != (columnStyle & SubItemCellStyles.Expandable))
                                            {
                                                // We only handle null for expandable cells.
                                                // A complex cell would already have been expanded
                                                // when the branch initially loaded.
                                                ExpansionOptions expandOptions;
                                                var tnSubItem = ExpandTreeNode(
                                                    tn,
                                                    null,
                                                    row,
                                                    column,
                                                    ObjectStyle.SubItemExpansion,
                                                    false,
                                                    out expandOptions,
                                                    out changeCount,
                                                    out subItemChangeCount);
                                                if (tnSubItem != null)
                                                {
                                                    if (tnNext == null)
                                                    {
                                                        // Create a new anchor
                                                        tnNext = new TREENODE_Complex();
                                                        tnNext.Index = row;
                                                        InsertIndexedNode(tn, tnNext, ref tnAttachCache);
                                                    }
                                                    tnSubItem.SubItemRoot = true;
                                                    // UNDONE: Would be nice to store a global column in Index
                                                    tnSubItem.Index = VirtualTreeConstant.NullIndex;
                                                    tnSubItem.Parent = tnNext;
                                                    sn = new SUBITEMNODE();
                                                    sn.Column = column;
                                                    sn.RootNode = tnSubItem;
                                                    if (snPrev == null)
                                                    {
                                                        sn.NextSibling = tnNext.FirstSubItem;
                                                        tnNext.FirstSubItem = sn;
                                                    }
                                                    else
                                                    {
                                                        sn.NextSibling = snPrev.NextSibling;
                                                        snPrev.NextSibling = sn;
                                                    }

                                                    // Adjust for ChangeFullCountRecursive call
                                                    tnSubItem.FullCount -= changeCount;
                                                    tnSubItem.FullSubItemGain -= subItemChangeCount;
                                                    if (tnFirstUnexpanded == null)
                                                    {
                                                        tnFirstUnexpanded = tnSubItem;
                                                        totalChangeCount += changeCount;
                                                        totalSubItemChangeCount += subItemChangeCount;
                                                    }
                                                    else
                                                    {
                                                        inSubItemTerritory = true;
                                                        ChangeFullCountRecursive(
                                                            tnSubItem, changeCount, subItemChangeCount, tnFirstUnexpanded,
                                                            out subItemRemainder);
                                                        totalSubItemChangeCount += subItemRemainder;
                                                    }
                                                    tnNext = tnSubItem;
                                                }
                                                else
                                                {
                                                    // Break the outer loop
                                                    tnNext = null;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            tnNext = sn.RootNode;
                                            inSubItemTerritory = tnFirstUnexpanded != null;
                                        }
                                    }
                                }
                            }
                            else if (tnNext == null
                                     || tnNext.Branch == null)
                            {
                                var insertNode = tnNext == null;
                                tnNext = ExpandTreeNode(tn, tnNext, row, 0, false, out changeCount, out subItemChangeCount);
                                if (insertNode)
                                {
                                    // If the branch was set coming in, then the node already existed
                                    // for a subitem expansion and is already in the list, so we
                                    // only insert if we created a node for this position.
                                    InsertIndexedNode(tn, tnNext, ref tnAttachCache);
                                }

                                // Adjust back to prepare for the ChangeFullCountRecursive loop that will happen
                                // eventually. If this is the first expanded, then the one below will do nothing.
                                if (tnFirstUnexpanded == null)
                                {
                                    tnFirstUnexpanded = tnNext;
                                    tnNext.FullSubItemGain -= subItemChangeCount;
                                    tnNext.FullCount -= changeCount;
                                    totalChangeCount += changeCount;
                                    totalSubItemChangeCount += subItemChangeCount;
                                }
                                else
                                {
                                    ChangeFullCountRecursive(tn, changeCount, subItemChangeCount, tnFirstUnexpanded, out subItemRemainder);
                                    totalSubItemChangeCount += subItemRemainder;
                                    if (!inSubItemTerritory)
                                    {
                                        totalChangeCount += changeCount;
                                    }
                                }
                            }
                            tn = tnNext;
                        }
                        break;
                }
            }

            // Now, walk back up the chain to ensure that all parent nodes are expanded
            // We've only tracked information from the first unexpanded node, not the
            // one we first found, so we have to walk back up from the point our information
            // is current at. Track the offset so we have a global position if we make it
            // to the top without hitting an unexpanded item.
            tn = (tnFirstUnexpanded == null) ? tnStartNode : tnFirstUnexpanded;
            var backedUpPastStartNode = false;
            while (tn != null)
            {
                if (!backedUpPastStartNode
                    && tn == tnStartNode)
                {
                    backedUpPastStartNode = true;
                }
                tnNext = tn.Parent;
                if (!tn.Expanded)
                {
                    if (!retVal)
                    {
                        // We can't find the object we're looking for, and any expansion we've made isn't
                        // visible. Notify up to this point and get out of the routine. There is no
                        // change to the visible state, so eventing is not needed.
                        if (tnFirstUnexpanded != null)
                        {
                            ChangeFullCountRecursive(tnFirstUnexpanded, totalChangeCount, totalSubItemChangeCount);
                        }
                        return VirtualTreeCoordinate.Invalid;
                    }

                    // Recurse up to (but not including) the current node. For this reason, we
                    // keep adding onto the old totals.
                    subItemRemainder = 0;
                    if (tnFirstUnexpanded != null)
                    {
                        ChangeFullCountRecursive(tnFirstUnexpanded, totalChangeCount, totalSubItemChangeCount, tnNext, out subItemRemainder);
                    }
                    tnFirstUnexpanded = tnNext;
                    firstUnexpandedColumnOffset = 0;
                    firstUnexpandedRow = 0; // Set below
                    firstUnexpandedRowSubItemAdjust = 0; // UNDONE_SINGLECOLUMN: Verify
                    totalChangeCount += tnNext.FullCount;
                    totalSubItemChangeCount = tnNext.FullSubItemGain + subItemRemainder;
                    tnNext.FullCount = 0;
                    tnNext.FullSubItemGain = 0;
                }
                tnNext = tn.Parent;
                if (tn.SubItemRoot)
                {
                    if (backedUpPastStartNode)
                    {
                        column = tnNext.FirstSubItem.ColumnOfRootNode(tn);
                        if (tnFirstUnexpanded != null)
                        {
                            firstUnexpandedColumnOffset += column;
                        }
                        else
                        {
                            totalSubItemChangeCount += totalChangeCount;
                            totalChangeCount = 0;
                        }
                        totalColumnOffset += column;
                        if (!tn.ComplexSubItem)
                        {
                            ++totalRowOffset;
                            ++firstUnexpandedRow;
                        }
                    }

                    // Skip the subitem anchor
                    tnNext = tnNext.Parent;
                }
                else if (backedUpPastStartNode && tnNext != null)
                {
                    rowOffset = tnNext.GetChildOffset(tn.Index, out rowOffsetSubItemAdjust);
                    firstUnexpandedRow += rowOffset;
                    firstUnexpandedRowSubItemAdjust += rowOffsetSubItemAdjust;
                    totalRowOffset += rowOffset;
                    totalRowOffsetSubItemAdjust += rowOffsetSubItemAdjust;
                }
                tn = tnNext;
            }

            // Recurse the parent even if retVal is false, there may have been some
            // changes that partially expanded the tree and need to be accounted for.
            if ((totalChangeCount + totalSubItemChangeCount) > 0)
            {
                Debug.Assert(tnFirstUnexpanded != null); // The count can't change if nothing expanded
                // There is a lot of extra work to do if we have to fire redraw events
                if (ItemCountChanged != null)
                {
                    Debug.Assert(tnFirstUnexpanded.Parent != null); // The root node is always expanded
                    SubItemColumnAdjustment[] subItemChanges;
                    var parentRowOffset = 0;
                    var affectedSubItemColumns = new AffectedSubItems(true);
                    int rowIncr;
                    var adjustColumn = firstUnexpandedColumnOffset;
                    var singleColumnSubItemAdjust = 0;
                    // TrackCell is currently broken for all values after absRow, but it will work down
                    // to the row we are curently expanding. We need this call to get the affectedSubItemColumns.
                    // UNDONE: We should be able to calculate affectedSubItemColumns during the course of this
                    // routine instead of rewalking the tree here.
                    TrackCell(
                        firstUnexpandedRow, ref adjustColumn, ref parentRowOffset, ref affectedSubItemColumns, ref singleColumnSubItemAdjust);
                    ChangeFullCountRecursive(
                        tnFirstUnexpanded, totalChangeCount, totalSubItemChangeCount, null, ref affectedSubItemColumns, out rowIncr,
                        out subItemChanges);
                    DelayTurnOffRedraw();
                    // UNDONE: Verify tnFirstUnexpanded.ImmedSubItemGain passed here
                    ItemCountChanged(
                        this,
                        new ItemCountChangedEventArgs(
                            this, firstUnexpandedRow, firstUnexpandedColumnOffset, rowIncr, firstUnexpandedRow - 1,
                            tnFirstUnexpanded.ImmedSubItemGain, subItemChanges, true));
                }
                else
                {
                    ChangeFullCountRecursive(tnFirstUnexpanded, totalChangeCount, totalSubItemChangeCount);
                }
                if (firstUnexpandedColumnOffset == 0
                    && GetStateFlag(TreeStateFlags.FireSingleColumnItemCountChanged))
                {
                    DelayTurnOffSingleColumnRedraw();
                    var singleTree = SingleColumnTree;
                    (singleTree as SingleColumnView).myItemCountChanged(
                        singleTree,
                        new ItemCountChangedEventArgs(
                            singleTree, firstUnexpandedRow - firstUnexpandedRowSubItemAdjust, 0, totalChangeCount,
                            firstUnexpandedRow - firstUnexpandedRowSubItemAdjust - 1, 0, null, true));
                }
            }

            if (retVal)
            {
                targetRow += totalRowOffset;
                targetColumn += totalColumnOffset;
            }
            return retVal ? new VirtualTreeCoordinate(targetRow, targetColumn) : VirtualTreeCoordinate.Invalid;
        }
Example #3
0
        //Return size of expansion
        private void ToggleExpansion(
            int absRow, int column, out bool allowRecursion, out int singleColumnSubItemAdjust, out int itemExpansionCount,
            out int subItemExpansionCount, out int rowChange, out int blanksAboveChange, out SubItemColumnAdjustment[] subItemChanges)
        {
            TREENODE tnCur;
            TREENODE tnSubItemAnchor;
            TREENODE tnUnexpandedSubItemAnchor;
            TREENODE tn1;
            TREENODE tn2;
            SUBITEMNODE sn;
            SUBITEMNODE snPrev;
            itemExpansionCount = subItemExpansionCount = 0;
            rowChange = 0;
            singleColumnSubItemAdjust = 0;
            subItemChanges = null;
            allowRecursion = true; //Default to true, too many implementations are missing this, and most are actually recursive
            var localColumn = column;
            var parentRowOffset = 0;
            var affectedColumns = new AffectedSubItems(true);
            var pos = TrackCell(absRow, ref localColumn, ref parentRowOffset, ref affectedColumns, ref singleColumnSubItemAdjust);
            var tnRecurseOn = pos.ParentNode;
            var subItemExpansion = localColumn != 0;
            blanksAboveChange = 0;
            tnCur = pos.ParentNode.GetChildNode(pos.Index);
            tnSubItemAnchor = null;
            tnUnexpandedSubItemAnchor = null;
            snPrev = null;
            if (subItemExpansion)
            {
                Debug.Assert(pos.SubItemOffset == 0); // TrackIndex messed up
                tnSubItemAnchor = tnCur;
                if (tnCur != null)
                {
                    sn = tnCur.SubItemAtColumn(localColumn, out snPrev);
                    tnCur = (sn != null) ? sn.RootNode : null;
                }
            }
            else if (tnCur != null
                     && tnCur.Branch == null)
            {
                tnUnexpandedSubItemAnchor = tnCur;
                tnCur = null;
            }
            if (tnCur != null)
            {
                blanksAboveChange = tnCur.ImmedSubItemGain;
                if (tnCur.Expanded)
                {
                    itemExpansionCount = -tnCur.FullCount;
                    subItemExpansionCount = -tnCur.ExpandedSubItemGain;
                    switch (tnCur.CloseAction)
                    {
                        case BranchCollapseAction.CloseAndDiscard:
                            tn1 = pos.ParentNode.FirstChild;
                            Debug.Assert(tn1 != null, "");
                            tn2 = null;
                            while (tn1 != tnCur)
                            {
                                //ptnCur is a child of the parent node, should never miss it completely
                                Debug.Assert(tn1 != null, "");
                                tn2 = tn1;
                                tn1 = tn1.NextSibling;
                            }
                            if (tn2 != null)
                            {
                                tn2.NextSibling = tn1.NextSibling;
                            }
                            else
                            {
                                pos.ParentNode.FirstChild = tn1.NextSibling;
                            }
                            FreeRecursive(ref tnCur);
                            break;

                        case BranchCollapseAction.CloseChildren:
                            tn1 = tnCur.FirstChild;
                            while (tn1 != null)
                            {
                                tn2 = tn1.NextSibling;
                                FreeRecursive(ref tn1);
                                tn1 = tn2;
                            }
                            tn1 = tn2 = null;
                            tnCur.FirstChild = null;
                            tnCur.FullCount = tnCur.ImmedCount;
                            goto case BranchCollapseAction.Nothing;
                        case BranchCollapseAction.Nothing:
                            tnCur.Expanded = false;
                            break;
                        default:
                            Debug.Assert(false, "Bogus BranchCollapseAction");
                            break;
                    }
                }
                else
                {
                    tnCur.Expanded = true;
                    allowRecursion = tnCur.AllowRecursion;
                    itemExpansionCount = tnCur.FullCount;
                    subItemExpansionCount = tnCur.ExpandedSubItemGain;
                }
            }
            else
            {
                tnCur = ExpandTreeNode(
                    pos.ParentNode,
                    tnUnexpandedSubItemAnchor,
                    pos.Index,
                    localColumn,
                    !subItemExpansion,
                    out itemExpansionCount,
                    out subItemExpansionCount);

                // Make sure we don't crash if the branch returns null. If this happens,
                // the branch should stop returning true for IsExpandable and initiate
                // an DisplayDataChanged event to update the expansion bitmap.
                if (tnCur == null)
                {
                    allowRecursion = false;
                    return;
                }

                allowRecursion = tnCur.AllowRecursion;

                // We need to insert the node ourselves
                if (subItemExpansion)
                {
                    if (tnSubItemAnchor == null)
                    {
                        // TREENODE_Complex is the lowest common denominator
                        // that supports multi column expansion. This node may
                        // be upgraded later if an expansion is actually made
                        // on this item.
                        tnSubItemAnchor = new TREENODE_Complex();
                        tnSubItemAnchor.Index = pos.Index;
                        TREENODE tnDummy = null;
                        // UNDONE_MC: Might want to insert last so there are no lasting side effects in case of failure
                        InsertIndexedNode(pos.ParentNode, tnSubItemAnchor, ref tnDummy);
                    }
                    tnCur.SubItemRoot = true;
                    // UNDONE_MC: Should we store the column in the blank index field of the root
                    // instead of in the SUBITEMNODE? This would save calculating the column with
                    // SUBITEMNODE.ColumnOfRootNode when we need it.
                    tnCur.Index = VirtualTreeConstant.NullIndex;
                    tnCur.Parent = tnSubItemAnchor;
                    sn = new SUBITEMNODE();
                    sn.Column = localColumn;
                    sn.RootNode = tnCur;
                    if (snPrev == null)
                    {
                        sn.NextSibling = tnSubItemAnchor.FirstSubItem;
                        tnSubItemAnchor.FirstSubItem = sn;
                    }
                    else
                    {
                        sn.NextSibling = snPrev.NextSibling;
                        snPrev.NextSibling = sn;
                    }
                }
            }
            if ((itemExpansionCount + subItemExpansionCount) != 0)
            {
                if (subItemExpansion)
                {
                    // An item increment will be picked up by the first pass in
                    // ChangeFullCountRecursive and passed back up the chain. The
                    // value is calculated in the call to AdjustSubItemGain, which is
                    // why we do not call that function here. However, ChangeFullCountRecursive
                    // also adjusts the following two values, so we compensate here.
                    Debug.Assert(tnCur.FullCount == Math.Abs(itemExpansionCount));
                    Debug.Assert(tnCur.FullSubItemGain == Math.Abs(subItemExpansionCount));
                    tnCur.FullCount -= itemExpansionCount;
                    tnCur.FullSubItemGain -= subItemExpansionCount;
                    tnRecurseOn = tnCur;
                }
                ChangeFullCountRecursive(
                    tnRecurseOn,
                    itemExpansionCount,
                    subItemExpansionCount,
                    null,
                    ref affectedColumns,
                    out rowChange,
                    out subItemChanges);
            }
        }
Example #4
0
        /// <summary>
        ///     Used by IMultiColumnTree.UpdateCellStyle implementations in derived classes
        /// </summary>
        /// <param name="branch">Target branch</param>
        /// <param name="row">Target row</param>
        /// <param name="column">Target column</param>
        /// <param name="makeComplex">Action to take</param>
        protected void UpdateCellStyle(IBranch branch, int row, int column, bool makeComplex)
        {
            var tnNext = LocateTrackedNode(branch);
            Debug.Assert(tnNext != null); //Expect LocateTrackedNode to throw otherwise
            var keyOffSubItemRoot = !makeComplex && row == -1 && column == 0;
            if (!keyOffSubItemRoot)
            {
                // Do an exception-inducing cast here. The branch must be a multi-column
                var mcBranch = (IMultiColumnBranch)branch;
                // UNDONE_MC: This is a branch-relative column value, which may not be the absolute
                // column in the grid. Need a good way of either calculating or storing the absolute
                // column for a given branch. The unused Index property on a SubItemRoot node is a good
                // candidate slot for this data, which would minimize recursion required to calculate this.
                if (row < 0
                    || row > tnNext.ImmedCount)
                {
                    throw new ArgumentOutOfRangeException("row");
                }
                var columnStyle = mcBranch.ColumnStyles(column);
                if (0 == (columnStyle & SubItemCellStyles.Complex))
                {
                    throw new ArgumentException(VirtualTreeStrings.GetString(VirtualTreeStrings.ComplexColumnCellStyleException));
                }
            }
            // UNDONE_MC: This is not correct for the nested complex scenario. Calculate
            // an accurate absolute column for each branch usage.
            var absColumn = column;
            TREENODE tnChild;
            TREENODE tnPrevChild;
            SUBITEMNODE sn;
            SUBITEMNODE snPrev;
            ExpansionOptions options;
            int itemIncr;
            int subItemIncr;
            TREENODE tnNewSubItem;
            TREENODE tnParent;
            while (tnNext != null)
            {
                tnParent = tnNext;
                if (keyOffSubItemRoot)
                {
                    if (!tnNext.ComplexSubItem)
                    {
                        tnNext = tnParent.NextNode;
                        continue;
                    }
                    // Set up all of the variables to be just like the keying off
                    // the parent branch.
                    tnPrevChild = null;
                    tnChild = tnNext.Parent;
                    column = tnChild.FirstSubItem.ColumnOfRootNode(tnNext);
                    sn = tnChild.SubItemAtColumn(column, out snPrev);
                    tnNext = tnChild.Parent;
                    row = tnChild.Index;
                }
                else
                {
                    tnChild = tnParent.GetChildNode(row, out tnPrevChild);
                    if (tnChild != null)
                    {
                        sn = tnChild.SubItemAtColumn(column, out snPrev);
                    }
                    else
                    {
                        sn = snPrev = null;
                    }
                }
                // We either need a subitem node and a move to not being complex, or not subitem
                // node and a move to complex. This condition satisfies both so we can combine some processing.
                if ((sn == null) == makeComplex)
                {
                    if (makeComplex)
                    {
                        tnNewSubItem = ExpandTreeNode(
                            tnParent,
                            null,
                            row,
                            column,
                            ObjectStyle.SubItemRootBranch,
                            false,
                            out options,
                            out itemIncr,
                            out subItemIncr);
                        if (tnNewSubItem == null)
                        {
                            tnNext = tnParent.NextNode;
                            continue;
                        }
                        if (tnChild == null)
                        {
                            // See comments in ExpandInitialComplexSubItems
                            tnChild = new TREENODE_Complex();
                            tnChild.Index = row;
                            InsertIndexedNode(tnParent, tnChild, ref tnPrevChild);
                        }
                        tnNewSubItem.SubItemRoot = true;
                        if (0 == (options & ExpansionOptions.UseAsSubItemExpansion))
                        {
                            tnNewSubItem.ComplexSubItem = true;
                        }
                        tnNewSubItem.Index = VirtualTreeConstant.NullIndex;
                        tnNewSubItem.Parent = tnChild;
                        sn = new SUBITEMNODE();
                        sn.Column = column;
                        sn.RootNode = tnNewSubItem;
                        if (snPrev == null)
                        {
                            sn.NextSibling = tnChild.FirstSubItem;
                            tnChild.FirstSubItem = sn;
                        }
                        else
                        {
                            sn.NextSibling = snPrev.NextSibling;
                            snPrev.NextSibling = sn;
                        }
                    }
                    else
                    {
                        // Delete the expansion
                        if (snPrev == null)
                        {
                            tnChild.FirstSubItem = sn.NextSibling;
                        }
                        else
                        {
                            snPrev.NextSibling = sn.NextSibling;
                        }
                        FreeRecursive(ref sn.RootNode);
                    }
                    subItemIncr = tnChild.AdjustSubItemGain();
                    if (subItemIncr != 0)
                    {
                        if (ItemCountChanged != null)
                        {
                            int dummySingleColumnAbsRow; // This action does not affect the single column view
                            var absRow = EnumAbsoluteIndices(row, ref tnNext, out dummySingleColumnAbsRow).Row;
                            if (absRow != VirtualTreeConstant.NullIndex)
                            {
                                SubItemColumnAdjustment[] subItemChanges;
                                var parentRowOffset = 0;
                                var affectedSubItemColumns = new AffectedSubItems(true);
                                var singleColumnSubItemAdjust = 0;
                                int rowIncr;
                                // We need to track all of this for expanded nodes to get the correct information for the event.
                                var adjustColumn = absColumn;

                                // TrackCell is currently broken for all values after absRow, but it will work down
                                // to the row we are curently expanding. We need this call to get the affectedSubItemColumns.
                                TrackCell(
                                    absRow, ref adjustColumn, ref parentRowOffset, ref affectedSubItemColumns, ref singleColumnSubItemAdjust);
                                Debug.Assert(adjustColumn == 0);
                                    // This should pick up the new list now in this cell, so the column will always be zero
                                ChangeFullCountRecursive(
                                    tnChild, 0, subItemIncr, null, ref affectedSubItemColumns, out rowIncr, out subItemChanges);
                                DelayTurnOffRedraw();
                                ItemCountChanged(
                                    this,
                                    new ItemCountChangedEventArgs(
                                        this, absRow, absColumn, rowIncr, absRow - 1, tnChild.ImmedSubItemGain, subItemChanges, true));
                                tnNext = tnParent.NextNode;
                                continue;
                            }
                        }
                        ChangeFullCountRecursive(tnChild, 0, subItemIncr);
                    }
                    else
                    {
                        // UNDONE: Nothing changed from a global structure perspective,
                        // the cell contents may have. Defer to DisplayDataChanged at this point
                    }
                }
                tnNext = tnParent.NextNode;
            }
            ClearPositionCache(); //Cached absolute information is toast.
        }
Example #5
0
 /// <summary>
 ///     Attempt to expand complex sub items in a multi-column branch. Called
 ///     immediately after a new node is created.
 /// </summary>
 /// <param name="tn">The node for the parent branch</param>
 /// <param name="totalIncrease">The cumulative subitem gain</param>
 private void ExpandInitialComplexSubItems(TREENODE_Multi tn, out int totalIncrease)
 {
     // The algorithm will walk sequentially through the branch and
     // create a new tree node for each row. We walk all columns
     // in a given row to make it easier to build the TREENODE list
     // attached to the parent.
     Debug.Assert(tn.FirstChild == null);
     Debug.Assert(tn.ComplexColumns); // Check before calling
     var mcBranch = tn.Branch as IMultiColumnBranch;
     var columnCount = (mcBranch == null) ? 1 : mcBranch.ColumnCount;
     totalIncrease = 0;
     if (columnCount > 1)
     {
         // Get an array with the complex columns
         int iCol;
         var complexColumnCount = 0;
         for (iCol = 1; iCol < columnCount; ++iCol)
         {
             if (0 != (tn.SubItemStyle(iCol) & SubItemCellStyles.Complex))
             {
                 ++complexColumnCount;
             }
         }
         if (complexColumnCount > 0)
         {
             var complexColumns = new int[complexColumnCount];
             var jaggedColumns = tn.JaggedColumns;
             var maxRow = tn.FullCount;
             var maxColumn = columnCount - 1;
             int iRow;
             int itemIncr;
             int subItemIncr;
             TREENODE tnSubItemAnchor;
             TREENODE tnSubItem;
             TREENODE tnPrevHint;
             SUBITEMNODE snPrev;
             SUBITEMNODE sn;
             complexColumnCount = 0;
             ExpansionOptions options;
             for (iCol = 1; iCol < columnCount; ++iCol)
             {
                 if (0 != (tn.SubItemStyle(iCol) & SubItemCellStyles.Complex))
                 {
                     complexColumns[complexColumnCount] = iCol;
                     ++complexColumnCount;
                 }
             }
             // Walk the columns that matter and link up the returned tree nodes
             tnPrevHint = null;
             Debug.Assert(tn.FirstChild == null); // This is initial expansion only
             for (iRow = 0; iRow < maxRow; ++iRow)
             {
                 snPrev = null;
                 tnSubItemAnchor = null;
                 if (jaggedColumns)
                 {
                     maxColumn = mcBranch.GetJaggedColumnCount(iRow) - 1;
                 }
                 for (iCol = 0; iCol < complexColumnCount; ++iCol)
                 {
                     if (jaggedColumns && complexColumns[iCol] > maxColumn)
                     {
                         break;
                     }
                     options = 0;
                     tnSubItem = ExpandTreeNode(
                         tn,
                         null,
                         iRow,
                         complexColumns[iCol],
                         ObjectStyle.SubItemRootBranch,
                         false,
                         out options,
                         out itemIncr,
                         out subItemIncr);
                     if (tnSubItem != null)
                     {
                         if (snPrev == null)
                         {
                             // First node for this row, go ahead and create a dummy node
                             // TREENODE_Complex is the lowest common denominator
                             // that supports multi column expansion. This node may
                             // be upgraded later if an expansion is actually made
                             // on this item.
                             tnSubItemAnchor = new TREENODE_Complex();
                             tnSubItemAnchor.Index = iRow;
                             // UNDONE_MC: Might want to insert last so there are no lasting side effects in case of failure
                             InsertIndexedNode(tn, tnSubItemAnchor, ref tnPrevHint);
                         }
                         // UNDONE_MC: Should we store the column in the blank index field of the root
                         // instead of in the SUBITEMNODE? This would save calculating the column with
                         // SUBITEMNODE.ColumnOfRootNode when we need it.
                         tnSubItem.SubItemRoot = true;
                         if (0 == (options & ExpansionOptions.UseAsSubItemExpansion))
                         {
                             tnSubItem.ComplexSubItem = true;
                         }
                         tnSubItem.Index = VirtualTreeConstant.NullIndex;
                         tnSubItem.Parent = tnSubItemAnchor;
                         sn = new SUBITEMNODE();
                         sn.Column = complexColumns[iCol];
                         sn.RootNode = tnSubItem;
                         if (snPrev == null)
                         {
                             sn.NextSibling = tnSubItemAnchor.FirstSubItem;
                             tnSubItemAnchor.FirstSubItem = sn;
                         }
                         else
                         {
                             sn.NextSibling = snPrev.NextSibling;
                             snPrev.NextSibling = sn;
                         }
                         snPrev = sn;
                     }
                     if (tnSubItemAnchor != null)
                     {
                         var adjustment = tnSubItemAnchor.AdjustSubItemGain();
                         tnSubItemAnchor.FullSubItemGain += adjustment;
                         totalIncrease += adjustment;
                     }
                 }
             }
         }
     }
 }
Example #6
0
 public override sealed SUBITEMNODE SubItemAtColumn(int column, out SUBITEMNODE snPrev)
 {
     var sn = FirstSubItem;
     snPrev = null;
     while (sn != null)
     {
         if (sn.Column >= column)
         {
             return (sn.Column == column) ? sn : null;
         }
         snPrev = sn;
         sn = sn.NextSibling;
     }
     return null;
 }