コード例 #1
0
 private void Initialize(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow, int itemCount)
 {
     if (columnPermutation != null)
     {
         column = columnPermutation.GetNativeColumn(column);
     }
     myColumn       = column;
     myColumnInTree = column;
     myStartRow     = startRow;
     myEndRow       = endRow;
     if (endRow < startRow &&
         endRow >= 0)
     {
         myCycle    = true;
         myLimitRow = itemCount - 1;
     }
     else
     {
         myCycle    = false;
         myLimitRow = (endRow < 0) ? itemCount - 1 : endRow;
     }
     myNextStartRow       = startRow;
     myCurrentRow         = startRow - 1;
     myCurrentRelativeRow = myFirstRelativeRow = myLastRelativeRow = myRelativeColumn = myTrailingBlanks = myLevel = 0;
     myIsSimpleCell       = false;
     myReturnBlankAnchors = returnBlankAnchors;
     myColumnPermutation  = columnPermutation;
     myBranch             = null;
 }
コード例 #2
0
 private void Initialize(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow, int itemCount)
 {
     if (columnPermutation != null)
     {
         column = columnPermutation.GetNativeColumn(column);
     }
     myColumn = column;
     myColumnInTree = column;
     myStartRow = startRow;
     myEndRow = endRow;
     if (endRow < startRow
         && endRow >= 0)
     {
         myCycle = true;
         myLimitRow = itemCount - 1;
     }
     else
     {
         myCycle = false;
         myLimitRow = (endRow < 0) ? itemCount - 1 : endRow;
     }
     myNextStartRow = startRow;
     myCurrentRow = startRow - 1;
     myCurrentRelativeRow = myFirstRelativeRow = myLastRelativeRow = myRelativeColumn = myTrailingBlanks = myLevel = 0;
     myIsSimpleCell = false;
     myReturnBlankAnchors = returnBlankAnchors;
     myColumnPermutation = columnPermutation;
     myBranch = null;
 }
コード例 #3
0
 /// <summary>
 ///     Create a new enumerator
 /// </summary>
 /// <param name="column">The column to enumerate</param>
 /// <param name="columnPermutation">
 ///     The column permutation to apply. If this
 ///     is provided, then column is relative to the permutation.
 /// </param>
 /// <param name="returnBlankAnchors">
 ///     If an item is on a horizontal blank expansion, then
 ///     return the anchor for that item. All blanks are skipped if this is false.
 /// </param>
 /// <param name="rowFilter">
 ///     An array of items to return. The array must be sorted in ascending order
 ///     and all values must be valid indices in the tree.
 /// </param>
 /// <param name="markExcludedFilterItems">If true, items in the filter that are not returned will be marked by bitwise inverting them (~initialIndex)</param>
 protected ColumnItemEnumerator(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int[] rowFilter, bool markExcludedFilterItems)
 {
     var startRow = rowFilter[0];
     var endRow = rowFilter[rowFilter.Length - 1];
     Initialize(column, columnPermutation, returnBlankAnchors, startRow, endRow, endRow - startRow + 1);
     myMarkFilterExclusions = markExcludedFilterItems;
     myFilter = rowFilter;
     myFilterRow = 0;
 }
コード例 #4
0
        /// <summary>
        ///     Create a new enumerator
        /// </summary>
        /// <param name="column">The column to enumerate</param>
        /// <param name="columnPermutation">
        ///     The column permutation to apply. If this
        ///     is provided, then column is relative to the permutation.
        /// </param>
        /// <param name="returnBlankAnchors">
        ///     If an item is on a horizontal blank expansion, then
        ///     return the anchor for that item. All blanks are skipped if this is false.
        /// </param>
        /// <param name="rowFilter">
        ///     An array of items to return. The array must be sorted in ascending order
        ///     and all values must be valid indices in the tree.
        /// </param>
        /// <param name="markExcludedFilterItems">If true, items in the filter that are not returned will be marked by bitwise inverting them (~initialIndex)</param>
        protected ColumnItemEnumerator(
            int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int[] rowFilter, bool markExcludedFilterItems)
        {
            var startRow = rowFilter[0];
            var endRow   = rowFilter[rowFilter.Length - 1];

            Initialize(column, columnPermutation, returnBlankAnchors, startRow, endRow, endRow - startRow + 1);
            myMarkFilterExclusions = markExcludedFilterItems;
            myFilter    = rowFilter;
            myFilterRow = 0;
        }
