21 changed files with 1651 additions and 151 deletions
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
<Properties> |
||||
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" /> |
||||
<MonoDevelop.Ide.Workbench ActiveDocument="src\Libraries\NRefactory\ICSharpCode.NRefactory.CSharp\IndentEngine\IndentState.cs"> |
||||
<Files> |
||||
<File FileName="src\AddIns\BackendBindings\CSharpBinding\Project\Src\OutlinePad\AstNodeHelper.cs" Line="35" Column="51" /> |
||||
<File FileName="src\AddIns\BackendBindings\CSharpBinding\Project\Src\OutlinePad\CSharpOutlineContentHost.xaml.cs" Line="49" Column="3" /> |
||||
<File FileName="src\AddIns\BackendBindings\CSharpBinding\Project\Src\OutlinePad\CSharpOutlineContentHost.xaml" Line="8" Column="8" /> |
||||
<File FileName="src\AddIns\BackendBindings\CSharpBinding\Project\Src\OutlinePad\CSharpOutlineNode.cs" Line="121" Column="5" /> |
||||
<File FileName="src\Libraries\NRefactory\ICSharpCode.NRefactory.CSharp\IndentEngine\IndentState.cs" Line="1703" Column="5" /> |
||||
</Files> |
||||
</MonoDevelop.Ide.Workbench> |
||||
<MonoDevelop.Ide.DebuggingService.Breakpoints> |
||||
<BreakpointStore /> |
||||
</MonoDevelop.Ide.DebuggingService.Breakpoints> |
||||
<MonoDevelop.Ide.DebuggingService.PinnedWatches /> |
||||
</Properties> |
@ -0,0 +1,544 @@
@@ -0,0 +1,544 @@
|
||||
// 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; |
||||
using System.Windows.Media; |
||||
using System.Text; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using ICSharpCode.AvalonEdit.Highlighting; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace CSharpBinding.OutlinePad |
||||
{ |
||||
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<ParameterDeclaration> 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<TypeParameterDeclaration> 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.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); |
||||
} |
||||
|
||||
internal static void SetRegionEndInfos(CSharpOutlineNode node, AstNode dataNode) { |
||||
var preProcessorNode = (PreProcessorDirective)dataNode; |
||||
node.Name = "********************"; |
||||
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.Name = 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.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;
|
||||
|
||||
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.Name = 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.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"; |
||||
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.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;
|
||||
|
||||
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.Name = (varInitializer != null) |
||||
? varInitializer.Name |
||||
: "<unknown>"; |
||||
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.Name = typeNode.Name; |
||||
node.IsExpanded = true; |
||||
|
||||
if (colorizeNode) |
||||
node.ForegroundBrush = (interfaceHighLighting.Foreground as SimpleHighlightingBrush).GetBrush(null); |
||||
|
||||
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.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"; |
||||
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.Name = methodNode.Name; |
||||
|
||||
node.Name += " " |
||||
+ 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.Name = 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.Name = propertyNode.Name; |
||||
|
||||
if (colorizeNode) |
||||
node.ForegroundBrush = Brushes.Black; |
||||
|
||||
if (showExtendedInfos) { |
||||
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"; |
||||
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.Name = indexerNode.ReturnType.ToString() |
||||
+ " " |
||||
+ indexerNode.ThisToken.ToString() |
||||
+ indexerNode.LBracketToken |
||||
+ GetParameterDeclsAsString(indexerNode.Parameters) |
||||
+ indexerNode.RBracketToken; |
||||
if (colorizeNode) |
||||
node.ForegroundBrush = Brushes.Black; |
||||
|
||||
if (showExtendedInfos) { |
||||
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: |
||||
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.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;
|
||||
} |
||||
|
||||
public static bool IsConstructor(AstNode node) { |
||||
return (node is ConstructorDeclaration); |
||||
} |
||||
|
||||
internal static void SetConstructorNodeInfos(CSharpOutlineNode node, AstNode dataNode) { |
||||
var constructorNode = (ConstructorDeclaration)dataNode; |
||||
node.Name = constructorNode.Name; |
||||
|
||||
if (colorizeNode) |
||||
node.ForegroundBrush = Brushes.Black; |
||||
|
||||
node.Name += " " |
||||
+ 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.Name = Path.GetFileName(((SyntaxTree)dataNode).FileName); |
||||
node.IconName = "C#.File.FullFile"; |
||||
node.IsExpanded = true; |
||||
node.Weight = FontWeights.Bold; |
||||
|
||||
if (colorizeNode) |
||||
node.ForegroundBrush = Brushes.Black; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,128 @@
@@ -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.
|
||||
|
||||
using System; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.AvalonEdit.Folding; |
||||
using System.Linq; |
||||
|
||||
namespace CSharpBinding.OutlinePad |
||||
{ |
||||
/// <summary>
|
||||
/// RemoveNodeCommand.
|
||||
/// </summary>
|
||||
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); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// SelectRegionCommand.
|
||||
/// </summary>
|
||||
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); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// HandleFoldingCommand
|
||||
/// </summary>
|
||||
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; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
<DockPanel x:Class="CSharpBinding.OutlinePad.CSharpOutlineContentHost" |
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
xmlns:treeview="http://icsharpcode.net/sharpdevelop/treeview" |
||||
> |
||||
<treeview:SharpTreeView |
||||
x:Name="treeView" |
||||
AllowDrop="True" |
||||
AllowDropOrder="True" |
||||
MouseDoubleClick="TreeViewMouseDoubleClick" |
||||
MouseLeftButtonUp="TreeView_MouseLeftButtonUp" |
||||
/> |
||||
</DockPanel> |
@ -0,0 +1,323 @@
@@ -0,0 +1,323 @@
|
||||
// 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 System.Windows.Threading; |
||||
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; |
||||
|
||||
namespace CSharpBinding.OutlinePad |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for CSharpOutlineContentHost.xaml
|
||||
/// </summary>
|
||||
public partial class CSharpOutlineContentHost : DockPanel, IOutlineContentHost, IDisposable |
||||
{ |
||||
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; |
||||
const bool optionSelectActiveTreeNode = true; |
||||
const 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(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 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; |
||||
|
||||
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) { |
||||
node.Children.Add(BuildNode(node, dataChildren[i])); |
||||
|
||||
} else if (i >= dataCount) { |
||||
while (node.Children.Count > dataCount) |
||||
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]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
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) { |
||||
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; |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,169 @@
@@ -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.Core.Presentation; |
||||
using System.Windows.Controls; |
||||
|
||||
namespace CSharpBinding.OutlinePad |
||||
{ |
||||
class CSharpOutlineNode : SharpTreeNode |
||||
{ |
||||
string name, iconName; |
||||
|
||||
public string Name { |
||||
get { return name; } |
||||
set { |
||||
if (this.name != value) { |
||||
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 { |
||||
if (iconName != value) { |
||||
iconName = value; |
||||
this.RaisePropertyChanged("Icon"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
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<CSharpOutlineNode>().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<CSharpOutlineNode>()) { |
||||
CSharpNode.DeleteCore(); |
||||
} |
||||
} |
||||
|
||||
void DeleteCore() |
||||
{ |
||||
Editor.Document.Remove(StartMarker.Offset, EndMarker.Offset - StartMarker.Offset); |
||||
} |
||||
|
||||
public override object Text { |
||||
get { return Name; } |
||||
} |
||||
|
||||
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 { |
||||
if (weight != value) { |
||||
weight = value; |
||||
RaisePropertyChanged("FontWeight"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
FontStyle style = FontStyles.Normal; |
||||
public FontStyle Style { |
||||
get { |
||||
return style; |
||||
} |
||||
set { |
||||
if (style != value) { |
||||
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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,51 @@
@@ -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 CSharpBinding.OutlinePad |
||||
{ |
||||
/// <summary>
|
||||
/// Description of TextLocationExtensions.
|
||||
/// </summary>
|
||||
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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,51 @@
@@ -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 |
||||
{ |
||||
/// <summary>
|
||||
/// Description of TextLocationExtensions.
|
||||
/// </summary>
|
||||
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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,263 @@
@@ -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 |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for XamlOutlineContentHost.xaml
|
||||
/// </summary>
|
||||
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<AXmlElement>().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<AXmlElement>()) |
||||
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; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,134 +0,0 @@
@@ -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 |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for XamlOutlineContentHost.xaml
|
||||
/// </summary>
|
||||
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<AXmlElement>().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<AXmlElement>()) |
||||
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; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue