11 changed files with 361 additions and 152 deletions
@ -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,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 @@ |
|||||||
|
// 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 @@ |
|||||||
// 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