コード例 #5
0
        protected VirtualTreeCoordinate GetNavigationTarget(
            TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
        {
            var targetRow = sourceRow;
            var targetColumn = sourceColumn;
            if (myRootNode == null)
            {
                return VirtualTreeCoordinate.Invalid;
            }
            var startColumn = sourceColumn;

            var retVal = false;
            var expansion = GetBlankExpansion(sourceRow, sourceColumn, columnPermutation);
            sourceRow = expansion.TopRow;
            var nativeSourceColumn = sourceColumn;
            if (expansion.AnchorColumn != VirtualTreeConstant.NullIndex)
            {
                sourceColumn = expansion.AnchorColumn;
            }
            if (columnPermutation != null)
            {
                nativeSourceColumn = columnPermutation.GetNativeColumn(sourceColumn);
            }

            var localColumn = nativeSourceColumn;
            var lastSubItem = false;
            var pos = TrackCell(sourceRow, ref localColumn, ref lastSubItem);
            TREENODE tnChild;
            var attemptNextColumn = false;
            int selectColumn;
            TREENODE tnParent = null;
            var rowOffset = 0;
            switch (direction)
            {
                case TreeNavigation.Parent:
                case TreeNavigation.ComplexParent:
                    if (localColumn == 0
                        &&
                        (pos.ParentAbsolute != -1 ||
                         (pos.ParentNode.SubItemRoot && !pos.ParentNode.ComplexSubItem)))
                    {
                        if (nativeSourceColumn > 0)
                        {
                            // This is more work than column zero. The parent
                            // absolute is relative to the root node in the branch.
                            targetRow = sourceRow - pos.ParentNode.GetChildOffset(pos.Index);
                        }
                        else
                        {
                            targetRow = pos.ParentAbsolute;
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                    }
                    else if (direction == TreeNavigation.ComplexParent)
                    {
                        if (pos.ParentNode.ComplexSubItem)
                        {
                            targetColumn = nativeSourceColumn - pos.ParentNode.Parent.FirstSubItem.ColumnOfRootNode(pos.ParentNode);
                            if ((columnPermutation == null)
                                || (-1 != (targetColumn = columnPermutation.GetPermutedColumn(targetColumn))))
                            {
                                targetRow = sourceRow - pos.ParentNode.GetChildOffset(pos.Index) + 1;
                                retVal = true;
                            }
                        }
                        else if (localColumn > 0)
                        {
                            targetColumn = nativeSourceColumn - localColumn;
                            if ((columnPermutation == null)
                                || (-1 != (targetColumn = columnPermutation.GetPermutedColumn(targetColumn))))
                            {
                                targetRow = sourceRow;
                                retVal = true;
                            }
                        }
                    }
                    break;
                case TreeNavigation.FirstChild:
                case TreeNavigation.LastChild:
                    // FirstChild and LastChild share code for testing if the node is expanded
                    tnChild = pos.ParentNode.GetChildNode(pos.Index);
                    if (localColumn > 0
                        && tnChild != null)
                    {
                        var sn = tnChild.SubItemAtColumn(localColumn);
                        tnChild = (sn == null) ? null : sn.RootNode;
                    }
                    if (tnChild != null
                        && tnChild.Expanded
                        && tnChild.ImmedCount > 0)
                    {
                        // Right jumps to FirstChild, test LastChild, not FirstChild, so
                        // else handles both elements.
                        if (direction == TreeNavigation.LastChild)
                        {
                            targetRow = sourceRow + tnChild.GetChildOffset(tnChild.ImmedCount - 1);
                        }
                        else
                        {
                            targetRow = sourceRow + tnChild.ImmedSubItemGain + 1;
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                    }
                    else if (attemptNextColumn)
                    {
                        goto case TreeNavigation.RightColumn;
                    }
                    break;
                case TreeNavigation.RightColumn:
                    {
                        // Move right to the next column. Note that this is not a natural
                        // thing to do from the tree perspective because the closest element
                        // to the right is likely to be only a distant relative of the current
                        // node, but the user is unlikely to appreciate this distinction and
                        // just wants to move right, so we let them.
                        if (nativeSourceColumn == 0
                            || localColumn > 0)
                        {
                            if (columnPermutation == null)
                            {
                                if (pos.ParentNode.GetColumnCount(pos.Index) > (localColumn + 1))
                                {
                                    targetRow = sourceRow;
                                    targetColumn = sourceColumn + 1;
                                    retVal = true;
                                }
                            }
                            else if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                            {
                                targetColumn = GetBlankExpansion(sourceRow, expansion.RightColumn + 1, columnPermutation).AnchorColumn;
                                targetRow = sourceRow;
                                retVal = true;
                            }
                        }
                        else
                        {
                            // Walk back up this tree until we get to a subitem root node, tracking
                            // offsets as we go.
                            tnParent = pos.ParentNode;
                            rowOffset = tnParent.GetChildOffset(pos.Index);
                            while (!tnParent.SubItemRoot)
                            {
                                tnChild = tnParent;
                                tnParent = tnChild.Parent;
                                rowOffset += tnParent.GetChildOffset(tnChild.Index);
                            }
                            if (tnParent.ComplexSubItem)
                            {
                                --rowOffset;
                            }
                            tnChild = tnParent;
                            tnParent = tnChild.Parent;

                            // Find the SUBITEMNODE for the next column and the next column
                            // index. The sub item node may be null if the next column is simple.
                            SUBITEMNODE snNext = null;
                            selectColumn = -1;
                            if (columnPermutation == null)
                            {
                                if (localColumn < (tnParent.Parent.GetColumnCount(tnParent.Index) - 1))
                                {
                                    var sn = tnParent.FirstSubItem;
                                    while (sn.RootNode != tnChild)
                                    {
                                        sn = sn.NextSibling;
                                    }
                                    var snTestNext = sn.NextSibling;
                                    if (snTestNext != null
                                        && (snTestNext.Column - sn.Column) == 1)
                                    {
                                        snNext = snTestNext;
                                    }
                                    selectColumn = sourceColumn + 1;
                                }
                            }
                            else
                            {
                                if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                                {
                                    selectColumn = GetBlankExpansion(sourceRow, expansion.RightColumn + 1, columnPermutation).AnchorColumn;
                                    // Note that column zero has no subitem node, so this covers this case
                                    // UNDONE_MC: Need local column, not global
                                    snNext = tnParent.SubItemAtColumn(columnPermutation.GetNativeColumn(selectColumn));
                                }
                            }

                            if (selectColumn != -1)
                            {
                                if (snNext != null)
                                {
                                    var nextGain = snNext.RootNode.TotalCount;
                                    if (snNext.RootNode.ComplexSubItem)
                                    {
                                        --nextGain;
                                    }
                                    else if (!snNext.RootNode.Expanded)
                                    {
                                        nextGain = 0;
                                    }
                                    if (nextGain < rowOffset)
                                    {
                                        targetRow = sourceRow - rowOffset + nextGain;
                                    }
                                    else
                                    {
                                        targetRow = sourceRow;
                                    }
                                }
                                else
                                {
                                    targetRow = sourceRow - rowOffset;
                                }
                                targetColumn = selectColumn;
                                retVal = true;
                            }
                        }
                        break;
                    }
                case TreeNavigation.NextSibling:
                    // Test localColumn. Expandable and simple cells don't have siblings,
                    // and all other nodes will give back a localColumn of 0.
                    if (localColumn == 0
                        && pos.Index < (pos.ParentNode.ImmedCount - 1))
                    {
                        targetRow = sourceRow + 1;
                        tnChild = pos.ParentNode.GetChildNode(pos.Index);
                        if (tnChild != null)
                        {
                            targetRow += tnChild.TotalCount;
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                    }
                    break;
                case TreeNavigation.PreviousSibling:
                    if (localColumn == 0
                        && pos.Index > 0)
                    {
                        if (pos.ParentNode.ComplexSubItem)
                        {
                            // The parent absolute is -1 and can't be used to give back a real count, 
                            // so use a more expensive algorithm in this case.
                            targetRow = sourceRow - pos.ParentNode.GetChildOffset(pos.Index) + pos.ParentNode.GetChildOffset(pos.Index - 1);
                        }
                        else
                        {
                            targetRow = pos.ParentAbsolute + pos.ParentNode.GetChildOffset(pos.Index - 1);
                        }
                        targetColumn = sourceColumn;
                        retVal = true;
                        break;
                    }
                    break;
                case TreeNavigation.Up:
                    while (targetRow > 0)
                    {
                        expansion = GetBlankExpansion(targetRow - 1, startColumn, columnPermutation);
                        targetRow = expansion.TopRow;
                        if (startColumn == expansion.AnchorColumn)
                        {
                            retVal = true;
                            break;
                        }
                    }
                    break;
                case TreeNavigation.Down:
                    while (expansion.BottomRow < (myRootNode.TotalCount - 1))
                    {
                        // Just return the next non-blank column
                        var testRow = expansion.BottomRow + 1;
                        expansion = GetBlankExpansion(testRow, startColumn, columnPermutation);
                        targetRow = expansion.TopRow;
                        if (startColumn == expansion.AnchorColumn
                            && targetRow >= testRow)
                        {
                            retVal = true;
                            break;
                        }
                    }
                    break;
                case TreeNavigation.LeftColumn:
                    if (localColumn > 0)
                    {
                        if (columnPermutation == null)
                        {
                            if (sourceColumn > 0)
                            {
                                targetRow = sourceRow;
                                targetColumn = sourceColumn - 1;
                                retVal = true;
                            }
                        }
                        else if (expansion.LeftColumn > 0)
                        {
                            targetRow = sourceRow;
                            targetColumn = GetBlankExpansion(targetRow, expansion.LeftColumn - 1, columnPermutation).AnchorColumn;
                            retVal = true;
                        }
                    }
                    else
                    {
                        // tnParent may have been set already in TreeNavigation.Left, only set it if needed
                        // Note that the nativeSourceColumn == 0 case can happen with a columnPermutation only
                        if (tnParent == null
                            && nativeSourceColumn != 0)
                        {
                            tnParent = pos.ParentNode;
                            rowOffset = tnParent.GetChildOffset(pos.Index);
                            while (!tnParent.SubItemRoot)
                            {
                                tnChild = tnParent;
                                tnParent = tnChild.Parent;
                                rowOffset += tnParent.GetChildOffset(tnChild.Index);
                            }
                            if (tnParent.ComplexSubItem)
                            {
                                --rowOffset;
                            }
                        }
                        selectColumn = -1;
                        SUBITEMNODE snPrev = null;
                        if (columnPermutation == null)
                        {
                            if (tnParent != null
                                && tnParent.Parent != null)
                            {
                                var sn = tnParent.Parent.FirstSubItem;
                                SUBITEMNODE snTestPrev = null;
                                while (sn.RootNode != tnParent)
                                {
                                    snTestPrev = sn;
                                    sn = sn.NextSibling;
                                }
                                if (snTestPrev != null
                                    && (sn.Column - snTestPrev.Column) == 1)
                                {
                                    snPrev = snTestPrev;
                                }
                            }
                            selectColumn = sourceColumn - 1;
                        }
                        else if (expansion.LeftColumn > 0)
                        {
                            selectColumn = GetBlankExpansion(sourceRow, expansion.LeftColumn - 1, columnPermutation).AnchorColumn;
                            if (tnParent != null)
                            {
                                // Note that column zero has no subitem node, so this covers this case
                                // UNDONE_MC: Need local column, not global
                                snPrev = tnParent.Parent.SubItemAtColumn(columnPermutation.GetNativeColumn(selectColumn));
                            }
                        }
                        if (selectColumn != -1)
                        {
                            targetColumn = selectColumn;
                            retVal = true;
                            if (snPrev == null)
                            {
                                // The previous column is the parent node or a simple cell. Move
                                // to that cell.
                                targetRow = sourceRow - rowOffset;
                            }
                            else
                            {
                                // The most closely related node to the left is the 0 node in the
                                // previous column. However, this node is not spatially closest
                                // to the current cell. The subtle the distinction that the closest
                                // cell is only a distant relative of the current one is generally lost
                                // on the user, so we just let them move left to the current value.
                                var prevGain = snPrev.RootNode.TotalCount;
                                if (snPrev.RootNode.ComplexSubItem)
                                {
                                    --prevGain;
                                }
                                else if (!snPrev.RootNode.Expanded)
                                {
                                    prevGain = 0;
                                }
                                if (prevGain < rowOffset)
                                {
                                    targetRow = sourceRow - rowOffset + prevGain;
                                }
                                else
                                {
                                    targetRow = sourceRow;
                                }
                            }
                        }
                    }
                    break;
                case TreeNavigation.Left:
                    if (sourceColumn > 0)
                    {
                        if (localColumn > 0
                            ||
                            (pos.Index == 0 && pos.ParentNode.ComplexSubItem))
                        {
                            // Move left one column
                            if (columnPermutation == null)
                            {
                                targetRow = sourceRow;
                                targetColumn = sourceColumn - 1;
                                retVal = true;
                            }
                            else if (expansion.LeftColumn > 0)
                            {
                                targetRow = sourceRow;
                                targetColumn = GetBlankExpansion(sourceRow, expansion.LeftColumn - 1, columnPermutation).AnchorColumn;
                                retVal = true;
                            }
                            break;
                        }
                        else if (pos.ParentNode.ComplexSubItem
                                 && pos.Index > 0)
                        {
                            tnParent = pos.ParentNode;
                            rowOffset = tnParent.GetChildOffset(pos.Index) - 1;
                            goto case TreeNavigation.LeftColumn;
                        }
                        else if (nativeSourceColumn == 0
                                 && pos.ParentNode.Index == -1)
                        {
                            goto case TreeNavigation.LeftColumn;
                        }
                    }
                    goto case TreeNavigation.Parent;
                case TreeNavigation.Right:
                    if (MultiColumnSupport)
                    {
                        if ((sourceColumn == 0)
                            ||
                            (pos.ParentNode.ComplexSubItem && pos.Index == 0)
                            ||
                            (localColumn > 0))
                        {
                            if (columnPermutation == null)
                            {
                                if (localColumn < (pos.ParentNode.GetColumnCount(pos.Index) - 1))
                                {
                                    targetRow = sourceRow;
                                    targetColumn = sourceColumn + 1;
                                    retVal = true;
                                    break;
                                }
                            }
                            else if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                            {
                                targetRow = sourceRow;
                                targetColumn = GetBlankExpansion(sourceRow, expansion.RightColumn + 1, columnPermutation).AnchorColumn;
                                retVal = true;
                                break;
                            }
                        }
                        else if (columnPermutation == null)
                        {
                            if (sourceColumn < (ColumnCount - 1))
                            {
                                // If firstchild doesn't go anywhere, then attempt
                                // to move to the next branch.
                                attemptNextColumn = true;
                            }
                        }
                        else if (expansion.RightColumn < (columnPermutation.VisibleColumnCount - 1))
                        {
                            attemptNextColumn = true;
                        }
                    }
                    goto case TreeNavigation.FirstChild;
            }
            return retVal ? new VirtualTreeCoordinate(targetRow, targetColumn) : VirtualTreeCoordinate.Invalid;
        }
コード例 #6
0
        private void SetSelectionColumn_PreserveBasic(
            int oldColumn, ColumnPermutation oldPermutation, int newColumn, bool allowAnchoredBlanks, bool fireEvents)
        {
            var indices = SelectedIndicesArray;
            int index;
            if (indices != null)
            {
                var hWnd = Handle; // forces evaluation of Handle
                var firstVisible = TopIndex;
                var lastVisible = firstVisible + myPartlyVisibleCountIgnoreHScroll - 1;

                // Grab information from the previous column to give us a baseline. Not
                // all of the items in indices will correspond to items in the old column.
                var oldIndices = (int[])indices.Clone();
                var oldIter = myTree.EnumerateColumnItems(
                    oldColumn, (oldPermutation != null) ? oldPermutation : myColumnPermutation, allowAnchoredBlanks, oldIndices, true);
                while (oldIter.MoveNext())
                {
                    ; // Spin the enumerator to mark the rows
                }

                var iter = myTree.EnumerateColumnItems(newColumn, myColumnPermutation, allowAnchoredBlanks, indices, true);
                while (iter.MoveNext())
                {
                    ; // Spin the enumerator to mark the rows
                }
                var count = indices.Length;
                var lastStart = -1;
                var lastEnd = -1;
                var newEnd = -1;
                for (var i = 0; i < count; ++i)
                {
                    index = indices[i];
                    if (index < 0
                        || oldIndices[i] < 0)
                    {
                        newEnd = (index < 0) ? ~index : index;
                        if (lastEnd == -1)
                        {
                            lastStart = lastEnd = newEnd;
                        }
                        else if (1 == (newEnd - lastEnd))
                        {
                            ++lastEnd;
                        }
                        else
                        {
                            SetSelectionRange(lastStart, lastEnd, false);
                            lastStart = lastEnd = newEnd;
                        }
                    }
                    else if (index >= firstVisible
                             && index <= lastVisible)
                    {
                        InvalidateItem(index, -1, NativeMethods.RedrawWindowFlags.Invalidate);
                    }
                }
                if (lastStart != -1)
                {
                    SetSelectionRange(lastStart, lastEnd, false);
                }
            }
            if (fireEvents)
            {
                OnSelectionChanged(EventArgs.Empty);
            }
        }
コード例 #7
0
 ColumnItemEnumerator ITree.EnumerateColumnItems(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow)
 {
     return new ColumnItemEnumeratorSingleColumnImpl(myParent, startRow, endRow);
 }
コード例 #8
0
            VirtualTreeCoordinate ITree.GetNavigationTarget(
                TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
            {
                Debug.Assert(sourceColumn == 0);
                sourceColumn = 0;
                var targetRow = sourceRow;
                if (myParent.myRootNode == null)
                {
                    return VirtualTreeCoordinate.Invalid;
                }

                var retVal = false;

                var pos = myParent.TrackSingleColumnRow(sourceRow);
                TREENODE tnChild;
                switch (direction)
                {
                    case TreeNavigation.Left:
                    case TreeNavigation.Parent:
                    case TreeNavigation.ComplexParent:
                        if (pos.ParentAbsolute != -1)
                        {
                            targetRow = pos.ParentAbsolute;
                            retVal = true;
                        }
                        break;
                    case TreeNavigation.Right:
                    case TreeNavigation.FirstChild:
                    case TreeNavigation.LastChild:
                        // FirstChild and LastChild share code for testing if the node is expanded
                        tnChild = pos.ParentNode.GetChildNode(pos.Index);
                        if (tnChild != null
                            && tnChild.Expanded
                            && tnChild.ImmedCount > 0)
                        {
                            // Right jumps to FirstChild, test LastChild, not FirstChild, so
                            // else handles both elements.
                            if (direction == TreeNavigation.LastChild)
                            {
                                targetRow = sourceRow + tnChild.GetSingleColumnChildOffset(tnChild.ImmedCount - 1);
                            }
                            else
                            {
                                targetRow = sourceRow + 1;
                            }
                            retVal = true;
                        }
                        break;
                    case TreeNavigation.NextSibling:
                        // Test localColumn. Expandable and simple cells don't have siblings,
                        // and all other nodes will give back a localColumn of 0.
                        if (pos.Index < (pos.ParentNode.ImmedCount - 1))
                        {
                            targetRow = sourceRow + 1;
                            tnChild = pos.ParentNode.GetChildNode(pos.Index);
                            if (tnChild != null)
                            {
                                targetRow += tnChild.FullCount;
                            }
                            retVal = true;
                        }
                        break;
                    case TreeNavigation.PreviousSibling:
                        if (pos.Index > 0)
                        {
                            targetRow = pos.ParentAbsolute + pos.ParentNode.GetSingleColumnChildOffset(pos.Index - 1);
                            retVal = true;
                        }
                        break;
                    case TreeNavigation.Up:
                        if (targetRow > 0)
                        {
                            --targetRow;
                            retVal = true;
                        }
                        break;
                    case TreeNavigation.Down:
                        if (targetRow < (myParent.myRootNode.FullCount - 1))
                        {
                            ++targetRow;
                            retVal = true;
                        }
                        break;
                        //case TreeNavigation.RightColumn:
                        //case TreeNavigation.LeftColumn:
                }
                return retVal ? new VirtualTreeCoordinate(targetRow, 0) : VirtualTreeCoordinate.Invalid;
            }
コード例 #9
0
        private void EnumOrderedListItems(
            ref int nextStartRow,
            int column,
            ColumnPermutation permutation,
            bool returnBlankAnchors,
            out IBranch branch,
            out int treeColumn,
            out int firstRelativeRow,
            out int lastRelativeRow,
            out int relativeColumn,
            out int level,
            out int trailingBlanks,
            out bool simpleCell)
        {
            trailingBlanks = 0;
            relativeColumn = column;
            treeColumn = column;
            var pos = TrackCell(nextStartRow, ref relativeColumn);
            TREENODE tn;
            var columnCount = 0;
            var tnParent = pos.ParentNode;
            level = pos.Level;
            var processItem = true;
            var verifyColumnCount = false;
            if (pos.IsBlank(relativeColumn))
            {
                // We're currently in a blank cell. Determine the next non-blank cell in this column
                // unless we've been asked to return the blank expansions.
                columnCount = tnParent.GetColumnCount(pos.Index);
                if (relativeColumn >= columnCount)
                {
                    tn = null;
                    if (returnBlankAnchors)
                    {
                        // For returning blank anchors, we need to see if we're within
                        // the range of rows supported by the last column in this row that
                        // has items.
                        if (permutation != null)
                        {
                            var expansion = permutation.GetColumnExpansion(
                                permutation.GetPermutedColumn(relativeColumn), columnCount - 1
                                /*UNDONE_MC: Column count local, not global, relativeColumn local, not global*/);
                            if (expansion.AnchorColumn == VirtualTreeConstant.NullIndex)
                            {
                                processItem = false;
                            }
                            else
                            {
                                // UNDONE_MC: Global and relative not the same
                                relativeColumn = treeColumn = permutation.GetNativeColumn(expansion.AnchorColumn);
                            }
                        }
                        else
                        {
                            // UNDONE_MC: Global and relative not the same
                            relativeColumn = treeColumn = columnCount - 1;
                        }
                        if (processItem)
                        {
                            pos = TrackCell(nextStartRow, ref relativeColumn);
                            if (pos.IsBlank(relativeColumn))
                            {
                                processItem = false;
                            }
                            else
                            {
                                tnParent = pos.ParentNode;
                                level = pos.Level;
                                verifyColumnCount = tnParent.JaggedColumns;
                            }
                        }
                    }
                    else
                    {
                        processItem = false;
                    }
                    if (!processItem)
                    {
                        // This isn't perfect, but a call to GetBlankExpansion is unlikely to give better information,
                        // so we just move one at a time. Moving one row at a time is relatively harmless here and shouldn't
                        // cause any sort of noticeable performance hit.
                        level = -1;
                        if ((tnParent.ExpandedSubItemGain != 0)
                            && (null != (tn = tnParent.GetChildNode(pos.Index))))
                        {
                            // If there is a reason to check, then go looking for the full subitem gain
                            // of a child at this node.
                            trailingBlanks = tn.ImmedSubItemGain - pos.SubItemOffset + 1; // Include this item in the blank count
                            nextStartRow += trailingBlanks;
                        }
                        else
                        {
                            trailingBlanks = 1; // Ask the next item
                            ++nextStartRow;
                        }
                    }
                }
                else
                {
                    processItem = false;
                    tn = tnParent.GetChildNode(pos.Index);
                    if (relativeColumn != 0)
                    {
                        // Be consistent with GetItemInfo
                        level = -1;
                    }
                    trailingBlanks = tn.ImmedSubItemGain - pos.SubItemOffset + 1; // Include this item in the blank count
                    nextStartRow += trailingBlanks;
                }
                if (nextStartRow >= myRootNode.TotalCount)
                {
                    nextStartRow = VirtualTreeConstant.NullIndex;
                }
            }
            if (processItem)
            {
                lastRelativeRow = tnParent.ImmedCount - 1; // Default value if nothing else found
                branch = tnParent.Branch;
                firstRelativeRow = pos.Index;
                int subItemGain;
                var totalSubItemGain = 0;
                trailingBlanks = 0;
                var lastVerifiedColumnCount = pos.Index;
                for (tn = tnParent.FirstChild; tn != null; tn = tn.NextSibling)
                {
                    if (pos.Index <= tn.Index)
                    {
                        for (; tn != null; tn = tn.NextSibling)
                        {
                            if (verifyColumnCount)
                            {
                                // In this case, we only want to use columns with
                                // the current column count. This prevents requests with
                                // returnBlankAnchors true from attaching to an anchor in
                                // the same column.
                                var testIndex = tn.Index;
                                for (var i = lastVerifiedColumnCount + 1; i <= testIndex; ++i)
                                {
                                    if (tnParent.GetColumnCount(i) != columnCount)
                                    {
                                        lastRelativeRow = lastVerifiedColumnCount = i - 1;
                                        testIndex = -1;
                                        break;
                                    }
                                }
                                if (testIndex == -1)
                                {
                                    tn = null;
                                    break;
                                }
                                lastVerifiedColumnCount = testIndex;
                            }
                            subItemGain = tn.ImmedSubItemGain;
                            if ((tn.Expanded && tn.ImmedCount > 0)
                                || (subItemGain > 0))
                            {
                                lastRelativeRow = tn.Index;
                                trailingBlanks = subItemGain;
                                break;
                            }
                            totalSubItemGain += subItemGain;
                        }
                        break;
                    }
                }

                if (verifyColumnCount && lastVerifiedColumnCount < lastRelativeRow)
                {
                    for (var i = lastVerifiedColumnCount + 1; i <= lastRelativeRow; ++i)
                    {
                        if (tnParent.GetColumnCount(i) != columnCount)
                        {
                            lastRelativeRow = i - 1;
                            break;
                        }
                    }
                }

                nextStartRow += lastRelativeRow - firstRelativeRow + totalSubItemGain + 1;
                if (tn != null)
                {
                    nextStartRow += tn.ImmedSubItemGain; // Undo later if not correct
                    if (relativeColumn != 0)
                    {
                        // Don't pretest SubItemStyle, can't tell if we got a complex or expanded node
                        var sn = tn.SubItemAtColumn(relativeColumn);
                        if (sn != null)
                        {
                            var subItemRoot = sn.RootNode;
                            if (!subItemRoot.ComplexSubItem
                                && subItemRoot.Expanded
                                && subItemRoot.TotalCount > 0)
                            {
                                // We went too far, undo
                                nextStartRow -= tn.ImmedSubItemGain;
                            }
                        }
                    }
                }
                // See if we're looking at a simple cell. This extra
                // information is needed by ComputeWidthOfRange on the
                // control side to get an accurate width, so we need to
                // be consistent with GetItemInfo here.
                if (level == 0 && MultiColumnSupport)
                {
                    if (!tnParent.MultiColumn)
                    {
                        simpleCell = tnParent.InSubItemColumn && tnParent.NoChildExpansion;
                    }
                    else if (column == 0)
                    {
                        simpleCell = tnParent.NoChildExpansion;
                    }
                    else
                    {
                        simpleCell = !(pos.IsExpanded(column) || pos.IsExpandable(column));
                    }
                }
                else
                {
                    simpleCell = false;
                }

                Debug.Assert(nextStartRow <= myRootNode.TotalCount, "Off end of list");
                if (nextStartRow == myRootNode.TotalCount) // == instead of >= OK with assert
                {
                    nextStartRow = VirtualTreeConstant.NullIndex;
                }
            }
            else
            {
                branch = null;
                simpleCell = false;
                firstRelativeRow = lastRelativeRow = VirtualTreeConstant.NullIndex;
            }
        }
コード例 #10
0
 ColumnItemEnumerator ITree.EnumerateColumnItems(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow)
 {
     return EnumerateColumnItems(column, columnPermutation, returnBlankAnchors, startRow, endRow);
 }
コード例 #11
0
        private void SetSelectionColumn_PreserveBasic(
            int oldColumn, ColumnPermutation oldPermutation, int newColumn, bool allowAnchoredBlanks, bool fireEvents)
        {
            var indices = SelectedIndicesArray;
            int index;

            if (indices != null)
            {
                var hWnd         = Handle; // forces evaluation of Handle
                var firstVisible = TopIndex;
                var lastVisible  = firstVisible + myPartlyVisibleCountIgnoreHScroll - 1;

                // Grab information from the previous column to give us a baseline. Not
                // all of the items in indices will correspond to items in the old column.
                var oldIndices = (int[])indices.Clone();
                var oldIter    = myTree.EnumerateColumnItems(
                    oldColumn, (oldPermutation != null) ? oldPermutation : myColumnPermutation, allowAnchoredBlanks, oldIndices, true);
                while (oldIter.MoveNext())
                {
                    ; // Spin the enumerator to mark the rows
                }

                var iter = myTree.EnumerateColumnItems(newColumn, myColumnPermutation, allowAnchoredBlanks, indices, true);
                while (iter.MoveNext())
                {
                    ; // Spin the enumerator to mark the rows
                }
                var count     = indices.Length;
                var lastStart = -1;
                var lastEnd   = -1;
                var newEnd    = -1;
                for (var i = 0; i < count; ++i)
                {
                    index = indices[i];
                    if (index < 0 ||
                        oldIndices[i] < 0)
                    {
                        newEnd = (index < 0) ? ~index : index;
                        if (lastEnd == -1)
                        {
                            lastStart = lastEnd = newEnd;
                        }
                        else if (1 == (newEnd - lastEnd))
                        {
                            ++lastEnd;
                        }
                        else
                        {
                            SetSelectionRange(lastStart, lastEnd, false);
                            lastStart = lastEnd = newEnd;
                        }
                    }
                    else if (index >= firstVisible &&
                             index <= lastVisible)
                    {
                        InvalidateItem(index, -1, NativeMethods.RedrawWindowFlags.Invalidate);
                    }
                }
                if (lastStart != -1)
                {
                    SetSelectionRange(lastStart, lastEnd, false);
                }
            }
            if (fireEvents)
            {
                OnSelectionChanged(EventArgs.Empty);
            }
        }
コード例 #12
0
        /// <summary>
        ///     Switch the selection column. For multiselect, the behavior is highly dependent on the
        ///     the ColumnSelectionTransferAction property and the prior state of the permutation, if
        ///     the permutation is being reordered
        /// </summary>
        /// <param name="column">The new selection column</param>
        /// <param name="oldPermutation">The old column permuation</param>
        /// <param name="fireEvents">True if this routine should fire selection events</param>
        private void SetSelectionColumn(int column, ColumnPermutation oldPermutation, bool fireEvents)
        {
            Debug.Assert(oldPermutation != null || column != mySelectionColumn);
            var iCaret = CurrentIndex;

            DismissLabelEdit(false, false);
            var oldColumn = mySelectionColumn;

            mySelectionColumn = column;

            if (GetStyleFlag(VTCStyleFlags.MultiSelect))
            {
                switch (myColumnSelectionAction)
                {
                case ColumnSelectionTransferAction.PreserveNonBlankCells:
                    SetSelectionColumn_PreserveBasic(oldColumn, oldPermutation, column, false, fireEvents);
                    break;

                case ColumnSelectionTransferAction.PreserveAnchoredCells:
                    SetSelectionColumn_PreserveBasic(oldColumn, oldPermutation, column, true, fireEvents);
                    break;

                case ColumnSelectionTransferAction.PreserveSharedAnchors:
                    SetSelectionColumn_PreserveAnchors(oldColumn, oldPermutation, column, false, fireEvents);
                    break;

                case ColumnSelectionTransferAction.PreserveSharedAnchorsOnly:
                    SetSelectionColumn_PreserveAnchors(oldColumn, oldPermutation, column, true, fireEvents);
                    break;

                case ColumnSelectionTransferAction.ClearSelectedRows:
                    SetSelectionColumn_Clear(fireEvents);
                    break;
                }
            }
            else if (iCaret != -1 && fireEvents)
            {
                CurrentIndex = iCaret;
            }

            if (oldColumn != mySelectionColumn)
            {
                // This may cause a focus change, because the caret moves to a different column.
                if (!GetStateFlag(VTCStateFlags.RestoringSelection) &&
                    VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectFocus, this) &&
                    Focused)
                {
                    VirtualTreeAccEvents.Notify(
                        VirtualTreeAccEvents.eventObjectFocus, CurrentIndex,
                        CurrentColumn, this);
                }

                // ensure newly selected column is scrolled into view.
                if (HasHorizontalScrollBar)
                {
                    ScrollColumnIntoView(CurrentColumn);
                }

                // make sure we invalidate the caret item
                if (CurrentIndex != VirtualTreeConstant.NullIndex)
                {
                    InvalidateItem(CurrentIndex, -1, NativeMethods.RedrawWindowFlags.Invalidate);
                }
            }
        }
コード例 #13
0
 /// <summary>
 ///     Create a new enumerator
 /// </summary>
 /// <param name="column">The column to enumerate</param>
 /// <param name="columnPermutation">
 ///     The column permutation to apply. If this
 ///     is provided, then column is relative to the permutation.
 /// </param>
 /// <param name="returnBlankAnchors">
 ///     If an item is on a horizontal blank expansion, then
 ///     return the anchor for that item. All blanks are skipped if this is false.
 /// </param>
 /// <param name="startRow">The first row to return, 0 to ITree.VisibleItemCount - 1</param>
 /// <param name="endRow">The first row to return, 0 to ITree.VisibleItemCount - 1, can be less than startRow</param>
 /// <param name="itemCount">The number of rows in the desired enumeration range</param>
 protected ColumnItemEnumerator(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow, int itemCount)
 {
     Initialize(column, columnPermutation, returnBlankAnchors, startRow, endRow, itemCount);
 }
コード例 #14
0
 ColumnItemEnumerator ITree.EnumerateColumnItems(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int[] rowFilter, bool markExcludedFilterItems)
 {
     return EnumerateColumnItems(column, columnPermutation, returnBlankAnchors, rowFilter, markExcludedFilterItems);
 }
コード例 #15
0
        private void SetSelectionColumn_PreserveAnchors(
            int oldColumn, ColumnPermutation oldPermutation, int newColumn, bool sharedAnchorsOnly, bool fireEvents)
        {
            var indices = SelectedIndicesArray;

            if (indices != null)
            {
                var hWnd         = Handle; // forces evaluation of Handle
                var firstVisible = TopIndex;
                var lastVisible  = firstVisible + myPartlyVisibleCountIgnoreHScroll - 1;

                // Grab information from the previous column to give us a baseline. Not
                // all of the items in indices will correspond to items in the old column.
                // We walk the old array simultaneously with the iterator to track the column
                // numbers for each item.
                var oldIndices = (int[])indices.Clone();
                var oldIter    = myTree.EnumerateColumnItems(
                    oldColumn, (oldPermutation != null) ? oldPermutation : myColumnPermutation, true, oldIndices, true);
                var nextFilterIndex = 0;
                while (oldIter.MoveNext())
                {
                    while (oldIndices[nextFilterIndex] < 0)
                    {
                        ++nextFilterIndex;
                    }
                    Debug.Assert(oldIndices[nextFilterIndex] == oldIter.RowInTree);

                    // Record the column in the array, the iterator is no longer using this filter slot
                    oldIndices[nextFilterIndex] = oldIter.ColumnInTree;
                    ++nextFilterIndex;
                }

                var iter = myTree.EnumerateColumnItems(newColumn, myColumnPermutation, true, indices, true);
                var expectColumnInTree = (myColumnPermutation != null) ? myColumnPermutation.GetNativeColumn(newColumn) : newColumn;
                nextFilterIndex = 0;
                int  oldIndex;
                bool caughtUpToIter;
                bool tossItem;
                var  lastStart      = -1;
                var  lastEnd        = -1;
                var  newEnd         = -1;
                var  count          = indices.Length;
                var  iteratorIsLive = true;
                while (iteratorIsLive && (iteratorIsLive = iter.MoveNext()) ||
                       nextFilterIndex < count)
                {
                    do
                    {
                        var index = indices[nextFilterIndex];
                        caughtUpToIter = index >= 0;
                        tossItem       = !caughtUpToIter;
                        if (caughtUpToIter)
                        {
                            oldIndex = oldIndices[nextFilterIndex];
                            if (oldIndex < 0)
                            {
                                tossItem = true;
                            }
                            else if (sharedAnchorsOnly)
                            {
                                // The old column is stored in the oldIndex value for this case, allowing easy comparison
                                tossItem = oldIndex != iter.ColumnInTree;
                            }
                            else
                            {
                                tossItem = !(iter.ColumnInTree == expectColumnInTree || iter.ColumnInTree == oldIndex);
                            }
                        }
                        else
                        {
                            tossItem = true;
                        }
                        if (tossItem)
                        {
                            newEnd = (index < 0) ? ~index : index;
                            if (lastEnd == -1)
                            {
                                lastStart = lastEnd = newEnd;
                            }
                            else if (1 == (newEnd - lastEnd))
                            {
                                ++lastEnd;
                            }
                            else
                            {
                                SetSelectionRange(lastStart, lastEnd, false);
                                lastStart = lastEnd = newEnd;
                            }
                        }
                        else if (index >= firstVisible &&
                                 index <= lastVisible)
                        {
                            InvalidateItem(index, -1, NativeMethods.RedrawWindowFlags.Invalidate);
                        }

                        // Increment and check bounds
                        ++nextFilterIndex;
                        if (!iteratorIsLive &&
                            nextFilterIndex >= count)
                        {
                            break;
                        }
                    }while (!caughtUpToIter);
                }
                // Finish off last section
                if (lastStart != -1)
                {
                    SetSelectionRange(lastStart, lastEnd, false);
                }
            }
            if (fireEvents)
            {
                OnSelectionChanged(EventArgs.Empty);
            }
        }
コード例 #16
0
 /// <summary>
 ///     Walk the items in a single tree column. EnumerateColumnItems is much more efficient
 ///     than calling GetItemInfo for each row in the column. The behavior of the returned
 ///     iterator is undefined if the tree structure changes during iteration.
 /// </summary>
 /// <param name="column">The column to iterate</param>
 /// <param name="columnPermutation">
 ///     The column permutation to apply. If this
 ///     is provided, then column is relative to the permutation.
 /// </param>
 /// <param name="returnBlankAnchors">
 ///     If an item is on a horizontal blank expansion, then
 ///     return the anchor for that item. All blanks are skipped if this is false.
 /// </param>
 /// <param name="rowFilter">
 ///     An array of items to return. The array must be sorted in ascending order
 ///     and all values must be valid indices in the tree.
 /// </param>
 /// <param name="markExcludedFilterItems">If true, items in the filter that are not returned will be marked by bitwise inverting them (~initialIndex)</param>
 protected ColumnItemEnumerator EnumerateColumnItems(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int[] rowFilter, bool markExcludedFilterItems)
 {
     return new ColumnItemEnumeratorImpl(this, column, columnPermutation, returnBlankAnchors, rowFilter, markExcludedFilterItems);
 }
コード例 #17
0
 public ColumnItemEnumeratorImpl(
     VirtualTree tree, int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow)
     :
         base(column, columnPermutation, returnBlankAnchors, startRow, endRow, (tree as ITree).VisibleItemCount)
 {
     myTree = tree;
 }
コード例 #18
0
 /// <summary>
 ///     Walk the items in a single tree column. EnumerateColumnItems is much more efficient
 ///     than calling GetItemInfo for each row in the column. The behavior of the returned
 ///     iterator is undefined if the tree structure changes during iteration.
 /// </summary>
 /// <param name="column">The column to iterate</param>
 /// <param name="columnPermutation">
 ///     The column permutation to apply. If this
 ///     is provided, then column is relative to the permutation.
 /// </param>
 /// <param name="returnBlankAnchors">
 ///     If an item is on a horizontal blank expansion, then
 ///     return the anchor for that item. All blanks are skipped if this is false.
 /// </param>
 /// <param name="startRow">The position of the first item to return</param>
 /// <param name="endRow">
 ///     The position of the last item to return. If endRow is less than startRow, the
 ///     the iterator will cycle back to the top of the tree. To search to the end of the list, pass an endRow
 ///     of -1 (VirtualTreeConstant.NullIndex)
 /// </param>
 protected ColumnItemEnumerator EnumerateColumnItems(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow)
 {
     return new ColumnItemEnumeratorImpl(this, column, columnPermutation, returnBlankAnchors, startRow, endRow);
 }
コード例 #19
0
 public ColumnItemEnumeratorImpl(
     VirtualTree tree, int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int[] rowFilter,
     bool markExcludedFilterItems)
     :
         base(column, columnPermutation, returnBlankAnchors, rowFilter, markExcludedFilterItems)
 {
     myTree = tree;
 }
コード例 #20
0
 BlankExpansionData ITree.GetBlankExpansion(int row, int column, ColumnPermutation columnPermutation)
 {
     // The blank expansion in a single-column tree is always the single item
     return new BlankExpansionData(row, 0);
 }
コード例 #21
0
 BlankExpansionData ITree.GetBlankExpansion(int row, int column, ColumnPermutation columnPermutation)
 {
     return GetBlankExpansion(row, column, columnPermutation);
 }
コード例 #22
0
 ColumnItemEnumerator ITree.EnumerateColumnItems(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int[] rowFilter, bool markExcludedFilterItems)
 {
     return new ColumnItemEnumeratorSingleColumnImpl(myParent, rowFilter, markExcludedFilterItems);
 }
コード例 #23
0
        protected BlankExpansionData GetBlankExpansion(int row, int column, ColumnPermutation columnPermutation)
        {
            if (!MultiColumnSupport)
            {
                // There is no way to get blank cells in a single-column tree
                return new BlankExpansionData(row, column);
            }
            else if (columnPermutation != null)
            {
                var permutedColumns = columnPermutation.GetColumnExpansion(column, ColumnWidthOfRow(row) - 1);
                // The consumer should not let the user do this but we need to handle it gracefully.
                // Make sure we have a row count by pulling the native row count from row 0 if the
                // row is fully blank, and from the native permutation column if it is not.
                var nativeData = GetBlankExpansion(
                    row,
                    (permutedColumns.AnchorColumn == VirtualTreeConstant.NullIndex)
                        ? 0
                        : columnPermutation.GetNativeColumn(permutedColumns.AnchorColumn), null);
                // Get the row data from the native expansion and combine with the columns from
                // the permuted expansion.
                return new BlankExpansionData(
                    nativeData.TopRow, permutedColumns.LeftColumn, nativeData.BottomRow, permutedColumns.RightColumn,
                    permutedColumns.AnchorColumn);
            }
            else
            {
                int topRow;
                int leftColumn;
                int bottomRow;
                int rightColumn;
                topRow = bottomRow = row;
                leftColumn = rightColumn = column;
                var localColumn = column;
                var lastSubItem = false;
                var pos = TrackCell(row, ref localColumn, ref lastSubItem);

                // Check the column range
                var lastNonBlankColumn = pos.ParentNode.GetColumnCount(pos.Index) - 1;
                var columnDiff = lastNonBlankColumn - localColumn;
                var localColumnAdjusted = false;
                var rowPadding = 0;
                if (columnDiff <= 0)
                {
                    // Unfortunately, there is no easy check to see if we should apply this
                    // column expansion or not. It should only be supplied if the node is a
                    // child of either a complex sub item or the root node, not in other case.
                    var tn = pos.ParentNode;
                    var nextIndex = pos.Index;
                    var onLastItem = tn.InSubItemColumn;
                    while (tn != null)
                    {
                        if (onLastItem)
                        {
                            // While we're walking the loop, see if we're on the last cell
                            if (nextIndex < (tn.FullCount - 1))
                            {
                                onLastItem = false;
                            }
                            else
                            {
                                nextIndex = tn.Index;
                            }
                        }
                        if (tn.SubItemRoot)
                        {
                            if (tn.MultiColumn)
                            {
                                // UNDONE_MC: Not sure about this one
                                tn = null;
                            }
                            else
                            {
                                // We're looking at an expandable subitem. If this is in
                                // the last column, then we need to expand to its right and treat
                                // the parent node as the real owner. We're also in a perfect position
                                // to see if we need extra row padding at the end.
                                var subitemOwner = tn.Parent;
                                if (onLastItem)
                                {
                                    rowPadding = subitemOwner.ImmedSubItemGain - tn.FullCount;
                                    if (tn.ComplexSubItem)
                                    {
                                        ++rowPadding;
                                    }
                                }
                                lastNonBlankColumn = subitemOwner.Parent.GetColumnCount(subitemOwner.Index) - 1;
                                columnDiff = lastNonBlankColumn - subitemOwner.FirstSubItem.ColumnOfRootNode(tn);
                                if (columnDiff <= 0)
                                {
                                    tn = null;
                                }
                            }
                            break;
                        }
                        tn = tn.Parent;
                    }
                    if (tn == null)
                    {
                        if (!pos.ParentNode.InSubItemColumn)
                        {
                            localColumn += columnDiff;
                            localColumnAdjusted = true;
                        }
                        leftColumn += columnDiff;
                        rightColumn = ColumnCount - 1;
                    }
                }

                // Check the row range. Note that this does not depend on the column,
                // any column in the given column range provides the same answer.
                var tnChild = pos.ParentNode.GetChildNode(pos.Index);
                if (localColumn > 0
                    && tnChild != null)
                {
                    var sn = tnChild.SubItemAtColumn(localColumn);
                    var tnSubItemRoot = (sn == null) ? null : sn.RootNode;
                    Debug.Assert(tnChild == null || !tnChild.ComplexSubItem); // A complex subitem should track to column 0
                    if (tnSubItemRoot != null
                        && tnSubItemRoot.Expanded
                        && tnSubItemRoot.FullCount > 0)
                    {
                        if (localColumnAdjusted)
                        {
                            // We are in a region with subitems, but we hit to the
                            // right of the last column, which happens to be expanded.
                            var lastRowInCell = tnSubItemRoot.FullCount;
                            if (tnSubItemRoot.ComplexSubItem)
                            {
                                --lastRowInCell;
                            }

                            // If the item is on or after
                            if (pos.SubItemOffset >= lastRowInCell)
                            {
                                topRow -= pos.SubItemOffset;
                                bottomRow = topRow + tnChild.ImmedSubItemGain;
                                topRow += lastRowInCell;
                            }
                            tnChild = null;
                        }
                        else
                        {
                            if (pos.SubItemOffset > 0)
                            {
                                topRow -= pos.SubItemOffset;
                                bottomRow = topRow + tnChild.ImmedSubItemGain;
                                // UNDONE_MC: This doesn't handle a multicolumn complex column
                                topRow += tnSubItemRoot.FullCount;
                                if (tnSubItemRoot.ComplexSubItem)
                                {
                                    --topRow;
                                }
                                tnChild = null;
                            }
                        }
                    }
                }
                if (tnChild != null)
                {
                    if (pos.SubItemOffset > 0)
                    {
                        topRow -= pos.SubItemOffset;
                        bottomRow = topRow + tnChild.ImmedSubItemGain;
                    }
                    else
                    {
                        bottomRow += tnChild.ImmedSubItemGain;
                    }
                }
                if (rowPadding != 0)
                {
                    bottomRow += rowPadding;
                }

                return new BlankExpansionData(topRow, leftColumn, bottomRow, rightColumn, leftColumn);
            }
        }
コード例 #24
0
        /// <summary>
        ///     Switch the selection column. For multiselect, the behavior is highly dependent on the
        ///     the ColumnSelectionTransferAction property and the prior state of the permutation, if
        ///     the permutation is being reordered
        /// </summary>
        /// <param name="column">The new selection column</param>
        /// <param name="oldPermutation">The old column permuation</param>
        /// <param name="fireEvents">True if this routine should fire selection events</param>
        private void SetSelectionColumn(int column, ColumnPermutation oldPermutation, bool fireEvents)
        {
            Debug.Assert(oldPermutation != null || column != mySelectionColumn);
            var iCaret = CurrentIndex;
            DismissLabelEdit(false, false);
            var oldColumn = mySelectionColumn;
            mySelectionColumn = column;

            if (GetStyleFlag(VTCStyleFlags.MultiSelect))
            {
                switch (myColumnSelectionAction)
                {
                    case ColumnSelectionTransferAction.PreserveNonBlankCells:
                        SetSelectionColumn_PreserveBasic(oldColumn, oldPermutation, column, false, fireEvents);
                        break;
                    case ColumnSelectionTransferAction.PreserveAnchoredCells:
                        SetSelectionColumn_PreserveBasic(oldColumn, oldPermutation, column, true, fireEvents);
                        break;
                    case ColumnSelectionTransferAction.PreserveSharedAnchors:
                        SetSelectionColumn_PreserveAnchors(oldColumn, oldPermutation, column, false, fireEvents);
                        break;
                    case ColumnSelectionTransferAction.PreserveSharedAnchorsOnly:
                        SetSelectionColumn_PreserveAnchors(oldColumn, oldPermutation, column, true, fireEvents);
                        break;
                    case ColumnSelectionTransferAction.ClearSelectedRows:
                        SetSelectionColumn_Clear(fireEvents);
                        break;
                }
            }
            else if (iCaret != -1 && fireEvents)
            {
                CurrentIndex = iCaret;
            }

            if (oldColumn != mySelectionColumn)
            {
                // This may cause a focus change, because the caret moves to a different column.
                if (!GetStateFlag(VTCStateFlags.RestoringSelection)
                    && VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectFocus, this)
                    && Focused)
                {
                    VirtualTreeAccEvents.Notify(
                        VirtualTreeAccEvents.eventObjectFocus, CurrentIndex,
                        CurrentColumn, this);
                }

                // ensure newly selected column is scrolled into view.
                if (HasHorizontalScrollBar)
                {
                    ScrollColumnIntoView(CurrentColumn);
                }

                // make sure we invalidate the caret item
                if (CurrentIndex != VirtualTreeConstant.NullIndex)
                {
                    InvalidateItem(CurrentIndex, -1, NativeMethods.RedrawWindowFlags.Invalidate);
                }
            }
        }
コード例 #25
0
 VirtualTreeCoordinate ITree.GetNavigationTarget(
     TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
 {
     return GetNavigationTarget(direction, sourceRow, sourceColumn, columnPermutation);
 }
コード例 #26
0
        private void SetSelectionColumn_PreserveAnchors(
            int oldColumn, ColumnPermutation oldPermutation, int newColumn, bool sharedAnchorsOnly, bool fireEvents)
        {
            var indices = SelectedIndicesArray;
            if (indices != null)
            {
                var hWnd = Handle; // forces evaluation of Handle
                var firstVisible = TopIndex;
                var lastVisible = firstVisible + myPartlyVisibleCountIgnoreHScroll - 1;

                // Grab information from the previous column to give us a baseline. Not
                // all of the items in indices will correspond to items in the old column.
                // We walk the old array simultaneously with the iterator to track the column
                // numbers for each item.
                var oldIndices = (int[])indices.Clone();
                var oldIter = myTree.EnumerateColumnItems(
                    oldColumn, (oldPermutation != null) ? oldPermutation : myColumnPermutation, true, oldIndices, true);
                var nextFilterIndex = 0;
                while (oldIter.MoveNext())
                {
                    while (oldIndices[nextFilterIndex] < 0)
                    {
                        ++nextFilterIndex;
                    }
                    Debug.Assert(oldIndices[nextFilterIndex] == oldIter.RowInTree);

                    // Record the column in the array, the iterator is no longer using this filter slot
                    oldIndices[nextFilterIndex] = oldIter.ColumnInTree;
                    ++nextFilterIndex;
                }

                var iter = myTree.EnumerateColumnItems(newColumn, myColumnPermutation, true, indices, true);
                var expectColumnInTree = (myColumnPermutation != null) ? myColumnPermutation.GetNativeColumn(newColumn) : newColumn;
                nextFilterIndex = 0;
                int oldIndex;
                bool caughtUpToIter;
                bool tossItem;
                var lastStart = -1;
                var lastEnd = -1;
                var newEnd = -1;
                var count = indices.Length;
                var iteratorIsLive = true;
                while (iteratorIsLive && (iteratorIsLive = iter.MoveNext())
                       || nextFilterIndex < count)
                {
                    do
                    {
                        var index = indices[nextFilterIndex];
                        caughtUpToIter = index >= 0;
                        tossItem = !caughtUpToIter;
                        if (caughtUpToIter)
                        {
                            oldIndex = oldIndices[nextFilterIndex];
                            if (oldIndex < 0)
                            {
                                tossItem = true;
                            }
                            else if (sharedAnchorsOnly)
                            {
                                // The old column is stored in the oldIndex value for this case, allowing easy comparison
                                tossItem = oldIndex != iter.ColumnInTree;
                            }
                            else
                            {
                                tossItem = !(iter.ColumnInTree == expectColumnInTree || iter.ColumnInTree == oldIndex);
                            }
                        }
                        else
                        {
                            tossItem = true;
                        }
                        if (tossItem)
                        {
                            newEnd = (index < 0) ? ~index : index;
                            if (lastEnd == -1)
                            {
                                lastStart = lastEnd = newEnd;
                            }
                            else if (1 == (newEnd - lastEnd))
                            {
                                ++lastEnd;
                            }
                            else
                            {
                                SetSelectionRange(lastStart, lastEnd, false);
                                lastStart = lastEnd = newEnd;
                            }
                        }
                        else if (index >= firstVisible
                                 && index <= lastVisible)
                        {
                            InvalidateItem(index, -1, NativeMethods.RedrawWindowFlags.Invalidate);
                        }

                        // Increment and check bounds
                        ++nextFilterIndex;
                        if (!iteratorIsLive
                            && nextFilterIndex >= count)
                        {
                            break;
                        }
                    }
                    while (!caughtUpToIter);
                }
                // Finish off last section
                if (lastStart != -1)
                {
                    SetSelectionRange(lastStart, lastEnd, false);
                }
            }
            if (fireEvents)
            {
                OnSelectionChanged(EventArgs.Empty);
            }
        }
コード例 #27
0
 /// <summary>
 ///     Create a new enumerator
 /// </summary>
 /// <param name="column">The column to enumerate</param>
 /// <param name="columnPermutation">
 ///     The column permutation to apply. If this
 ///     is provided, then column is relative to the permutation.
 /// </param>
 /// <param name="returnBlankAnchors">
 ///     If an item is on a horizontal blank expansion, then
 ///     return the anchor for that item. All blanks are skipped if this is false.
 /// </param>
 /// <param name="startRow">The first row to return, 0 to ITree.VisibleItemCount - 1</param>
 /// <param name="endRow">The first row to return, 0 to ITree.VisibleItemCount - 1, can be less than startRow</param>
 /// <param name="itemCount">The number of rows in the desired enumeration range</param>
 protected ColumnItemEnumerator(
     int column, ColumnPermutation columnPermutation, bool returnBlankAnchors, int startRow, int endRow, int itemCount)
 {
     Initialize(column, columnPermutation, returnBlankAnchors, startRow, endRow, itemCount);
 }