Browse Source

Added an XPath Query pad - can be used to run xpaths on the active XML document and highlights the resulting matches.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1662 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 19 years ago
parent
commit
6052f22389
  1. 1
      data/resources/image/BitmapResources/BitmapResources.res
  2. BIN
      data/resources/image/BitmapResources/PadIcons/XPathQuery.png
  3. 3
      data/resources/layouts/Debug.xml
  4. 3
      data/resources/layouts/Default.xml
  5. 3
      data/resources/layouts/Plain.xml
  6. 5
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/AssignStylesheetCommand.cs
  7. 2
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/CreateSchemaCommand.cs
  8. 2
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/FormatXmlCommand.cs
  9. 2
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/OpenStylesheetCommand.cs
  10. 25
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/RemoveXPathHighlightingCommand.cs
  11. 2
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/RunXslTransformCommand.cs
  12. 2
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/ValidateXmlCommand.cs
  13. 167
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathNodeMatch.cs
  14. 59
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathNodeTextMarker.cs
  15. 659
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathQueryControl.cs
  16. 68
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathQueryPad.cs
  17. 66
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlNamespace.cs
  18. 103
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs
  19. 23
      src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.addin
  20. 6
      src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj
  21. 276
      src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockDocument.cs
  22. 85
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/GetNamespacesFromListViewTestFixture.cs
  23. 56
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/NamespaceGridColumnWidthsLoadedTestFixture.cs
  24. 60
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/NamespacePropertiesLoaded.cs
  25. 62
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/NamespacePropertiesSaved.cs
  26. 175
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/RunXPathQueryTests.cs
  27. 105
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XPathNodeTextMarkerTests.cs
  28. 93
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XPathQueryHistoryTestFixture.cs
  29. 74
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XPathResultsListViewColumnWidthsTestFixture.cs
  30. 25
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XmlNamespaceTests.cs
  31. 56
      src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XmlNamespaceToStringTests.cs
  32. 20
      src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj
  33. BIN
      src/Main/StartUp/Project/Resources/BitmapResources.resources

1
data/resources/image/BitmapResources/BitmapResources.res

@ -245,6 +245,7 @@ PadIcons.LoadedModules = PadIcons\LoadedModules.png @@ -245,6 +245,7 @@ PadIcons.LoadedModules = PadIcons\LoadedModules.png
PadIcons.LocalVariables = PadIcons\LocalVariables.png
PadIcons.Threads = PadIcons\Threads.png
PadIcons.Exceptions = PadIcons\Exceptions.png
PadIcons.XPathQuery = PadIcons\XPathQuery.png
#SharpQuery icons
Icons.16x16.SharpQuery.DataBaseRoot = SharpQueryIcons\Icons.16x16.SharpQuery.Database.png

BIN
data/resources/image/BitmapResources/PadIcons/XPathQuery.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

3
data/resources/layouts/Debug.xml

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<!-- DockPanel configuration file. Author: Weifen Luo, all rights reserved. -->
<!-- !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!! -->
<DockPanel FormatVersion="1.0" DockLeftPortion="0.196180555555556" DockRightPortion="0.172743055555556" DockTopPortion="0.25" DockBottomPortion="0.25" ActiveDocumentPane="-1" ActivePane="0">
<Contents Count="30">
<Contents Count="31">
<Content ID="0" PersistString="ICSharpCode.SharpDevelop.Project.ProjectBrowserPad" AutoHidePortion="0.25" IsHidden="False" IsFloat="False" />
<Content ID="1" PersistString="ICSharpCode.SharpDevelop.Gui.ClassBrowser" AutoHidePortion="0.25" IsHidden="False" IsFloat="False" />
<Content ID="2" PersistString="ICSharpCode.SharpDevelop.Gui.SideBarView" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
<Content ID="27" PersistString="ICSharpCode.UnitTesting.PadContent" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="28" PersistString="ICSharpCode.WixBinding.SetupDialogListPad" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="29" PersistString="SharpDbTools.ServerBrowserTool" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="30" PersistString="ICSharpCode.XmlEditor.XPathQueryPad" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
</Contents>
<Panes Count="7">
<Pane ID="0" DockState="DockLeft" ActiveContent="0">

3
data/resources/layouts/Default.xml

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<!-- DockPanel configuration file. Author: Weifen Luo, all rights reserved. -->
<!-- !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!! -->
<DockPanel FormatVersion="1.0" DockLeftPortion="0.196180555555556" DockRightPortion="0.172743055555556" DockTopPortion="0.25" DockBottomPortion="0.25" ActiveDocumentPane="-1" ActivePane="-1">
<Contents Count="30">
<Contents Count="31">
<Content ID="0" PersistString="ICSharpCode.SharpDevelop.Project.ProjectBrowserPad" AutoHidePortion="0.25" IsHidden="False" IsFloat="False" />
<Content ID="1" PersistString="ICSharpCode.SharpDevelop.Gui.ClassBrowser" AutoHidePortion="0.25" IsHidden="False" IsFloat="False" />
<Content ID="2" PersistString="ICSharpCode.SharpDevelop.Gui.SideBarView" AutoHidePortion="0.25" IsHidden="False" IsFloat="False" />
@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
<Content ID="27" PersistString="ICSharpCode.UnitTesting.PadContent" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="28" PersistString="ICSharpCode.WixBinding.SetupDialogListPad" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="29" PersistString="SharpDbTools.ServerBrowserTool" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="30" PersistString="ICSharpCode.XmlEditor.XPathQueryPad" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
</Contents>
<Panes Count="5">
<Pane ID="0" DockState="DockRight" ActiveContent="6">

3
data/resources/layouts/Plain.xml

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<!-- DockPanel configuration file. Author: Weifen Luo, all rights reserved. -->
<!-- !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!! -->
<DockPanel FormatVersion="1.0" DockLeftPortion="0.196180555555556" DockRightPortion="0.172743055555556" DockTopPortion="0.25" DockBottomPortion="0.25" ActiveDocumentPane="-1" ActivePane="-1">
<Contents Count="30">
<Contents Count="31">
<Content ID="0" PersistString="ICSharpCode.SharpDevelop.Project.ProjectBrowserPad" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="1" PersistString="ICSharpCode.SharpDevelop.Gui.ClassBrowser" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="2" PersistString="ICSharpCode.SharpDevelop.Gui.SideBarView" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
<Content ID="27" PersistString="ICSharpCode.UnitTesting.PadContent" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="28" PersistString="ICSharpCode.WixBinding.SetupDialogListPad" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="29" PersistString="SharpDbTools.ServerBrowserTool" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
<Content ID="30" PersistString="ICSharpCode.XmlEditor.XPathQueryPad" AutoHidePortion="0.25" IsHidden="True" IsFloat="False" />
</Contents>
<Panes Count="5">
<Pane ID="0" DockState="DockRight" ActiveContent="-1">

5
src/AddIns/DisplayBindings/XmlEditor/Project/Src/AssignStylesheetCommand.cs

@ -23,7 +23,7 @@ namespace ICSharpCode.XmlEditor @@ -23,7 +23,7 @@ namespace ICSharpCode.XmlEditor
public override void Run()
{
// Get active xml document.
XmlView xmlView = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as XmlView;
XmlView xmlView = XmlView.ActiveXmlView;
if (xmlView != null) {
// Prompt user for filename.
@ -38,8 +38,7 @@ namespace ICSharpCode.XmlEditor @@ -38,8 +38,7 @@ namespace ICSharpCode.XmlEditor
public static string BrowseForStylesheetFile()
{
using (OpenFileDialog dialog = new OpenFileDialog())
{
using (OpenFileDialog dialog = new OpenFileDialog()) {
dialog.AddExtension = true;
dialog.Multiselect = false;
dialog.CheckFileExists = true;

2
src/AddIns/DisplayBindings/XmlEditor/Project/Src/CreateSchemaCommand.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.XmlEditor @@ -30,7 +30,7 @@ namespace ICSharpCode.XmlEditor
public override void Run()
{
// Find active XmlView.
XmlView xmlView = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as XmlView;
XmlView xmlView = XmlView.ActiveXmlView;
if (xmlView != null) {
// Create a schema based on the xml.

2
src/AddIns/DisplayBindings/XmlEditor/Project/Src/FormatXmlCommand.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.XmlEditor @@ -20,7 +20,7 @@ namespace ICSharpCode.XmlEditor
public override void Run()
{
// Find active XmlView.
XmlView xmlView = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as XmlView;
XmlView xmlView = XmlView.ActiveXmlView;
if (xmlView != null) {
xmlView.FormatXml();
}

2
src/AddIns/DisplayBindings/XmlEditor/Project/Src/OpenStylesheetCommand.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.XmlEditor @@ -20,7 +20,7 @@ namespace ICSharpCode.XmlEditor
{
public override void Run()
{
XmlView xmlView = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as XmlView;
XmlView xmlView = XmlView.ActiveXmlView;
if (xmlView != null) {
if (xmlView.StylesheetFileName != null) {
try {

25
src/AddIns/DisplayBindings/XmlEditor/Project/Src/RemoveXPathHighlightingCommand.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.XmlEditor
{
public class RemoveXPathHighlightingCommand : AbstractMenuCommand
{
public override void Run()
{
XPathQueryPad pad = XPathQueryPad.Instance;
if (pad != null) {
pad.RemoveXPathHighlighting();
}
}
}
}

2
src/AddIns/DisplayBindings/XmlEditor/Project/Src/RunXslTransformCommand.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.XmlEditor @@ -27,7 +27,7 @@ namespace ICSharpCode.XmlEditor
/// </summary>
public override void Run()
{
XmlView xmlView = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as XmlView;
XmlView xmlView = XmlView.ActiveXmlView;
if (xmlView != null) {
if (xmlView is XslOutputView) {

2
src/AddIns/DisplayBindings/XmlEditor/Project/Src/ValidateXmlCommand.cs

@ -24,7 +24,7 @@ namespace ICSharpCode.XmlEditor @@ -24,7 +24,7 @@ namespace ICSharpCode.XmlEditor
public override void Run()
{
// Find active XmlView.
XmlView xmlView = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as XmlView;
XmlView xmlView = XmlView.ActiveXmlView;
if (xmlView != null) {
// Validate the xml.
xmlView.ValidateXml();

167
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathNodeMatch.cs

@ -0,0 +1,167 @@ @@ -0,0 +1,167 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Xml;
using System.Xml.XPath;
namespace ICSharpCode.XmlEditor
{
/// <summary>
/// Stores an XmlNode and its associated line number and position after an
/// XPath query has been evaluated.
/// </summary>
public class XPathNodeMatch : IXmlLineInfo
{
int? lineNumber;
int linePosition;
string value;
string displayValue;
XPathNodeType nodeType;
/// <summary>
/// Creates an XPathNodeMatch from the navigator which should be position on the
/// node.
/// </summary>
/// <remarks>
/// We deliberately use the OuterXml when we find a Namespace since the
/// navigator location returned starts from the xmlns attribute.
/// </remarks>
public XPathNodeMatch(XPathNavigator currentNavigator)
{
SetLineNumbers(currentNavigator as IXmlLineInfo);
nodeType = currentNavigator.NodeType;
switch (nodeType) {
case XPathNodeType.Text:
SetTextValue(currentNavigator);
break;
case XPathNodeType.Comment:
SetCommentValue(currentNavigator);
break;
case XPathNodeType.Namespace:
SetNamespaceValue(currentNavigator);
break;
case XPathNodeType.Element:
SetElementValue(currentNavigator);
break;
case XPathNodeType.ProcessingInstruction:
SetProcessingInstructionValue(currentNavigator);
break;
case XPathNodeType.Attribute:
SetAttributeValue(currentNavigator);
break;
default:
value = currentNavigator.LocalName;
displayValue = value;
break;
}
}
/// <summary>
/// Line numbers are zero based.
/// </summary>
public int LineNumber {
get {
return lineNumber.GetValueOrDefault(0);
}
}
/// <summary>
/// Line positions are zero based.
/// </summary>
public int LinePosition {
get {
return linePosition;
}
}
public bool HasLineInfo()
{
return lineNumber.HasValue;
}
/// <summary>
/// Gets the text value of the node.
/// </summary>
public string Value {
get {
return value;
}
}
/// <summary>
/// Gets the node display value. This includes the angle brackets if it is
/// an element, for example.
/// </summary>
public string DisplayValue {
get {
return displayValue;
}
}
public XPathNodeType NodeType {
get {
return nodeType;
}
}
void SetElementValue(XPathNavigator navigator)
{
value = navigator.Name;
if (navigator.IsEmptyElement) {
displayValue = String.Concat("<", value, "/>");
} else {
displayValue = String.Concat("<", value, ">");
}
}
void SetTextValue(XPathNavigator navigator)
{
value = navigator.Value;
displayValue = value;
}
void SetCommentValue(XPathNavigator navigator)
{
value = navigator.Value;
displayValue = navigator.OuterXml;
}
void SetNamespaceValue(XPathNavigator navigator)
{
value = navigator.OuterXml;
displayValue = value;
}
void SetProcessingInstructionValue(XPathNavigator navigator)
{
value = navigator.Name;
displayValue = navigator.OuterXml;
}
void SetAttributeValue(XPathNavigator navigator)
{
value = navigator.Name;
displayValue = String.Concat("@", value);
}
/// <summary>
/// Takes one of the xml line number so the numbers are now zero
/// based instead of one based.
/// </summary>
/// <remarks>A namespace query (e.g. //namespace::*) will return
/// a line info of -1, -1 for the xml namespace. Which looks like
/// a bug in the XPathDocument class.</remarks>
void SetLineNumbers(IXmlLineInfo lineInfo)
{
if (lineInfo.HasLineInfo() && lineInfo.LineNumber > 0) {
lineNumber = lineInfo.LineNumber - 1;
linePosition = lineInfo.LinePosition - 1;
}
}
}
}

59
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathNodeTextMarker.cs

@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.TextEditor.Document;
using System;
using System.Drawing;
namespace ICSharpCode.XmlEditor
{
/// <summary>
/// A text marker for an XPath query match.
/// </summary>
public class XPathNodeTextMarker : TextMarker
{
public static readonly Color MarkerBackColor = Color.FromArgb(159, 255, 162);
public XPathNodeTextMarker(int offset, XPathNodeMatch node) : base(offset, node.Value.Length, TextMarkerType.SolidBlock, MarkerBackColor)
{
}
/// <summary>
/// Adds markers for each XPathNodeMatch.
/// </summary>
public static void AddMarkers(MarkerStrategy markerStrategy, XPathNodeMatch[] nodes)
{
foreach (XPathNodeMatch node in nodes) {
AddMarker(markerStrategy, node);
}
}
/// <summary>
/// Adds a single marker for the XPathNodeMatch.
/// </summary>
public static void AddMarker(MarkerStrategy markerStrategy, XPathNodeMatch node)
{
if (node.HasLineInfo() && node.Value.Length > 0) {
LineSegment lineSegment = markerStrategy.Document.GetLineSegment(node.LineNumber);
markerStrategy.AddMarker(new XPathNodeTextMarker(lineSegment.Offset + node.LinePosition, node));
}
}
/// <summary>
/// Removes all the XPathNodeMarkers from the marker strategy.
/// </summary>
public static void RemoveMarkers(MarkerStrategy markerStrategy)
{
markerStrategy.RemoveAll(IsXPathNodeTextMarkerMatch);
}
static bool IsXPathNodeTextMarkerMatch(TextMarker marker)
{
return marker is XPathNodeTextMarker;
}
}
}

659
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathQueryControl.cs

@ -0,0 +1,659 @@ @@ -0,0 +1,659 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor.Document;
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
namespace ICSharpCode.XmlEditor
{
public class XPathQueryControl : System.Windows.Forms.UserControl, IMementoCapable
{
const int ErrorImageIndex = 0;
const string NamespacesProperty = "Namespaces";
const string PrefixColumnWidthProperty = "NamespacesDataGridView.PrefixColumn.Width";
const string MatchColumnWidthProperty = "XPathResultsListView.MatchColumn.Width";
const string LineColumnWidthProperty = "XPathResultsListView.LineColumn.Width";
const string XPathComboBoxTextProperty = "XPathQuery.LastQuery";
const string XPathComboBoxItemsProperty = "XPathQuery.History";
/// <summary>
/// The filename that the last query was executed on.
/// </summary>
string fileName = String.Empty;
/// <summary>
/// The total number of xpath queries to remember.
/// </summary>
const int xpathQueryHistoryLimit = 5;
bool ignoreXPathTextChanges;
enum MoveCaret {
ByJumping = 1,
ByScrolling = 2
}
public XPathQueryControl()
{
InitializeComponent();
InitImageList();
xPathComboBox.KeyDown += XPathComboBoxKeyDown;
InitAutoCompleteMode();
}
/// <summary>
/// Adds a namespace to the namespace list.
/// </summary>
public void AddNamespace(string prefix, string uri)
{
namespacesDataGridView.Rows.Add(new object[] {prefix, uri});
}
/// <summary>
/// Gets the list of namespaces in the namespace list.
/// </summary>
public ReadOnlyCollection<XmlNamespace> GetNamespaces()
{
List<XmlNamespace> namespaces = new List<XmlNamespace>();
for (int i = 0; i < namespacesDataGridView.Rows.Count - 1; ++i) {
DataGridViewRow row = namespacesDataGridView.Rows[i];
string prefix = GetPrefix(row);
string uri = GetNamespace(row);
if (prefix.Length == 0 && uri.Length == 0) {
// Ignore.
} else {
namespaces.Add(new XmlNamespace(prefix, uri));
}
}
return new ReadOnlyCollection<XmlNamespace>(namespaces);
}
public DataGridView NamespacesDataGridView {
get {
return namespacesDataGridView;
}
}
public ListView XPathResultsListView {
get {
return xPathResultsListView;
}
}
public ComboBox XPathComboBox {
get {
return xPathComboBox;
}
}
/// <summary>
/// Creates a properties object that contains the current state of the
/// control.
/// </summary>
public Properties CreateMemento()
{
Properties properties = new Properties();
// Save namespaces.
properties.Set(NamespacesProperty, GetNamespaceStringArray());
// Save namespace data grid column widths.
properties.Set<int>(PrefixColumnWidthProperty, prefixColumn.Width);
// Save xpath results list view column widths.
properties.Set<int>(MatchColumnWidthProperty, matchColumnHeader.Width);
properties.Set<int>(LineColumnWidthProperty, lineColumnHeader.Width);
// Save xpath query history.
properties.Set(XPathComboBoxTextProperty, XPathComboBox.Text);
properties.Set(XPathComboBoxItemsProperty, GetXPathHistory());
return properties;
}
/// <summary>
/// Reloads the state of the control.
/// </summary>
public void SetMemento(Properties memento)
{
ignoreXPathTextChanges = true;
try {
// Set namespaces.
string[] namespaces = memento.Get(NamespacesProperty, new string[0]);
foreach (string ns in namespaces) {
XmlNamespace xmlNamespace = XmlNamespace.FromString(ns);
AddNamespace(xmlNamespace.Prefix, xmlNamespace.Uri);
}
// Set namespace data grid column widths.
prefixColumn.Width = memento.Get<int>(PrefixColumnWidthProperty, 50);
// Set xpath results list view column widths.
matchColumnHeader.Width = memento.Get<int>(MatchColumnWidthProperty, 432);
lineColumnHeader.Width = memento.Get<int>(LineColumnWidthProperty, 60);
// Set xpath query history.
XPathComboBox.Text = memento.Get(XPathComboBoxTextProperty, String.Empty);
string[] xpaths = memento.Get(XPathComboBoxItemsProperty, new string[0]);
foreach (string xpath in xpaths) {
xPathComboBox.Items.Add(xpath);
}
} finally {
ignoreXPathTextChanges = false;
}
}
/// <summary>
/// Called when the active workbench window has changed.
/// </summary>
public void ActiveWindowChanged()
{
UpdateQueryButtonState();
}
/// <summary>
/// Removes all the XPath Node markers from all the open documents.
/// </summary>
public void RemoveXPathNodeTextMarkers()
{
foreach (IViewContent view in WorkbenchSingleton.Workbench.ViewContentCollection) {
ITextEditorControlProvider textEditorProvider = view as ITextEditorControlProvider;
if (textEditorProvider != null) {
XPathNodeTextMarker.RemoveMarkers(textEditorProvider.TextEditorControl.Document.MarkerStrategy);
textEditorProvider.TextEditorControl.Refresh();
}
}
}
/// <summary>
/// Disposes resources used by the control.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
#region Forms Designer generated code
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
System.ComponentModel.IContainer components = null;
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.xPathLabel = new System.Windows.Forms.Label();
this.xPathComboBox = new System.Windows.Forms.ComboBox();
this.queryButton = new System.Windows.Forms.Button();
this.tabControl = new System.Windows.Forms.TabControl();
this.xPathResultsTabPage = new System.Windows.Forms.TabPage();
this.xPathResultsListView = new System.Windows.Forms.ListView();
this.matchColumnHeader = new System.Windows.Forms.ColumnHeader();
this.lineColumnHeader = new System.Windows.Forms.ColumnHeader();
this.imageList = new System.Windows.Forms.ImageList(this.components);
this.namespacesTabPage = new System.Windows.Forms.TabPage();
this.namespacesDataGridView = new System.Windows.Forms.DataGridView();
this.prefixColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.namespaceColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.tabControl.SuspendLayout();
this.xPathResultsTabPage.SuspendLayout();
this.namespacesTabPage.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.namespacesDataGridView)).BeginInit();
this.SuspendLayout();
//
// xPathLabel
//
this.xPathLabel.Location = new System.Drawing.Point(3, 3);
this.xPathLabel.Name = "xPathLabel";
this.xPathLabel.Size = new System.Drawing.Size(46, 19);
this.xPathLabel.TabIndex = 0;
this.xPathLabel.Text = "XPath:";
this.xPathLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// xPathComboBox
//
this.xPathComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.xPathComboBox.FormattingEnabled = true;
this.xPathComboBox.Location = new System.Drawing.Point(55, 3);
this.xPathComboBox.Name = "xPathComboBox";
this.xPathComboBox.Size = new System.Drawing.Size(438, 21);
this.xPathComboBox.TabIndex = 1;
this.xPathComboBox.TextChanged += new System.EventHandler(this.XPathComboBoxTextChanged);
this.xPathComboBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.XPathComboBoxKeyDown);
//
// queryButton
//
this.queryButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.queryButton.Enabled = false;
this.queryButton.Location = new System.Drawing.Point(499, 3);
this.queryButton.Name = "queryButton";
this.queryButton.Size = new System.Drawing.Size(70, 23);
this.queryButton.TabIndex = 2;
this.queryButton.Text = "Query";
this.queryButton.UseVisualStyleBackColor = true;
this.queryButton.Click += new System.EventHandler(this.QueryButtonClick);
//
// tabControl
//
this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tabControl.Controls.Add(this.xPathResultsTabPage);
this.tabControl.Controls.Add(this.namespacesTabPage);
this.tabControl.Location = new System.Drawing.Point(0, 30);
this.tabControl.Name = "tabControl";
this.tabControl.SelectedIndex = 0;
this.tabControl.Size = new System.Drawing.Size(572, 208);
this.tabControl.TabIndex = 3;
//
// xPathResultsTabPage
//
this.xPathResultsTabPage.Controls.Add(this.xPathResultsListView);
this.xPathResultsTabPage.Location = new System.Drawing.Point(4, 22);
this.xPathResultsTabPage.Name = "xPathResultsTabPage";
this.xPathResultsTabPage.Padding = new System.Windows.Forms.Padding(3);
this.xPathResultsTabPage.Size = new System.Drawing.Size(564, 182);
this.xPathResultsTabPage.TabIndex = 0;
this.xPathResultsTabPage.Text = "Results";
this.xPathResultsTabPage.UseVisualStyleBackColor = true;
//
// xPathResultsListView
//
this.xPathResultsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.matchColumnHeader,
this.lineColumnHeader});
this.xPathResultsListView.Dock = System.Windows.Forms.DockStyle.Fill;
this.xPathResultsListView.FullRowSelect = true;
this.xPathResultsListView.HideSelection = false;
this.xPathResultsListView.Location = new System.Drawing.Point(3, 3);
this.xPathResultsListView.MultiSelect = false;
this.xPathResultsListView.Name = "xPathResultsListView";
this.xPathResultsListView.Size = new System.Drawing.Size(558, 176);
this.xPathResultsListView.SmallImageList = this.imageList;
this.xPathResultsListView.TabIndex = 0;
this.xPathResultsListView.UseCompatibleStateImageBehavior = false;
this.xPathResultsListView.View = System.Windows.Forms.View.Details;
this.xPathResultsListView.ItemActivate += new System.EventHandler(this.XPathResultsListViewItemActivate);
this.xPathResultsListView.SelectedIndexChanged += new System.EventHandler(this.XPathResultsListViewSelectedIndexChanged);
//
// matchColumnHeader
//
this.matchColumnHeader.Text = "Match";
this.matchColumnHeader.Width = 432;
//
// lineColumnHeader
//
this.lineColumnHeader.Text = "Line";
//
// imageList
//
this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
this.imageList.ImageSize = new System.Drawing.Size(16, 16);
this.imageList.TransparentColor = System.Drawing.Color.Transparent;
//
// namespacesTabPage
//
this.namespacesTabPage.Controls.Add(this.namespacesDataGridView);
this.namespacesTabPage.Location = new System.Drawing.Point(4, 22);
this.namespacesTabPage.Name = "namespacesTabPage";
this.namespacesTabPage.Padding = new System.Windows.Forms.Padding(3);
this.namespacesTabPage.Size = new System.Drawing.Size(564, 182);
this.namespacesTabPage.TabIndex = 1;
this.namespacesTabPage.Text = "Namespaces";
this.namespacesTabPage.UseVisualStyleBackColor = true;
//
// namespacesDataGridView
//
this.namespacesDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.namespacesDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.prefixColumn,
this.namespaceColumn});
this.namespacesDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
this.namespacesDataGridView.Location = new System.Drawing.Point(3, 3);
this.namespacesDataGridView.MultiSelect = false;
this.namespacesDataGridView.Name = "namespacesDataGridView";
this.namespacesDataGridView.RowHeadersWidth = 25;
this.namespacesDataGridView.ShowEditingIcon = false;
this.namespacesDataGridView.Size = new System.Drawing.Size(558, 176);
this.namespacesDataGridView.TabIndex = 0;
//
// prefixColumn
//
this.prefixColumn.HeaderText = "Prefix";
this.prefixColumn.Name = "prefixColumn";
this.prefixColumn.Width = 50;
//
// namespaceColumn
//
this.namespaceColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
this.namespaceColumn.HeaderText = "Namespace";
this.namespaceColumn.Name = "namespaceColumn";
//
// XPathQueryControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tabControl);
this.Controls.Add(this.queryButton);
this.Controls.Add(this.xPathComboBox);
this.Controls.Add(this.xPathLabel);
this.Name = "XPathQueryControl";
this.Size = new System.Drawing.Size(572, 238);
this.tabControl.ResumeLayout(false);
this.xPathResultsTabPage.ResumeLayout(false);
this.namespacesTabPage.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.namespacesDataGridView)).EndInit();
this.ResumeLayout(false);
}
private System.Windows.Forms.ImageList imageList;
private System.Windows.Forms.DataGridViewTextBoxColumn namespaceColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn prefixColumn;
private System.Windows.Forms.DataGridView namespacesDataGridView;
private System.Windows.Forms.ColumnHeader lineColumnHeader;
private System.Windows.Forms.ColumnHeader matchColumnHeader;
private System.Windows.Forms.ListView xPathResultsListView;
private System.Windows.Forms.TabPage namespacesTabPage;
private System.Windows.Forms.TabPage xPathResultsTabPage;
private System.Windows.Forms.TabControl tabControl;
private System.Windows.Forms.Button queryButton;
private System.Windows.Forms.ComboBox xPathComboBox;
private System.Windows.Forms.Label xPathLabel;
#endregion
void XPathComboBoxTextChanged(object sender, EventArgs e)
{
if (!ignoreXPathTextChanges) {
UpdateQueryButtonState();
}
}
void UpdateQueryButtonState()
{
queryButton.Enabled = IsXPathQueryEntered && XmlView.IsXmlViewActive;
}
bool IsXPathQueryEntered {
get {
return xPathComboBox.Text.Length > 0;
}
}
void QueryButtonClick(object sender, EventArgs e)
{
RunXPathQuery();
}
void RunXPathQuery()
{
XmlView view = XmlView.ActiveXmlView;
if (view == null) {
return;
}
try {
MarkerStrategy markerStrategy = view.TextEditorControl.Document.MarkerStrategy;
fileName = view.FileName;
if (fileName == null) {
fileName = view.UntitledName;
}
// Clear previous XPath results.
ClearResults();
XPathNodeTextMarker.RemoveMarkers(markerStrategy);
// Run XPath query.
XPathNodeMatch[] nodes = view.SelectNodes(xPathComboBox.Text, GetNamespaces());
if (nodes.Length > 0) {
AddXPathResults(nodes);
XPathNodeTextMarker.AddMarkers(markerStrategy, nodes);
} else {
AddNoXPathResult();
}
AddXPathToHistory();
} catch (XPathException xpathEx) {
AddErrorResult(xpathEx);
} catch (XmlException xmlEx) {
AddErrorResult(xmlEx);
} finally {
view.TextEditorControl.Refresh();
}
}
void ClearResults()
{
xPathResultsListView.Items.Clear();
}
void AddXPathResults(XPathNodeMatch[] nodes)
{
foreach (XPathNodeMatch node in nodes) {
ListViewItem item = new ListViewItem(node.DisplayValue);
if (node.HasLineInfo()) {
int line = node.LineNumber + 1;
item.SubItems.Add(line.ToString());
}
item.Tag = node;
xPathResultsListView.Items.Add(item);
}
}
void AddNoXPathResult()
{
xPathResultsListView.Items.Add("XPath query found 0 items.");
}
void AddErrorResult(XmlException ex)
{
ListViewItem item = new ListViewItem(ex.Message, ErrorImageIndex);
item.SubItems.Add(ex.LineNumber.ToString());
item.Tag = ex;
xPathResultsListView.Items.Add(item);
}
void AddErrorResult(XPathException ex)
{
ListViewItem item = new ListViewItem(String.Concat("XPath: ", ex.Message), ErrorImageIndex);
item.Tag = ex;
xPathResultsListView.Items.Add(item);
}
void InitImageList()
{
try {
imageList.Images.Add(ResourceService.GetBitmap("Icons.16x16.Error"));
} catch (ResourceNotFoundException) { }
}
void InitAutoCompleteMode()
{
try {
xPathComboBox.AutoCompleteMode = AutoCompleteMode.Suggest;
xPathComboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
} catch (ThreadStateException) { }
}
void XPathResultsListViewItemActivate(object sender, EventArgs e)
{
JumpToResultLocation();
}
/// <summary>
/// Switches focus to the location of the XPath query result.
/// </summary>
void JumpToResultLocation()
{
MoveCaretToResultLocation(MoveCaret.ByJumping);
}
/// <summary>
/// Scrolls the text editor so the location of the XPath query results is visible.
/// </summary>
void ScrollToResultLocation()
{
MoveCaretToResultLocation(MoveCaret.ByScrolling);
}
void MoveCaretToResultLocation(MoveCaret moveCaret)
{
if (xPathResultsListView.SelectedItems.Count > 0) {
ListViewItem item = xPathResultsListView.SelectedItems[0];
XPathNodeMatch xPathNodeMatch = item.Tag as XPathNodeMatch;
XPathException xpathException = item.Tag as XPathException;
XmlException xmlException = item.Tag as XmlException;
if (xPathNodeMatch != null) {
MoveCaretToXPathNodeMatch(moveCaret, xPathNodeMatch);
} else if (xmlException != null) {
MoveCaretToXmlException(moveCaret, xmlException);
} else if (xpathException != null && moveCaret == MoveCaret.ByJumping) {
xPathComboBox.Focus();
}
}
}
void MoveCaretToXPathNodeMatch(MoveCaret moveCaret, XPathNodeMatch node)
{
if (moveCaret == MoveCaret.ByJumping) {
JumpTo(fileName, node.LineNumber, node.LinePosition);
} else {
ScrollTo(fileName, node.LineNumber, node.LinePosition);
}
}
void MoveCaretToXmlException(MoveCaret moveCaret, XmlException ex)
{
int line = ex.LineNumber - 1;
int column = ex.LinePosition - 1;
if (moveCaret == MoveCaret.ByJumping) {
JumpTo(fileName, line, column);
} else {
ScrollTo(fileName, line, column);
}
}
void JumpTo(string fileName, int line, int column)
{
FileService.JumpToFilePosition(fileName, line, column);
}
void ScrollTo(string fileName, int line, int column)
{
XmlView view = XmlView.ActiveXmlView;
if (view != null && IsFileNameMatch(view)) {
view.TextEditorControl.ActiveTextAreaControl.ScrollTo(line, column);
}
}
/// <summary>
/// Tests whether the specified view matches the filename the XPath
/// results were found in.
/// </summary>
bool IsFileNameMatch(XmlView view)
{
return FileUtility.IsEqualFileName(fileName, view.FileName) || FileUtility.IsEqualFileName(fileName, view.UntitledName);
}
/// <summary>
/// Gets the namespaces and prefixes as a string array.
/// </summary>
string[] GetNamespaceStringArray()
{
List<string> namespaces = new List<string>();
foreach (XmlNamespace ns in GetNamespaces()) {
namespaces.Add(ns.ToString());
}
return namespaces.ToArray();
}
/// <summary>
/// Gets the previously used XPath queries from the combo box drop down list.
/// </summary>
/// <returns></returns>
string [] GetXPathHistory()
{
List<string> xpaths = new List<string>();
foreach (string xpath in xPathComboBox.Items) {
xpaths.Add(xpath);
}
return xpaths.ToArray();
}
/// <summary>
/// Gets the namespace prefix in the specified row.
/// </summary>
string GetPrefix(DataGridViewRow row)
{
string prefix = (string)row.Cells[0].Value;
if (prefix != null) {
return prefix;
}
return String.Empty;
}
/// <summary>
/// Gets the namespace stored in the row.
/// </summary>
string GetNamespace(DataGridViewRow row)
{
string ns = (string)row.Cells[1].Value;
if (ns != null) {
return ns;
}
return String.Empty;
}
/// <summary>
/// Adds the text in the combo box to the combo box drop down list.
/// </summary>
void AddXPathToHistory()
{
string newXPath = xPathComboBox.Text;
if (!xPathComboBox.Items.Contains(newXPath)) {
xPathComboBox.Items.Insert(0, newXPath);
if (xPathComboBox.Items.Count > xpathQueryHistoryLimit) {
xPathComboBox.Items.RemoveAt(xpathQueryHistoryLimit);
}
}
}
void XPathComboBoxKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Return) {
RunXPathQuery();
}
}
void XPathResultsListViewSelectedIndexChanged(object sender, EventArgs e)
{
ScrollToResultLocation();
}
}
}

68
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XPathQueryPad.cs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.XmlEditor
{
public class XPathQueryPad : AbstractPadContent
{
public const string XPathQueryControlProperties = "XPathQueryControl.Options";
XPathQueryControl xPathQueryControl;
bool disposed;
static XPathQueryPad instance;
public XPathQueryPad()
{
xPathQueryControl = new XPathQueryControl();
WorkbenchSingleton.Workbench.ActiveWorkbenchWindowChanged += ActiveWorkbenchWindowChanged;
Properties properties = PropertyService.Get(XPathQueryControlProperties, new Properties());
xPathQueryControl.SetMemento(properties);
instance = this;
}
public static XPathQueryPad Instance {
get {
return instance;
}
}
/// <summary>
/// The <see cref="System.Windows.Forms.Control"/> representing the pad.
/// </summary>
public override Control Control {
get {
return xPathQueryControl;
}
}
public override void Dispose()
{
if (!disposed) {
disposed = true;
WorkbenchSingleton.Workbench.ActiveWorkbenchWindowChanged -= ActiveWorkbenchWindowChanged;
Properties properties = xPathQueryControl.CreateMemento();
PropertyService.Set(XPathQueryControlProperties, properties);
xPathQueryControl.Dispose();
}
}
public void RemoveXPathHighlighting()
{
xPathQueryControl.RemoveXPathNodeTextMarkers();
}
void ActiveWorkbenchWindowChanged(object source, EventArgs e)
{
xPathQueryControl.ActiveWindowChanged();
}
}
}

66
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlNamespace.cs

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.XmlEditor
{
/// <summary>
/// A namespace Uri and a prefix.
/// </summary>
public class XmlNamespace
{
string prefix = String.Empty;
string uri = String.Empty;
const string prefixToStringStart = "Prefix [";
const string uriToStringMiddle = "] Uri [";
public XmlNamespace(string prefix, string uri)
{
this.prefix = prefix;
this.uri = uri;
}
public string Prefix {
get {
return prefix;
}
}
public string Uri {
get {
return uri;
}
}
public override string ToString()
{
return String.Concat(prefixToStringStart, prefix, uriToStringMiddle, uri, "]");
}
/// <summary>
/// Creates an XmlNamespace instance from the given string that is in the
/// format returned by ToString.
/// </summary>
public static XmlNamespace FromString(string s)
{
int prefixIndex = s.IndexOf(prefixToStringStart);
if (prefixIndex >= 0) {
prefixIndex += prefixToStringStart.Length;
int uriIndex = s.IndexOf(uriToStringMiddle, prefixIndex);
if (uriIndex >= 0) {
string prefix = s.Substring(prefixIndex, uriIndex - prefixIndex);
uriIndex += uriToStringMiddle.Length;
string uri = s.Substring(uriIndex, s.Length - (uriIndex + 1));
return new XmlNamespace(prefix, uri);
}
}
return new XmlNamespace(String.Empty, String.Empty);
}
}
}

103
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs

@ -5,9 +5,17 @@ @@ -5,9 +5,17 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Windows.Forms;
@ -16,13 +24,6 @@ using System.Xml.Schema; @@ -16,13 +24,6 @@ using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Xsl;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.XmlEditor
{
/// <summary>
@ -63,6 +64,32 @@ namespace ICSharpCode.XmlEditor @@ -63,6 +64,32 @@ namespace ICSharpCode.XmlEditor
XmlSchemaManager.UserSchemaRemoved += new EventHandler(UserSchemaRemoved);
}
/// <summary>
/// Gets the active XmlView.
/// </summary>
/// <returns><see langword="null"/> if the active view is not an XmlView.</returns>
public static XmlView ActiveXmlView {
get {
IWorkbench workbench = WorkbenchSingleton.Workbench;
if (workbench != null) {
IWorkbenchWindow window = workbench.ActiveWorkbenchWindow;
if (window != null) {
return window.ActiveViewContent as XmlView;
}
}
return null;
}
}
/// <summary>
/// Gets whether the active view is an XmlView.
/// </summary>
public static bool IsXmlViewActive {
get {
return ActiveXmlView != null;
}
}
public override string TabPageText {
get {
return "XML";
@ -116,6 +143,53 @@ namespace ICSharpCode.XmlEditor @@ -116,6 +143,53 @@ namespace ICSharpCode.XmlEditor
return new string[0];
}
/// <summary>
/// Finds the xml nodes that match the specified xpath.
/// </summary>
/// <returns>An array of XPathNodeMatch items. These include line number
/// and line position information aswell as the node found.</returns>
public static XPathNodeMatch[] SelectNodes(string xml, string xpath, ReadOnlyCollection<XmlNamespace> namespaces)
{
XPathDocument doc = new XPathDocument(new StringReader(xml));
XPathNavigator navigator = doc.CreateNavigator();
// Add namespaces.
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(navigator.NameTable);
foreach (XmlNamespace xmlNamespace in namespaces) {
namespaceManager.AddNamespace(xmlNamespace.Prefix, xmlNamespace.Uri);
}
// Run the xpath query.
XPathNodeIterator iterator = navigator.Select(xpath, namespaceManager);
List<XPathNodeMatch> nodes = new List<XPathNodeMatch>();
while (iterator.MoveNext()) {
nodes.Add(new XPathNodeMatch(iterator.Current));
}
return nodes.ToArray();
}
/// <summary>
/// Finds the xml nodes that match the specified xpath.
/// </summary>
/// <returns>An array of XPathNodeMatch items. These include line number
/// and line position information aswell as the node found.</returns>
public static XPathNodeMatch[] SelectNodes(string xml, string xpath)
{
List<XmlNamespace> list = new List<XmlNamespace>();
return SelectNodes(xml, xpath, new ReadOnlyCollection<XmlNamespace>(list));
}
/// <summary>
/// Finds the xml nodes in the current document that match the specified xpath.
/// </summary>
/// <returns>An array of XPathNodeMatch items. These include line number
/// and line position information aswell as the node found.</returns>
public XPathNodeMatch[] SelectNodes(string xpath, ReadOnlyCollection<XmlNamespace> namespaces)
{
return SelectNodes(Text, xpath, namespaces);
}
/// <summary>
/// Validates the xml against known schemas.
/// </summary>
@ -197,7 +271,6 @@ namespace ICSharpCode.XmlEditor @@ -197,7 +271,6 @@ namespace ICSharpCode.XmlEditor
get {
return stylesheetFileName;
}
set {
stylesheetFileName = value;
}
@ -265,7 +338,6 @@ namespace ICSharpCode.XmlEditor @@ -265,7 +338,6 @@ namespace ICSharpCode.XmlEditor
// ParserUpdateThread uses the text property via IEditable, I had an exception
// because multiple threads were accessing the GapBufferStrategy at the same time.
internal string GetText()
{
return xmlEditor.Document.TextContent;
@ -278,16 +350,18 @@ namespace ICSharpCode.XmlEditor @@ -278,16 +350,18 @@ namespace ICSharpCode.XmlEditor
public string Text {
get {
if (WorkbenchSingleton.InvokeRequired)
if (WorkbenchSingleton.InvokeRequired) {
return WorkbenchSingleton.SafeThreadFunction<string>(GetText);
else
} else {
return GetText();
}
}
set {
if (WorkbenchSingleton.InvokeRequired)
if (WorkbenchSingleton.InvokeRequired) {
WorkbenchSingleton.SafeThreadCall(SetText, value);
else
} else {
SetText(value);
}
}
}
@ -604,8 +678,9 @@ namespace ICSharpCode.XmlEditor @@ -604,8 +678,9 @@ namespace ICSharpCode.XmlEditor
{
if(e.ChangeType != WatcherChangeTypes.Deleted) {
wasChangedExternally = true;
if (xmlEditor.IsHandleCreated)
if (xmlEditor.IsHandleCreated) {
xmlEditor.BeginInvoke(new MethodInvoker(OnFileChangedEventInvoked));
}
}
}

23
src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.addin

@ -128,6 +128,9 @@ @@ -128,6 +128,9 @@
label = "${res:XML.TextAreaContextMenu.Indent}"
shortcut = "Control|I"
class = "ICSharpCode.SharpDevelop.DefaultEditor.Commands.IndentSelection" />
<MenuItem id = "HideXPathResults"
label = "Hide &amp;XPath Results"
class = "ICSharpCode.XmlEditor.RemoveXPathHighlightingCommand"/>
<MenuItem id = "FileMode" label = "${res:XML.TextAreaContextMenu.FileMode}" type="Menu">
<MenuItem id = "HighlightBuilder" type="Builder" class = "ICSharpCode.SharpDevelop.DefaultEditor.Commands.HighlightingTypeBuilder" />
</MenuItem>
@ -154,4 +157,24 @@ @@ -154,4 +157,24 @@
<Path path = "/AddIns/XmlEditor/EditActions">
<EditAction id = "XmlCompletionPopup" class = "ICSharpCode.XmlEditor.CodeCompletionPopupCommand" keys = "Control|Space"/>
</Path>
<!-- XPath Query pad -->
<Path name = "/SharpDevelop/Workbench/Pads">
<Pad id = "XPathQueryPad"
category = "Tools"
icon = "PadIcons.XPathQuery"
title = "XPath Query"
insertafter = "UnitTestingPad"
class = "ICSharpCode.XmlEditor.XPathQueryPad"/>
</Path>
<!-- Menu options to turn off XPath Query result highlighting -->
<Path name = "/SharpDevelop/Workbench/MainMenu/Edit/Format">
<Condition name = "WindowActive" activewindow="ICSharpCode.XmlEditor.XmlView">
<MenuItem id = "RemoveXPathHighlighting"
insertafter = "ShowCodeCoverage"
label = "Hide &amp;XPath Results"
class = "ICSharpCode.XmlEditor.RemoveXPathHighlightingCommand"/>
</Condition>
</Path>
</AddIn>

6
src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj

@ -107,6 +107,12 @@ @@ -107,6 +107,12 @@
<Link>Configuration\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Src\FormatXmlCommand.cs" />
<Compile Include="Src\XPathQueryPad.cs" />
<Compile Include="Src\XPathQueryControl.cs" />
<Compile Include="Src\XmlNamespace.cs" />
<Compile Include="Src\XPathNodeMatch.cs" />
<Compile Include="Src\XPathNodeTextMarker.cs" />
<Compile Include="Src\RemoveXPathHighlightingCommand.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj">

276
src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockDocument.cs

@ -0,0 +1,276 @@ @@ -0,0 +1,276 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.TextEditor.Document;
using System;
using System.Collections.Generic;
namespace XmlEditor.Tests.Utils
{
/// <summary>
/// Helper class that implements the Text Editor library's IDocument interface.
/// </summary>
public class MockDocument : IDocument
{
List<LineSegment> lineSegments = new List<LineSegment>();
public MockDocument()
{
}
public event EventHandler UpdateCommited;
public event DocumentEventHandler DocumentAboutToBeChanged;
public event DocumentEventHandler DocumentChanged;
public event EventHandler TextContentChanged;
public void AddLines(string code)
{
int offset = 0;
string[] lines = code.Split('\n');
foreach (string line in lines) {
int delimiterLength = 1;
if (line.Length > 0 && line[line.Length - 1] == '\r') {
delimiterLength = 2;
}
LineSegment lineSegment = new LineSegment(offset, offset + line.Length, delimiterLength);
lineSegments.Add(lineSegment);
offset += line.Length + lineSegment.DelimiterLength - 1;
}
}
public ITextEditorProperties TextEditorProperties {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public ICSharpCode.TextEditor.Undo.UndoStack UndoStack {
get {
throw new NotImplementedException();
}
}
public bool ReadOnly {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public IFormattingStrategy FormattingStrategy {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public ITextBufferStrategy TextBufferStrategy {
get {
throw new NotImplementedException();
}
}
public FoldingManager FoldingManager {
get {
throw new NotImplementedException();
}
}
public IHighlightingStrategy HighlightingStrategy {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public BookmarkManager BookmarkManager {
get {
throw new NotImplementedException();
}
}
public ICustomLineManager CustomLineManager {
get {
throw new NotImplementedException();
}
}
public MarkerStrategy MarkerStrategy {
get {
throw new NotImplementedException();
}
}
public System.Collections.Generic.List<LineSegment> LineSegmentCollection {
get {
return lineSegments;
}
}
public int TotalNumberOfLines {
get {
if (lineSegments.Count == 0) {
return 1;
}
return ((LineSegment)lineSegments[lineSegments.Count - 1]).DelimiterLength > 0 ? lineSegments.Count + 1 : lineSegments.Count;
}
}
public string TextContent {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public int TextLength {
get {
throw new NotImplementedException();
}
}
public System.Collections.Generic.List<ICSharpCode.TextEditor.TextAreaUpdate> UpdateQueue {
get {
throw new NotImplementedException();
}
}
public void UpdateSegmentListOnDocumentChange<T>(System.Collections.Generic.List<T> list, DocumentEventArgs e) where T : ISegment
{
throw new NotImplementedException();
}
public int GetLineNumberForOffset(int offset)
{
throw new NotImplementedException();
}
public LineSegment GetLineSegmentForOffset(int offset)
{
throw new NotImplementedException();
}
public LineSegment GetLineSegment(int lineNumber)
{
return lineSegments[lineNumber];
}
public int GetFirstLogicalLine(int lineNumber)
{
throw new NotImplementedException();
}
public int GetLastLogicalLine(int lineNumber)
{
throw new NotImplementedException();
}
public int GetVisibleLine(int lineNumber)
{
throw new NotImplementedException();
}
public int GetNextVisibleLineAbove(int lineNumber, int lineCount)
{
throw new NotImplementedException();
}
public int GetNextVisibleLineBelow(int lineNumber, int lineCount)
{
throw new NotImplementedException();
}
public void Insert(int offset, string text)
{
throw new NotImplementedException();
}
public void Remove(int offset, int length)
{
throw new NotImplementedException();
}
public void Replace(int offset, int length, string text)
{
throw new NotImplementedException();
}
public char GetCharAt(int offset)
{
throw new NotImplementedException();
}
public string GetText(int offset, int length)
{
throw new NotImplementedException();
}
public string GetText(ISegment segment)
{
throw new NotImplementedException();
}
public System.Drawing.Point OffsetToPosition(int offset)
{
throw new NotImplementedException();
}
public int PositionToOffset(System.Drawing.Point p)
{
throw new NotImplementedException();
}
public void RequestUpdate(ICSharpCode.TextEditor.TextAreaUpdate update)
{
throw new NotImplementedException();
}
public void CommitUpdate()
{
throw new NotImplementedException();
}
void OnUpdateCommited()
{
if (UpdateCommited != null) {
}
}
void OnDocumentAboutToBeChanged()
{
if (DocumentAboutToBeChanged != null) {
}
}
void OnDocumentChanged()
{
if (DocumentChanged != null) {
}
}
void OnTextContentChanged()
{
if (TextContentChanged != null) {
}
}
}
}

85
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/GetNamespacesFromListViewTestFixture.cs

@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
namespace XmlEditor.Tests.XPathQuery
{
/// <summary>
/// Adds a set of namespaces to the XPathQueryControl and gets them back.
/// </summary>
[TestFixture]
public class GetNamespacesFromListViewTestFixture
{
List<XmlNamespace> expectedNamespaces;
ReadOnlyCollection<XmlNamespace> namespaces;
List<XmlNamespace> namespacesAddedToGrid;
[SetUp]
public void SetUpFixture()
{
using (XPathQueryControl queryControl = new XPathQueryControl()) {
expectedNamespaces = new List<XmlNamespace>();
expectedNamespaces.Add(new XmlNamespace("w", "http://www.wix.com"));
expectedNamespaces.Add(new XmlNamespace("s", "http://sharpdevelop.com"));
foreach (XmlNamespace ns in expectedNamespaces) {
queryControl.AddNamespace(ns.Prefix, ns.Uri);
}
namespacesAddedToGrid = new List<XmlNamespace>();
for (int i = 0; i < queryControl.NamespacesDataGridView.Rows.Count - 1; ++i) {
DataGridViewRow row = queryControl.NamespacesDataGridView.Rows[i];
namespacesAddedToGrid.Add(new XmlNamespace((string)row.Cells[0].Value, (string)row.Cells[1].Value));
}
namespaces = queryControl.GetNamespaces();
}
}
[Test]
public void NamespacesMatch()
{
for (int i = 0; i < expectedNamespaces.Count; ++i) {
XmlNamespace expectedNamespace = expectedNamespaces[i];
XmlNamespace actualNamespace = namespaces[i];
Assert.AreEqual(expectedNamespace.Prefix, actualNamespace.Prefix);
Assert.AreEqual(expectedNamespace.Uri, actualNamespace.Uri);
}
}
[Test]
public void TwoNamespacesReturned()
{
Assert.AreEqual(2, namespaces.Count);
}
[Test]
public void GridNamespacesMatch()
{
for (int i = 0; i < expectedNamespaces.Count; ++i) {
XmlNamespace expectedNamespace = expectedNamespaces[i];
XmlNamespace actualNamespace = namespacesAddedToGrid[i];
Assert.AreEqual(expectedNamespace.Prefix, actualNamespace.Prefix);
Assert.AreEqual(expectedNamespace.Uri, actualNamespace.Uri);
}
}
[Test]
public void TwoNamespacesAddedToGrid()
{
Assert.AreEqual(2, namespacesAddedToGrid.Count);
}
}
}

56
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/NamespaceGridColumnWidthsLoadedTestFixture.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
namespace XmlEditor.Tests.XPathQuery
{
/// <summary>
/// Tests that the grid column widths are remembered by the query control.
/// </summary>
[TestFixture]
public class NamespaceGridColumnWidthsLoadedTestFixture
{
int prefixColumnWidthAfterLoad;
int prefixColumnWidthAfterSave;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (XPathQueryControl queryControl = new XPathQueryControl()) {
Properties p = new Properties();
p.Set("NamespacesDataGridView.PrefixColumn.Width", 10);
queryControl.SetMemento(p);
prefixColumnWidthAfterLoad = queryControl.NamespacesDataGridView.Columns["prefixColumn"].Width;
queryControl.NamespacesDataGridView.Columns["prefixColumn"].Width = 40;
p = queryControl.CreateMemento();
prefixColumnWidthAfterSave = p.Get<int>("NamespacesDataGridView.PrefixColumn.Width", 0);
}
}
[Test]
public void PrefixColumnWidthAfterLoad()
{
Assert.AreEqual(10, prefixColumnWidthAfterLoad);
}
[Test]
public void PrefixColumnWidthAfterSave()
{
Assert.AreEqual(40, prefixColumnWidthAfterSave);
}
}
}

60
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/NamespacePropertiesLoaded.cs

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
namespace XmlEditor.Tests.XPathQuery
{
[TestFixture]
public class NamespacePropertiesLoaded
{
List<XmlNamespace> expectedNamespaces;
ReadOnlyCollection<XmlNamespace> actualNamespaces;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (XPathQueryControl queryControl = new XPathQueryControl()) {
Properties p = new Properties();
expectedNamespaces = new List<XmlNamespace>();
expectedNamespaces.Add(new XmlNamespace("f", "http://foo.com"));
expectedNamespaces.Add(new XmlNamespace("s", "http://sharpdevelop.com"));
List<string> namespaces = new List<string>();
foreach (XmlNamespace xmlNamespace in expectedNamespaces) {
namespaces.Add(xmlNamespace.ToString());
}
p.Set("Namespaces", namespaces.ToArray());
queryControl.SetMemento(p);
actualNamespaces = queryControl.GetNamespaces();
}
}
[Test]
public void TwoNamespacesAdded()
{
Assert.AreEqual(2, actualNamespaces.Count);
}
[Test]
public void NamespacesAdded()
{
for (int i = 0; i < expectedNamespaces.Count; ++i) {
XmlNamespace expectedNamespace = expectedNamespaces[i];
XmlNamespace actualNamespace = actualNamespaces[i];
Assert.AreEqual(expectedNamespace.Prefix, actualNamespace.Prefix);
Assert.AreEqual(expectedNamespace.Uri, actualNamespace.Uri);
}
}
}
}

62
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/NamespacePropertiesSaved.cs

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
namespace XmlEditor.Tests.XPathQuery
{
[TestFixture]
public class NamespacePropertiesSaved
{
List<XmlNamespace> expectedNamespaces;
string[] actualNamespaces;
[SetUp]
public void SetUpFixture()
{
using (XPathQueryControl queryControl = new XPathQueryControl()) {
expectedNamespaces = new List<XmlNamespace>();
expectedNamespaces.Add(new XmlNamespace("f", "http://foo.com"));
expectedNamespaces.Add(new XmlNamespace("s", "http://sharpdevelop.com"));
foreach (XmlNamespace xmlNamespace in expectedNamespaces) {
queryControl.AddNamespace(xmlNamespace.Prefix, xmlNamespace.Uri);
}
// Blank prefix and uris should be ignored.
queryControl.AddNamespace(String.Empty, String.Empty);
// Null cell values ignored.
queryControl.NamespacesDataGridView.Rows.Add(new object[] {null, null});
Properties p = queryControl.CreateMemento();
actualNamespaces = p.Get("Namespaces", new string[0]);
}
}
[Test]
public void TwoNamespacesAdded()
{
Assert.AreEqual(2, actualNamespaces.Length);
}
[Test]
public void NamespacesAdded()
{
for (int i = 0; i < expectedNamespaces.Count; ++i) {
XmlNamespace expectedNamespace = expectedNamespaces[i];
string actualNamespace = actualNamespaces[i];
Assert.AreEqual(expectedNamespace.ToString(), actualNamespace);
}
}
}
}

175
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/RunXPathQueryTests.cs

@ -0,0 +1,175 @@ @@ -0,0 +1,175 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Xml;
using System.Xml.XPath;
namespace XmlEditor.Tests.XPathQuery
{
[TestFixture]
public class RunXPathQueryTests
{
[Test]
public void OneElementNode()
{
string xml = "<root>\r\n" +
"\t<foo/>\r\n" +
"</root>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//foo");
XPathNodeMatch node = nodes[0];
IXmlLineInfo lineInfo = node as IXmlLineInfo;
Assert.AreEqual(1, nodes.Length);
Assert.AreEqual(1, node.LineNumber);
Assert.AreEqual(2, node.LinePosition);
Assert.AreEqual("foo", node.Value);
Assert.AreEqual("<foo/>", node.DisplayValue);
Assert.AreEqual(XPathNodeType.Element, node.NodeType);
Assert.IsNotNull(lineInfo);
}
[Test]
public void OneElementNodeWithNamespace()
{
string xml = "<root xmlns='http://foo.com'>\r\n" +
"\t<foo></foo>\r\n" +
"</root>";
List<XmlNamespace> namespaces = new List<XmlNamespace>();
namespaces.Add(new XmlNamespace("f", "http://foo.com"));
ReadOnlyCollection<XmlNamespace> readOnlyNamespaces = new ReadOnlyCollection<XmlNamespace>(namespaces);
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//f:foo", readOnlyNamespaces);
XPathNodeMatch node = nodes[0];
IXmlLineInfo lineInfo = node as IXmlLineInfo;
Assert.AreEqual(1, nodes.Length);
Assert.AreEqual(1, node.LineNumber);
Assert.AreEqual(2, node.LinePosition);
Assert.AreEqual("foo", node.Value);
Assert.AreEqual("<foo>", node.DisplayValue);
Assert.AreEqual(XPathNodeType.Element, node.NodeType);
Assert.IsNotNull(lineInfo);
}
[Test]
public void ElementWithNamespacePrefix()
{
string xml = "<f:root xmlns:f='http://foo.com'>\r\n" +
"\t<f:foo></f:foo>\r\n" +
"</f:root>";
List<XmlNamespace> namespaces = new List<XmlNamespace>();
namespaces.Add(new XmlNamespace("fo", "http://foo.com"));
ReadOnlyCollection<XmlNamespace> readOnlyNamespaces = new ReadOnlyCollection<XmlNamespace>(namespaces);
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//fo:foo", readOnlyNamespaces);
XPathNodeMatch node = nodes[0];
IXmlLineInfo lineInfo = node as IXmlLineInfo;
Assert.AreEqual(1, nodes.Length);
Assert.AreEqual(1, node.LineNumber);
Assert.AreEqual(2, node.LinePosition);
Assert.AreEqual("f:foo", node.Value);
Assert.AreEqual("<f:foo>", node.DisplayValue);
Assert.AreEqual(XPathNodeType.Element, node.NodeType);
Assert.IsNotNull(lineInfo);
}
[Test]
public void NoNodeFound()
{
string xml = "<root>\r\n" +
"\t<foo/>\r\n" +
"</root>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//bar");
Assert.AreEqual(0, nodes.Length);
}
[Test]
public void TextNode()
{
string xml = "<root>\r\n" +
"\t<foo>test</foo>\r\n" +
"</root>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//foo/text()");
XPathNodeMatch node = nodes[0];
Assert.AreEqual(1, nodes.Length);
Assert.AreEqual(1, node.LineNumber);
Assert.AreEqual(6, node.LinePosition);
Assert.AreEqual("test", node.Value);
Assert.AreEqual("test", node.DisplayValue);
}
[Test]
public void CommentNode()
{
string xml = "<!-- Test --><root/>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//comment()");
XPathNodeMatch node = nodes[0];
Assert.AreEqual(1, nodes.Length);
Assert.AreEqual(0, node.LineNumber);
Assert.AreEqual(4, node.LinePosition);
Assert.AreEqual(" Test ", node.Value);
Assert.AreEqual("<!-- Test -->", node.DisplayValue);
}
[Test]
public void EmptyCommentNode()
{
string xml = "<!----><root/>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//comment()");
XPathNodeMatch node = nodes[0];
Assert.AreEqual(1, nodes.Length);
Assert.AreEqual(0, node.LineNumber);
Assert.AreEqual(4, node.LinePosition);
Assert.AreEqual(String.Empty, node.Value);
Assert.AreEqual("<!---->", node.DisplayValue);
}
[Test]
public void NamespaceNode()
{
string xml = "<root xmlns='http://foo.com'/>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//namespace::*");
XPathNodeMatch node = nodes[0];
XPathNodeMatch xmlNamespaceNode = nodes[1];
Assert.AreEqual(2, nodes.Length);
Assert.AreEqual(0, node.LineNumber);
Assert.AreEqual(6, node.LinePosition);
Assert.AreEqual("xmlns=\"http://foo.com\"", node.Value);
Assert.AreEqual("xmlns=\"http://foo.com\"", node.DisplayValue);
Assert.IsFalse(xmlNamespaceNode.HasLineInfo());
Assert.AreEqual("xmlns:xml=\"http://www.w3.org/XML/1998/namespace\"", xmlNamespaceNode.Value);
}
[Test]
public void ProcessingInstructionNode()
{
string xml = "<root><?test processinstruction='1.0'?></root>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//processing-instruction()");
XPathNodeMatch node = nodes[0];
Assert.AreEqual("test", node.Value);
Assert.AreEqual("<?test processinstruction='1.0'?>", node.DisplayValue);
Assert.AreEqual(0, node.LineNumber);
Assert.AreEqual(8, node.LinePosition);
}
[Test]
public void AttributeNode()
{
string xml = "<root>\r\n" +
"\t<foo Id='ab'></foo>\r\n" +
"</root>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//foo/@Id");
XPathNodeMatch node = nodes[0];
Assert.AreEqual(1, nodes.Length);
Assert.AreEqual(1, node.LineNumber);
Assert.AreEqual(6, node.LinePosition);
Assert.AreEqual("Id", node.Value);
Assert.AreEqual("@Id", node.DisplayValue);
}
}
}

105
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XPathNodeTextMarkerTests.cs

@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.TextEditor.Document;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Xml;
using System.Xml.XPath;
using XmlEditor.Tests.Utils;
namespace XmlEditor.Tests.XPathQuery
{
[TestFixture]
public class XPathNodeTextMarkerTests
{
[Test]
public void OneNodeMarked()
{
string xml = "<root><foo/></root>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//root");
MockDocument doc = new MockDocument();
doc.AddLines(xml);
MarkerStrategy markerStrategy = new MarkerStrategy(doc);
XPathNodeTextMarker.AddMarkers(markerStrategy, nodes);
List<TextMarker> markers = new List<TextMarker>();
foreach (TextMarker marker in markerStrategy.TextMarker) {
markers.Add(marker);
}
// Remove markers.
XPathNodeTextMarker.RemoveMarkers(markerStrategy);
List<TextMarker> markersAfterRemove = new List<TextMarker>();
foreach (TextMarker markerAfterRemove in markerStrategy.TextMarker) {
markers.Add(markerAfterRemove);
}
XPathNodeTextMarker xpathNodeTextMarker = (XPathNodeTextMarker)markers[0];
Assert.AreEqual(1, markers.Count);
Assert.AreEqual(1, xpathNodeTextMarker.Offset);
Assert.AreEqual(4, xpathNodeTextMarker.Length);
Assert.AreEqual(TextMarkerType.SolidBlock, xpathNodeTextMarker.TextMarkerType);
Assert.AreEqual(0, markersAfterRemove.Count);
Assert.AreEqual(XPathNodeTextMarker.MarkerBackColor, xpathNodeTextMarker.Color);
}
/// <summary>
/// Tests that XPathNodeMatch with an empty string value are not marked since
/// the MarkerStrategy cannot use a TextMarker with a length of 0.
/// </summary>
[Test]
public void EmptyCommentNode()
{
string xml = "<!----><root/>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//comment()");
MockDocument doc = new MockDocument();
doc.AddLines(xml);
MarkerStrategy markerStrategy = new MarkerStrategy(doc);
XPathNodeTextMarker.AddMarkers(markerStrategy, nodes);
List<TextMarker> markers = new List<TextMarker>();
foreach (TextMarker marker in markerStrategy.TextMarker) {
markers.Add(marker);
}
Assert.AreEqual(0, markers.Count);
Assert.AreEqual(1, nodes.Length);
}
/// <summary>
/// Note that the XPathDocument.SelectNodes call returns a bad XPathNode set
/// back. It finds a namespace node at 0, 0, even though it uses one based
/// line information, it should really return false from HasLineInfo, but it
/// does not. In our XPathNodeMatch we return false from HasLineInfo.
/// </summary>
[Test]
public void NamespaceQuery()
{
string xml = "<?xml version='1.0'?>\r\n" +
"<Xml1></Xml1>";
XPathNodeMatch[] nodes = XmlView.SelectNodes(xml, "//namespace::*");
MockDocument doc = new MockDocument();
doc.AddLines(xml);
MarkerStrategy markerStrategy = new MarkerStrategy(doc);
XPathNodeTextMarker.AddMarkers(markerStrategy, nodes);
List<TextMarker> markers = new List<TextMarker>();
foreach (TextMarker marker in markerStrategy.TextMarker) {
markers.Add(marker);
}
Assert.AreEqual(0, markers.Count);
Assert.AreEqual(1, nodes.Length);
}
}
}

93
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XPathQueryHistoryTestFixture.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
namespace XmlEditor.Tests.XPathQuery
{
/// <summary>
/// Tests that the XPath queries are remembered.
/// </summary>
[TestFixture]
public class XPathQueryHistoryTestFixture
{
string[] expectedXPathsAfterLoad;
string[] comboBoxItemsAfterLoad;
string comboBoxTextAfterLoad;
string[] expectedXPathsAfterSave;
string xpathQueryAfterSave;
string[] xpathsAfterSave;
[SetUp]
public void SetUpFixture()
{
using (XPathQueryControl queryControl = new XPathQueryControl()) {
Properties p = new Properties();
p.Set("XPathQuery.LastQuery", "//w:Wix");
expectedXPathsAfterLoad = new string[] {"//w:Fragment", "//w:Dialog"};
p.Set("XPathQuery.History", expectedXPathsAfterLoad);
queryControl.SetMemento(p);
comboBoxTextAfterLoad = queryControl.XPathComboBox.Text;
comboBoxItemsAfterLoad = GetComboBoxItems(queryControl.XPathComboBox);
queryControl.XPathComboBox.Text = "*";
queryControl.XPathComboBox.Items.Clear();
queryControl.XPathComboBox.Items.Add("xs:schema");
expectedXPathsAfterSave = GetComboBoxItems(queryControl.XPathComboBox);
p = queryControl.CreateMemento();
xpathQueryAfterSave = p.Get("XPathQuery.LastQuery", String.Empty);
xpathsAfterSave = p.Get("XPathQuery.History", new string[0]);
}
}
string[] GetComboBoxItems(ComboBox comboBox)
{
List<string> items = new List<string>();
foreach (string item in comboBox.Items) {
items.Add(item);
}
return items.ToArray();
}
[Test]
public void ComboBoxTextAfterLoad()
{
Assert.AreEqual("//w:Wix", comboBoxTextAfterLoad);
}
[Test]
public void ComboBoxItemsAfterLoad()
{
for (int i = 0; i < expectedXPathsAfterLoad.Length; ++i) {
Assert.AreEqual(expectedXPathsAfterLoad[i], comboBoxItemsAfterLoad[i]);
}
}
[Test]
public void XPathQueryTextAfterSave()
{
Assert.AreEqual("*", xpathQueryAfterSave);
}
[Test]
public void XPathsAfterSave()
{
for (int i = 0; i < expectedXPathsAfterSave.Length; ++i) {
Assert.AreEqual(expectedXPathsAfterSave[i], xpathsAfterSave[i]);
}
}
}
}

74
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XPathResultsListViewColumnWidthsTestFixture.cs

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.Core;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
namespace XmlEditor.Tests.XPathQuery
{
/// <summary>
/// Tests that the XPath results list view column widths are remembered.
/// </summary>
[TestFixture]
public class XPathResultsListViewColumnWidthsTestFixture
{
int matchColumnWidthAfterLoad;
int lineColumnWidthAfterLoad;
int matchColumnWidthAfterSave;
int lineColumnWidthAfterSave;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (XPathQueryControl queryControl = new XPathQueryControl()) {
Properties p = new Properties();
p.Set("XPathResultsListView.MatchColumn.Width", 10);
p.Set("XPathResultsListView.LineColumn.Width", 20);
queryControl.SetMemento(p);
matchColumnWidthAfterLoad = queryControl.XPathResultsListView.Columns[0].Width;
lineColumnWidthAfterLoad = queryControl.XPathResultsListView.Columns[1].Width;
queryControl.XPathResultsListView.Columns[0].Width = 40;
queryControl.XPathResultsListView.Columns[1].Width = 50;
p = queryControl.CreateMemento();
matchColumnWidthAfterSave = p.Get<int>("XPathResultsListView.MatchColumn.Width", 0);
lineColumnWidthAfterSave = p.Get<int>("XPathResultsListView.LineColumn.Width", 0);
}
}
[Test]
public void MatchColumnWidthAfterLoad()
{
Assert.AreEqual(10, matchColumnWidthAfterLoad);
}
[Test]
public void LineColumnWidthAfterLoad()
{
Assert.AreEqual(20, lineColumnWidthAfterLoad);
}
[Test]
public void MatchColumnWidthAfterSave()
{
Assert.AreEqual(40, matchColumnWidthAfterSave);
}
[Test]
public void LineColumnWidthAfterSave()
{
Assert.AreEqual(50, lineColumnWidthAfterSave);
}
}
}

25
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XmlNamespaceTests.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
namespace XmlEditor.Tests.XPathQuery
{
[TestFixture]
public class XmlNamespaceTests
{
[Test]
public void SimpleNamespace()
{
XmlNamespace ns = new XmlNamespace("s", "http://sharpdevelop.com");
Assert.AreEqual("s", ns.Prefix);
Assert.AreEqual("http://sharpdevelop.com", ns.Uri);
}
}
}

56
src/AddIns/DisplayBindings/XmlEditor/Test/XPathQuery/XmlNamespaceToStringTests.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using System;
namespace XmlEditor.Tests.XPathQuery
{
[TestFixture]
public class XmlNamespaceToStringTests
{
[Test]
public void PrefixAndNamespaceToString()
{
XmlNamespace ns = new XmlNamespace("f", "http://foo.com");
Assert.AreEqual("Prefix [f] Uri [http://foo.com]", ns.ToString());
}
[Test]
public void PrefixAndNamespaceFromString()
{
XmlNamespace ns = XmlNamespace.FromString("Prefix [f] Uri [http://foo.com]");
Assert.AreEqual("f", ns.Prefix);
Assert.AreEqual("http://foo.com", ns.Uri);
}
[Test]
public void EmptyPrefixAndNamespaceFromString()
{
XmlNamespace ns = XmlNamespace.FromString("Prefix [] Uri [http://foo.com]");
Assert.AreEqual(String.Empty, ns.Prefix);
Assert.AreEqual("http://foo.com", ns.Uri);
}
[Test]
public void PrefixAndEmptyNamespaceFromString()
{
XmlNamespace ns = XmlNamespace.FromString("Prefix [f] Uri []");
Assert.AreEqual("f", ns.Prefix);
Assert.AreEqual(String.Empty, ns.Uri);
}
[Test]
public void FromEmptyString()
{
XmlNamespace ns = XmlNamespace.FromString(String.Empty);
Assert.AreEqual(String.Empty, ns.Prefix);
Assert.AreEqual(String.Empty, ns.Uri);
}
}
}

