From df3d79371cba1304ef4e03d6d225c4ad10d04891 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Thu, 14 Sep 2006 20:48:20 +0000 Subject: [PATCH] Added a new view to the XML Editor which shows the XML as a tree view. Not feature complete. Currently it is possible to edit existing attribute values and element text but not add new ones or remove existing ones. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1797 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Resources/XmlElementTreeNodeIcon.png | Bin 0 -> 469 bytes .../Project/Resources/XmlTextTreeNodeIcon.png | Bin 0 -> 533 bytes .../XmlEditor/Project/Src/IXmlTreeView.cs | 64 +++ .../Src/XmlAttributePropertyDescriptor.cs | 96 ++++ .../Project/Src/XmlAttributeTypeDescriptor.cs | 96 ++++ .../Project/Src/XmlElementTreeNode.cs | 73 +++ .../XmlEditor/Project/Src/XmlTextTreeNode.cs | 59 +++ .../XmlEditor/Project/Src/XmlTreeEditor.cs | 97 ++++ .../XmlEditor/Project/Src/XmlTreeView.cs | 81 ++++ .../Src/XmlTreeViewContainerControl.cs | 418 ++++++++++++++++++ .../Project/Src/XmlTreeViewControl.cs | 109 +++++ .../XmlEditor/Project/Src/XmlView.cs | 38 +- .../XmlEditor/Project/XmlEditor.csproj | 11 + .../Test/Tree/AttributeChangedTestFixture.cs | 44 ++ .../Tree/DocumentElementOnlyTestFixture.cs | 42 ++ ...xpandChildNodesInTreeControlTestFixture.cs | 180 ++++++++ ...lAttributePropertyDescriptorTestFixture.cs | 97 ++++ .../RootNodeAddedToTreeControlTestFixture.cs | 89 ++++ .../Tree/TextNodeTextChangedTestFixture.cs | 82 ++++ .../Tree/TreeControlViewStateTestFixture.cs | 61 +++ .../Tree/ViewInvalidXmlDocumentTestFixture.cs | 46 ++ .../XmlAttributeTypeDescriptorTestFixture.cs | 50 +++ .../Tree/XmlElementSelectedTestFixture.cs | 62 +++ .../Test/Tree/XmlElementTreeNodeTests.cs | 52 +++ .../Test/Tree/XmlTextSelectedTestFixture.cs | 49 ++ .../Test/Tree/XmlTextTreeNodeTextTests.cs | 59 +++ .../Test/Tree/XmlTreeViewTestFixtureBase.cs | 32 ++ .../XmlEditor/Test/Utils/MockXmlTreeView.cs | 123 ++++++ .../XmlEditor/Test/XmlEditor.Tests.csproj | 16 + 29 files changed, 2219 insertions(+), 7 deletions(-) create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Resources/XmlElementTreeNodeIcon.png create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Resources/XmlTextTreeNodeIcon.png create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/IXmlTreeView.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributePropertyDescriptor.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributeTypeDescriptor.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlElementTreeNode.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTextTreeNode.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeEditor.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeView.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewControl.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AttributeChangedTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/DocumentElementOnlyTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ExpandChildNodesInTreeControlTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/GetXmlAttributePropertyDescriptorTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/RootNodeAddedToTreeControlTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TextNodeTextChangedTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TreeControlViewStateTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ViewInvalidXmlDocumentTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlAttributeTypeDescriptorTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementSelectedTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementTreeNodeTests.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextSelectedTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextTreeNodeTextTests.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewTestFixtureBase.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockXmlTreeView.cs diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/XmlElementTreeNodeIcon.png b/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/XmlElementTreeNodeIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..424d161295aae9f56097cc137ed83f4a4dc71b41 GIT binary patch literal 469 zcmV;`0V@89P)vXU%B2@8qD!X;&6(kv`ovOvNtP!bj_P!<+Sm>AQH+YH0FjLWzi65}pJ zS@;A$&pC5B4!haNTTi|3d7tP1{GZ=@6y?uX&k@8A+{6@Wt)dnOKjGjVyf5Imhp{Ud zI)m;*Xx)X{4X9Xw;zh`IK&lNACLqq@4haN4!1oFZ4`96(RYlRFZ4c^w`Z;eF(q|xX zQUoNT0{%DfJb~?2PwtfNP1{hl4&@&Gd-7DM*dVa>3{J5g>8#FX@k8Avn8kXD3v!(L zy(aK|1lOZ}*>?i%`_Qljm0l=Yg8VtiutSp7C=wmPeg~tM`epMDREu@fG8789ECHul zk2qAj8yt)WVfY++kM$(;DwMh*SHPtS^`FHC1|t{He+nI9y-}=3k_+Y`Q>;ge!?XWl zFc^R?q240aYvj#MLcJ*b<|)%*>ZHLXSVH>~|Nr^|Z_m$YhjS%f00000 LNkvXXu0mjf`Dw`B literal 0 HcmV?d00001 diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/XmlTextTreeNodeIcon.png b/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/XmlTextTreeNodeIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..2c56bf4e68010fecf75e55a284c225553bdf79c4 GIT binary patch literal 533 zcmV+w0_y#VP)Zbb(QMRd zwOW`v8`UazZk$eR<Rh!7KF z<1Ccl(Vre591n5#%1FBwn6(YeL4uIjo<0M|Ts(Ta*)>>NGxDrXv;LQ6USayd+2MdZ zuaPx^TbB+1pb!=iF@ozbiWAftF&rR4UJqU`=0go0-ya +// +// +// +// $Revision$ +// + +using System; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + public interface IXmlTreeView + { + /// + /// Displays an error message indicating that the xml tree view + /// could not display the xml since the xml is not well formed. + /// + /// The exception that occurred when the xml + /// was loaded. + void ShowXmlIsNotWellFormedMessage(XmlException ex); + + /// + /// Gets or sets whether this view needs saving. + /// + bool IsDirty {get; set;} + + /// + /// Gets or sets the xml document element. + /// + XmlElement DocumentElement {get; set;} + + /// + /// Gets the xml element selected. + /// + XmlElement SelectedElement {get;} + + /// + /// Shows the attributes for the selected xml element in the view. + /// + void ShowAttributes(XmlAttributeCollection attributes); + + /// + /// Removes the attributes from the view. + /// + void ClearAttributes(); + + /// + /// Shows the xml element text content. + /// + void ShowTextContent(string text); + + /// + /// Gets the text content currently on display. + /// + string TextContent {get;} + + /// + /// Gets the xml element text node. + /// + XmlText SelectedTextNode {get;} + + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributePropertyDescriptor.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributePropertyDescriptor.cs new file mode 100644 index 0000000000..b57f5183f0 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributePropertyDescriptor.cs @@ -0,0 +1,96 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + /// + /// Property descriptor for an XmlAttribute. This is used when displaying + /// an XmlAttribute in the property grid. + /// + public class XmlAttributePropertyDescriptor : PropertyDescriptor + { + XmlAttribute xmlAttribute; + public XmlAttributePropertyDescriptor(XmlAttribute xmlAttribute) + : base(xmlAttribute.LocalName, new Attribute[0]) + { + this.xmlAttribute = xmlAttribute; + } + + /// + /// Gets the property descriptors for the specified attributes. + /// + public static PropertyDescriptorCollection GetProperties(XmlAttributeCollection xmlAttributes) + { + List properties = new List(); + foreach (XmlAttribute xmlAttribute in xmlAttributes) { + properties.Add(new XmlAttributePropertyDescriptor(xmlAttribute)); + } + return new PropertyDescriptorCollection(properties.ToArray()); + } + + public override Type ComponentType { + get { + return typeof(String); + } + } + + public override bool IsReadOnly { + get { + return false; + } + } + + /// + /// Returns the property type in this case a string. + /// + public override Type PropertyType { + get { + return typeof(String); + } + } + + public override bool CanResetValue(object component) + { + return false; + } + + /// + /// Gets the value of the xml attribute. + /// + public override object GetValue(object component) + { + return xmlAttribute.Value; + } + + public override void ResetValue(object component) + { + } + + /// + /// Sets the xml attribute value. + /// + public override void SetValue(object component, object value) + { + xmlAttribute.Value = (String)value; + } + + /// + /// If the current value has changed from the default value then this + /// method will return true. + /// + public override bool ShouldSerializeValue(object component) + { + return true; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributeTypeDescriptor.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributeTypeDescriptor.cs new file mode 100644 index 0000000000..ee670be0f0 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlAttributeTypeDescriptor.cs @@ -0,0 +1,96 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + /// + /// Type descriptor that allows us to display properties in the property grid + /// for Xml attributes. + /// + public class XmlAttributeTypeDescriptor : ICustomTypeDescriptor + { + PropertyDescriptorCollection properties; + + public XmlAttributeTypeDescriptor(XmlAttributeCollection xmlAttributes) + { + if (xmlAttributes != null) { + properties = XmlAttributePropertyDescriptor.GetProperties(xmlAttributes); + } else { + properties = new PropertyDescriptorCollection(new XmlAttributePropertyDescriptor[0]); + } + } + + public AttributeCollection GetAttributes() + { + return null; + } + + public string GetClassName() + { + return null; + } + + public string GetComponentName() + { + return null; + } + + public TypeConverter GetConverter() + { + return null; + } + + public EventDescriptor GetDefaultEvent() + { + return null; + } + + public PropertyDescriptor GetDefaultProperty() + { + return null; + } + + public object GetEditor(Type editorBaseType) + { + return null; + } + + public EventDescriptorCollection GetEvents() + { + return null; + } + + public EventDescriptorCollection GetEvents(Attribute[] attributes) + { + return null; + } + + public PropertyDescriptorCollection GetProperties() + { + return GetProperties(new Attribute[0]); + } + + public PropertyDescriptorCollection GetProperties(Attribute[] attributes) + { + return properties; + } + + /// + /// Returns this class instance. + /// + public object GetPropertyOwner(PropertyDescriptor pd) + { + return this; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlElementTreeNode.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlElementTreeNode.cs new file mode 100644 index 0000000000..d58a516287 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlElementTreeNode.cs @@ -0,0 +1,73 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.SharpDevelop.Gui; +using System; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + public class XmlElementTreeNode : ExtTreeNode + { + public const string XmlElementTreeNodeImageKey = "XmlElementTreeNodeImage"; + + XmlElement element; + + public XmlElementTreeNode(XmlElement element) + { + this.element = element; + Text = GetDisplayText(element); + Tag = element; + ImageKey = XmlElementTreeNodeImageKey; + + if (element.HasChildNodes) { + // Add dummy node so that the tree node can be + // expanded in the tree view. + Nodes.Add(new ExtTreeNode()); + } + } + + /// + /// Gets the XmlElement associated with this tree node. + /// + public XmlElement XmlElement { + get { + return element; + } + } + + /// + /// Adds child elements to this tree node. + /// + protected override void Initialize() + { + Nodes.Clear(); + foreach (XmlNode childNode in element.ChildNodes) { + XmlElement childElement = childNode as XmlElement; + XmlText text = childNode as XmlText; + if (childElement != null) { + XmlElementTreeNode treeNode = new XmlElementTreeNode(childElement); + treeNode.AddTo(this); + } else if (text != null) { + XmlTextTreeNode treeNode = new XmlTextTreeNode(text); + treeNode.AddTo(this); + } + } + } + + /// + /// Gets the tree node's text for the element. + /// + static string GetDisplayText(XmlElement element) + { + if (element.Prefix.Length > 0) { + return String.Concat(element.Prefix, ":", element.LocalName); + } + return element.LocalName; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTextTreeNode.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTextTreeNode.cs new file mode 100644 index 0000000000..39ed5e3d41 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTextTreeNode.cs @@ -0,0 +1,59 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.SharpDevelop.Gui; +using System; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + public class XmlTextTreeNode : ExtTreeNode + { + public const string XmlTextTreeNodeImageKey = "XmlTextTreeNodeImage"; + + XmlText xmlText; + + public XmlTextTreeNode(XmlText xmlText) + { + this.xmlText = xmlText; + ImageKey = XmlTextTreeNodeImageKey; + SelectedImageKey = ImageKey; + Text = GetDisplayText(xmlText.InnerText); + } + + public XmlText XmlText { + get { + return xmlText; + } + } + + /// + /// Gets the text to display for this tree node. + /// + /// If the text is a single line then it is returned, but + /// trimmed. If the text has multiple lines then the first line that + /// is not empty is returned. This line may have "..." appended to indicate + /// there is more text for this node that is not being displayed. The + /// "..." will be appended only if there are multiple lines containing + /// text. + static string GetDisplayText(string s) + { + string[] lines = s.Trim().Split('\n'); + for (int i = 0; i < lines.Length; ++i) { + string line = lines[i].Trim(); + if (line.Length > 0) { + if (lines.Length == 1) { + return line; + } else { + return String.Concat(line, "..."); + } + } + } + return String.Empty; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeEditor.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeEditor.cs new file mode 100644 index 0000000000..d1dfb3417c --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeEditor.cs @@ -0,0 +1,97 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + /// + /// The class that is responsible for controlling the editing of the + /// Xml tree view. + /// + public class XmlTreeEditor + { + IXmlTreeView view; + XmlDocument document; + + public XmlTreeEditor(IXmlTreeView view) + { + this.view = view; + } + + /// + /// Loads the xml into the editor. + /// + public void LoadXml(string xml) + { + try { + document = new XmlDocument(); + document.LoadXml(xml); + XmlElement documentElement = document.DocumentElement; + view.DocumentElement = documentElement; + } catch (XmlException ex) { + view.ShowXmlIsNotWellFormedMessage(ex); + } + } + + /// + /// Gets the Xml document being edited. + /// + public XmlDocument Document { + get { + return document; + } + } + + /// + /// The selected xml element in the view has changed. + /// + public void SelectedElementChanged() + { + XmlElement selectedElement = view.SelectedElement; + if (selectedElement != null) { + view.ShowAttributes(selectedElement.Attributes); + } else { + view.ClearAttributes(); + } + } + + /// + /// The selected xml text node in the view has changed. + /// + public void SelectedTextNodeChanged() + { + XmlText selectedTextNode = view.SelectedTextNode; + if (selectedTextNode != null) { + view.ShowTextContent(selectedTextNode.InnerText); + } else { + view.ShowTextContent(String.Empty); + } + } + + /// + /// The attribute value has changed. + /// + public void AttributeValueChanged() + { + view.IsDirty = true; + } + + /// + /// The text content has been changed in the view. + /// + public void TextContentChanged() + { + XmlText textNode = view.SelectedTextNode; + if (textNode != null) { + view.IsDirty = true; + textNode.Value = view.TextContent; + } + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeView.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeView.cs new file mode 100644 index 0000000000..f9db8de104 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeView.cs @@ -0,0 +1,81 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; +using System; +using System.Windows.Forms; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + /// + /// The secondary view content that displays the XML document as a tree view. + /// + public class XmlTreeView : AbstractSecondaryViewContent + { + XmlTreeViewContainerControl treeViewContainer = new XmlTreeViewContainerControl(); + XmlView xmlView; + bool disposed; + + public XmlTreeView(XmlView xmlView) + { + this.xmlView = xmlView; + treeViewContainer.DirtyChanged += TreeViewContainerDirtyChanged; + } + + public override Control Control { + get { + return treeViewContainer; + } + } + + public override string TabPageText { + get { + return "XML Tree"; + } + } + + public override void Dispose() + { + if (!disposed) { + disposed = true; + treeViewContainer.Dispose(); + } + } + + public override void Selected() + { + treeViewContainer.LoadXml(xmlView.Text); + xmlView.CheckIsWellFormed(); + } + + public override void Deselecting() + { + if (!disposed) { + if (treeViewContainer.IsDirty) { + xmlView.ReplaceAll(treeViewContainer.Document.OuterXml); + treeViewContainer.IsDirty = false; + } + } + } + + public XmlElement DocumentElement { + get { + return treeViewContainer.TreeView.DocumentElement; + } + set { + treeViewContainer.DocumentElement = value; + } + } + + void TreeViewContainerDirtyChanged(object source, EventArgs e) + { + xmlView.IsDirty = treeViewContainer.IsDirty; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs new file mode 100644 index 0000000000..e8dccf94be --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs @@ -0,0 +1,418 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + /// + /// This user control holds both the XmlTreeViewControl and the + /// attributes property grid in a split container. This is separate from + /// the XmlTreeView class so we can use the forms designer to design this control. + /// + public class XmlTreeViewContainerControl : System.Windows.Forms.UserControl, IXmlTreeView + { + XmlTreeEditor editor; + bool dirty; + bool errorMessageTextBoxVisible; + bool attributesGridVisible = true; + bool textBoxVisible; + + public event EventHandler DirtyChanged; + + public XmlTreeViewContainerControl() + { + InitializeComponent(); + InitImages(); + } + + /// + /// Gets or sets whether the xml document needs saving. + /// + public bool IsDirty { + get { + return dirty; + } + set { + dirty = value; + } + } + + /// + /// Gets or sets the error message to display. + /// + public string ErrorMessage { + get { + return errorMessageTextBox.Text; + } + set { + errorMessageTextBox.Text = value; + } + } + + /// + /// Gets or sets whether the error message is visible. When visible the + /// error message text box replaces the property grid. + /// + public bool IsErrorMessageTextBoxVisible { + get { + return errorMessageTextBoxVisible; + } + set { + errorMessageTextBoxVisible = value; + if (value) { + errorMessageTextBox.BringToFront(); + errorMessageTextBox.TabStop = true;; + IsAttributesGridVisible = false; + IsTextBoxVisible = false; + } else { + errorMessageTextBox.SendToBack(); + errorMessageTextBox.TabStop = false; + } + } + } + + public XmlTreeViewControl TreeView { + get { + return xmlElementTreeView; + } + } + + public void ShowXmlIsNotWellFormedMessage(XmlException ex) + { + xmlElementTreeView.Clear(); + ErrorMessage = ex.Message; + IsErrorMessageTextBoxVisible = true; + } + + public XmlElement DocumentElement { + get { + return xmlElementTreeView.DocumentElement; + } + set { + xmlElementTreeView.DocumentElement = value; + } + } + + /// + /// Displays the specified xml as a tree. + /// + public void LoadXml(string xml) + { + textBox.Clear(); + IsAttributesGridVisible = true; + ClearAttributes(); + + editor = new XmlTreeEditor(this); + editor.LoadXml(xml); + + // Expand document element node. This ensures that the view state + // can be restored since the child nodes are lazily added. + if (xmlElementTreeView.Nodes.Count > 0) { + xmlElementTreeView.Nodes[0].Expand(); + } + } + + /// + /// Gets the xml document created from the loaded Xml. + /// + public XmlDocument Document { + get { + return editor.Document; + } + } + + /// + /// Shows the attributes. + /// + public void ShowAttributes(XmlAttributeCollection attributes) + { + IsAttributesGridVisible = true; + attributesGrid.SelectedObject = new XmlAttributeTypeDescriptor(attributes); + } + + /// + /// Clears all the attributes currently on display. + /// + public void ClearAttributes() + { + attributesGrid.SelectedObject = null; + } + + /// + /// Shows the xml element's text content after the user has + /// selected the text node. + /// + public void ShowTextContent(string text) + { + IsTextBoxVisible = true; + textBox.Text = text; + } + + /// + /// Gets the text node text currently on display. + /// + public string TextContent { + get { + return textBox.Text; + } + } + + /// + /// Gets the element currently selected. + /// + public XmlElement SelectedElement { + get { + return xmlElementTreeView.SelectedElement; + } + } + + /// + /// Gets the element text node currently selected. + /// + public XmlText SelectedTextNode { + get { + return xmlElementTreeView.SelectedTextNode; + } + } + + /// + /// Disposes resources used by the control. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + #region Forms Designer generated code + + /// + /// Designer variable used to keep track of non-visual components. + /// + System.ComponentModel.IContainer components = null; + + /// + /// 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. + /// + void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + ICSharpCode.SharpDevelop.Gui.ExtTreeViewComparer extTreeViewComparer1 = new ICSharpCode.SharpDevelop.Gui.ExtTreeViewComparer(); + this.splitContainer = new System.Windows.Forms.SplitContainer(); + this.xmlElementTreeView = new ICSharpCode.XmlEditor.XmlTreeViewControl(); + this.attributesGrid = new System.Windows.Forms.PropertyGrid(); + this.errorMessageTextBox = new System.Windows.Forms.RichTextBox(); + this.textBox = new System.Windows.Forms.RichTextBox(); + this.splitContainer.Panel1.SuspendLayout(); + this.splitContainer.Panel2.SuspendLayout(); + this.splitContainer.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer + // + this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer.Location = new System.Drawing.Point(0, 0); + this.splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + this.splitContainer.Panel1.Controls.Add(this.xmlElementTreeView); + // + // splitContainer.Panel2 + // + this.splitContainer.Panel2.Controls.Add(this.attributesGrid); + this.splitContainer.Panel2.Controls.Add(this.errorMessageTextBox); + this.splitContainer.Panel2.Controls.Add(this.textBox); + this.splitContainer.Size = new System.Drawing.Size(562, 326); + this.splitContainer.SplitterDistance = 185; + this.splitContainer.SplitterWidth = 2; + this.splitContainer.TabIndex = 0; + this.splitContainer.TabStop = false; + // + // xmlElementTreeView + // + this.xmlElementTreeView.AllowDrop = true; + this.xmlElementTreeView.CanClearSelection = true; + this.xmlElementTreeView.Dock = System.Windows.Forms.DockStyle.Fill; + this.xmlElementTreeView.DocumentElement = null; + this.xmlElementTreeView.DrawMode = System.Windows.Forms.TreeViewDrawMode.OwnerDrawText; + this.xmlElementTreeView.HideSelection = false; + this.xmlElementTreeView.ImageIndex = 0; + this.xmlElementTreeView.IsSorted = false; + this.xmlElementTreeView.Location = new System.Drawing.Point(0, 0); + this.xmlElementTreeView.Name = "xmlElementTreeView"; + this.xmlElementTreeView.NodeSorter = extTreeViewComparer1; + this.xmlElementTreeView.SelectedImageIndex = 0; + this.xmlElementTreeView.Size = new System.Drawing.Size(185, 326); + this.xmlElementTreeView.TabIndex = 0; + this.xmlElementTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.XmlElementTreeViewAfterSelect); + // + // attributesGrid + // + this.attributesGrid.Dock = System.Windows.Forms.DockStyle.Fill; + this.attributesGrid.HelpVisible = false; + this.attributesGrid.Location = new System.Drawing.Point(0, 0); + this.attributesGrid.Name = "attributesGrid"; + this.attributesGrid.PropertySort = System.Windows.Forms.PropertySort.Alphabetical; + this.attributesGrid.Size = new System.Drawing.Size(375, 326); + this.attributesGrid.TabIndex = 1; + this.attributesGrid.ToolbarVisible = false; + this.attributesGrid.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.AttributesGridPropertyValueChanged); + // + // errorMessageTextBox + // + this.errorMessageTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.errorMessageTextBox.Location = new System.Drawing.Point(0, 0); + this.errorMessageTextBox.Name = "errorMessageTextBox"; + this.errorMessageTextBox.Size = new System.Drawing.Size(375, 326); + this.errorMessageTextBox.TabIndex = 0; + this.errorMessageTextBox.TabStop = false; + this.errorMessageTextBox.Text = ""; + // + // textBox + // + this.textBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBox.Location = new System.Drawing.Point(0, 0); + this.textBox.Name = "textBox"; + this.textBox.Size = new System.Drawing.Size(375, 326); + this.textBox.TabIndex = 2; + this.textBox.TabStop = false; + this.textBox.Text = ""; + this.textBox.TextChanged += new System.EventHandler(this.TextBoxTextChanged); + // + // XmlTreeViewContainerControl + // + this.Controls.Add(this.splitContainer); + this.Name = "XmlTreeViewContainerControl"; + this.Size = new System.Drawing.Size(562, 326); + this.splitContainer.Panel1.ResumeLayout(false); + this.splitContainer.Panel2.ResumeLayout(false); + this.splitContainer.ResumeLayout(false); + this.ResumeLayout(false); + } + private System.Windows.Forms.RichTextBox textBox; + private System.Windows.Forms.PropertyGrid attributesGrid; + private System.Windows.Forms.RichTextBox errorMessageTextBox; + private ICSharpCode.XmlEditor.XmlTreeViewControl xmlElementTreeView; + private System.Windows.Forms.SplitContainer splitContainer; + + #endregion + + /// + /// Creates an image list that will be used for the XmlTreeViewControl. + /// + void InitImages() + { + if (components == null) { + components = new Container(); + } + ImageList images = new ImageList(components); + Image xmlElementImage = Image.FromStream(GetType().Assembly.GetManifestResourceStream("ICSharpCode.XmlEditor.Resources.XmlElementTreeNodeIcon.png")); + images.Images.Add(XmlElementTreeNode.XmlElementTreeNodeImageKey, xmlElementImage); + Image xmlTextImage = Image.FromStream(GetType().Assembly.GetManifestResourceStream("ICSharpCode.XmlEditor.Resources.XmlTextTreeNodeIcon.png")); + images.Images.Add(XmlTextTreeNode.XmlTextTreeNodeImageKey, xmlTextImage); + xmlElementTreeView.ImageList = images; + } + + void XmlElementTreeViewAfterSelect(object sender, TreeViewEventArgs e) + { + if (xmlElementTreeView.IsTextNodeSelected) { + editor.SelectedTextNodeChanged(); + } else { + editor.SelectedElementChanged(); + } + } + + void TextBoxTextChanged(object sender, EventArgs e) + { + bool previousIsDirty = dirty; + editor.TextContentChanged(); + OnXmlChanged(previousIsDirty); + } + + void AttributesGridPropertyValueChanged(object s, PropertyValueChangedEventArgs e) + { + bool previousIsDirty = dirty; + editor.AttributeValueChanged(); + OnXmlChanged(previousIsDirty); + } + + /// + /// Raises the dirty changed event if the dirty flag has changed. + /// + void OnXmlChanged(bool previousIsDirty) + { + if (previousIsDirty != dirty) { + OnDirtyChanged(); + } + } + + /// + /// Raises the DirtyChanged event. + /// + void OnDirtyChanged() + { + if (DirtyChanged != null) { + DirtyChanged(this, new EventArgs()); + } + } + + /// + /// Gets or sets whether the attributes grid is visible. + /// + bool IsAttributesGridVisible { + get { + return attributesGridVisible; + } + set { + attributesGridVisible = value; + if (value) { + attributesGrid.BringToFront(); + attributesGrid.TabStop = true; + IsTextBoxVisible = false; + IsErrorMessageTextBoxVisible = false; + } else { + attributesGrid.SendToBack(); + attributesGrid.TabStop = false; + } + } + } + + /// + /// Gets or sets whether the text node text box is visible. + /// + bool IsTextBoxVisible { + get { + return textBoxVisible; + } + set { + textBoxVisible = value; + if (value) { + textBox.BringToFront(); + textBox.TabStop = true; + IsAttributesGridVisible = false; + IsErrorMessageTextBoxVisible = false; + } else { + textBox.SendToBack(); + textBox.TabStop = false; + } + } + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewControl.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewControl.cs new file mode 100644 index 0000000000..58cf874cb0 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewControl.cs @@ -0,0 +1,109 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; +using System; +using System.ComponentModel; +using System.Windows.Forms; +using System.Windows.Forms.Design; +using System.Xml; + +namespace ICSharpCode.XmlEditor +{ + /// + /// Displays a tree of XML elements. This is a separate control so it can + /// be unit tested. It has no SharpDevelop specific parts, for example, + /// the context menus are defined in the XmlTreeViewContainerControl. + /// + public class XmlTreeViewControl : ExtTreeView + { + const string ViewStatePropertyName = "XmlTreeViewControl.ViewState"; + + XmlElement documentElement; + + public XmlTreeViewControl() + { + } + + [Browsable(false)] + public XmlElement DocumentElement { + get { + return documentElement; + } + set { + documentElement = value; + + // Update display. + BeginUpdate(); + try { + ShowDocumentElement(); + } finally { + EndUpdate(); + } + } + } + + public XmlElement SelectedElement { + get { + XmlElementTreeNode xmlElementTreeNode = SelectedNode as XmlElementTreeNode; + if (xmlElementTreeNode != null) { + return xmlElementTreeNode.XmlElement; + } + return null; + } + } + + public bool IsElementSelected { + get { + return SelectedElement != null; + } + } + + public XmlText SelectedTextNode { + get { + XmlTextTreeNode xmlTextTreeNode = SelectedNode as XmlTextTreeNode; + if (xmlTextTreeNode != null) { + return xmlTextTreeNode.XmlText; + } + + return null; + } + } + + public bool IsTextNodeSelected { + get { + return SelectedTextNode != null; + } + } + + /// + /// Saves the current state of the tree. + /// + public void SaveViewState(Properties properties) + { + properties.Set(ViewStatePropertyName, ExtTreeView.GetViewStateString(this)); + } + + /// + /// Restores the node state of the tree. + /// + public void RestoreViewState(Properties properties) + { + ExtTreeView.ApplyViewStateString(properties.Get(ViewStatePropertyName, String.Empty), this); + } + + void ShowDocumentElement() + { + Nodes.Clear(); + if (documentElement != null) { + XmlElementTreeNode node = new XmlElementTreeNode(documentElement); + node.AddTo(this); + } + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs index 1b013e7cc5..a6c7a72e11 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlView.cs @@ -49,6 +49,7 @@ namespace ICSharpCode.XmlEditor bool wasChangedExternally; static MessageViewCategory category; string stylesheetFileName; + XmlTreeView xmlTreeView; public XmlView() { @@ -65,6 +66,9 @@ namespace ICSharpCode.XmlEditor XmlEditorAddInOptions.PropertyChanged += PropertyChanged; XmlSchemaManager.UserSchemaAdded += new EventHandler(UserSchemaAdded); XmlSchemaManager.UserSchemaRemoved += new EventHandler(UserSchemaRemoved); + + xmlTreeView = new XmlTreeView(this); + SecondaryViewContents.Add(xmlTreeView); } /// @@ -364,9 +368,7 @@ namespace ICSharpCode.XmlEditor TaskService.ClearExceptCommentTasks(); if (IsWellFormed) { - string xml = SimpleFormat(IndentedFormat(Text)); - xmlEditor.Document.Replace(0, xmlEditor.Document.TextLength, xml); - UpdateFolding(); + ReplaceAll(Text); } else { ShowErrorList(); } @@ -417,6 +419,29 @@ namespace ICSharpCode.XmlEditor } } + /// + /// Checks that the xml is well formed. Any errors are displayed in the + /// errors list. + /// + public void CheckIsWellFormed() + { + TaskService.ClearExceptCommentTasks(); + if (!IsWellFormed) { + ShowErrorList(); + } + } + + /// + /// Replaces the entire text of the xml view with the xml in the + /// specified. The xml will be formatted. + /// + public void ReplaceAll(string xml) + { + string formattedXml = SimpleFormat(IndentedFormat(xml)); + xmlEditor.Document.Replace(0, xmlEditor.Document.TextLength, formattedXml); + UpdateFolding(); + } + #region IEditable interface public IClipboardHandler ClipboardHandler { @@ -604,9 +629,8 @@ namespace ICSharpCode.XmlEditor xmlEditor.Document.HighlightingStrategy = highlightingStrategy; } } - xmlEditor.ActiveTextAreaControl.TextArea.TextView.FirstVisibleLine = properties.Get("VisibleLine", 0); - - xmlEditor.Document.FoldingManager.DeserializeFromString(properties.Get("Foldings", "")); + xmlEditor.ActiveTextAreaControl.TextArea.TextView.FirstVisibleLine = properties.Get("VisibleLine", 0); + xmlEditor.Document.FoldingManager.DeserializeFromString(properties.Get("Foldings", String.Empty)); } public Properties CreateMemento() @@ -1005,7 +1029,7 @@ namespace ICSharpCode.XmlEditor bool IsWellFormed { get { try { - XmlDocument Document = new XmlDocument( ); + XmlDocument Document = new XmlDocument(); Document.LoadXml(Text); return true; } catch(XmlException ex) { diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj b/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj index a890ef2972..6eaf7739db 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj @@ -115,6 +115,17 @@ + + + + + + + + + + + diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AttributeChangedTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AttributeChangedTestFixture.cs new file mode 100644 index 0000000000..3c63fcb7a4 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AttributeChangedTestFixture.cs @@ -0,0 +1,44 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + /// + /// Tests that an attribute being changed updates the xml document and + /// sets the view to be dirty. + /// + [TestFixture] + public class AttributeChangedTestFixture : XmlTreeViewTestFixtureBase + { + [SetUp] + public void SetUpFixture() + { + base.InitFixture(); + mockXmlTreeView.SelectedElement = mockXmlTreeView.DocumentElement; + editor.SelectedElementChanged(); + XmlAttribute attribute = mockXmlTreeView.DocumentElement.Attributes["first"]; + attribute.Value = "new value"; + editor.AttributeValueChanged(); + } + + [Test] + public void IsDirty() + { + Assert.IsTrue(mockXmlTreeView.IsDirty); + } + + protected override string GetXml() + { + return ""; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/DocumentElementOnlyTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/DocumentElementOnlyTestFixture.cs new file mode 100644 index 0000000000..6699dc5a13 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/DocumentElementOnlyTestFixture.cs @@ -0,0 +1,42 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; +using XmlEditor.Tests.Utils; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class DocumentElementOnlyTestFixture : XmlTreeViewTestFixtureBase + { + [TestFixtureSetUp] + public void SetUpFixture() + { + base.InitFixture(); + } + + [Test] + public void RootElementAdded() + { + Assert.AreEqual("root", mockXmlTreeView.DocumentElement.Name); + } + + [Test] + public void RootElementInDocument() + { + Assert.IsTrue(Object.ReferenceEquals(editor.Document.DocumentElement, mockXmlTreeView.DocumentElement)); + } + + protected override string GetXml() + { + return ""; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ExpandChildNodesInTreeControlTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ExpandChildNodesInTreeControlTestFixture.cs new file mode 100644 index 0000000000..c5072d6258 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ExpandChildNodesInTreeControlTestFixture.cs @@ -0,0 +1,180 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Windows.Forms; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class ExpandChildNodesInTreeControlTestFixture + { + ExtTreeNode rootNode; + XmlDocument doc; + ExtTreeNode firstChildNode; + ExtTreeNode secondChildNode; + ExtTreeNode textChildNode; + ExtTreeNode textNode; + bool rootNodeHadChildrenBeforeExpansion; + bool firstChildNodeHadChildrenBeforeExpansion; + XmlElement rootNodeElement; + XmlElement textNodeElement; + bool isRootElementSelected; + bool isTextContentSelectedBeforeTextNodeSelected; + bool isTextContentSelectedAfterTextNodeSelected; + XmlText textContentBefore; + XmlText textContentAfter; + + [TestFixtureSetUp] + public void SetUpFixture() + { + doc = new XmlDocument(); + doc.LoadXml("some text"); + using (XmlTreeViewControl treeView = new XmlTreeViewControl()) { + treeView.DocumentElement = doc.DocumentElement; + treeView.SelectedNode = treeView.Nodes[0]; + rootNodeElement = treeView.SelectedElement; + isRootElementSelected = treeView.IsElementSelected; + rootNode = (ExtTreeNode)treeView.SelectedNode; + rootNodeHadChildrenBeforeExpansion = rootNode.Nodes.Count > 0; + rootNode.Expanding(); + firstChildNode = (ExtTreeNode)rootNode.Nodes[0]; + firstChildNodeHadChildrenBeforeExpansion = firstChildNode.Nodes.Count > 0; + firstChildNode.Expanding(); + secondChildNode = (ExtTreeNode)firstChildNode.Nodes[0]; + textChildNode = (ExtTreeNode)rootNode.Nodes[1]; + textChildNode.Expanding(); + textNode = (ExtTreeNode)textChildNode.Nodes[0]; + isTextContentSelectedBeforeTextNodeSelected = treeView.IsTextNodeSelected; + textContentBefore = treeView.SelectedTextNode; + treeView.SelectedNode = textNode; + isTextContentSelectedAfterTextNodeSelected = treeView.IsTextNodeSelected; + textContentAfter = treeView.SelectedTextNode; + textNodeElement = treeView.SelectedElement; + } + } + + [Test] + public void RootElementIsDocumentElement() + { + Assert.IsTrue(Object.ReferenceEquals(rootNodeElement, doc.DocumentElement)); + } + + [Test] + public void RootNodeHadChildrenBeforeExpansion() + { + Assert.IsTrue(rootNodeHadChildrenBeforeExpansion); + } + + [Test] + public void RootNodeText() + { + Assert.AreEqual("root", rootNode.Text); + } + + [Test] + public void FirstChildNodeHadChildrenBeforeExpansion() + { + Assert.IsTrue(firstChildNodeHadChildrenBeforeExpansion); + } + + [Test] + public void FirstChildNodeText() + { + Assert.AreEqual("firstChild", firstChildNode.Text); + } + + [Test] + public void FirstChildNodeImageKey() + { + Assert.AreEqual(XmlElementTreeNode.XmlElementTreeNodeImageKey, firstChildNode.ImageKey); + } + + [Test] + public void SecondChildNodeText() + { + Assert.AreEqual("secondChild", secondChildNode.Text); + } + + [Test] + public void SecondChildNodeImageKey() + { + Assert.AreEqual(XmlElementTreeNode.XmlElementTreeNodeImageKey, secondChildNode.ImageKey); + } + + [Test] + public void TextChildNodeText() + { + Assert.AreEqual("textChild", textChildNode.Text); + } + + [Test] + public void TextNodeExists() + { + Assert.IsNotNull(textNode); + } + + [Test] + public void TextNodeImageKey() + { + Assert.AreEqual(XmlTextTreeNode.XmlTextTreeNodeImageKey, textNode.ImageKey); + } + + [Test] + public void TextNodeSelectedImageKey() + { + Assert.AreEqual(XmlTextTreeNode.XmlTextTreeNodeImageKey, textNode.SelectedImageKey); + } + + [Test] + public void TextNodeText() + { + Assert.AreEqual("some text", textNode.Text); + } + + [Test] + public void NoElementForSelectedTextNode() + { + Assert.IsNull(textNodeElement); + } + + [Test] + public void IsElementSelectedForRootNode() + { + Assert.IsTrue(isRootElementSelected); + } + + [Test] + public void TextContentNotSelectedBeforeTextNodeSelected() + { + Assert.IsFalse(isTextContentSelectedBeforeTextNodeSelected); + } + + [Test] + public void TextContentSelectedAfterTextNodeSelected() + { + Assert.IsTrue(isTextContentSelectedAfterTextNodeSelected); + } + + [Test] + public void TextNodeNotSelectedBeforeTextNodeSelected() + { + Assert.IsNull(textContentBefore); + } + + [Test] + public void TextNodeSelectedAfterTextNodeSelected() + { + Assert.IsNotNull(textContentAfter); + Assert.AreEqual("some text", textContentAfter.InnerText); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/GetXmlAttributePropertyDescriptorTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/GetXmlAttributePropertyDescriptorTestFixture.cs new file mode 100644 index 0000000000..7d67a4d903 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/GetXmlAttributePropertyDescriptorTestFixture.cs @@ -0,0 +1,97 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.ComponentModel; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class GetXmlAttributePropertyDescriptorTestFixture + { + PropertyDescriptorCollection properties; + XmlAttributePropertyDescriptor firstAttributePropertyDescriptor; + XmlAttributePropertyDescriptor secondAttributePropertyDescriptor; + XmlAttribute firstAttribute; + + [SetUp] + public void Init() + { + XmlDocument document = new XmlDocument(); + document.LoadXml(""); + firstAttribute = document.DocumentElement.GetAttributeNode("first"); + properties = XmlAttributePropertyDescriptor.GetProperties(document.DocumentElement.Attributes); + firstAttributePropertyDescriptor = (XmlAttributePropertyDescriptor)properties["first"]; + secondAttributePropertyDescriptor = (XmlAttributePropertyDescriptor)properties["second"]; + } + + [Test] + public void TwoPropertyDescriptors() + { + Assert.AreEqual(2, properties.Count); + } + + [Test] + public void FirstPropertyName() + { + Assert.AreEqual("first", firstAttributePropertyDescriptor.Name); + } + + [Test] + public void FirstPropertyComponentType() + { + Assert.AreEqual(typeof(String), firstAttributePropertyDescriptor.ComponentType); + } + + [Test] + public void FirstPropertyReadOnly() + { + Assert.IsFalse(firstAttributePropertyDescriptor.IsReadOnly); + } + + [Test] + public void FirstPropertyType() + { + Assert.AreEqual(typeof(String), firstAttributePropertyDescriptor.PropertyType); + } + + [Test] + public void FirstPropertyCanResetValue() + { + Assert.IsFalse(firstAttributePropertyDescriptor.CanResetValue(null)); + } + + [Test] + public void FirstPropertyShouldSerializeValue() + { + Assert.IsTrue(firstAttributePropertyDescriptor.ShouldSerializeValue(null)); + } + + [Test] + public void FirstPropertyValue() + { + Assert.AreEqual("a", (String)firstAttributePropertyDescriptor.GetValue(null)); + } + + [Test] + public void SecondPropertyValue() + { + Assert.AreEqual("b", (String)secondAttributePropertyDescriptor.GetValue(null)); + } + + [Test] + public void SetFirstPropertyValue() + { + firstAttributePropertyDescriptor.SetValue(null, "new value"); + Assert.AreEqual("new value", (String)firstAttributePropertyDescriptor.GetValue(null)); + Assert.AreEqual("new value", firstAttribute.Value); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/RootNodeAddedToTreeControlTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/RootNodeAddedToTreeControlTestFixture.cs new file mode 100644 index 0000000000..152135a6a3 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/RootNodeAddedToTreeControlTestFixture.cs @@ -0,0 +1,89 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Windows.Forms; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class RootNodeAddedToTreeControlTestFixture + { + XmlElementTreeNode rootNode; + int nodeCount; + XmlDocument doc; + XmlElement initialElementSelected; + bool initialIsElementSelected; + + [TestFixtureSetUp] + public void SetUpFixture() + { + doc = new XmlDocument(); + doc.LoadXml(""); + using (XmlTreeViewControl treeView = new XmlTreeViewControl()) { + treeView.DocumentElement = doc.DocumentElement; + initialElementSelected = treeView.SelectedElement; + initialIsElementSelected = treeView.IsElementSelected; + + // Set the document element again to make sure the existing node + // is removed. + doc.LoadXml(""); + treeView.DocumentElement = null; + treeView.DocumentElement = doc.DocumentElement; + + rootNode = (XmlElementTreeNode)treeView.Nodes[0]; + nodeCount = treeView.Nodes.Count; + } + } + + [Test] + public void NoElementSelectedInitially() + { + Assert.IsNull(initialElementSelected); + } + + [Test] + public void IsNoElementSelectedInitially() + { + Assert.IsFalse(initialIsElementSelected); + } + + [Test] + public void OneNodeAdded() + { + Assert.AreEqual(1, nodeCount); + } + + [Test] + public void RootNodeText() + { + Assert.AreEqual("root", rootNode.Text); + } + + [Test] + public void ImageKey() + { + Assert.AreEqual(XmlElementTreeNode.XmlElementTreeNodeImageKey, rootNode.ImageKey); + } + + [Test] + public void RootNodeHasNoChildren() + { + Assert.AreEqual(0, rootNode.Nodes.Count); + } + + [Test] + public void RootXmlElement() + { + Assert.IsTrue(Object.ReferenceEquals(rootNode.XmlElement, doc.DocumentElement)); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TextNodeTextChangedTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TextNodeTextChangedTestFixture.cs new file mode 100644 index 0000000000..c2aed72d64 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TextNodeTextChangedTestFixture.cs @@ -0,0 +1,82 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + /// + /// Tests that the text for a text node being changed updates the xml document and + /// sets the view to be dirty. + /// + [TestFixture] + public class TextNodeTextChangedTestFixture : XmlTreeViewTestFixtureBase + { + XmlText textNode; + + [SetUp] + public void SetUpFixture() + { + base.InitFixture(); + + // User selects text node and alters its text. + textNode = (XmlText)mockXmlTreeView.DocumentElement.FirstChild; + mockXmlTreeView.SelectedTextNode = textNode; + editor.SelectedTextNodeChanged(); + mockXmlTreeView.TextContentDisplayed = "new value"; + editor.TextContentChanged(); + + // The user then selects another element and then switches + // back to the text node. + mockXmlTreeView.SelectedElement = mockXmlTreeView.DocumentElement; + editor.SelectedElementChanged(); + mockXmlTreeView.TextContentDisplayed = String.Empty; + mockXmlTreeView.SelectedTextNode = textNode; + editor.SelectedTextNodeChanged(); + } + + [Test] + public void IsDirty() + { + Assert.IsTrue(mockXmlTreeView.IsDirty); + } + + [Test] + public void TextContentDisplayed() + { + Assert.AreEqual("new value", mockXmlTreeView.TextContentDisplayed); + } + + [Test] + public void TextNodeUpdated() + { + Assert.AreEqual("new value", textNode.Value); + } + + /// + /// Tests that no exception occurs when the view's text node is null and + /// that the IsDirty flag is not set to true when there is no text node. + /// + [Test] + public void NoTextNodeSelected() + { + mockXmlTreeView.IsDirty = false; + mockXmlTreeView.SelectedTextNode = null; + editor.TextContentChanged(); + + Assert.IsFalse(mockXmlTreeView.IsDirty); + } + + protected override string GetXml() + { + return "text"; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TreeControlViewStateTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TreeControlViewStateTestFixture.cs new file mode 100644 index 0000000000..b7619bb96f --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/TreeControlViewStateTestFixture.cs @@ -0,0 +1,61 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class TreeControlViewStateTestFixture + { + Properties savedProperties = new Properties(); + Properties restoredProperties = new Properties(); + string expectedSavedViewState; + + [TestFixtureSetUp] + public void SetUpFixture() + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml("texttext"); + + // Save view state. + using (XmlTreeViewControl treeView = new XmlTreeViewControl()) { + treeView.DocumentElement = doc.DocumentElement; + ExtTreeNode node = (ExtTreeNode)treeView.Nodes[0]; + node.Expanding(); + expectedSavedViewState = ExtTreeView.GetViewStateString(treeView); + treeView.SaveViewState(savedProperties); + } + + // Load view state. + using (XmlTreeViewControl treeView = new XmlTreeViewControl()) { + treeView.DocumentElement = doc.DocumentElement; + ExtTreeNode node = (ExtTreeNode)treeView.Nodes[0]; + node.Expanding(); + treeView.RestoreViewState(restoredProperties); + } + } + + [Test] + public void ViewStateSaved() + { + string savedViewState = (string)savedProperties.Get("XmlTreeViewControl.ViewState"); + Assert.AreEqual(expectedSavedViewState, savedViewState); + } + + [Test] + public void ViewStateLoaded() + { + Assert.AreEqual(String.Empty, restoredProperties.Get("XmlTreeViewControl.ViewState")); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ViewInvalidXmlDocumentTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ViewInvalidXmlDocumentTestFixture.cs new file mode 100644 index 0000000000..7031bf6663 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/ViewInvalidXmlDocumentTestFixture.cs @@ -0,0 +1,46 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; +using XmlEditor.Tests.Utils; + +namespace XmlEditor.Tests.Tree +{ + /// + /// Tests that the XmlTreeEditor shows an error message when the xml + /// is not well formed. + /// + [TestFixture] + public class ViewInvalidXmlDocumentTestFixture : XmlTreeViewTestFixtureBase + { + [TestFixtureSetUp] + public void SetUpFixture() + { + base.InitFixture(); + } + + [Test] + public void IsXmlNotWellFormedErrorDisplayed() + { + Assert.IsTrue(mockXmlTreeView.IsXmlNotWellFormedMessageDisplayed); + } + + [Test] + public void XmlExceptionPassedToView() + { + Assert.IsNotNull(mockXmlTreeView.NotWellFormedExceptionPassed); + } + + protected override string GetXml() + { + return ""; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlAttributeTypeDescriptorTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlAttributeTypeDescriptorTestFixture.cs new file mode 100644 index 0000000000..01baf763c5 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlAttributeTypeDescriptorTestFixture.cs @@ -0,0 +1,50 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.ComponentModel; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class XmlAttributeTypeDescriptorTestFixture + { + XmlAttributeTypeDescriptor typeDescriptor; + + [SetUp] + public void Init() + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(""); + typeDescriptor = new XmlAttributeTypeDescriptor(doc.DocumentElement.Attributes); + } + + [Test] + public void OneProperty() + { + PropertyDescriptorCollection properties = typeDescriptor.GetProperties(); + Assert.AreEqual(1, properties.Count); + } + + [Test] + public void PropertyName() + { + PropertyDescriptorCollection properties = typeDescriptor.GetProperties(); + PropertyDescriptor descriptor = properties[0]; + Assert.AreEqual("first", descriptor.Name); + } + + [Test] + public void PropertyOwner() + { + Assert.IsTrue(Object.ReferenceEquals(typeDescriptor, typeDescriptor.GetPropertyOwner(null))); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementSelectedTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementSelectedTestFixture.cs new file mode 100644 index 0000000000..4e8a2b8ca4 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementSelectedTestFixture.cs @@ -0,0 +1,62 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + /// + /// A tree node that represents an xml element is selected. This test + /// checks that the XmlTreeEditor tells the view to display the + /// element's attributes. + /// + [TestFixture] + public class XmlElementSelectedTestFixture : XmlTreeViewTestFixtureBase + { + [SetUp] + public void SetUpFixture() + { + base.InitFixture(); + mockXmlTreeView.SelectedElement = mockXmlTreeView.DocumentElement; + editor.SelectedElementChanged(); + } + + [Test] + public void AttributesDisplayed() + { + Assert.AreEqual(2, mockXmlTreeView.AttributesDisplayed.Count); + } + + [Test] + public void FirstAttributeName() + { + Assert.AreEqual("first", mockXmlTreeView.AttributesDisplayed[0].Name); + } + + [Test] + public void SecondAttributeName() + { + Assert.AreEqual("second", mockXmlTreeView.AttributesDisplayed[1].Name); + } + + [Test] + public void NoElementSelected() + { + mockXmlTreeView.SelectedElement = null; + editor.SelectedElementChanged(); + Assert.AreEqual(0, mockXmlTreeView.AttributesDisplayed.Count); + } + + protected override string GetXml() + { + return ""; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementTreeNodeTests.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementTreeNodeTests.cs new file mode 100644 index 0000000000..1c8c3e406a --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlElementTreeNodeTests.cs @@ -0,0 +1,52 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class XmlElementTreeNodeTextTests + { + XmlDocument doc; + + [TestFixtureSetUp] + public void SetUpFixture() + { + doc = new XmlDocument(); + doc.LoadXml(""); + } + + [Test] + public void UnqualifiedName() + { + XmlElement element = doc.CreateElement("child"); + XmlElementTreeNode node = new XmlElementTreeNode(element); + Assert.AreEqual("child", node.Text); + } + + [Test] + public void QualifiedName() + { + XmlElement element = doc.CreateElement("child", "http://test.com"); + XmlElementTreeNode node = new XmlElementTreeNode(element); + Assert.AreEqual("child", node.Text); + } + + [Test] + public void PrefixedName() + { + XmlElement element = doc.CreateElement("t", "child", "http://test.com"); + XmlElementTreeNode node = new XmlElementTreeNode(element); + Assert.AreEqual("t:child", node.Text); + } + + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextSelectedTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextSelectedTestFixture.cs new file mode 100644 index 0000000000..bee14c017d --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextSelectedTestFixture.cs @@ -0,0 +1,49 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + /// + /// Tests that the XmlTreeEditor tells the view to show the text when + /// an XmlText node is selected. + /// + [TestFixture] + public class XmlTextSelectedTestFixture : XmlTreeViewTestFixtureBase + { + [SetUp] + public void SetUpFixture() + { + base.InitFixture(); + mockXmlTreeView.SelectedTextNode = (XmlText)mockXmlTreeView.DocumentElement.FirstChild; + editor.SelectedTextNodeChanged(); + } + + [Test] + public void IsViewShowingText() + { + Assert.AreEqual("text here", mockXmlTreeView.TextContentDisplayed); + } + + [Test] + public void TextNodeNotSelected() + { + mockXmlTreeView.SelectedTextNode = null; + editor.SelectedTextNodeChanged(); + Assert.AreEqual(String.Empty, mockXmlTreeView.TextContentDisplayed); + } + + protected override string GetXml() + { + return "text here"; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextTreeNodeTextTests.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextTreeNodeTextTests.cs new file mode 100644 index 0000000000..f336c5f205 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTextTreeNodeTextTests.cs @@ -0,0 +1,59 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using System; +using System.Xml; + +namespace XmlEditor.Tests.Tree +{ + [TestFixture] + public class XmlTextTreeNodeTextTests + { + XmlDocument doc; + + [TestFixtureSetUp] + public void SetUpFixture() + { + doc = new XmlDocument(); + doc.LoadXml(""); + } + + [Test] + public void WhiteSpaceRemoved() + { + XmlText text = doc.CreateTextNode(" \t\tTest\t\t "); + XmlTextTreeNode node = new XmlTextTreeNode(text); + Assert.AreEqual("Test", node.Text); + } + + [Test] + public void TextOnSecondLine() + { + XmlText text = doc.CreateTextNode("\r\nTest"); + XmlTextTreeNode node = new XmlTextTreeNode(text); + Assert.AreEqual("Test", node.Text); + } + + [Test] + public void ThreeLinesTextOnSecondLine() + { + XmlText text = doc.CreateTextNode("\r\nTest\r\n"); + XmlTextTreeNode node = new XmlTextTreeNode(text); + Assert.AreEqual("Test", node.Text); + } + + [Test] + public void TwoLines() + { + XmlText text = doc.CreateTextNode("Test\r\nSecond Line"); + XmlTextTreeNode node = new XmlTextTreeNode(text); + Assert.AreEqual("Test...", node.Text); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewTestFixtureBase.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewTestFixtureBase.cs new file mode 100644 index 0000000000..c7cd930d57 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewTestFixtureBase.cs @@ -0,0 +1,32 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using System; +using System.Xml; +using XmlEditor.Tests.Utils; + +namespace XmlEditor.Tests.Tree +{ + public abstract class XmlTreeViewTestFixtureBase + { + protected MockXmlTreeView mockXmlTreeView; + protected XmlTreeEditor editor; + + public void InitFixture() + { + mockXmlTreeView = new MockXmlTreeView(); + editor = new XmlTreeEditor(mockXmlTreeView); + editor.LoadXml(GetXml()); + } + + protected virtual string GetXml() + { + return String.Empty; + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockXmlTreeView.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockXmlTreeView.cs new file mode 100644 index 0000000000..39949b0c08 --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockXmlTreeView.cs @@ -0,0 +1,123 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.XmlEditor; +using System; +using System.Collections.Generic; +using System.Xml; + +namespace XmlEditor.Tests.Utils +{ + public class MockXmlTreeView : IXmlTreeView + { + bool notWellFormedMessageDisplayed; + XmlException notWellFormedException; + XmlElement documentElement; + XmlElement selectedElement; + List attributesDisplayed = new List(); + string textContentDisplayed; + XmlText selectedTextNode; + bool dirty; + + public MockXmlTreeView() + { + } + + public void ShowXmlIsNotWellFormedMessage(XmlException ex) + { + notWellFormedMessageDisplayed = true; + notWellFormedException = ex; + } + + public bool IsDirty { + get { + return dirty; + } + set { + dirty = value; + } + } + + public XmlElement DocumentElement { + get { + return documentElement; + } + set { + documentElement = value; + } + } + + public XmlElement SelectedElement { + get { + return selectedElement; + } + set { + selectedElement = value; + } + } + + public XmlText SelectedTextNode { + get { + return selectedTextNode; + } + set { + selectedTextNode = value; + } + } + + public void ShowAttributes(XmlAttributeCollection attributes) + { + attributesDisplayed = new List(); + foreach (XmlAttribute attribute in attributes) { + attributesDisplayed.Add(attribute); + } + } + + public void ClearAttributes() + { + attributesDisplayed.Clear(); + } + + public void ShowTextContent(string text) + { + textContentDisplayed = text; + } + + public string TextContent { + get { + return textContentDisplayed; + } + } + + public List AttributesDisplayed { + get { + return attributesDisplayed; + } + } + + public string TextContentDisplayed { + get { + return textContentDisplayed; + } + set { + textContentDisplayed = value; + } + } + + public bool IsXmlNotWellFormedMessageDisplayed { + get { + return notWellFormedMessageDisplayed; + } + } + + public XmlException NotWellFormedExceptionPassed { + get { + return notWellFormedException; + } + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj b/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj index c93058689e..4c7a42e925 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj @@ -119,6 +119,21 @@ + + + + + + + + + + + + + + + @@ -145,6 +160,7 @@ ICSharpCode.Core + \ No newline at end of file