Example #1
0
		/// <summary>
		/// Reimplementation of <see cref="ITree.GetNavigationTarget"/> to fix issues with the Down navigation direction
		/// </summary>
		protected new VirtualTreeCoordinate GetNavigationTarget(TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
		{
			// UNDONE: MSBUG GetNavigationTarget calls the internal method to get its blank expansion, not
			// the interface, so we have no way to override it. Duplicate the GetNavigationTarget fix here for
			// the 'Down' navigation target.
			BlankExpansionData blankExpansion;
			switch (direction)
			{
				case TreeNavigation.Down:
					blankExpansion = GetBlankExpansion(sourceRow, sourceColumn, columnPermutation);
					if (blankExpansion.Anchor.IsValid)
					{
						int lastRow = ((ITree)this).VisibleItemCount - 1;
						while (blankExpansion.BottomRow < lastRow)
						{
							// Just return the next non-blank column
							int testRow = blankExpansion.BottomRow + 1;
							blankExpansion = GetBlankExpansion(testRow, sourceColumn, columnPermutation);
							if (!blankExpansion.Anchor.IsValid)
							{
								break;
							}
							int topRow = blankExpansion.TopRow;
							if (sourceColumn == blankExpansion.AnchorColumn && topRow >= testRow)
							{
								return new VirtualTreeCoordinate(topRow, sourceColumn);
							}
						}
					}
					return VirtualTreeCoordinate.Invalid;
				case TreeNavigation.Right:
					// If no column permutation is specified and we're on the first row in a complex
					// subitem expansion, then the provided implementation does not go right.
					// MSBUG: VirtualTree.GetNavigationTarget is looking at the column count of the
					// ParentNode of a complex subitem. The column count in this case is always 1.
					if (columnPermutation == null)
					{
						VirtualTreeCoordinate retVal = base.GetNavigationTarget(TreeNavigation.Right, sourceRow, sourceColumn, null);
						int lastAllowedSourceColumn;
						if (!retVal.IsValid &&
							sourceColumn < (lastAllowedSourceColumn = (ColumnCount - 1)) &&
							(blankExpansion = GetBlankExpansion(sourceRow, sourceColumn, null)).Anchor.IsValid &&
							blankExpansion.RightColumn < lastAllowedSourceColumn)
						{
							retVal = GetBlankExpansion(sourceRow, blankExpansion.RightColumn + 1, null).Anchor;
						}
						return retVal;
					}
					break;
				case TreeNavigation.LeftColumn:
					if (sourceColumn == 0)
					{
						// UNDONE: MSBUG Navigating LeftColumn from column 0 is crashing
						return VirtualTreeCoordinate.Invalid;
					}
					break;
			}
			return base.GetNavigationTarget(direction, sourceRow, sourceColumn, columnPermutation);
		}
        /// <summary>
        /// Reimplementation of <see cref="ITree.GetNavigationTarget"/> to fix issues with the Down navigation direction
        /// </summary>
        protected new VirtualTreeCoordinate GetNavigationTarget(TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
        {
            // UNDONE: MSBUG GetNavigationTarget calls the internal method to get its blank expansion, not
            // the interface, so we have no way to override it. Duplicate the GetNavigationTarget fix here for
            // the 'Down' navigation target.
            BlankExpansionData blankExpansion;

            switch (direction)
            {
            case TreeNavigation.Down:
                blankExpansion = GetBlankExpansion(sourceRow, sourceColumn, columnPermutation);
                if (blankExpansion.Anchor.IsValid)
                {
                    int lastRow = ((ITree)this).VisibleItemCount - 1;
                    while (blankExpansion.BottomRow < lastRow)
                    {
                        // Just return the next non-blank column
                        int testRow = blankExpansion.BottomRow + 1;
                        blankExpansion = GetBlankExpansion(testRow, sourceColumn, columnPermutation);
                        if (!blankExpansion.Anchor.IsValid)
                        {
                            break;
                        }
                        int topRow = blankExpansion.TopRow;
                        if (sourceColumn == blankExpansion.AnchorColumn && topRow >= testRow)
                        {
                            return(new VirtualTreeCoordinate(topRow, sourceColumn));
                        }
                    }
                }
                return(VirtualTreeCoordinate.Invalid);

            case TreeNavigation.Right:
                // If no column permutation is specified and we're on the first row in a complex
                // subitem expansion, then the provided implementation does not go right.
                // MSBUG: VirtualTree.GetNavigationTarget is looking at the column count of the
                // ParentNode of a complex subitem. The column count in this case is always 1.
                if (columnPermutation == null)
                {
                    VirtualTreeCoordinate retVal = base.GetNavigationTarget(TreeNavigation.Right, sourceRow, sourceColumn, null);
                    int lastAllowedSourceColumn;
                    if (!retVal.IsValid &&
                        sourceColumn < (lastAllowedSourceColumn = (ColumnCount - 1)) &&
                        (blankExpansion = GetBlankExpansion(sourceRow, sourceColumn, null)).Anchor.IsValid &&
                        blankExpansion.RightColumn < lastAllowedSourceColumn)
                    {
                        retVal = GetBlankExpansion(sourceRow, blankExpansion.RightColumn + 1, null).Anchor;
                    }
                    return(retVal);
                }
                break;

            case TreeNavigation.LeftColumn:
                if (sourceColumn == 0)
                {
                    // UNDONE: MSBUG Navigating LeftColumn from column 0 is crashing
                    return(VirtualTreeCoordinate.Invalid);
                }
                break;
            }
            return(base.GetNavigationTarget(direction, sourceRow, sourceColumn, columnPermutation));
        }
 VirtualTreeCoordinate ITree.GetNavigationTarget(TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
 {
     return(GetNavigationTarget(direction, sourceRow, sourceColumn, columnPermutation));
 }
Example #4
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;
            }
Example #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;
        }
Example #6
0
 VirtualTreeCoordinate ITree.GetNavigationTarget(
     TreeNavigation direction, int sourceRow, int sourceColumn, ColumnPermutation columnPermutation)
 {
     return GetNavigationTarget(direction, sourceRow, sourceColumn, columnPermutation);
 }