20
src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj

@ -92,6 +92,17 @@ @@ -92,6 +92,17 @@
<Compile Include="Schema\MissingSchemaElementTestFixture.cs" />
<Compile Include="Schema\AllElementTestFixture.cs" />
<Compile Include="Parser\InsideAttributeValueTestFixture.cs" />
<Compile Include="XPathQuery\XmlNamespaceTests.cs" />
<Compile Include="XPathQuery\GetNamespacesFromListViewTestFixture.cs" />
<Compile Include="XPathQuery\RunXPathQueryTests.cs" />
<Compile Include="XPathQuery\NamespacePropertiesLoaded.cs" />
<Compile Include="XPathQuery\XmlNamespaceToStringTests.cs" />
<Compile Include="XPathQuery\NamespacePropertiesSaved.cs" />
<Compile Include="XPathQuery\NamespaceGridColumnWidthsLoadedTestFixture.cs" />
<Compile Include="XPathQuery\XPathResultsListViewColumnWidthsTestFixture.cs" />
<Compile Include="XPathQuery\XPathQueryHistoryTestFixture.cs" />
<Compile Include="XPathQuery\XPathNodeTextMarkerTests.cs" />
<Compile Include="Utils\MockDocument.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Schema\" />
@ -108,6 +119,15 @@ @@ -108,6 +119,15 @@
<Name>XmlEditor</Name>
<Private>True</Private>
</ProjectReference>
<Folder Include="XPathQuery" />
<ProjectReference Include="..\..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj">
<Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project>
<Name>ICSharpCode.SharpDevelop</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Main\Core\Project\ICSharpCode.Core.csproj">
<Project>{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}</Project>
<Name>ICSharpCode.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

BIN
src/Main/StartUp/Project/Resources/BitmapResources.resources

Binary file not shown.
Loading…
Cancel
Save