From a00d800e14264a32adb102c0343724ec35222582 Mon Sep 17 00:00:00 2001 From: JohnnyBravo75 Date: Thu, 24 Jul 2014 17:45:15 +0200 Subject: [PATCH 1/6] TestCommit --- .../CSharpBinding/Project/Src/CSharpTextEditorExtension.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs index f308877041..0851efb6a9 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs @@ -59,6 +59,7 @@ namespace CSharpBinding editor.ContextActionProviders.AddRange(contextActionProviders); } + // Create instance of options adapter and register it as service var formattingPolicy = CSharpFormattingPolicies.Instance.GetProjectOptions(SD.ProjectService.FindProjectContainingFile(editor.FileName)); var textEditor = editor.GetService(); From ccf71cc67e35673cdfd741cdc6cf0cc05e138ec5 Mon Sep 17 00:00:00 2001 From: JohnnyBravo75 Date: Thu, 24 Jul 2014 22:03:22 +0200 Subject: [PATCH 2/6] C# Outline Pad A c# outline pad, based on the syntax tree --- .../CSharpBinding/Project/CSharpBinding.addin | 11 + .../Project/CSharpBinding.csproj | 9 + .../Project/Src/CSharpTextEditorExtension.cs | 29 + .../Project/Src/OutlinePad/AstNodeHelper.cs | 524 ++++++++++++++++++ .../Src/OutlinePad/CSharpOutlineCommands.cs | 128 +++++ .../OutlinePad/CSharpOutlineContentHost.xaml | 13 + .../CSharpOutlineContentHost.xaml.cs | 352 ++++++++++++ .../Src/OutlinePad/CSharpOutlineNode.cs | 169 ++++++ .../Src/OutlinePad/ExtensionMethods.cs | 51 ++ .../Highlighting/HighlightingColorizer.cs | 3 + .../ICSharpCode.TreeView/SharpTreeNode.cs | 8 + 11 files changed, 1297 insertions(+) create mode 100644 src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs create mode 100644 src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs create mode 100644 src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml create mode 100644 src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs create mode 100644 src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs create mode 100644 src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin index b70e3a2dcf..221dddc0f8 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin @@ -33,6 +33,17 @@ + + + + + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index 970be27a88..00a094c92b 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -115,6 +115,13 @@ CSharpProjectFormattingOptions.xaml Code + + + + CSharpOutlineContentHost.xaml + + + @@ -264,6 +271,7 @@ + @@ -274,6 +282,7 @@ + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs index 0851efb6a9..93a886b242 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpTextEditorExtension.cs @@ -24,10 +24,14 @@ using System.Reflection; using ICSharpCode.AvalonEdit; using CSharpBinding.FormattingStrategy; using CSharpBinding.Refactoring; +using CSharpBinding.OutlinePad; using ICSharpCode.Core; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Refactoring; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.AvalonEdit.Rendering; + namespace CSharpBinding { public class CSharpTextEditorExtension : ITextEditorExtension @@ -46,6 +50,8 @@ namespace CSharpBinding TextEditorOptions originalEditorOptions; + CSharpOutlineContentHost contentHost; + public void Attach(ITextEditor editor) { this.editor = editor; @@ -75,6 +81,17 @@ namespace CSharpBinding // Set TextEditor's options to same object originalEditorOptions = textEditor.Options; textEditor.Options = options.TextEditorOptions; + + // add the outline pad + var textView = textEditor.TextArea.TextView; + if (textView != null) { + if (SD.Workbench != null) { + // add the CSharpOutlineContentHost, which manages the tree view + contentHost = new CSharpOutlineContentHost(editor); + textView.Services.AddService(typeof(IOutlineContentHost), contentHost); + } + textView.Services.AddService(typeof(CSharpTextEditorExtension), this); + } } } @@ -83,13 +100,25 @@ namespace CSharpBinding var textEditor = editor.GetService(); if (textEditor != null) { var textView = textEditor.TextArea.TextView; + // Unregister our ITextEditorOptions instance from editor var optionsService = textView.GetService(); if ((optionsService != null) && (optionsService == options)) textView.Services.RemoveService(typeof(ITextEditorOptions)); + // Reset TextEditor options, too? if ((textEditor.Options != null) && (textEditor.Options == options.TextEditorOptions)) textEditor.Options = originalEditorOptions; + + // remove the outline pad + if (textView != null) { + if (contentHost != null) { + textView.Services.RemoveService(typeof(IOutlineContentHost)); + contentHost.Dispose(); + contentHost = null; + } + textView.Services.RemoveService(typeof(CSharpTextEditorExtension)); + } } codeManipulation.Dispose(); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs new file mode 100644 index 0000000000..c193578637 --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs @@ -0,0 +1,524 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +namespace CSharpBinding.OutlinePad +{ + using System; + using System.IO; + using System.Linq; + using System.Windows; + using System.Windows.Media; + using System.Text; + + using ICSharpCode.NRefactory.CSharp; + using ICSharpCode.AvalonEdit.Highlighting; + + internal static class AstNodeHelper { + + static bool showExtendedInfos = true; + static bool colorizeNode = false; + static HighlightingColor nameSpaceHighLighting, regionHighLighting, classHighLighting, methodHighLighting, interfaceHighLighting; + + static AstNodeHelper() { + var highlightingDefinition = HighlightingManager.Instance.GetDefinition("C#"); + + nameSpaceHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "NamespaceKeywords"); + regionHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "Preprocessor"); + classHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "ReferenceTypeKeywords"); + interfaceHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "ReferenceTypeKeywords"); + methodHighLighting = highlightingDefinition.NamedHighlightingColors.First( x => x.Name == "MethodCall"); + } + + private static Modifiers GetAccessModifier(AstNode node) { + var accessModifier = node.Children.FirstOrDefault(x => x is CSharpModifierToken && + ((x as CSharpModifierToken).Modifier == Modifiers.Public || + (x as CSharpModifierToken).Modifier == Modifiers.Protected || + (x as CSharpModifierToken).Modifier == Modifiers.Private || + (x as CSharpModifierToken).Modifier == Modifiers.Internal )) as CSharpModifierToken; + + // special case: All members in an interface are public, although they have no access modifier + if (accessModifier == null && IsInterface(node.Parent)) { + return Modifiers.Public; + } + return accessModifier == null ? Modifiers.None : accessModifier.Modifier; + } + + private static string GetParameterDeclsAsString(AstNodeCollection parameterDecls) { + var parameterString = new StringBuilder(); + int current = 0; + foreach (var paramDecl in parameterDecls) { + if (paramDecl.ParameterModifier != ParameterModifier.None) { + parameterString.Append(paramDecl.ParameterModifier.ToString().ToLower()); + parameterString.Append(" "); + } + parameterString.Append(paramDecl.Type.ToString()); + parameterString.Append(" "); + parameterString.Append(paramDecl.Name); + + if (current < (parameterDecls.Count - 1)) { + parameterString.Append(", "); + } + current++; + } + + return parameterString.ToString(); + } + + private static string GetTypeParameterDeclsAsString(AstNodeCollection parameterDecls) { + var parameterString = new StringBuilder(); + int current = 0; + foreach (var paramDecl in parameterDecls) { + parameterString.Append(paramDecl.NameToken.ToString()); + + if (current < (parameterDecls.Count - 1)) { + parameterString.Append(", "); + } + current++; + } + + return parameterString.ToString(); + } + + public static bool IsAllowedNode(AstNode node) { + return (IsRegionStart(node) + || IsRegionEnd(node) + || IsClass(node) + || IsInterface(node) + || IsMethod(node) + || IsField(node) + || IsProperty(node) + || IsNameSpace(node) + || IsConstructor(node) + || IsEvent(node) + || IsDelegate(node) + || IsIndexer(node) + || IsEnum(node) + || IsEnumMember(node) + || IsStruct(node) + || IsOperator(node) + ); + } + + public static bool IsRegionStart(AstNode node) { + return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Region); + } + + internal static void SetRegionStartInfos(CSharpOutlineNode node, AstNode dataNode) { + var preProcessorNode = (PreProcessorDirective)dataNode; + node.ElementName = "****** " + preProcessorNode.Argument + " *****"; + node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); +// node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal; + } + + public static bool IsRegionEnd(AstNode node) { + return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Endregion); + } + + internal static void SetRegionEndInfos(CSharpOutlineNode node, AstNode dataNode) { + var preProcessorNode = (PreProcessorDirective)dataNode; + node.ElementName = "*********************"; + node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); +// node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal; + } + + public static bool IsDelegate(AstNode node) { + return (node is DelegateDeclaration); + } + + internal static void SetDelegateNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var typeNode = (DelegateDeclaration)dataNode; + node.ElementName = typeNode.Name; + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; +// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Delegate"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedDelegate"; + break; + case Modifiers.Private: + node.IconName = "Icons.16x16.PrivateDelegate"; + break; + default: + node.IconName = "Icons.16x16.InternalDelegate"; + break; + } + } + + public static bool IsStruct(AstNode node) { + return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Struct); + } + + internal static void SetStructNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var typeNode = (TypeDeclaration)dataNode; + node.ElementName = typeNode.Name; + if (colorizeNode) + node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); +// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal; + node.IsExpanded = true; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Struct"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedStruct"; + break; + case Modifiers.Private: + node.IconName = "Icons.16x16.PrivateStruct"; + break; + default: + node.IconName = "Icons.16x16.InternalStruct"; + break; + } + } + + public static bool IsEnumMember(AstNode node) { + return (node is EnumMemberDeclaration); + } + + internal static void SetEnumMemberNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var enumMemberNode = (EnumMemberDeclaration)dataNode; + node.ElementName = enumMemberNode.Name; + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + node.IconName = "Icons.16x16.Enum"; + } + + public static bool IsEnum(AstNode node) { + return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Enum); + } + + internal static void SetEnumNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var typeNode = (TypeDeclaration)dataNode; + node.ElementName = typeNode.Name; + if (colorizeNode) + node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); + node.IsExpanded = true; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Enum"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedEnum"; + break; + case Modifiers.Private: + node.IconName = "Icons.16x16.PrivateEnum"; + break; + default: + node.IconName = "Icons.16x16.InternalEnum"; + break; + } + } + + public static bool IsClass(AstNode node) { + return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Class); + } + + internal static void SetClassNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var typeNode = (TypeDeclaration)dataNode; + node.ElementName = typeNode.Name + + typeNode.LChevronToken + + GetTypeParameterDeclsAsString(typeNode.TypeParameters) + + typeNode.RChevronToken; + if (colorizeNode) + node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); +// node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal; + node.IsExpanded = true; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Class"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedClass"; + break; + case Modifiers.Private: + node.IconName = "Icons.16x16.PrivateClass"; + break; + default: + node.IconName = "Icons.16x16.InternalClass"; + break; + } + } + + public static bool IsEvent(AstNode node) { + return (node is EventDeclaration); + } + + internal static void SetEventNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var eventNode = (EventDeclaration)dataNode; + var varInitializer = eventNode.Children.FirstOrDefault(x => x is VariableInitializer) as VariableInitializer; + node.ElementName = (varInitializer != null) + ? varInitializer.Name + : ""; + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Event"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedEvent"; + break; + default: + node.IconName = "Icons.16x16.PrivateEvent"; + break; + } + } + + public static bool IsInterface(AstNode node) { + return (node is TypeDeclaration && (node as TypeDeclaration).ClassType == ClassType.Interface); + } + + internal static void SetInterfaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var typeNode = (TypeDeclaration)dataNode; + node.ElementName = typeNode.Name; + if (colorizeNode) + node.ForegroundBrush = (interfaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); + node.IsExpanded = true; + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Interface"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedInterface"; + break; + case Modifiers.Private: + node.IconName = "Icons.16x16.PrivateInterface"; + break; + default: + node.IconName = "Icons.16x16.InternalInterface"; + break; + } + } + + public static bool IsOperator(AstNode node) { + return (node is OperatorDeclaration); + } + + internal static void SetOperatorNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var operatorNode = (OperatorDeclaration)dataNode; + node.ElementName = operatorNode.OperatorToken + + " " + operatorNode.OperatorTypeToken; + + if (showExtendedInfos) { + node.ElementName += " " + operatorNode.LParToken + + GetParameterDeclsAsString(operatorNode.Parameters) + + operatorNode.RParToken; + } + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Method"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedMethod"; + break; + default: + node.IconName = "Icons.16x16.PrivateMethod"; + break; + } + } + + public static bool IsMethod(AstNode node) { + return (node is MethodDeclaration); + } + + internal static void SetMethodNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var methodNode = (MethodDeclaration)dataNode; + node.ElementName = methodNode.Name; + + node.ElementName += " " + methodNode.LParToken + + (showExtendedInfos ? GetParameterDeclsAsString(methodNode.Parameters) : "") + + methodNode.RParToken; + + if (colorizeNode) + node.ForegroundBrush = (methodHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); +// node.Weight = methodHighLighting.FontWeight != null ? methodHighLighting.FontWeight.Value : FontWeights.Normal; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Method"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedMethod"; + break; + default: + node.IconName = "Icons.16x16.PrivateMethod"; + break; + } + } + + public static bool IsField(AstNode node) { + return (node is FieldDeclaration); + } + + internal static void SetFieldNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + + var fieldNode = (FieldDeclaration)dataNode; + var fieldName = new StringBuilder(); + int current = 0; + foreach (var varInitializer in fieldNode.Variables) { + fieldName.Append(varInitializer.Name); + + if (current < (fieldNode.Variables.Count - 1)) { + fieldName.Append(", "); + } + current++; + } + + node.ElementName = fieldName.ToString(); + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Field"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedField"; + break; + default: + node.IconName = "Icons.16x16.PrivateField"; + break; + } + } + + public static bool IsProperty(AstNode node) { + return (node is PropertyDeclaration); + } + + internal static void SetPropertyNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var propertyNode = (PropertyDeclaration)dataNode; + node.ElementName = propertyNode.Name; + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + if (showExtendedInfos) { + node.ElementName += " " + propertyNode.LBraceToken + + " " + propertyNode.Getter.Keyword + (!string.IsNullOrEmpty(propertyNode.Getter.Keyword.ToString()) ? ";" : "") + + " " + propertyNode.Setter.Keyword + (!string.IsNullOrEmpty(propertyNode.Setter.Keyword.ToString()) ? ";" : "") + + " " + propertyNode.RBraceToken; + } + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Property"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedProperty"; + break; + default: + node.IconName = "Icons.16x16.PrivateProperty"; + break; + } + } + + public static bool IsIndexer(AstNode node) { + return (node is IndexerDeclaration); + } + + internal static void SetIndexerNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var indexerNode = (IndexerDeclaration)dataNode; + node.ElementName = indexerNode.ReturnType.ToString() + " " + indexerNode.ThisToken.ToString() + + indexerNode.LBracketToken + + GetParameterDeclsAsString(indexerNode.Parameters) + + indexerNode.RBracketToken; + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + if (showExtendedInfos) { + node.ElementName += " " + indexerNode.LBraceToken + + " " + indexerNode.Getter.Keyword + (!string.IsNullOrEmpty(indexerNode.Getter.Keyword.ToString()) ? ";" : "") + + " " + indexerNode.Setter.Keyword + (!string.IsNullOrEmpty(indexerNode.Setter.Keyword.ToString()) ? ";" : "") + + " " + indexerNode.RBraceToken; + } + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Property"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedProperty"; + break; + default: + node.IconName = "Icons.16x16.PrivateProperty"; + break; + } + } + + public static bool IsNameSpace(AstNode node) { + return (node is NamespaceDeclaration); + } + + internal static void SetNameSpaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var nameSpaceNode = (NamespaceDeclaration)dataNode; + node.ElementName = nameSpaceNode.Name; + node.IconName = "Icons.16x16.NameSpace"; + node.IsExpanded = true; + if (colorizeNode) + node.ForegroundBrush = (nameSpaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); +// node.Weight = nameSpaceHighLighting.FontWeight != null ? nameSpaceHighLighting.FontWeight.Value : FontWeights.Normal; + } + + public static bool IsConstructor(AstNode node) { + return (node is ConstructorDeclaration); + } + + internal static void SetConstructorNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + var constructorNode = (ConstructorDeclaration)dataNode; + node.ElementName = constructorNode.Name; + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + + node.ElementName += " " + + constructorNode.LParToken + + (showExtendedInfos ? GetParameterDeclsAsString(constructorNode.Parameters) : "") + + constructorNode.RParToken; + + switch(GetAccessModifier(dataNode)) { + case Modifiers.Public: + node.IconName = "Icons.16x16.Method"; + break; + case Modifiers.Protected: + node.IconName = "Icons.16x16.ProtectedMethod"; + break; + default: + node.IconName = "Icons.16x16.PrivateMethod"; + break; + } + } + + public static bool IsDocument(AstNode node) { + return (node is SyntaxTree); + } + + internal static void SetDocumentNodeInfos(CSharpOutlineNode node, AstNode dataNode) { + node.ElementName = Path.GetFileName(((SyntaxTree)dataNode).FileName); + node.IconName = "C#.File.FullFile"; + node.IsExpanded = true; + node.Weight = FontWeights.Bold; + if (colorizeNode) + node.ForegroundBrush = Brushes.Black; + } + } +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs new file mode 100644 index 0000000000..4815cc9211 --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs @@ -0,0 +1,128 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +namespace CSharpBinding.OutlinePad +{ + using System; + using ICSharpCode.SharpDevelop; + using ICSharpCode.AvalonEdit.Folding; + using System.Linq; + + /// + /// RemoveNodeCommand. + /// + public class RemoveNodeCommand : SimpleCommand + { + public override bool CanExecute(object parameter) { + var node = parameter as CSharpOutlineNode; + if (node == null) + return false; + if (node.StartMarker == null || node.EndMarker == null) + return false; + if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted) + return false; + if (node.EndMarker.Offset == 0) + return false; + if (node.EndMarker.Offset < node.StartMarker.Offset) + return false; + return true; + } + + public override void Execute(object parameter) { + var node = parameter as CSharpOutlineNode; + node.Editor.Document.Remove(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset); + } + } + + /// + /// SelectRegionCommand. + /// + public class SelectRegionCommand : SimpleCommand + { + public override bool CanExecute(object parameter) { + var node = parameter as CSharpOutlineNode; + if (node == null) + return false; + if (node.StartMarker == null || node.EndMarker == null) + return false; + if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted) + return false; + if (node.EndMarker.Offset == 0) + return false; + if (node.EndMarker.Offset < node.StartMarker.Offset) + return false; + return true; + } + + public override void Execute(object parameter) { + var node = parameter as CSharpOutlineNode; + node.Editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset); + } + } + + /// + /// HandleFoldingCommand + /// + public class HandleFoldingCommand : SimpleCommand + { + public override bool CanExecute(object parameter) { + var node = parameter as CSharpOutlineNode; + if (node == null) + return false; + if (node.StartMarker == null || node.EndMarker == null) + return false; + if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted) + return false; + if (node.EndMarker.Offset == 0) + return false; + if (node.EndMarker.Offset < node.StartMarker.Offset) + return false; + return true; + } + + public override void Execute(object parameter) { + var node = parameter as CSharpOutlineNode; + + if (node == null || node.Editor == null) + return; + + FoldingManager foldingManager = node.Editor.GetService(typeof(FoldingManager)) as FoldingManager; + + if (foldingManager == null) + return; + + // The endline is, where the first child starts. The folding has to be + // between the StartMarker.Line of the current node and the StartMarker.Line of the first child. + int endLine = node.StartMarker.Line; + var firstChild = node.Children.FirstOrDefault(); + if (firstChild != null) { + endLine = (firstChild as CSharpOutlineNode).StartMarker.Line; + } + + FoldingSection folding = foldingManager.GetNextFolding(node.StartMarker.Offset); + + if (folding == null) + return; + // is next folding below the endline, the it belongs to a other node + if (node.Editor.Document.GetLineForOffset(folding.StartOffset).LineNumber >= endLine) + return; + + folding.IsFolded = !node.IsExpanded; + } + } +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml new file mode 100644 index 0000000000..bda20483ed --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs new file mode 100644 index 0000000000..ae470525c2 --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs @@ -0,0 +1,352 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Linq; +using System.Windows.Controls; +using System.Windows.Input; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Parser; +using CSharpBinding.Parser; +using System.Windows.Threading; +using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.AvalonEdit.Folding; + +namespace CSharpBinding.OutlinePad +{ + /// + /// Interaction logic for CSharpOutlineContentHost.xaml + /// + public partial class CSharpOutlineContentHost : DockPanel, IOutlineContentHost, IDisposable + { + ITextEditor editor; + DispatcherTimer updateTreeTimer = new DispatcherTimer(); + DispatcherTimer scrollToNodeTimer = new DispatcherTimer(); + SyntaxTree syntaxTree; + TextLocation? lastCaretLocation; + CSharpOutlineNode selectedNode = null; + static double refreshDelayInMilliSec = 1000; + static bool optionSelectActiveTreeNode = true; + static bool optionSelectRange = false; + + public CSharpOutlineContentHost(ITextEditor editor) { + this.editor = editor; + this.editor.Caret.LocationChanged += CaretLocationChanged; + + InitializeComponent(); + + SD.ParserService.ParseInformationUpdated += ParseInfoUpdated; + + this.updateTreeTimer.Interval = TimeSpan.FromMilliseconds(refreshDelayInMilliSec); + this.updateTreeTimer.Tick += this.UpdateTreeTimer_Tick; + + this.scrollToNodeTimer.Interval = TimeSpan.FromMilliseconds(200); + this.scrollToNodeTimer.Tick += this.ScrollToNodeTimer_Tick; + } + + void ParseInfoUpdated(object sender, ParseInformationEventArgs e) { + if (this.editor == null || !FileUtility.IsEqualFileName(this.editor.FileName, e.FileName)) + return; + + var parseInfo = e.NewParseInformation as CSharpFullParseInformation; + if (parseInfo != null && parseInfo.SyntaxTree != null) { + this.updateTreeTimer.Stop(); + this.syntaxTree = parseInfo.SyntaxTree; + this.updateTreeTimer.Start(); + } + } + + void CaretLocationChanged(object sender, EventArgs e) + { + SelectActiveTreeNode(); + } + + void SelectActiveTreeNode() { + if (!optionSelectActiveTreeNode) + return; + // prevent unnecessary looping, when both CaretLocationChanged and ParseUpdateChanged are fired. + if (this.lastCaretLocation.HasValue && this.lastCaretLocation == this.editor.Caret.Location) + return; + // same line, mostly in the same region, no update needed (there is a small inaccuracy, when entering a method/member) +// if (this.lastCaretLocation.HasValue && this.lastCaretLocation.Value.Line == this.editor.Caret.Location.Line) +// return; + + this.lastCaretLocation = this.editor.Caret.Location; + selectedNode = null; + FindNodeFromLocation(this.editor.Caret.Location, treeView.Root as CSharpOutlineNode); + if (selectedNode != null && treeView.SelectedItem != selectedNode) { + treeView.SelectedItem = selectedNode; + + if (!scrollToNodeTimer.IsEnabled) { + scrollToNodeTimer.Start(); + } + } + } + + bool IsRangeInside(TextLocation outerStartLocation, TextLocation outerEndLocation, + TextLocation innerStartLocation, TextLocation innerEndLocation) { + if (outerStartLocation.IsEmpty || outerStartLocation.IsInfinite() || + outerEndLocation.IsEmpty || outerEndLocation.IsInfinite() || + innerStartLocation.IsEmpty || innerStartLocation.IsInfinite() || + innerEndLocation.IsEmpty || innerEndLocation.IsInfinite()) + return false; + + const int virtualLineLength = 200; + var outerRange = (outerEndLocation.Line - outerStartLocation.Line) * virtualLineLength - outerStartLocation.Column + outerEndLocation.Column; + var innerRange = (innerEndLocation.Line - innerStartLocation.Line) * virtualLineLength - innerStartLocation.Column + innerEndLocation.Column; + return innerRange < outerRange; + } + + void FindNodeFromLocation(TextLocation location, CSharpOutlineNode node) { + if (node == null) + return; + if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted) + return; + + if (location.IsInside(node.StartMarker.Location, node.EndMarker.Location) + && (selectedNode == null || IsRangeInside(selectedNode.AstNodeItem.StartLocation, selectedNode.AstNodeItem.EndLocation, + node.AstNodeItem.StartLocation, node.AstNodeItem.EndLocation))) { + selectedNode = node; + } + + foreach(var child in node.Children) { + FindNodeFromLocation(location, child as CSharpOutlineNode); + } + } + + void UpdateTreeTimer_Tick(Object sender, EventArgs args) { + this.updateTreeTimer.Stop(); + this.UpdateTree(this.syntaxTree); + this.SelectActiveTreeNode(); + } + + void ScrollToNodeTimer_Tick(Object sender, EventArgs args) { + this.scrollToNodeTimer.Stop(); + if (selectedNode != null) { + treeView.ScrollIntoView(selectedNode); + } + } + + void UpdateTree(AstNode syntaxTree) { + if (syntaxTree == null) + return; + + if (treeView.Root == null) { + treeView.Root = new CSharpOutlineNode(); + SetNodeInfos(treeView.Root as CSharpOutlineNode, null, syntaxTree); + } + + this.UpdateNode(treeView.Root as CSharpOutlineNode, syntaxTree); + } + + void UpdateNode(CSharpOutlineNode node, AstNode dataNode) { + if (dataNode == null || node == null) + return; + + SetNodeInfos(node, null, dataNode); + + // Filter the children, for only the needed/wanted nodes + var dataChildren = dataNode.Children.Where(childNode => AstNodeHelper.IsAllowedNode(childNode)).ToList(); + + int childrenCount = node.Children.Count; + int dataCount = dataChildren.Count; + + for (int i = 0; i < Math.Max(childrenCount, dataCount); i++) { + if (i >= childrenCount) { + +// if (AstNodeHelper.IsRegionStart(dataChildren[i])) { +// var regionNode = new CSharpOutlineNode(); +// SetNodeInfos(regionNode, node, dataChildren[i]); +// node.Children.Add(regionNode); +// node = regionNode; +// continue; +// } +// if (AstNodeHelper.IsRegionEnd(dataChildren[i])) { +// node = node.Parent; +// continue; +// } + + node.Children.Add(BuildNode(node, dataChildren[i])); + + } else if (i >= dataCount) { + while (node.Children.Count > dataCount) + node.Children.RemoveAt(dataCount); + + } else { + UpdateNode(node.Children[i] as CSharpOutlineNode, dataChildren[i]); + } + } + } + + CSharpOutlineNode BuildNode(CSharpOutlineNode parentNode, AstNode dataNode) { + + var node = new CSharpOutlineNode(); + SetNodeInfos(node, parentNode, dataNode); + + // Filter the children, for only the needed/wanted nodes + var dataChildren = dataNode.Children.Where(v => AstNodeHelper.IsAllowedNode(v)).ToList(); + foreach (var child in dataChildren) { +// if (AstNodeHelper.IsRegionStart(child)) { +// var regionNode = new CSharpOutlineNode(); +// SetNodeInfos(regionNode, node, child); +// node.Children.Add(regionNode); +// node = regionNode; +// continue; +// } +// if (AstNodeHelper.IsRegionEnd(child)) { +// node = node.Parent; +// continue; +// } + + node.Children.Add(BuildNode(node, child)); + + } + return node; + } + + void SetNodeInfos(CSharpOutlineNode node, CSharpOutlineNode parentNode, AstNode dataNode) { + + int startOffset = 0; + int textLength = Math.Max(editor.Document.TextLength - 1,0); + if (!dataNode.StartLocation.IsValid() || dataNode.StartLocation.Line > editor.Document.LineCount) + startOffset = 0; + else + startOffset = editor.Document.GetOffset(dataNode.StartLocation); + + int endOffset = 0; + if (!dataNode.EndLocation.IsValid() || dataNode.EndLocation.Line > editor.Document.LineCount) + endOffset = textLength; + else + endOffset = editor.Document.GetOffset(dataNode.EndLocation); + + node.AstNodeItem = dataNode; + node.StartMarker = editor.Document.CreateAnchor(MinMax(startOffset, 0, textLength)); + node.EndMarker = editor.Document.CreateAnchor(MinMax(endOffset, 0, textLength)); + node.Editor = editor; + node.Parent = parentNode; + + if (AstNodeHelper.IsDocument(dataNode)) + AstNodeHelper.SetDocumentNodeInfos(node, dataNode); + + if (AstNodeHelper.IsNameSpace(dataNode)) + AstNodeHelper.SetNameSpaceNodeInfos(node, dataNode); + + if (AstNodeHelper.IsRegionStart(dataNode)) + AstNodeHelper.SetRegionStartInfos(node, dataNode); + + if (AstNodeHelper.IsRegionEnd(dataNode)) + AstNodeHelper.SetRegionEndInfos(node, dataNode); + + if (AstNodeHelper.IsClass(dataNode)) + AstNodeHelper.SetClassNodeInfos(node, dataNode); + + if (AstNodeHelper.IsInterface(dataNode)) + AstNodeHelper.SetInterfaceNodeInfos(node, dataNode); + + if (AstNodeHelper.IsConstructor(dataNode)) + AstNodeHelper.SetConstructorNodeInfos(node, dataNode); + + if (AstNodeHelper.IsField(dataNode)) + AstNodeHelper.SetFieldNodeInfos(node, dataNode); + + if (AstNodeHelper.IsProperty(dataNode)) + AstNodeHelper.SetPropertyNodeInfos(node, dataNode); + + if (AstNodeHelper.IsMethod(dataNode)) + AstNodeHelper.SetMethodNodeInfos(node, dataNode); + + if (AstNodeHelper.IsEvent(dataNode)) + AstNodeHelper.SetEventNodeInfos(node, dataNode); + + if (AstNodeHelper.IsDelegate(dataNode)) + AstNodeHelper.SetDelegateNodeInfos(node, dataNode); + + if (AstNodeHelper.IsIndexer(dataNode)) + AstNodeHelper.SetIndexerNodeInfos(node, dataNode); + + if (AstNodeHelper.IsEnum(dataNode)) + AstNodeHelper.SetEnumNodeInfos(node, dataNode); + + if (AstNodeHelper.IsEnumMember(dataNode)) + AstNodeHelper.SetEnumMemberNodeInfos(node, dataNode); + + if (AstNodeHelper.IsStruct(dataNode)) + AstNodeHelper.SetStructNodeInfos(node, dataNode); + + if (AstNodeHelper.IsOperator(dataNode)) + AstNodeHelper.SetOperatorNodeInfos(node, dataNode); + } + + static int MinMax(int value, int lower, int upper) { + return Math.Min(Math.Max(value, lower), upper); + } + + void TreeView_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + var node = treeView.SelectedItem as CSharpOutlineNode; + if (node == null) + return; + + if (optionSelectRange) + editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset); + FileService.JumpToFilePosition(this.editor.FileName, node.AstNodeItem.StartLocation.Line, node.AstNodeItem.StartLocation.Column); + } + + void TreeViewMouseDoubleClick(object sender, MouseButtonEventArgs e) { + } + + public object OutlineContent { + get { return this; } + } + + public void Dispose() { + SD.ParserService.ParseInformationUpdated -= ParseInfoUpdated; + + if (this.editor != null) { + if (this.editor.Caret != null) + this.editor.Caret.LocationChanged -= CaretLocationChanged; + this.editor = null; + } + + this.syntaxTree = null; + this.lastCaretLocation = null; + this.selectedNode = null; + + if (this.updateTreeTimer != null) { + this.updateTreeTimer.Stop(); + this.updateTreeTimer.Tick -= this.UpdateTreeTimer_Tick; + this.updateTreeTimer = null; + } + + if (this.scrollToNodeTimer != null) { + this.scrollToNodeTimer.Stop(); + this.scrollToNodeTimer.Tick -= this.ScrollToNodeTimer_Tick; + this.scrollToNodeTimer = null; + } + } + + + } + +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs new file mode 100644 index 0000000000..ef4224e37b --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs @@ -0,0 +1,169 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.TreeView; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.Core.Presentation; +using System.Windows.Controls; +using ICSharpCode.AvalonEdit.Folding; + +namespace CSharpBinding.OutlinePad +{ + class CSharpOutlineNode : SharpTreeNode + { + string elementName, name, iconName; + + public string ElementName { + get { return elementName; } + set { + this.elementName = value; + this.RaisePropertyChanged("Text"); + } + } + + public string Name { + get { return name; } + set { + this.name = value; + this.RaisePropertyChanged("Text"); + } + } + + public override object ToolTip { + get { return this.GetSourceText(); } + } + + public ITextAnchor StartMarker { get; set; } + public ITextAnchor EndMarker { get; set; } + public ITextEditor Editor { get; set; } + public AstNode AstNodeItem { get; set; } + public new CSharpOutlineNode Parent { get; set; } + + public string IconName { + get { return iconName; } + set { + iconName = value; + this.RaisePropertyChanged("Icon"); + } + } + + public string GetSourceText() { + if (StartMarker.IsDeleted || EndMarker.IsDeleted) + return ""; + + return Editor.Document.GetText(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset); + } + + public override bool CanDelete(SharpTreeNode[] nodes) { + return nodes.OfType().All(n => n.Parent != null); + } + + public override void Delete(SharpTreeNode[] nodes) { + DeleteWithoutConfirmation(nodes); + } + + public override void DeleteWithoutConfirmation(SharpTreeNode[] nodes) { + foreach (CSharpOutlineNode CSharpNode in nodes.OfType()) { + CSharpNode.DeleteCore(); + } + } + + void DeleteCore() + { + Editor.Document.Remove(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset); + } + + public override object Text { + get { return (!string.IsNullOrEmpty(Name) ? ElementName + " (" + Name + ")" : ElementName); } + } + + public override object Icon { + get { return !string.IsNullOrEmpty(this.IconName) + ? SD.ResourceService.GetImageSource(this.IconName) + : null; } + } + + public override Brush Foreground { + get { return foregroundBrush ?? SystemColors.WindowTextBrush; } + } + + Brush foregroundBrush; + public Brush ForegroundBrush { + get { + return foregroundBrush; + } + set { + foregroundBrush = value; + RaisePropertyChanged("Foreground"); + } + } + + FontWeight weight = FontWeights.Normal; + public FontWeight Weight { + get { + return weight; + } + set { + weight = value; + RaisePropertyChanged("FontWeight"); + } + } + FontStyle style = FontStyles.Normal; + public FontStyle Style { + get { + return style; + } + set { + style = value; + RaisePropertyChanged("FontStyle"); + } + } + + public override FontWeight FontWeight { + get { return Weight; } + } + + public override FontStyle FontStyle { + get { return Style; } + } + + public override void ShowContextMenu(ContextMenuEventArgs e) + { + MenuService.ShowContextMenu(null, this, "/SharpDevelop/Pads/OutlinePad/ContextMenu/NodeActions"); + } + + protected override void OnExpanding() { + var cmd = new HandleFoldingCommand(); + if (cmd.CanExecute(this)) + cmd.Execute(this); + } + protected override void OnCollapsing() { + var cmd = new HandleFoldingCommand(); + if (cmd.CanExecute(this)) + cmd.Execute(this); + } + } +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs new file mode 100644 index 0000000000..0b62999986 --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +namespace CSharpBinding.OutlinePad +{ + using System; + using ICSharpCode.NRefactory; + + /// + /// Description of TextLocationExtensions. + /// + static class TextLocationExtensions { + + public static bool IsInfinite(this TextLocation location) { + return location == null || location.Line == int.MaxValue || location.Column == int.MaxValue; + } + + public static bool IsValid(this TextLocation location) { + if (location.IsEmpty) + return false; + if (location.IsInfinite()) + return false; + return true; + } + + public static bool IsInside(this TextLocation location, TextLocation startLocation, TextLocation endLocation) { + if (location.IsEmpty) + return false; + + return location.Line >= startLocation.Line && + (location.Line <= endLocation.Line || endLocation.Line == -1) && + (location.Line != startLocation.Line || location.Column >= startLocation.Column) && + (location.Line != endLocation.Line || location.Column <= endLocation.Column); + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs index 68a625745e..fef10c4f68 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs @@ -330,6 +330,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting // so it will always invalidate the next visual line when a folded line is constructed // and the highlighting stack has changed. + if (fromLineNumber > textView.Document.LineCount || toLineNumber > textView.Document.LineCount) + return; + if (fromLineNumber == toLineNumber) { textView.Redraw(textView.Document.GetLineByNumber(fromLineNumber)); } else { diff --git a/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs b/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs index 84426dd7e5..be50c48cff 100644 --- a/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs +++ b/src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs @@ -136,6 +136,14 @@ namespace ICSharpCode.TreeView get { return Parent != null ? Parent.Level + 1 : 0; } } + public virtual FontWeight FontWeight { + get { return FontWeights.Normal; } + } + + public virtual FontStyle FontStyle { + get { return FontStyles.Normal; } + } + public bool IsRoot { get { return Parent == null; } From a6241eb0c704b8decb36020267a9b8411b7d7fb3 Mon Sep 17 00:00:00 2001 From: JohnnyBravo75 Date: Thu, 24 Jul 2014 23:44:08 +0200 Subject: [PATCH 3/6] renamed timervariable --- .../Src/OutlinePad/CSharpOutlineContentHost.xaml.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs index ae470525c2..46c9b4d9b4 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs @@ -42,13 +42,14 @@ namespace CSharpBinding.OutlinePad { ITextEditor editor; DispatcherTimer updateTreeTimer = new DispatcherTimer(); + const double updateDelayMilliseconds = 1000; DispatcherTimer scrollToNodeTimer = new DispatcherTimer(); + const double scrollDelayMilliseconds = 200; SyntaxTree syntaxTree; TextLocation? lastCaretLocation; - CSharpOutlineNode selectedNode = null; - static double refreshDelayInMilliSec = 1000; - static bool optionSelectActiveTreeNode = true; - static bool optionSelectRange = false; + CSharpOutlineNode selectedNode = null; + const bool optionSelectActiveTreeNode = true; + const bool optionSelectRange = false; public CSharpOutlineContentHost(ITextEditor editor) { this.editor = editor; @@ -58,10 +59,10 @@ namespace CSharpBinding.OutlinePad SD.ParserService.ParseInformationUpdated += ParseInfoUpdated; - this.updateTreeTimer.Interval = TimeSpan.FromMilliseconds(refreshDelayInMilliSec); + this.updateTreeTimer.Interval = TimeSpan.FromMilliseconds(updateDelayMilliseconds); this.updateTreeTimer.Tick += this.UpdateTreeTimer_Tick; - this.scrollToNodeTimer.Interval = TimeSpan.FromMilliseconds(200); + this.scrollToNodeTimer.Interval = TimeSpan.FromMilliseconds(scrollDelayMilliseconds); this.scrollToNodeTimer.Tick += this.ScrollToNodeTimer_Tick; } From e44a437f4dceafb5e28abf23374dac414245ca8b Mon Sep 17 00:00:00 2001 From: JohnnyBravo75 Date: Sun, 27 Jul 2014 03:27:12 +0200 Subject: [PATCH 4/6] Formating --- .../Project/Src/OutlinePad/AstNodeHelper.cs | 187 ++++++++++-------- .../Src/OutlinePad/CSharpOutlineNode.cs | 44 ++--- .../ICSharpCode.TreeView/Themes/Generic.xaml | 2 + 3 files changed, 127 insertions(+), 106 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs index c193578637..04f9f369d5 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs @@ -24,7 +24,6 @@ namespace CSharpBinding.OutlinePad using System.Windows; using System.Windows.Media; using System.Text; - using ICSharpCode.NRefactory.CSharp; using ICSharpCode.AvalonEdit.Highlighting; @@ -55,7 +54,9 @@ namespace CSharpBinding.OutlinePad if (accessModifier == null && IsInterface(node.Parent)) { return Modifiers.Public; } - return accessModifier == null ? Modifiers.None : accessModifier.Modifier; + return accessModifier == null + ? Modifiers.None + : accessModifier.Modifier; } private static string GetParameterDeclsAsString(AstNodeCollection parameterDecls) { @@ -96,21 +97,21 @@ namespace CSharpBinding.OutlinePad public static bool IsAllowedNode(AstNode node) { return (IsRegionStart(node) - || IsRegionEnd(node) - || IsClass(node) - || IsInterface(node) - || IsMethod(node) - || IsField(node) - || IsProperty(node) - || IsNameSpace(node) - || IsConstructor(node) - || IsEvent(node) - || IsDelegate(node) - || IsIndexer(node) - || IsEnum(node) - || IsEnumMember(node) - || IsStruct(node) - || IsOperator(node) + || IsRegionEnd(node) + || IsClass(node) + || IsInterface(node) + || IsMethod(node) + || IsField(node) + || IsProperty(node) + || IsNameSpace(node) + || IsConstructor(node) + || IsEvent(node) + || IsDelegate(node) + || IsIndexer(node) + || IsEnum(node) + || IsEnumMember(node) + || IsStruct(node) + || IsOperator(node) ); } @@ -120,7 +121,7 @@ namespace CSharpBinding.OutlinePad internal static void SetRegionStartInfos(CSharpOutlineNode node, AstNode dataNode) { var preProcessorNode = (PreProcessorDirective)dataNode; - node.ElementName = "****** " + preProcessorNode.Argument + " *****"; + node.Name = "****** " + preProcessorNode.Argument + " *****"; node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); // node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal; } @@ -131,7 +132,7 @@ namespace CSharpBinding.OutlinePad internal static void SetRegionEndInfos(CSharpOutlineNode node, AstNode dataNode) { var preProcessorNode = (PreProcessorDirective)dataNode; - node.ElementName = "*********************"; + node.Name = "*********************"; node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); // node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal; } @@ -141,8 +142,8 @@ namespace CSharpBinding.OutlinePad } internal static void SetDelegateNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var typeNode = (DelegateDeclaration)dataNode; - node.ElementName = typeNode.Name; + var typeNode = (DelegateDeclaration)dataNode; + node.Name = typeNode.Name; if (colorizeNode) node.ForegroundBrush = Brushes.Black; // node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal; @@ -168,12 +169,13 @@ namespace CSharpBinding.OutlinePad } internal static void SetStructNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var typeNode = (TypeDeclaration)dataNode; - node.ElementName = typeNode.Name; + var typeNode = (TypeDeclaration)dataNode; + node.Name = typeNode.Name; + node.IsExpanded = true; + if (colorizeNode) node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); // node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal; - node.IsExpanded = true; switch(GetAccessModifier(dataNode)) { case Modifiers.Public: @@ -196,8 +198,9 @@ namespace CSharpBinding.OutlinePad } internal static void SetEnumMemberNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var enumMemberNode = (EnumMemberDeclaration)dataNode; - node.ElementName = enumMemberNode.Name; + var enumMemberNode = (EnumMemberDeclaration)dataNode; + node.Name = enumMemberNode.Name; + if (colorizeNode) node.ForegroundBrush = Brushes.Black; node.IconName = "Icons.16x16.Enum"; @@ -208,12 +211,13 @@ namespace CSharpBinding.OutlinePad } internal static void SetEnumNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var typeNode = (TypeDeclaration)dataNode; - node.ElementName = typeNode.Name; - if (colorizeNode) - node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); + var typeNode = (TypeDeclaration)dataNode; + node.Name = typeNode.Name; node.IsExpanded = true; + if (colorizeNode) + node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); + switch(GetAccessModifier(dataNode)) { case Modifiers.Public: node.IconName = "Icons.16x16.Enum"; @@ -235,16 +239,17 @@ namespace CSharpBinding.OutlinePad } internal static void SetClassNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var typeNode = (TypeDeclaration)dataNode; - node.ElementName = typeNode.Name + var typeNode = (TypeDeclaration)dataNode; + node.Name = typeNode.Name + typeNode.LChevronToken + GetTypeParameterDeclsAsString(typeNode.TypeParameters) + typeNode.RChevronToken; + node.IsExpanded = true; + if (colorizeNode) node.ForegroundBrush = (classHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); // node.Weight = classHighLighting.FontWeight != null ? classHighLighting.FontWeight.Value : FontWeights.Normal; - node.IsExpanded = true; - + switch(GetAccessModifier(dataNode)) { case Modifiers.Public: node.IconName = "Icons.16x16.Class"; @@ -266,11 +271,11 @@ namespace CSharpBinding.OutlinePad } internal static void SetEventNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var eventNode = (EventDeclaration)dataNode; - var varInitializer = eventNode.Children.FirstOrDefault(x => x is VariableInitializer) as VariableInitializer; - node.ElementName = (varInitializer != null) - ? varInitializer.Name - : ""; + var eventNode = (EventDeclaration)dataNode; + var varInitializer = eventNode.Children.FirstOrDefault(x => x is VariableInitializer) as VariableInitializer; + node.Name = (varInitializer != null) + ? varInitializer.Name + : ""; if (colorizeNode) node.ForegroundBrush = Brushes.Black; @@ -292,11 +297,13 @@ namespace CSharpBinding.OutlinePad } internal static void SetInterfaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var typeNode = (TypeDeclaration)dataNode; - node.ElementName = typeNode.Name; + var typeNode = (TypeDeclaration)dataNode; + node.Name = typeNode.Name; + node.IsExpanded = true; + if (colorizeNode) node.ForegroundBrush = (interfaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); - node.IsExpanded = true; + switch(GetAccessModifier(dataNode)) { case Modifiers.Public: node.IconName = "Icons.16x16.Interface"; @@ -318,18 +325,20 @@ namespace CSharpBinding.OutlinePad } internal static void SetOperatorNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var operatorNode = (OperatorDeclaration)dataNode; - node.ElementName = operatorNode.OperatorToken - + " " + operatorNode.OperatorTypeToken; - - if (showExtendedInfos) { - node.ElementName += " " + operatorNode.LParToken - + GetParameterDeclsAsString(operatorNode.Parameters) - + operatorNode.RParToken; - } + var operatorNode = (OperatorDeclaration)dataNode; + node.Name = operatorNode.OperatorToken + + " " + + operatorNode.OperatorTypeToken; + if (colorizeNode) node.ForegroundBrush = Brushes.Black; - + + if (showExtendedInfos) { + node.Name += " " + + operatorNode.LParToken + + GetParameterDeclsAsString(operatorNode.Parameters) + + operatorNode.RParToken; + } switch(GetAccessModifier(dataNode)) { case Modifiers.Public: node.IconName = "Icons.16x16.Method"; @@ -348,12 +357,13 @@ namespace CSharpBinding.OutlinePad } internal static void SetMethodNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var methodNode = (MethodDeclaration)dataNode; - node.ElementName = methodNode.Name; + var methodNode = (MethodDeclaration)dataNode; + node.Name = methodNode.Name; - node.ElementName += " " + methodNode.LParToken - + (showExtendedInfos ? GetParameterDeclsAsString(methodNode.Parameters) : "") - + methodNode.RParToken; + node.Name += " " + + methodNode.LParToken + + (showExtendedInfos ? GetParameterDeclsAsString(methodNode.Parameters) : "") + + methodNode.RParToken; if (colorizeNode) node.ForegroundBrush = (methodHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); @@ -390,7 +400,8 @@ namespace CSharpBinding.OutlinePad current++; } - node.ElementName = fieldName.ToString(); + node.Name = fieldName.ToString(); + if (colorizeNode) node.ForegroundBrush = Brushes.Black; @@ -413,15 +424,17 @@ namespace CSharpBinding.OutlinePad internal static void SetPropertyNodeInfos(CSharpOutlineNode node, AstNode dataNode) { var propertyNode = (PropertyDeclaration)dataNode; - node.ElementName = propertyNode.Name; + node.Name = propertyNode.Name; + if (colorizeNode) node.ForegroundBrush = Brushes.Black; + if (showExtendedInfos) { - node.ElementName += " " + propertyNode.LBraceToken - + " " + propertyNode.Getter.Keyword + (!string.IsNullOrEmpty(propertyNode.Getter.Keyword.ToString()) ? ";" : "") - + " " + propertyNode.Setter.Keyword + (!string.IsNullOrEmpty(propertyNode.Setter.Keyword.ToString()) ? ";" : "") - + " " + propertyNode.RBraceToken; - } + node.Name += " " + propertyNode.LBraceToken + + " " + propertyNode.Getter.Keyword + (!string.IsNullOrEmpty(propertyNode.Getter.Keyword.ToString()) ? ";" : "") + + " " + propertyNode.Setter.Keyword + (!string.IsNullOrEmpty(propertyNode.Setter.Keyword.ToString()) ? ";" : "") + + " " + propertyNode.RBraceToken; + } switch(GetAccessModifier(dataNode)) { case Modifiers.Public: node.IconName = "Icons.16x16.Property"; @@ -441,17 +454,20 @@ namespace CSharpBinding.OutlinePad internal static void SetIndexerNodeInfos(CSharpOutlineNode node, AstNode dataNode) { var indexerNode = (IndexerDeclaration)dataNode; - node.ElementName = indexerNode.ReturnType.ToString() + " " + indexerNode.ThisToken.ToString() - + indexerNode.LBracketToken - + GetParameterDeclsAsString(indexerNode.Parameters) - + indexerNode.RBracketToken; + node.Name = indexerNode.ReturnType.ToString() + + " " + + indexerNode.ThisToken.ToString() + + indexerNode.LBracketToken + + GetParameterDeclsAsString(indexerNode.Parameters) + + indexerNode.RBracketToken; if (colorizeNode) node.ForegroundBrush = Brushes.Black; + if (showExtendedInfos) { - node.ElementName += " " + indexerNode.LBraceToken - + " " + indexerNode.Getter.Keyword + (!string.IsNullOrEmpty(indexerNode.Getter.Keyword.ToString()) ? ";" : "") - + " " + indexerNode.Setter.Keyword + (!string.IsNullOrEmpty(indexerNode.Setter.Keyword.ToString()) ? ";" : "") - + " " + indexerNode.RBraceToken; + node.Name += " " + indexerNode.LBraceToken + + " " + indexerNode.Getter.Keyword + (!string.IsNullOrEmpty(indexerNode.Getter.Keyword.ToString()) ? ";" : "") + + " " + indexerNode.Setter.Keyword + (!string.IsNullOrEmpty(indexerNode.Setter.Keyword.ToString()) ? ";" : "") + + " " + indexerNode.RBraceToken; } switch(GetAccessModifier(dataNode)) { case Modifiers.Public: @@ -471,10 +487,11 @@ namespace CSharpBinding.OutlinePad } internal static void SetNameSpaceNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - var nameSpaceNode = (NamespaceDeclaration)dataNode; - node.ElementName = nameSpaceNode.Name; - node.IconName = "Icons.16x16.NameSpace"; - node.IsExpanded = true; + var nameSpaceNode = (NamespaceDeclaration)dataNode; + node.Name = nameSpaceNode.Name; + node.IconName = "Icons.16x16.NameSpace"; + node.IsExpanded = true; + if (colorizeNode) node.ForegroundBrush = (nameSpaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); // node.Weight = nameSpaceHighLighting.FontWeight != null ? nameSpaceHighLighting.FontWeight.Value : FontWeights.Normal; @@ -486,14 +503,15 @@ namespace CSharpBinding.OutlinePad internal static void SetConstructorNodeInfos(CSharpOutlineNode node, AstNode dataNode) { var constructorNode = (ConstructorDeclaration)dataNode; - node.ElementName = constructorNode.Name; + node.Name = constructorNode.Name; + if (colorizeNode) node.ForegroundBrush = Brushes.Black; - node.ElementName += " " - + constructorNode.LParToken - + (showExtendedInfos ? GetParameterDeclsAsString(constructorNode.Parameters) : "") - + constructorNode.RParToken; + node.Name += " " + + constructorNode.LParToken + + (showExtendedInfos ? GetParameterDeclsAsString(constructorNode.Parameters) : "") + + constructorNode.RParToken; switch(GetAccessModifier(dataNode)) { case Modifiers.Public: @@ -513,10 +531,11 @@ namespace CSharpBinding.OutlinePad } internal static void SetDocumentNodeInfos(CSharpOutlineNode node, AstNode dataNode) { - node.ElementName = Path.GetFileName(((SyntaxTree)dataNode).FileName); - node.IconName = "C#.File.FullFile"; + node.Name = Path.GetFileName(((SyntaxTree)dataNode).FileName); + node.IconName = "C#.File.FullFile"; node.IsExpanded = true; - node.Weight = FontWeights.Bold; + node.Weight = FontWeights.Bold; + if (colorizeNode) node.ForegroundBrush = Brushes.Black; } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs index ef4224e37b..2d77de1fd2 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs @@ -25,33 +25,25 @@ using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.TreeView; using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.Core.Presentation; using System.Windows.Controls; -using ICSharpCode.AvalonEdit.Folding; namespace CSharpBinding.OutlinePad { class CSharpOutlineNode : SharpTreeNode { - string elementName, name, iconName; - - public string ElementName { - get { return elementName; } - set { - this.elementName = value; - this.RaisePropertyChanged("Text"); - } - } + string name, iconName; public string Name { get { return name; } set { - this.name = value; - this.RaisePropertyChanged("Text"); + if (this.name != value) { + this.name = value; + this.RaisePropertyChanged("Text"); + } } } - + public override object ToolTip { get { return this.GetSourceText(); } } @@ -65,14 +57,16 @@ namespace CSharpBinding.OutlinePad public string IconName { get { return iconName; } set { - iconName = value; - this.RaisePropertyChanged("Icon"); + if (iconName != value) { + iconName = value; + this.RaisePropertyChanged("Icon"); + } } } public string GetSourceText() { if (StartMarker.IsDeleted || EndMarker.IsDeleted) - return ""; + return string.Empty; return Editor.Document.GetText(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset); } @@ -97,7 +91,7 @@ namespace CSharpBinding.OutlinePad } public override object Text { - get { return (!string.IsNullOrEmpty(Name) ? ElementName + " (" + Name + ")" : ElementName); } + get { return Name; } } public override object Icon { @@ -127,18 +121,23 @@ namespace CSharpBinding.OutlinePad return weight; } set { - weight = value; - RaisePropertyChanged("FontWeight"); + if (weight != value) { + weight = value; + RaisePropertyChanged("FontWeight"); + } } } + FontStyle style = FontStyles.Normal; public FontStyle Style { get { return style; } set { - style = value; - RaisePropertyChanged("FontStyle"); + if (style != value) { + style = value; + RaisePropertyChanged("FontStyle"); + } } } @@ -160,6 +159,7 @@ namespace CSharpBinding.OutlinePad if (cmd.CanExecute(this)) cmd.Execute(this); } + protected override void OnCollapsing() { var cmd = new HandleFoldingCommand(); if (cmd.CanExecute(this)) diff --git a/src/Libraries/SharpTreeView/ICSharpCode.TreeView/Themes/Generic.xaml b/src/Libraries/SharpTreeView/ICSharpCode.TreeView/Themes/Generic.xaml index 5bc9529235..cc1bd2bc76 100644 --- a/src/Libraries/SharpTreeView/ICSharpCode.TreeView/Themes/Generic.xaml +++ b/src/Libraries/SharpTreeView/ICSharpCode.TreeView/Themes/Generic.xaml @@ -182,6 +182,8 @@ From c29b384d65a9eda33fc33a6aa14f9d9f4526faa8 Mon Sep 17 00:00:00 2001 From: JohnnyBravo75 Date: Mon, 28 Jul 2014 00:44:05 +0200 Subject: [PATCH 5/6] -FIX: Update of treenode did not work, new node is created an replaces the old. -CHG: Formating, cleanup --- .../Project/Src/OutlinePad/AstNodeHelper.cs | 27 +++++++------ .../Src/OutlinePad/CSharpOutlineCommands.cs | 10 ++--- .../CSharpOutlineContentHost.xaml.cs | 40 +++---------------- .../Src/OutlinePad/CSharpOutlineNode.cs | 4 +- .../Src/OutlinePad/ExtensionMethods.cs | 8 ++-- 5 files changed, 30 insertions(+), 59 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs index 04f9f369d5..ce669d5f37 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/AstNodeHelper.cs @@ -16,17 +16,18 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using System.Text; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.AvalonEdit.Highlighting; +using System.Collections.Generic; + namespace CSharpBinding.OutlinePad { - using System; - using System.IO; - using System.Linq; - using System.Windows; - using System.Windows.Media; - using System.Text; - using ICSharpCode.NRefactory.CSharp; - using ICSharpCode.AvalonEdit.Highlighting; - internal static class AstNodeHelper { static bool showExtendedInfos = true; @@ -114,17 +115,17 @@ namespace CSharpBinding.OutlinePad || IsOperator(node) ); } - + public static bool IsRegionStart(AstNode node) { return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Region); } internal static void SetRegionStartInfos(CSharpOutlineNode node, AstNode dataNode) { var preProcessorNode = (PreProcessorDirective)dataNode; - node.Name = "****** " + preProcessorNode.Argument + " *****"; + node.Name = "*****" + preProcessorNode.Argument + "****"; node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); // node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal; - } + } public static bool IsRegionEnd(AstNode node) { return (node is PreProcessorDirective && (node as PreProcessorDirective).Type == PreProcessorDirectiveType.Endregion); @@ -132,7 +133,7 @@ namespace CSharpBinding.OutlinePad internal static void SetRegionEndInfos(CSharpOutlineNode node, AstNode dataNode) { var preProcessorNode = (PreProcessorDirective)dataNode; - node.Name = "*********************"; + node.Name = "********************"; node.ForegroundBrush = (regionHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); // node.Weight = regionHighLighting.FontWeight != null ? regionHighLighting.FontWeight.Value : FontWeights.Normal; } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs index 4815cc9211..4c5704fa63 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineCommands.cs @@ -16,13 +16,13 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; +using ICSharpCode.SharpDevelop; +using ICSharpCode.AvalonEdit.Folding; +using System.Linq; + namespace CSharpBinding.OutlinePad { - using System; - using ICSharpCode.SharpDevelop; - using ICSharpCode.AvalonEdit.Folding; - using System.Linq; - /// /// RemoveNodeCommand. /// diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs index 46c9b4d9b4..788c5c6a0f 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml.cs @@ -20,7 +20,7 @@ using System; using System.Linq; using System.Windows.Controls; using System.Windows.Input; - +using System.Windows.Threading; using ICSharpCode.Core; using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.CSharp; @@ -29,9 +29,6 @@ using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Parser; using CSharpBinding.Parser; -using System.Windows.Threading; -using ICSharpCode.AvalonEdit.Highlighting; -using ICSharpCode.AvalonEdit.Folding; namespace CSharpBinding.OutlinePad { @@ -89,9 +86,6 @@ namespace CSharpBinding.OutlinePad // prevent unnecessary looping, when both CaretLocationChanged and ParseUpdateChanged are fired. if (this.lastCaretLocation.HasValue && this.lastCaretLocation == this.editor.Caret.Location) return; - // same line, mostly in the same region, no update needed (there is a small inaccuracy, when entering a method/member) -// if (this.lastCaretLocation.HasValue && this.lastCaretLocation.Value.Line == this.editor.Caret.Location.Line) -// return; this.lastCaretLocation = this.editor.Caret.Location; selectedNode = null; @@ -108,9 +102,9 @@ namespace CSharpBinding.OutlinePad bool IsRangeInside(TextLocation outerStartLocation, TextLocation outerEndLocation, TextLocation innerStartLocation, TextLocation innerEndLocation) { if (outerStartLocation.IsEmpty || outerStartLocation.IsInfinite() || - outerEndLocation.IsEmpty || outerEndLocation.IsInfinite() || + outerEndLocation.IsEmpty || outerEndLocation.IsInfinite() || innerStartLocation.IsEmpty || innerStartLocation.IsInfinite() || - innerEndLocation.IsEmpty || innerEndLocation.IsInfinite()) + innerEndLocation.IsEmpty || innerEndLocation.IsInfinite()) return false; const int virtualLineLength = 200; @@ -175,19 +169,6 @@ namespace CSharpBinding.OutlinePad for (int i = 0; i < Math.Max(childrenCount, dataCount); i++) { if (i >= childrenCount) { - -// if (AstNodeHelper.IsRegionStart(dataChildren[i])) { -// var regionNode = new CSharpOutlineNode(); -// SetNodeInfos(regionNode, node, dataChildren[i]); -// node.Children.Add(regionNode); -// node = regionNode; -// continue; -// } -// if (AstNodeHelper.IsRegionEnd(dataChildren[i])) { -// node = node.Parent; -// continue; -// } - node.Children.Add(BuildNode(node, dataChildren[i])); } else if (i >= dataCount) { @@ -195,6 +176,8 @@ namespace CSharpBinding.OutlinePad node.Children.RemoveAt(dataCount); } else { + // Create new node, the old node doesn´t update (seems to be a bug) + node.Children[i] = new CSharpOutlineNode(); UpdateNode(node.Children[i] as CSharpOutlineNode, dataChildren[i]); } } @@ -208,20 +191,7 @@ namespace CSharpBinding.OutlinePad // Filter the children, for only the needed/wanted nodes var dataChildren = dataNode.Children.Where(v => AstNodeHelper.IsAllowedNode(v)).ToList(); foreach (var child in dataChildren) { -// if (AstNodeHelper.IsRegionStart(child)) { -// var regionNode = new CSharpOutlineNode(); -// SetNodeInfos(regionNode, node, child); -// node.Children.Add(regionNode); -// node = regionNode; -// continue; -// } -// if (AstNodeHelper.IsRegionEnd(child)) { -// node = node.Parent; -// continue; -// } - node.Children.Add(BuildNode(node, child)); - } return node; } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs index 2d77de1fd2..c279a61d53 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineNode.cs @@ -155,13 +155,13 @@ namespace CSharpBinding.OutlinePad } protected override void OnExpanding() { - var cmd = new HandleFoldingCommand(); + var cmd = new HandleFoldingCommand(); if (cmd.CanExecute(this)) cmd.Execute(this); } protected override void OnCollapsing() { - var cmd = new HandleFoldingCommand(); + var cmd = new HandleFoldingCommand(); if (cmd.CanExecute(this)) cmd.Execute(this); } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs index 0b62999986..46eab1fe14 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/ExtensionMethods.cs @@ -16,11 +16,11 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -namespace CSharpBinding.OutlinePad -{ - using System; - using ICSharpCode.NRefactory; +using System; +using ICSharpCode.NRefactory; +namespace CSharpBinding.OutlinePad +{ /// /// Description of TextLocationExtensions. /// From 4d9f1f2fbe2222e257a4b12cdf2dd4a8487bce75 Mon Sep 17 00:00:00 2001 From: JohnnyBravo75 Date: Wed, 30 Jul 2014 22:01:03 +0200 Subject: [PATCH 6/6] Current changes, to be in sync --- SharpDevelop.userprefs | 16 ++ .../Project/CSharpBinding.csproj | 5 - .../OutlinePad/CSharpOutlineContentHost.xaml | 2 +- .../OutlinePad/ExtensionMethods.cs | 51 ++++ .../XamlOutlineContentHost.xaml | 4 +- .../OutlinePad/XamlOutlineContentHost.xaml.cs | 263 ++++++++++++++++++ .../{ => OutlinePad}/XamlOutlineNode.cs | 22 +- .../XamlBinding/XamlBinding.csproj | 14 +- .../XamlOutlineContentHost.xaml.cs | 134 --------- .../Project/FormsDesigner.csproj | 1 - .../ICSharpCode.Reporting.csproj | 1 - 11 files changed, 361 insertions(+), 152 deletions(-) create mode 100644 SharpDevelop.userprefs create mode 100644 src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/ExtensionMethods.cs rename src/AddIns/BackendBindings/XamlBinding/XamlBinding/{ => OutlinePad}/XamlOutlineContentHost.xaml (75%) create mode 100644 src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineContentHost.xaml.cs rename src/AddIns/BackendBindings/XamlBinding/XamlBinding/{ => OutlinePad}/XamlOutlineNode.cs (83%) delete mode 100644 src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineContentHost.xaml.cs diff --git a/SharpDevelop.userprefs b/SharpDevelop.userprefs new file mode 100644 index 0000000000..80bb0c2385 --- /dev/null +++ b/SharpDevelop.userprefs @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index 00a094c92b..663ee85d07 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -256,11 +256,6 @@ ICSharpCode.SharpDevelop.Widgets False - - {8035765F-D51F-4A0C-A746-2FD100E19419} - ICSharpCode.SharpDevelop.Widgets - False - {9E951B9F-6AC2-4537-9D0B-0AE7C026D5A1} FormsDesigner diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml index bda20483ed..b8fa41b195 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OutlinePad/CSharpOutlineContentHost.xaml @@ -9,5 +9,5 @@ AllowDropOrder="True" MouseDoubleClick="TreeViewMouseDoubleClick" MouseLeftButtonUp="TreeView_MouseLeftButtonUp" - /> + /> \ No newline at end of file diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/ExtensionMethods.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/ExtensionMethods.cs new file mode 100644 index 0000000000..a8fdd936d5 --- /dev/null +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/ExtensionMethods.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory; + +namespace ICSharpCode.XamlBinding +{ + /// + /// Description of TextLocationExtensions. + /// + static class TextLocationExtensions { + + public static bool IsInfinite(this TextLocation location) { + return location == null || location.Line == int.MaxValue || location.Column == int.MaxValue; + } + + public static bool IsValid(this TextLocation location) { + if (location.IsEmpty) + return false; + if (location.IsInfinite()) + return false; + return true; + } + + public static bool IsInside(this TextLocation location, TextLocation startLocation, TextLocation endLocation) { + if (location.IsEmpty) + return false; + + return location.Line >= startLocation.Line && + (location.Line <= endLocation.Line || endLocation.Line == -1) && + (location.Line != startLocation.Line || location.Column >= startLocation.Column) && + (location.Line != endLocation.Line || location.Column <= endLocation.Column); + } + } +} diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineContentHost.xaml b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineContentHost.xaml similarity index 75% rename from src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineContentHost.xaml rename to src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineContentHost.xaml index 55d8591cd9..3a1d4b93b8 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineContentHost.xaml +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineContentHost.xaml @@ -7,5 +7,7 @@ x:Name="treeView" AllowDrop="True" AllowDropOrder="True" - MouseDoubleClick="TreeViewMouseDoubleClick" /> + MouseDoubleClick="TreeViewMouseDoubleClick" + MouseLeftButtonUp="TreeView_MouseLeftButtonUp" + /> \ No newline at end of file diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineContentHost.xaml.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineContentHost.xaml.cs new file mode 100644 index 0000000000..019358d61d --- /dev/null +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineContentHost.xaml.cs @@ -0,0 +1,263 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.IO; +using System.Linq; +using System.Windows.Controls; +using System.Windows.Forms; +using System.Windows.Input; +using System.Windows.Threading; +using ICSharpCode.Core; +using ICSharpCode.NRefactory.Xml; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Parser; +using ICSharpCode.NRefactory; + + +namespace ICSharpCode.XamlBinding +{ + /// + /// Interaction logic for XamlOutlineContentHost.xaml + /// + public partial class XamlOutlineContentHost : DockPanel, IOutlineContentHost, IDisposable + { + ITextEditor editor; + DispatcherTimer updateTreeTimer = new DispatcherTimer(); + const double updateDelayMilliseconds = 500; + DispatcherTimer scrollToNodeTimer = new DispatcherTimer(); + const double scrollDelayMilliseconds = 200; + AXmlDocument document; + TextLocation? lastCaretLocation; + XamlOutlineNode selectedNode = null; + const bool optionSelectActiveTreeNode = true; + const bool optionSelectRange = false; + + public XamlOutlineContentHost(ITextEditor editor) + { + this.editor = editor; + this.editor.Caret.LocationChanged += CaretLocationChanged; + + InitializeComponent(); + + SD.ParserService.ParseInformationUpdated += ParseInfoUpdated; + + this.updateTreeTimer.Interval = TimeSpan.FromMilliseconds(updateDelayMilliseconds); + this.updateTreeTimer.Tick += this.UpdateTreeTimer_Tick; + + this.scrollToNodeTimer.Interval = TimeSpan.FromMilliseconds(scrollDelayMilliseconds); + this.scrollToNodeTimer.Tick += this.ScrollToNodeTimer_Tick; + } + + void ParseInfoUpdated(object sender, ParseInformationEventArgs e) + { + if (this.editor == null || !FileUtility.IsEqualFileName(this.editor.FileName, e.FileName)) + return; + + var parseInfo = e.NewParseInformation as XamlFullParseInformation; + if (parseInfo != null && parseInfo.Document != null) { + this.updateTreeTimer.Stop(); + this.document = parseInfo.Document; + this.updateTreeTimer.Start(); + } + } + + void CaretLocationChanged(object sender, EventArgs e) + { + SelectActiveTreeNode(); + } + + void SelectActiveTreeNode() { + if (!optionSelectActiveTreeNode) + return; + // prevent unnecessary looping, when both CaretLocationChanged and ParseUpdateChanged are fired. + if (this.lastCaretLocation.HasValue && this.lastCaretLocation == this.editor.Caret.Location) + return; + + this.lastCaretLocation = this.editor.Caret.Location; + selectedNode = null; + FindNodeFromLocation(this.editor.Caret.Location, treeView.Root as XamlOutlineNode); + if (selectedNode != null && treeView.SelectedItem != selectedNode) { + treeView.SelectedItem = selectedNode; + if (!scrollToNodeTimer.IsEnabled) { + scrollToNodeTimer.Start(); + } + } + } + + bool IsRangeInside(TextLocation outerStartLocation, TextLocation outerEndLocation, + TextLocation innerStartLocation, TextLocation innerEndLocation) { + if (outerStartLocation.IsEmpty || outerStartLocation.IsInfinite() || + outerEndLocation.IsEmpty || outerEndLocation.IsInfinite() || + innerStartLocation.IsEmpty || innerStartLocation.IsInfinite() || + innerEndLocation.IsEmpty || innerEndLocation.IsInfinite()) + return false; + + const int virtualLineLength = 200; + var outerRange = (outerEndLocation.Line - outerStartLocation.Line) * virtualLineLength - outerStartLocation.Column + outerEndLocation.Column; + var innerRange = (innerEndLocation.Line - innerStartLocation.Line) * virtualLineLength - innerStartLocation.Column + innerEndLocation.Column; + return innerRange < outerRange; + } + + void FindNodeFromLocation(TextLocation location, XamlOutlineNode node) { + if (node == null) + return; + if (node.StartMarker.IsDeleted || node.EndMarker.IsDeleted) + return; + + if (location.IsInside(node.StartMarker.Location, node.EndMarker.Location) + && (selectedNode == null || IsRangeInside(selectedNode.StartLocation, selectedNode.EndLocation, + node.StartLocation, node.EndLocation))) { + selectedNode = node; + } + + foreach(var child in node.Children) { + FindNodeFromLocation(location, child as XamlOutlineNode); + } + } + + void UpdateTreeTimer_Tick(Object sender, EventArgs args) { + this.updateTreeTimer.Stop(); + this.UpdateTree(this.document); + this.SelectActiveTreeNode(); + } + + void ScrollToNodeTimer_Tick(Object sender, EventArgs args) { + this.scrollToNodeTimer.Stop(); + if (selectedNode != null) { + treeView.ScrollIntoView(selectedNode); + } + } + + void UpdateTree(AXmlDocument root) + { + if (treeView.Root == null) { + treeView.Root = new XamlOutlineNode { + ElementName = "Document Root", + Name = Path.GetFileName(editor.FileName), + Editor = editor + }; + } + + UpdateNode(treeView.Root as XamlOutlineNode, root); + } + + void UpdateNode(XamlOutlineNode node, AXmlObject dataNode) + { + if (dataNode == null || node == null) + return; + int textLength = Math.Max(editor.Document.TextLength - 1,0); + if (dataNode is AXmlElement) { + var item = (AXmlElement)dataNode; + node.Name = item.GetAttributeValue("Name") ?? item.GetAttributeValue(XamlConst.XamlNamespace, "Name"); + node.ElementName = item.Name; + } + node.StartMarker = editor.Document.CreateAnchor(Utils.MinMax(dataNode.StartOffset, 0, textLength)); + node.EndMarker = editor.Document.CreateAnchor(Utils.MinMax(dataNode.EndOffset, 0, textLength)); + node.StartLocation = new TextLocation(node.StartMarker.Line, node.StartMarker.Column); + node.EndLocation = new TextLocation(node.EndMarker.Line, node.EndMarker.Column); + + var dataChildren = dataNode.Children.OfType().ToList(); + + int childrenCount = node.Children.Count; + int dataCount = dataChildren.Count; + + for (int i = 0; i < Math.Max(childrenCount, dataCount); i++) { + if (i >= childrenCount) { + node.Children.Add(BuildNode(dataChildren[i])); + } else if (i >= dataCount) { + while (node.Children.Count > dataCount) + node.Children.RemoveAt(dataCount); + } else { + UpdateNode(node.Children[i] as XamlOutlineNode, dataChildren[i]); + } + } + } + + XamlOutlineNode BuildNode(AXmlElement item) + { + XamlOutlineNode node = new XamlOutlineNode { + Name = item.GetAttributeValue("Name") ?? item.GetAttributeValue(XamlConst.XamlNamespace, "Name"), + ElementName = item.Name, + StartMarker = editor.Document.CreateAnchor(Utils.MinMax(item.StartOffset, 0, editor.Document.TextLength - 1)), + EndMarker = editor.Document.CreateAnchor(Utils.MinMax(item.EndOffset, 0, editor.Document.TextLength - 1)), + Editor = editor, + XmlNodeItem = item + }; + + node.StartLocation = new TextLocation(node.StartMarker.Line, node.StartMarker.Column); + node.EndLocation = new TextLocation(node.EndMarker.Line, node.EndMarker.Column); + node.IsExpanded = true; + + foreach (var child in item.Children.OfType()) + node.Children.Add(BuildNode(child)); + + return node; + } + + void TreeView_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + var node = treeView.SelectedItem as XamlOutlineNode; + if (node == null) + return; + + if (optionSelectRange) + editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset); + FileService.JumpToFilePosition(this.editor.FileName, node.StartMarker.Line, node.StartMarker.Column); + } + + void TreeViewMouseDoubleClick(object sender, MouseButtonEventArgs e) + { +// XamlOutlineNode node = treeView.SelectedItem as XamlOutlineNode; +// if (node == null) return; +// editor.Select(node.StartMarker.Offset, node.EndMarker.Offset - node.StartMarker.Offset); + } + + public object OutlineContent { + get { return this; } + } + + public void Dispose() { + SD.ParserService.ParseInformationUpdated -= ParseInfoUpdated; + + if (this.editor != null) { + if (this.editor.Caret != null) + this.editor.Caret.LocationChanged -= CaretLocationChanged; + this.editor = null; + } + + this.document = null; + this.lastCaretLocation = null; + this.selectedNode = null; + + if (this.updateTreeTimer != null) { + this.updateTreeTimer.Stop(); + this.updateTreeTimer.Tick -= this.UpdateTreeTimer_Tick; + this.updateTreeTimer = null; + } + + if (this.scrollToNodeTimer != null) { + this.scrollToNodeTimer.Stop(); + this.scrollToNodeTimer.Tick -= this.ScrollToNodeTimer_Tick; + this.scrollToNodeTimer = null; + } + } + } +} diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineNode.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineNode.cs similarity index 83% rename from src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineNode.cs rename to src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineNode.cs index 495b3a533e..2224a8bf3c 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineNode.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/OutlinePad/XamlOutlineNode.cs @@ -24,6 +24,8 @@ using ICSharpCode.NRefactory.Editor; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.TreeView; +using ICSharpCode.NRefactory.Xml; +using ICSharpCode.NRefactory; namespace ICSharpCode.XamlBinding { @@ -47,13 +49,20 @@ namespace ICSharpCode.XamlBinding } } - public ITextAnchor Marker { get; set; } + public override object ToolTip { + get { return this.GetSourceText(); } + } + + public ITextAnchor StartMarker { get; set; } public ITextAnchor EndMarker { get; set; } public ITextEditor Editor { get; set; } + public AXmlElement XmlNodeItem { get; set; } + public TextLocation StartLocation { get; set; } + public TextLocation EndLocation { get; set; } public string GetMarkupText() { - return Editor.Document.GetText(Marker.Offset, EndMarker.Offset - Marker.Offset); + return Editor.Document.GetText(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset); } protected override IDataObject GetDataObject(SharpTreeNode[] nodes) @@ -96,6 +105,13 @@ namespace ICSharpCode.XamlBinding // } // } + public string GetSourceText() { + if (StartMarker.IsDeleted || EndMarker.IsDeleted) + return string.Empty; + + return Editor.Document.GetText(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset); + } + public override bool CanDelete(SharpTreeNode[] nodes) { return nodes.OfType().All(n => n.Parent != null); @@ -115,7 +131,7 @@ namespace ICSharpCode.XamlBinding void DeleteCore() { - Editor.Document.Remove(Marker.Offset, EndMarker.Offset - Marker.Offset); + Editor.Document.Remove(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset); } public override object Text { diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj index b42dc3f77d..6d36e9c995 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj @@ -66,6 +66,12 @@ + + + XamlOutlineContentHost.xaml + Code + + @@ -109,11 +115,6 @@ - - XamlOutlineContentHost.xaml - Code - - {53DCA265-3C3C-42F9-B647-F72BA678122B} @@ -172,10 +173,11 @@ + - + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineContentHost.xaml.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineContentHost.xaml.cs deleted file mode 100644 index dc8fb4c0b3..0000000000 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineContentHost.xaml.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.IO; -using System.Linq; -using System.Windows.Controls; -using System.Windows.Input; - -using ICSharpCode.Core; -using ICSharpCode.NRefactory.Xml; -using ICSharpCode.SharpDevelop; -using ICSharpCode.SharpDevelop.Editor; -using ICSharpCode.SharpDevelop.Gui; -using ICSharpCode.SharpDevelop.Parser; - -namespace ICSharpCode.XamlBinding -{ - /// - /// Interaction logic for XamlOutlineContentHost.xaml - /// - public partial class XamlOutlineContentHost : DockPanel, IOutlineContentHost, IDisposable - { - ITextEditor editor; - - public XamlOutlineContentHost(ITextEditor editor) - { - this.editor = editor; - - InitializeComponent(); - - SD.ParserService.ParseInformationUpdated += ParseInfoUpdated; - } - - void ParseInfoUpdated(object sender, ParseInformationEventArgs e) - { - if (this.editor == null || !FileUtility.IsEqualFileName(this.editor.FileName, e.FileName)) - return; - - var parseInfo = e.NewParseInformation as XamlFullParseInformation; - if (parseInfo != null && parseInfo.Document != null) - UpdateTree(parseInfo.Document); - } - - void UpdateTree(AXmlDocument root) - { - if (treeView.Root == null) { - treeView.Root = new XamlOutlineNode { - ElementName = "Document Root", - Name = Path.GetFileName(editor.FileName), - Editor = editor - }; - } - - UpdateNode(treeView.Root as XamlOutlineNode, root); - } - - void UpdateNode(XamlOutlineNode node, AXmlObject dataNode) - { - if (dataNode == null || node == null) - return; - if (dataNode is AXmlElement) { - var item = (AXmlElement)dataNode; - node.Name = item.GetAttributeValue("Name") ?? item.GetAttributeValue(XamlConst.XamlNamespace, "Name"); - node.ElementName = item.Name; - } - node.Marker = editor.Document.CreateAnchor(Utils.MinMax(dataNode.StartOffset, 0, editor.Document.TextLength)); - node.EndMarker = editor.Document.CreateAnchor(Utils.MinMax(dataNode.EndOffset, 0, editor.Document.TextLength)); - - var dataChildren = dataNode.Children.OfType().ToList(); - - int childrenCount = node.Children.Count; - int dataCount = dataChildren.Count; - - for (int i = 0; i < Math.Max(childrenCount, dataCount); i++) { - if (i >= childrenCount) { - node.Children.Add(BuildNode(dataChildren[i])); - } else if (i >= dataCount) { - while (node.Children.Count > dataCount) - node.Children.RemoveAt(dataCount); - } else { - UpdateNode(node.Children[i] as XamlOutlineNode, dataChildren[i]); - } - } - } - - XamlOutlineNode BuildNode(AXmlElement item) - { - XamlOutlineNode node = new XamlOutlineNode { - Name = item.GetAttributeValue("Name") ?? item.GetAttributeValue(XamlConst.XamlNamespace, "Name"), - ElementName = item.Name, - Marker = editor.Document.CreateAnchor(Utils.MinMax(item.StartOffset, 0, editor.Document.TextLength - 1)), - EndMarker = editor.Document.CreateAnchor(Utils.MinMax(item.EndOffset, 0, editor.Document.TextLength - 1)), - Editor = editor - }; - - foreach (var child in item.Children.OfType()) - node.Children.Add(BuildNode(child)); - - return node; - } - - void TreeViewMouseDoubleClick(object sender, MouseButtonEventArgs e) - { - XamlOutlineNode node = treeView.SelectedItem as XamlOutlineNode; - if (node == null) return; - editor.Select(node.Marker.Offset, node.EndMarker.Offset - node.Marker.Offset); - } - - public object OutlineContent { - get { return this; } - } - - public void Dispose() - { - SD.ParserService.ParseInformationUpdated -= ParseInfoUpdated; - } - } -} diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj b/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj index 366aa3a811..1b41ab422d 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/FormsDesigner.csproj @@ -54,7 +54,6 @@ - diff --git a/src/AddIns/Misc/Reporting/ICSharpCode.Reporting/ICSharpCode.Reporting.csproj b/src/AddIns/Misc/Reporting/ICSharpCode.Reporting/ICSharpCode.Reporting.csproj index 707962a862..0ec76d2f32 100644 --- a/src/AddIns/Misc/Reporting/ICSharpCode.Reporting/ICSharpCode.Reporting.csproj +++ b/src/AddIns/Misc/Reporting/ICSharpCode.Reporting/ICSharpCode.Reporting.csproj @@ -198,7 +198,6 @@ -