/// <summary> /// Repositions the specified item into the specified base. /// </summary> /// <param name="itemToMove">The item to move.</param> /// <param name="baseItem">The base item.</param> private void RepositionItemIntoBase(BaseCodeItem itemToMove, ICodeItemParent baseItem) { if (itemToMove == baseItem) return; bool padWithNewLine = _insertBlankLinePaddingLogic.ShouldInstanceBeFollowedByBlankLine(itemToMove); int cursorOffset; var text = GetTextAndRemoveItem(itemToMove, out cursorOffset); baseItem.RefreshCachedPositionAndName(); var baseInsertPoint = baseItem.InsertPoint; var pastePoint = baseInsertPoint.CreateEditPoint(); pastePoint.Insert(text); pastePoint.Insert(Environment.NewLine); if (padWithNewLine) { pastePoint.Insert(Environment.NewLine); } pastePoint.EndOfLine(); baseInsertPoint.SmartFormat(pastePoint); if (cursorOffset >= 0) { baseInsertPoint.Parent.Selection.MoveToAbsoluteOffset(baseInsertPoint.AbsoluteCharOffset + cursorOffset); } itemToMove.RefreshCachedPositionAndName(); baseItem.RefreshCachedPositionAndName(); }
/// <summary> /// Gets the text and removes the specified item. /// </summary> /// <param name="itemToRemove">The item to remove.</param> /// <param name="cursorOffset"> /// The cursor's offset within the item being removed, otherwise -1. /// </param> private static string GetTextAndRemoveItem(BaseCodeItem itemToRemove, out int cursorOffset) { // Refresh the code item and capture its end points. itemToRemove.RefreshCachedPositionAndName(); var removeStartPoint = itemToRemove.StartPoint; var removeEndPoint = itemToRemove.EndPoint; // Determine the cursor's offset if within the item being removed. var cursorAbsoluteOffset = removeStartPoint.Parent.Selection.ActivePoint.AbsoluteCharOffset; if (cursorAbsoluteOffset >= removeStartPoint.AbsoluteCharOffset && cursorAbsoluteOffset <= removeEndPoint.AbsoluteCharOffset) { cursorOffset = cursorAbsoluteOffset - removeStartPoint.AbsoluteCharOffset; } else { cursorOffset = -1; } // Capture the text. var text = removeStartPoint.GetText(removeEndPoint); // Remove the text and cleanup whitespace. removeStartPoint.Delete(removeEndPoint); removeStartPoint.DeleteWhitespace(vsWhitespaceOptions.vsWhitespaceOptionsVertical); return text; }
/// <summary> /// Repositions the specified item below the specified base. /// </summary> /// <param name="itemToMove">The item to move.</param> /// <param name="baseItem">The base item.</param> private void RepositionItemBelowBase(BaseCodeItem itemToMove, BaseCodeItem baseItem) { if (itemToMove == baseItem) return; bool separateWithNewLine = ShouldBeSeparatedByNewLine(baseItem, itemToMove); int cursorOffset; var text = GetTextAndRemoveItem(itemToMove, out cursorOffset); baseItem.RefreshCachedPositionAndName(); var baseEndPoint = baseItem.EndPoint; var pastePoint = baseEndPoint.CreateEditPoint(); pastePoint.Insert(Environment.NewLine); if (separateWithNewLine) { pastePoint.Insert(Environment.NewLine); } var formatPoint = pastePoint.CreateEditPoint(); var insertPoint = pastePoint.CreateEditPoint(); pastePoint.Insert(text); formatPoint.EndOfLine(); baseEndPoint.SmartFormat(formatPoint); if (cursorOffset >= 0) { insertPoint.Parent.Selection.MoveToAbsoluteOffset(insertPoint.AbsoluteCharOffset + cursorOffset); } itemToMove.RefreshCachedPositionAndName(); baseItem.RefreshCachedPositionAndName(); }
/// <summary> /// Attempts to select the text of the specified code item. /// </summary> /// <param name="document">The document.</param> /// <param name="codeItem">The code item.</param> internal static void SelectCodeItem(Document document, BaseCodeItem codeItem) { var textDocument = document.GetTextDocument(); if (textDocument == null) return; try { codeItem.RefreshCachedPositionAndName(); textDocument.Selection.MoveToPoint(codeItem.StartPoint, false); textDocument.Selection.MoveToPoint(codeItem.EndPoint, true); textDocument.Selection.SwapAnchor(); } catch (Exception) { // Select operation may fail if element is no longer available. } finally { // Always set focus within the code editor window. document.Activate(); } }
/// <summary> /// Moves the specified item into the specified base. /// </summary> /// <param name="itemToMove">The item to move.</param> /// <param name="baseItem">The base item.</param> internal void MoveItemIntoBase(BaseCodeItem itemToMove, ICodeItemParent baseItem) { _undoTransactionHelper.Run(() => RepositionItemIntoBase(itemToMove, baseItem)); }
/// <summary> /// Attempts to get the type component string based on the specified code item. /// </summary> /// <param name="codeItem">The code item.</param> /// <returns>The type component of the partial image name, otherwise null.</returns> private static string GetTypeComponentString(BaseCodeItem codeItem) { switch (codeItem.Kind) { case KindCodeItem.Class: return "Class"; case KindCodeItem.Constructor: return "MethodConstructor"; case KindCodeItem.Delegate: return "Delegate"; case KindCodeItem.Destructor: return "MethodDestructor"; case KindCodeItem.Enum: return "Enum"; case KindCodeItem.Event: return "Event"; case KindCodeItem.Field: var codeItemField = (CodeItemField)codeItem; if (codeItemField.IsEnumItem) return "EnumItem"; if (codeItemField.IsConstant) return "Constant"; return "Field"; case KindCodeItem.Interface: return "Interface"; case KindCodeItem.Method: return "Method"; case KindCodeItem.Indexer: case KindCodeItem.Property: return "Property"; case KindCodeItem.Region: return "Region"; case KindCodeItem.Struct: return "Structure"; default: return null; } }
/// <summary> /// Attempts to move the cursor to the specified code item. /// </summary> /// <param name="document">The document.</param> /// <param name="codeItem">The code item.</param> /// <param name="centerOnWhole">True if the whole element should be used for centering.</param> internal static void MoveToCodeItem(Document document, BaseCodeItem codeItem, bool centerOnWhole) { var textDocument = document.GetTextDocument(); if (textDocument == null) return; try { object viewRangeEnd = null; TextPoint navigatePoint = null; codeItem.RefreshCachedPositionAndName(); textDocument.Selection.MoveToPoint(codeItem.StartPoint, false); if (centerOnWhole) { viewRangeEnd = codeItem.EndPoint; } var codeItemElement = codeItem as BaseCodeItemElement; if (codeItemElement != null) { navigatePoint = codeItemElement.CodeElement.GetStartPoint(vsCMPart.vsCMPartNavigate); } textDocument.Selection.AnchorPoint.TryToShow(vsPaneShowHow.vsPaneShowCentered, viewRangeEnd); if (navigatePoint != null) { textDocument.Selection.MoveToPoint(navigatePoint, false); } else { textDocument.Selection.FindText(codeItem.Name, (int)vsFindOptions.vsFindOptionsMatchInHiddenText); textDocument.Selection.MoveToPoint(textDocument.Selection.AnchorPoint, false); } } catch (Exception) { // Move operation may fail if element is no longer available. } finally { // Always set focus within the code editor window. document.Activate(); } }
/// <summary> /// Determines if the specified item is an ancestor of the specified base. /// </summary> /// <param name="item">The item.</param> /// <param name="baseItem">The base item.</param> /// <returns>True if item is an ancestor of the specified base, otherwise false.</returns> private static bool IsItemAncestorOfBase(BaseCodeItem item, BaseCodeItem baseItem) { var itemAsParent = item as ICodeItemParent; if (itemAsParent == null) { return false; } return itemAsParent.Children.Contains(baseItem) || itemAsParent.Children.Any(x => IsItemAncestorOfBase(x, baseItem)); }
/// <summary> /// Jumps to the specified code item. /// </summary> /// <param name="codeItem">The code item.</param> private void JumpToCodeItem(BaseCodeItem codeItem) { var viewModel = ViewModel; if (codeItem == null || viewModel == null || codeItem.StartOffset <= 0) return; Dispatcher.BeginInvoke( new Action(() => TextDocumentHelper.MoveToCodeItem(viewModel.Document, codeItem, Settings.Default.Digging_CenterOnWhole))); }
/// <summary> /// Composes a region based on the specified code item. /// </summary> /// <param name="codeItem">The code item.</param> /// <returns>A region.</returns> private CodeItemRegion ComposeRegionForCodeItem(BaseCodeItem codeItem) { if (codeItem == null) return null; var setting = MemberTypeSettingHelper.LookupByKind(codeItem.Kind); if (setting == null) return null; var regionName = string.Empty; if (Settings.Default.Reorganizing_RegionsIncludeAccessLevel) { var element = codeItem as BaseCodeItemElement; if (element != null) { var accessModifier = CodeElementHelper.GetAccessModifierKeyword(element.Access); if (accessModifier != null) { regionName = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(accessModifier) + " "; } } } regionName += setting.EffectiveName; return new CodeItemRegion { Name = regionName }; }
/// <summary> /// Determines the drop position for the specified drag event and the drop target. /// </summary> /// <param name="e"> /// The <see cref="System.Windows.DragEventArgs" /> instance containing the event data. /// </param> /// <param name="targetItem">The target item.</param> /// <param name="targetElement">The target element.</param> /// <returns>The drop position.</returns> private static DropPosition GetDropPosition(DragEventArgs e, BaseCodeItem targetItem, TreeViewItem targetElement) { var header = targetElement.Template.FindName("PART_HeaderBorder", targetElement) as FrameworkElement; var targetHeight = header?.ActualHeight ?? targetElement.ActualHeight; var dropPoint = e.GetPosition(targetElement); bool canDropOn = targetItem is ICodeItemParent; if (canDropOn) { bool isTopThird = dropPoint.Y <= targetHeight / 3; bool isBottomThird = dropPoint.Y > targetHeight * 2 / 3; return isTopThird ? DropPosition.Above : (isBottomThird ? DropPosition.Below : DropPosition.On); } bool isTopHalf = dropPoint.Y <= targetHeight / 2; return isTopHalf ? DropPosition.Above : DropPosition.Below; }
/// <summary> /// Determines if the specified code item belongs in the specified region. /// </summary> /// <param name="codeItem">The code item.</param> /// <param name="region">The region.</param> /// <returns>True if the specified code item belongs in the specified region, otherwise false.</returns> private bool CodeItemBelongsInRegion(BaseCodeItem codeItem, CodeItemRegion region) { return codeItem != null && _regionComparerByName.Equals(region, ComposeRegionForCodeItem(codeItem)); }
/// <summary> /// Shows a context menu for the specified code item. /// </summary> /// <param name="codeItem">The code item.</param> /// <param name="point">The point where the context menu should be shown.</param> private void ShowContextMenu(BaseCodeItem codeItem, Point point) { var viewModel = ViewModel; if (codeItem == null || viewModel == null) return; var menuCommandService = viewModel.Package.MenuCommandService; if (menuCommandService != null) { var contextMenuCommandID = new CommandID(GuidList.GuidCodeMaidContextSpadeBaseGroup, PkgCmdIDList.MenuIDCodeMaidContextSpade); viewModel.SelectedItem = codeItem; menuCommandService.ShowContextMenu(contextMenuCommandID, (int)point.X, (int)point.Y); viewModel.SelectedItem = null; } }
/// <summary> /// Attempts to build an image URI from the specified code item. /// </summary> /// <param name="codeItem">The code item.</param> /// <returns>The built URI, otherwise null.</returns> private string BuildImageURIString(BaseCodeItem codeItem) { string typeComponent = GetTypeComponentString(codeItem); string accessComponent = GetAccessString(codeItem as BaseCodeItemElement); if (typeComponent == null) return null; string uriString = string.Format("/SteveCadwallader.CodeMaid;component/UI/ToolWindows/Spade/Images/{0}/{1}{2}.png", ImagePath, typeComponent, accessComponent); return uriString; }
/// <summary> /// Determines if the two specified items should be separated by a newline. /// </summary> /// <param name="firstItem">The first item.</param> /// <param name="secondItem">The second item.</param> /// <returns>True if the items should be separated by a newline, otherwise false.</returns> private bool ShouldBeSeparatedByNewLine(BaseCodeItem firstItem, BaseCodeItem secondItem) { return _insertBlankLinePaddingLogic.ShouldInstanceBeFollowedByBlankLine(firstItem) || _insertBlankLinePaddingLogic.ShouldInstanceBePrecededByBlankLine(secondItem); }
/// <summary> /// Selects the specified code item. /// </summary> /// <param name="codeItem">The code item.</param> private void SelectCodeItem(BaseCodeItem codeItem) { var viewModel = ViewModel; if (codeItem == null || viewModel == null || codeItem.StartOffset <= 0) return; Dispatcher.BeginInvoke( new Action(() => TextDocumentHelper.SelectCodeItem(viewModel.Document, codeItem))); }
/// <summary> /// Moves the specified item below the specified base. /// </summary> /// <param name="itemToMove">The item to move.</param> /// <param name="baseItem">The base item.</param> internal void MoveItemBelowBase(BaseCodeItem itemToMove, BaseCodeItem baseItem) { _undoTransactionHelper.Run(() => RepositionItemBelowBase(itemToMove, baseItem)); }
/// <summary> /// Determines if the specified item is a candidate for deletion. /// </summary> /// <param name="codeItem">The code item.</param> /// <returns>True if the code item can be deleted, otherwise false.</returns> private static bool IsDeletable(BaseCodeItem codeItem) { return !(codeItem is CodeItemRegion) || !((CodeItemRegion)codeItem).IsPseudoGroup; }