From d079cdbc43d0cf1635f556d3ede573593ec5e0ed Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Fri, 29 Dec 2006 18:06:52 +0000 Subject: [PATCH] Fixed SD2-1182. Element and attribute names entered in the add element/attribute dialog are now validated. The add element/attribute dialog no longer displays a list box if there are no element/attribute names returned from the schema or if the xml document has no schema. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/2.1@2226 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Resources/AddAttributeDialog.xfrm | 60 ---- .../Project/Resources/AddElementDialog.xfrm | 60 ---- .../Project/Src/AddAttributeDialog.cs | 88 ----- .../XmlEditor/Project/Src/AddElementDialog.cs | 88 ----- .../XmlEditor/Project/Src/AddXmlNodeDialog.cs | 339 ++++++++++++++++++ .../Project/Src/IAddAttributeDialog.cs | 30 -- ...dElementDialog.cs => IAddXmlNodeDialog.cs} | 11 +- .../Src/XmlTreeViewContainerControl.cs | 22 +- .../XmlEditor/Project/XmlEditor.csproj | 8 +- .../Test/Tree/AddNewNodeDialogTestFixture.cs | 325 +++++++++++++++++ .../XmlEditor/Test/Tree/PasteTestFixture.cs | 11 + .../Tree/XmlTreeViewContainerTestFixture.cs | 30 ++ .../Test/Utils/DerivedAddXmlNodeDialog.cs | 39 ++ .../DerivedXmlTreeViewContainerControl.cs | 32 +- .../Test/Utils/MockAddAttributeDialog.cs | 65 ---- ...ementDialog.cs => MockAddXmlNodeDialog.cs} | 29 +- .../XmlEditor/Test/XmlEditor.Tests.csproj | 5 +- .../DisplayBindings/XmlEditor/XmlEditor.sln | 2 +- 18 files changed, 808 insertions(+), 436 deletions(-) delete mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddAttributeDialog.xfrm delete mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddElementDialog.xfrm delete mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddAttributeDialog.cs delete mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddElementDialog.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddXmlNodeDialog.cs delete mode 100644 src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddAttributeDialog.cs rename src/AddIns/DisplayBindings/XmlEditor/Project/Src/{IAddElementDialog.cs => IAddXmlNodeDialog.cs} (66%) create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AddNewNodeDialogTestFixture.cs create mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedAddXmlNodeDialog.cs delete mode 100644 src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddAttributeDialog.cs rename src/AddIns/DisplayBindings/XmlEditor/Test/Utils/{MockAddElementDialog.cs => MockAddXmlNodeDialog.cs} (61%) diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddAttributeDialog.xfrm b/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddAttributeDialog.xfrm deleted file mode 100644 index 717c5be774..0000000000 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddAttributeDialog.xfrm +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddElementDialog.xfrm b/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddElementDialog.xfrm deleted file mode 100644 index 4b59cb3d82..0000000000 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Resources/AddElementDialog.xfrm +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddAttributeDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddAttributeDialog.cs deleted file mode 100644 index 57ab796f3e..0000000000 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddAttributeDialog.cs +++ /dev/null @@ -1,88 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -using ICSharpCode.SharpDevelop.Gui.XmlForms; - -namespace ICSharpCode.XmlEditor -{ - public class AddAttributeDialog : BaseSharpDevelopForm, IAddAttributeDialog - { - ListBox attributesListBox; - Button okButton; - TextBox attributeTextBox; - - public AddAttributeDialog(string[] attributeNames) - { - SetupFromXmlStream(GetType().Assembly.GetManifestResourceStream("ICSharpCode.XmlEditor.Resources.AddAttributeDialog.xfrm")); - - okButton = (Button)ControlDictionary["okButton"]; - okButton.Enabled = false; - AcceptButton = okButton; - CancelButton = (Button)ControlDictionary["cancelButton"]; - - attributeTextBox = (TextBox)ControlDictionary["attributeTextBox"]; - attributeTextBox.TextChanged += AttributeTextBoxTextChanged; - - attributesListBox = (ListBox)ControlDictionary["attributesListBox"]; - attributesListBox.SelectedIndexChanged += AttributesListBoxSelectedIndexChanged; - foreach (string name in attributeNames) { - attributesListBox.Items.Add(name); - } - } - - /// - /// Gets the attribute names selected. - /// - public string[] AttributeNames { - get { - List attributeNames = new List(); - if (IsAttributeSelected) { - foreach (string attributeName in attributesListBox.SelectedItems) { - attributeNames.Add(attributeName); - } - } - string customAttributeName = attributeTextBox.Text.Trim(); - if (customAttributeName.Length > 0) { - attributeNames.Add(customAttributeName); - } - return attributeNames.ToArray(); - } - } - - void AttributesListBoxSelectedIndexChanged(object source, EventArgs e) - { - okButton.Enabled = IsOkButtonEnabled; - } - - void AttributeTextBoxTextChanged(object source, EventArgs e) - { - okButton.Enabled = IsOkButtonEnabled; - } - - bool IsAttributeSelected { - get { - return attributesListBox.SelectedIndex >= 0; - } - } - - bool IsOkButtonEnabled { - get { - return IsAttributeSelected || IsAttributeNameEntered; - } - } - - bool IsAttributeNameEntered { - get { - return attributeTextBox.Text.Trim().Length > 0; - } - } - } -} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddElementDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddElementDialog.cs deleted file mode 100644 index ef85a3936a..0000000000 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddElementDialog.cs +++ /dev/null @@ -1,88 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -using ICSharpCode.SharpDevelop.Gui.XmlForms; - -namespace ICSharpCode.XmlEditor -{ - public class AddElementDialog : BaseSharpDevelopForm, IAddElementDialog - { - ListBox elementsListBox; - Button okButton; - TextBox elementTextBox; - - public AddElementDialog(string[] elementNames) - { - SetupFromXmlStream(GetType().Assembly.GetManifestResourceStream("ICSharpCode.XmlEditor.Resources.AddElementDialog.xfrm")); - - okButton = (Button)ControlDictionary["okButton"]; - okButton.Enabled = false; - AcceptButton = okButton; - CancelButton = (Button)ControlDictionary["cancelButton"]; - - elementTextBox = (TextBox)ControlDictionary["elementTextBox"]; - elementTextBox.TextChanged += ElementTextBoxTextChanged; - - elementsListBox = (ListBox)ControlDictionary["elementsListBox"]; - elementsListBox.SelectedIndexChanged += ElementsListBoxSelectedIndexChanged; - foreach (string name in elementNames) { - elementsListBox.Items.Add(name); - } - } - - /// - /// Gets the element names selected. - /// - public string[] ElementNames { - get { - List elementNames = new List(); - if (IsElementSelected) { - foreach (string elementName in elementsListBox.SelectedItems) { - elementNames.Add(elementName); - } - } - string customElementName = elementTextBox.Text.Trim(); - if (customElementName.Length > 0) { - elementNames.Add(customElementName); - } - return elementNames.ToArray(); - } - } - - void ElementsListBoxSelectedIndexChanged(object source, EventArgs e) - { - okButton.Enabled = IsOkButtonEnabled; - } - - void ElementTextBoxTextChanged(object source, EventArgs e) - { - okButton.Enabled = IsOkButtonEnabled; - } - - bool IsElementSelected { - get { - return elementsListBox.SelectedIndex >= 0; - } - } - - bool IsOkButtonEnabled { - get { - return IsElementSelected || IsElementNameEntered; - } - } - - bool IsElementNameEntered { - get { - return elementTextBox.Text.Trim().Length > 0; - } - } - } -} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddXmlNodeDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddXmlNodeDialog.cs new file mode 100644 index 0000000000..8c18f9584a --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/AddXmlNodeDialog.cs @@ -0,0 +1,339 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using System.Xml; +using ICSharpCode.Core; + +namespace ICSharpCode.XmlEditor +{ + /// + /// Base class for the AddElementDialog and AddAttributeDialog. This + /// dialog presents a list of names and an extra text box for entering + /// a custom name. It is used to add a new node to the XML tree. It + /// contains all the core logic for the AddElementDialog and + /// AddAttributeDialog classes. + /// + public class AddXmlNodeDialog : System.Windows.Forms.Form, IAddXmlNodeDialog + { + public AddXmlNodeDialog() : this(new string[0]) + { + } + + /// + /// Creates the dialog and adds the specified names to the + /// list box. + /// + public AddXmlNodeDialog(string[] names) + { + InitializeComponent(); + InitStrings(); + if (names.Length > 0) { + AddNames(names); + } else { + RemoveNamesListBox(); + } + RightToLeftConverter.ConvertRecursive(this); + } + + /// + /// Gets the selected names in the list box together with the + /// custom name entered in the text box. + /// + public string[] GetNames() + { + // Add items selected in list box. + List names = new List(); + foreach (string name in namesListBox.SelectedItems) { + names.Add(name); + } + + // Add the custom name if entered. + string customName = customNameTextBox.Text.Trim(); + if (customName.Length > 0) { + names.Add(customName); + } + return names.ToArray(); + } + + /// + /// Gets the text from the error provider. + /// + public string GetError() + { + return errorProvider.GetError(customNameTextBox); + } + + /// + /// Gets or sets the custom name label's text. + /// + public string CustomNameLabelText { + get { + return customNameTextBoxLabel.Text; + } + set { + customNameTextBoxLabel.Text = value; + } + } + + /// + /// Disposes resources used by the form. + /// + /// 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); + } + + protected void NamesListBoxSelectedIndexChanged(object sender, EventArgs e) + { + UpdateOkButtonState(); + } + + protected void CustomNameTextBoxTextChanged(object sender, EventArgs e) + { + UpdateOkButtonState(); + } + + #region Windows Forms Designer generated code + + void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.namesListBox = new System.Windows.Forms.ListBox(); + this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components); + this.bottomPanel = new System.Windows.Forms.Panel(); + this.customNameTextBoxLabel = new System.Windows.Forms.Label(); + this.customNameTextBox = new System.Windows.Forms.TextBox(); + this.cancelButton = new System.Windows.Forms.Button(); + this.okButton = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit(); + this.bottomPanel.SuspendLayout(); + this.SuspendLayout(); + // + // namesListBox + // + this.namesListBox.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.namesListBox.FormattingEnabled = true; + this.namesListBox.Location = new System.Drawing.Point(0, 0); + this.namesListBox.Name = "namesListBox"; + this.namesListBox.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; + this.namesListBox.Size = new System.Drawing.Size(289, 173); + this.namesListBox.Sorted = true; + this.namesListBox.TabIndex = 1; + this.namesListBox.SelectedIndexChanged += new System.EventHandler(this.NamesListBoxSelectedIndexChanged); + // + // errorProvider + // + this.errorProvider.ContainerControl = this; + // + // bottomPanel + // + this.bottomPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.bottomPanel.Controls.Add(this.customNameTextBoxLabel); + this.bottomPanel.Controls.Add(this.customNameTextBox); + this.bottomPanel.Controls.Add(this.cancelButton); + this.bottomPanel.Controls.Add(this.okButton); + this.bottomPanel.Location = new System.Drawing.Point(0, 173); + this.bottomPanel.Name = "bottomPanel"; + this.bottomPanel.Size = new System.Drawing.Size(289, 73); + this.bottomPanel.TabIndex = 2; + // + // customNameTextBoxLabel + // + this.customNameTextBoxLabel.Location = new System.Drawing.Point(3, 10); + this.customNameTextBoxLabel.Name = "customNameTextBoxLabel"; + this.customNameTextBoxLabel.Size = new System.Drawing.Size(82, 23); + this.customNameTextBoxLabel.TabIndex = 3; + this.customNameTextBoxLabel.Text = "Custom:"; + // + // customNameTextBox + // + this.customNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.customNameTextBox.Location = new System.Drawing.Point(107, 10); + this.customNameTextBox.Name = "customNameTextBox"; + this.customNameTextBox.Size = new System.Drawing.Size(167, 20); + this.customNameTextBox.TabIndex = 4; + this.customNameTextBox.TextChanged += new System.EventHandler(this.CustomNameTextBoxTextChanged); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(199, 40); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 6; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.okButton.Enabled = false; + this.okButton.Location = new System.Drawing.Point(118, 40); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 5; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + // + // AddXmlNodeDialog + // + this.AcceptButton = this.okButton; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(289, 244); + this.Controls.Add(this.bottomPanel); + this.Controls.Add(this.namesListBox); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(289, 143); + this.Name = "AddXmlNodeDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit(); + this.bottomPanel.ResumeLayout(false); + this.bottomPanel.PerformLayout(); + this.ResumeLayout(false); + } + private System.Windows.Forms.Panel bottomPanel; + private System.ComponentModel.IContainer components; + private System.Windows.Forms.ErrorProvider errorProvider; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.TextBox customNameTextBox; + private System.Windows.Forms.Label customNameTextBoxLabel; + private System.Windows.Forms.ListBox namesListBox; + + #endregion + + /// + /// Adds the names to the list box. + /// + void AddNames(string[] names) + { + foreach (string name in names) { + namesListBox.Items.Add(name); + } + } + + /// + /// Enables or disables the ok button depending on whether any list + /// item is selected or a custom name has been entered. + /// + void UpdateOkButtonState() + { + okButton.Enabled = IsOkButtonEnabled; + } + + /// + /// Returns whether any items are selected in the list box. + /// + bool IsItemSelected { + get { + return namesListBox.SelectedIndex >= 0; + } + } + + bool IsOkButtonEnabled { + get { + return IsItemSelected || ValidateCustomName(); + } + } + + /// + /// Returns whether there is a valid string in the custom + /// name text box. The string must be a name that can be used to + /// create an xml element or attribute. + /// + bool ValidateCustomName() + { + string name = customNameTextBox.Text.Trim(); + if (name.Length > 0) { + try { + VerifyName(name); + errorProvider.Clear(); + return true; + } catch (XmlException ex) { + errorProvider.SetError(customNameTextBox, ex.Message); + } + } + return false; + } + + /// + /// Checks that the name would make a valid element name or + /// attribute name. Trying to use XmlConvert and its Verify methods + /// so the validation is not done ourselves. XmlDocument has a + /// CheckName method but this is not public. + /// + void VerifyName(string name) + { + // Check the qualification is valid. + string[] parts = name.Split(new char[] {':'}, 2); + if (parts.Length == 1) { + // No colons. + XmlConvert.VerifyName(name); + return; + } + + string firstPart = parts[0].Trim(); + string secondPart = parts[1].Trim(); + if (firstPart.Length > 0 && secondPart.Length > 0) { + XmlConvert.VerifyNCName(firstPart); + XmlConvert.VerifyNCName(secondPart); + } else { + // Throw an error using VerifyNCName since the + // qualified name parts have no strings. + XmlConvert.VerifyNCName(name); + } + } + + /// + /// Sets the control's text using string resources. + /// + void InitStrings() + { + okButton.Text = StringParser.Parse("${res:Global.OKButtonText}"); + cancelButton.Text = StringParser.Parse("${res:Global.CancelButtonText}"); + } + + /// + /// Removes the names list box from the dialog, re-positions the + /// remaining controls and resizes the dialog to fit. + /// + void RemoveNamesListBox() + { + using (namesListBox) { + Controls.Remove(namesListBox); + + // Reset the dialog's minimum size first so setting the + // ClientSize to something smaller works as expected. + MinimumSize = Size.Empty; + ClientSize = bottomPanel.Size; + MinimumSize = Size; + + // Make sure bottom panel fills the dialog when it is resized. + bottomPanel.Dock = DockStyle.Fill; + } + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddAttributeDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddAttributeDialog.cs deleted file mode 100644 index 7f4166fa3d..0000000000 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddAttributeDialog.cs +++ /dev/null @@ -1,30 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Windows.Forms; - -namespace ICSharpCode.XmlEditor -{ - /// - /// Interface for the AddAttributeDialog. - /// - public interface IAddAttributeDialog : IDisposable - { - /// - /// The attribute names that should be added. These are the - /// attribute names that the user selected in the dialog when - /// it was closed. - /// - string[] AttributeNames {get;} - - /// - /// Shows the dialog. - /// - DialogResult ShowDialog(); - } -} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddElementDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddXmlNodeDialog.cs similarity index 66% rename from src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddElementDialog.cs rename to src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddXmlNodeDialog.cs index a167e479a2..cad1e99e4a 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddElementDialog.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/IAddXmlNodeDialog.cs @@ -5,22 +5,23 @@ // $Revision$ // + using System; using System.Windows.Forms; namespace ICSharpCode.XmlEditor { /// - /// Interface for the AddElementDialog. + /// Interface for the AddXmlNodeDialog. /// - public interface IAddElementDialog : IDisposable + public interface IAddXmlNodeDialog : IDisposable { /// - /// The element names that should be added. These are the - /// element names that the user selected in the dialog when + /// The names that should be added. These are the + /// names that the user selected in the dialog when /// it was closed. /// - string[] ElementNames {get;} + string[] GetNames(); /// /// Shows the dialog. diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs index 419ae38041..f2a0dc1a7a 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlTreeViewContainerControl.cs @@ -296,9 +296,9 @@ namespace ICSharpCode.XmlEditor /// The attributes selected by the user. public string[] SelectNewAttributes(string[] attributes) { - using (IAddAttributeDialog addAttributeDialog = CreateAddAttributeDialog(attributes)) { + using (IAddXmlNodeDialog addAttributeDialog = CreateAddAttributeDialog(attributes)) { if (addAttributeDialog.ShowDialog() == DialogResult.OK) { - return addAttributeDialog.AttributeNames; + return addAttributeDialog.GetNames(); } return new string[0]; } @@ -321,9 +321,9 @@ namespace ICSharpCode.XmlEditor /// The elements selected by the user. public string[] SelectNewElements(string[] elements) { - using (IAddElementDialog addElementDialog = CreateAddElementDialog(elements)) { + using (IAddXmlNodeDialog addElementDialog = CreateAddElementDialog(elements)) { if (addElementDialog.ShowDialog() == DialogResult.OK) { - return addElementDialog.ElementNames; + return addElementDialog.GetNames(); } return new string[0]; } @@ -649,9 +649,12 @@ namespace ICSharpCode.XmlEditor /// /// The element names to be listed in the /// dialog. - protected virtual IAddElementDialog CreateAddElementDialog(string[] elementNames) + protected virtual IAddXmlNodeDialog CreateAddElementDialog(string[] elementNames) { - return new AddElementDialog(elementNames); + AddXmlNodeDialog dialog = new AddXmlNodeDialog(elementNames); + dialog.Text = StringParser.Parse("${res:ICSharpCode.XmlEditor.AddElementDialog.Title}"); + dialog.CustomNameLabelText = StringParser.Parse("${res:ICSharpCode.XmlEditor.AddElementDialog.CustomElementLabel}"); + return dialog; } /// @@ -659,9 +662,12 @@ namespace ICSharpCode.XmlEditor /// /// The attribute names to be listed in the /// dialog. - protected virtual IAddAttributeDialog CreateAddAttributeDialog(string[] attributeNames) + protected virtual IAddXmlNodeDialog CreateAddAttributeDialog(string[] attributeNames) { - return new AddAttributeDialog(attributeNames); + AddXmlNodeDialog dialog = new AddXmlNodeDialog(attributeNames); + dialog.Text = StringParser.Parse("${res:ICSharpCode.XmlEditor.AddAttributeDialog.Title}"); + dialog.CustomNameLabelText = StringParser.Parse("${res:ICSharpCode.XmlEditor.AddAttributeDialog.CustomAttributeLabel}"); + return dialog; } /// diff --git a/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj b/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj index 02acf44313..f6b9af441b 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj +++ b/src/AddIns/DisplayBindings/XmlEditor/Project/XmlEditor.csproj @@ -56,8 +56,8 @@ - - + + @@ -138,12 +138,8 @@ - - - - diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AddNewNodeDialogTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AddNewNodeDialogTestFixture.cs new file mode 100644 index 0000000000..2e38b7ba0a --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/AddNewNodeDialogTestFixture.cs @@ -0,0 +1,325 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; +using System.Xml; + +using ICSharpCode.Core; +using ICSharpCode.XmlEditor; +using NUnit.Framework; +using XmlEditor.Tests.Utils; + +namespace XmlEditor.Tests.Tree +{ + /// + /// Tests the AddXmlNodeDialog which is the base class for the + /// AddElementDialog and the AddAttributeDialog classes. All the + /// core logic for the two add dialogs is located in the AddXmlNodeDialog + /// since their behaviour is the same. + /// + [TestFixture] + public class AddNewNodeDialogTestFixture + { + DerivedAddXmlNodeDialog dialog; + ListBox namesListBox; + string[] names; + Button okButton; + Button cancelButton; + TextBox customNameTextBox; + Label customNameTextBoxLabel; + Panel bottomPanel; + + [TestFixtureSetUp] + public void SetUpFixture() + { + if (!PropertyService.Initialized) { + PropertyService.InitializeService(String.Empty, String.Empty, String.Empty); + } + } + + [SetUp] + public void Init() + { + names = new string[] {"Chimpanzee", "Monkey"}; + dialog = new DerivedAddXmlNodeDialog(names); + + // Get the various dialog controls that are to be used in this + // test fixture. + bottomPanel = (Panel)dialog.Controls["bottomPanel"]; + namesListBox = (ListBox)dialog.Controls["namesListBox"]; + okButton = (Button)bottomPanel.Controls["okButton"]; + cancelButton = (Button)bottomPanel.Controls["cancelButton"]; + customNameTextBox = (TextBox)bottomPanel.Controls["customNameTextBox"]; + customNameTextBoxLabel = (Label)bottomPanel.Controls["customNameTextBoxLabel"]; + } + + [TearDown] + public void TearDown() + { + dialog.Dispose(); + } + + [Test] + public void TwoNamesAddedToListBox() + { + Assert.AreEqual(2, namesListBox.Items.Count); + } + + [Test] + public void NamesAddedToListBox() + { + Assert.Contains("Chimpanzee", namesListBox.Items); + Assert.Contains("Monkey", namesListBox.Items); + } + + [Test] + public void OkButtonInitiallyDisabled() + { + Assert.IsFalse(okButton.Enabled); + } + + [Test] + public void OkButtonIsDialogAcceptButton() + { + Assert.AreSame(okButton, dialog.AcceptButton); + } + + [Test] + public void CancelButtonIsDialogCancelButton() + { + Assert.AreSame(cancelButton, dialog.CancelButton); + } + + /// + /// The dialog's Names property should not return any items + /// when nothing is selected in the list box or added to the + /// custom name text box. + /// + [Test] + public void NoNamesInitiallySelected() + { + Assert.AreEqual(0, dialog.GetNames().Length); + } + + [Test] + public void NamesSelectedAfterSelectingOneListBoxItem() + { + namesListBox.SelectedIndex = 0; + string[] expectedNames = new string[] {(string)namesListBox.Items[0]}; + string[] names = dialog.GetNames(); + + Assert.AreEqual(expectedNames, names); + } + + [Test] + public void NamesSelectedAfterSelectingTwoListBoxItems() + { + namesListBox.SelectedIndices.Add(0); + namesListBox.SelectedIndices.Add(1); + string[] expectedNames = new string[] {(string)namesListBox.Items[0], (string)namesListBox.Items[1]}; + string[] names = dialog.GetNames(); + + Assert.AreEqual(expectedNames, names); + } + + /// + /// Tests that the returned names from the dialog includes any + /// text in the custom name text box. Also check that the text box's + /// text is trimmed. + /// + [Test] + public void NamesSelectedAfterEnteringCustomName() + { + string customName = " customname "; + customNameTextBox.Text = customName; + string[] expectedNames = new string[] {customName.Trim()}; + string[] names = dialog.GetNames(); + + Assert.AreEqual(expectedNames, names); + } + + [Test] + public void OkButtonEnabledWhenListItemSelected() + { + namesListBox.SelectedIndex = 0; + dialog.CallNamesListBoxSelectedIndexChanged(); + + Assert.IsTrue(okButton.Enabled); + } + + [Test] + public void OkButtonEnabledWhenCustomNameEntered() + { + customNameTextBox.Text = "Custom"; + dialog.CallCustomNameTextBoxTextChanged(); + + Assert.IsTrue(okButton.Enabled); + } + + /// + /// Tests that a custom name string that contains spaces does not + /// cause the OK button to be enabled. + /// + [Test] + public void OkButtonDisabledWhenEmptyCustomNameStringEntered() + { + customNameTextBox.Text = " "; + dialog.CallCustomNameTextBoxTextChanged(); + + Assert.IsFalse(okButton.Enabled); + } + + [Test] + public void InvalidCustomNameEntered() + { + customNameTextBox.Text = ""; + dialog.CallCustomNameTextBoxTextChanged(); + + string error = dialog.GetError(); + string expectedError = null; + + try { + XmlConvert.VerifyName(customNameTextBox.Text); + Assert.Fail("XmlConvert.VerifyName should have failed."); + } catch (Exception ex) { + expectedError = ex.Message; + } + Assert.IsFalse(okButton.Enabled); + Assert.AreEqual(expectedError, error); + } + + [Test] + public void CustomNameWithTwoColonCharsEntered() + { + customNameTextBox.Text = "xsl:test:this"; + dialog.CallCustomNameTextBoxTextChanged(); + + string error = dialog.GetError(); + Assert.IsFalse(okButton.Enabled); + Assert.IsTrue(error.Length > 0); + } + + [Test] + public void CustomNameWithOneColonCharEntered() + { + customNameTextBox.Text = "xsl:test"; + dialog.CallCustomNameTextBoxTextChanged(); + + string error = dialog.GetError(); + Assert.IsTrue(okButton.Enabled); + Assert.AreEqual(0, error.Length); + } + + [Test] + public void CustomNameWithOneColonCharAtStart() + { + customNameTextBox.Text = ":test"; + dialog.CallCustomNameTextBoxTextChanged(); + + string error = dialog.GetError(); + Assert.IsFalse(okButton.Enabled); + Assert.IsTrue(error.Length > 0); + } + + [Test] + public void ErrorClearedAfterTextChanged() + { + InvalidCustomNameEntered(); + customNameTextBox.Text = "element"; + dialog.CallCustomNameTextBoxTextChanged(); + + Assert.IsTrue(okButton.Enabled); + Assert.AreEqual(0, dialog.GetError().Length); + } + + [Test] + public void StartPositionIsCenterParent() + { + Assert.AreEqual(FormStartPosition.CenterParent, dialog.StartPosition); + } + + [Test] + public void OkButtonDialogResult() + { + Assert.AreEqual(DialogResult.OK, okButton.DialogResult); + } + + [Test] + public void CancelButtonDialogResult() + { + Assert.AreEqual(DialogResult.Cancel, cancelButton.DialogResult); + } + + [Test] + public void ShowInTaskBar() + { + Assert.IsFalse(dialog.ShowInTaskbar); + } + + [Test] + public void MinimizeBox() + { + Assert.IsFalse(dialog.MinimizeBox); + } + + [Test] + public void MaximizeBox() + { + Assert.IsFalse(dialog.MaximizeBox); + } + + [Test] + public void ShowIcon() + { + Assert.IsFalse(dialog.ShowIcon); + } + + [Test] + public void SetCustomNameLabel() + { + dialog.CustomNameLabelText = "test"; + Assert.AreEqual("test", dialog.CustomNameLabelText); + Assert.AreEqual("test", customNameTextBoxLabel.Text); + } + + [Test] + public void RightToLeftConversion() + { + try { + PropertyService.Set("CoreProperties.UILanguage", RightToLeftConverter.RightToLeftLanguages[0]); + using (AddXmlNodeDialog dialog = new AddXmlNodeDialog()) { + Assert.AreEqual(RightToLeft.Yes, dialog.RightToLeft); + } + } finally { + PropertyService.Set("CoreProperties.UILanguage", Thread.CurrentThread.CurrentUICulture.Name); + } + } + + /// + /// Check that the list box is not on the form when there are no + /// names passed to the constructor of AddXmlNodeDialog. + /// + [Test] + public void NoListBoxShownWhenNoNames() + { + using (AddXmlNodeDialog dialog = new AddXmlNodeDialog(new string[0])) { + Size expectedClientSize = this.bottomPanel.Size; + Size expectedMinSize = dialog.Size; + + Panel bottomPanel = (Panel)dialog.Controls["bottomPanel"]; + + Assert.IsFalse(dialog.Controls.ContainsKey("namesListBox")); + Assert.AreEqual(DockStyle.Fill, bottomPanel.Dock); + Assert.AreEqual(expectedClientSize, dialog.ClientSize); + Assert.AreEqual(expectedMinSize, dialog.MinimumSize); + } + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/PasteTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/PasteTestFixture.cs index 2181e3cd73..50788a10ed 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/PasteTestFixture.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/PasteTestFixture.cs @@ -349,6 +349,17 @@ namespace XmlEditor.Tests.Tree Assert.IsNull(bodyElement.SelectSingleNode("p")); } + [Test] + public void CopyThenPasteToUnsupportedNode() + { + XmlNode node = editor.Document.CreateProcessingInstruction("a", "b"); + mockXmlTreeView.SelectedNode = node; + editor.Copy(); + mockXmlTreeView.SelectedElement = rootElement; + + Assert.IsFalse(editor.IsPasteEnabled); + } + /// /// Returns the xhtml strict schema as the default schema. /// diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewContainerTestFixture.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewContainerTestFixture.cs index df7bbb0b94..a028906165 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewContainerTestFixture.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Tree/XmlTreeViewContainerTestFixture.cs @@ -9,6 +9,7 @@ using System; using System.Windows.Forms; using System.Xml; +using ICSharpCode.Core; using ICSharpCode.XmlEditor; using NUnit.Framework; using XmlEditor.Tests.Utils; @@ -34,6 +35,15 @@ namespace XmlEditor.Tests.Tree XmlElementTreeNode htmlTreeNode; XmlTextTreeNode textTreeNode; + [TestFixtureSetUp] + public void SetUpFixture() + { + // Need to initialize the properties service. + if (!PropertyService.Initialized) { + PropertyService.InitializeService(String.Empty, String.Empty, String.Empty); + } + } + [SetUp] public void Init() { @@ -410,6 +420,26 @@ namespace XmlEditor.Tests.Tree Assert.IsNull(htmlTreeNode.XmlElement.SelectSingleNode("text()")); } + [Test] + public void CreateAddAttributeDialog() + { + AddXmlNodeDialog dialog = (AddXmlNodeDialog)treeViewContainer.CallCreateAddAttributeDialog(new string[0]); + Panel bottomPanel = (Panel)dialog.Controls["bottomPanel"]; + Label customNameTextBoxLabel = (Label)bottomPanel.Controls["customNameTextBoxLabel"]; + Assert.AreEqual(StringParser.Parse("${res:ICSharpCode.XmlEditor.AddAttributeDialog.Title}"), dialog.Text); + Assert.AreEqual(StringParser.Parse("${res:ICSharpCode.XmlEditor.AddAttributeDialog.CustomAttributeLabel}"), customNameTextBoxLabel.Text); + } + + [Test] + public void CreateAddElementeDialog() + { + AddXmlNodeDialog dialog = (AddXmlNodeDialog)treeViewContainer.CallCreateAddElementDialog(new string[0]); + Panel bottomPanel = (Panel)dialog.Controls["bottomPanel"]; + Label customNameTextBoxLabel = (Label)bottomPanel.Controls["customNameTextBoxLabel"]; + Assert.AreEqual(StringParser.Parse("${res:ICSharpCode.XmlEditor.AddElementDialog.Title}"), dialog.Text); + Assert.AreEqual(StringParser.Parse("${res:ICSharpCode.XmlEditor.AddElementDialog.CustomElementLabel}"), customNameTextBoxLabel.Text); + } + void TreeViewContainerDirtyChanged(object source, EventArgs e) { dirtyChanged = true; diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedAddXmlNodeDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedAddXmlNodeDialog.cs new file mode 100644 index 0000000000..f1aee3d25d --- /dev/null +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedAddXmlNodeDialog.cs @@ -0,0 +1,39 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.XmlEditor; + +namespace XmlEditor.Tests.Utils +{ + /// + /// Derived version of the AddXmlNodeDialog which allows us to test + /// various protected methods. + /// + public class DerivedAddXmlNodeDialog : AddXmlNodeDialog + { + public DerivedAddXmlNodeDialog(string[] names) : base(names) + { + } + + /// + /// Calls the base class's NamesListBoxSelectedIndexChanged method. + /// + public void CallNamesListBoxSelectedIndexChanged() + { + base.NamesListBoxSelectedIndexChanged(this, new EventArgs()); + } + + /// + /// Calls the base class's CustomNameTextBoxTextChanged method. + /// + public void CallCustomNameTextBoxTextChanged() + { + base.CustomNameTextBoxTextChanged(this, new EventArgs()); + } + } +} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedXmlTreeViewContainerControl.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedXmlTreeViewContainerControl.cs index d853a00136..48a22cba6e 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedXmlTreeViewContainerControl.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/DerivedXmlTreeViewContainerControl.cs @@ -111,23 +111,39 @@ namespace XmlEditor.Tests.Utils } /// - /// Returns a new MockAddElementDialog for testing. + /// Calls the XmlTreeViewContainer's CreateAddAttributeDialog method. /// - protected override IAddElementDialog CreateAddElementDialog(string[] elementNames) + public IAddXmlNodeDialog CallCreateAddAttributeDialog(string[] names) { - MockAddElementDialog dialog = new MockAddElementDialog(); - dialog.SetElementNamesToReturn(addElementDialogElementNamesReturned.ToArray()); + return base.CreateAddAttributeDialog(names); + } + + /// + /// Calls the XmlTreeViewContainer's CreateAddElementDialog method. + /// + public IAddXmlNodeDialog CallCreateAddElementDialog(string[] names) + { + return base.CreateAddElementDialog(names); + } + + /// + /// Returns a new MockAddXmlNodeDialog for testing. + /// + protected override IAddXmlNodeDialog CreateAddElementDialog(string[] elementNames) + { + MockAddXmlNodeDialog dialog = new MockAddXmlNodeDialog(); + dialog.SetNamesToReturn(addElementDialogElementNamesReturned.ToArray()); dialog.SetDialogResult(addElementDialogResult); return dialog; } /// - /// Returns a new MockAddAttributeDialog for testing. + /// Returns a new MockAddXmlNodeDialog for testing. /// - protected override IAddAttributeDialog CreateAddAttributeDialog(string[] attributeNames) + protected override IAddXmlNodeDialog CreateAddAttributeDialog(string[] attributeNames) { - MockAddAttributeDialog dialog = new MockAddAttributeDialog(); - dialog.SetAttributeNamesToReturn(addAttributeDialogAttributeNamesReturned.ToArray()); + MockAddXmlNodeDialog dialog = new MockAddXmlNodeDialog(); + dialog.SetNamesToReturn(addAttributeDialogAttributeNamesReturned.ToArray()); dialog.SetDialogResult(addAttributeDialogResult); return dialog; } diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddAttributeDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddAttributeDialog.cs deleted file mode 100644 index acdc4fe960..0000000000 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddAttributeDialog.cs +++ /dev/null @@ -1,65 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Collections.Generic; -using System.Windows.Forms; -using ICSharpCode.XmlEditor; - -namespace XmlEditor.Tests.Utils -{ - /// - /// Mocks the AddAttributeDialog so we can test the - /// XmlTreeViewContainerControl class when it displays - /// the AddAttributeDialog. - /// - public class MockAddAttributeDialog : IAddAttributeDialog - { - DialogResult dialogResult = DialogResult.OK; - List attributeNames = new List(); - - /// - /// Specifies the attribute names to return from the - /// IAddAttributeDialog.AttributeNames property. - /// - public void SetAttributeNamesToReturn(string[] names) - { - attributeNames.Clear(); - foreach (string name in names) { - attributeNames.Add(name); - } - } - - /// - /// Specifies the dialog result to return from the - /// IAddAttributeDialog.ShowDialog method. - /// - public void SetDialogResult(DialogResult result) - { - dialogResult = result; - } - - #region IAddAttributeDialog implementation - - public string[] AttributeNames { - get { - return attributeNames.ToArray(); - } - } - - public DialogResult ShowDialog() - { - return dialogResult; - } - - public void Dispose() - { - } - - #endregion - } -} diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddElementDialog.cs b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddXmlNodeDialog.cs similarity index 61% rename from src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddElementDialog.cs rename to src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddXmlNodeDialog.cs index 314864fbe9..7b20827db5 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddElementDialog.cs +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockAddXmlNodeDialog.cs @@ -13,42 +13,41 @@ using ICSharpCode.XmlEditor; namespace XmlEditor.Tests.Utils { /// - /// Mocks the AddElementDialog so we can test the + /// Mocks the AddXmlNodeDialog so we can test the /// XmlTreeViewContainerControl class when it displays - /// the AddElementDialog. + /// the AddElementDialog or the AddAttributeDialog. /// - public class MockAddElementDialog : IAddElementDialog + public class MockAddXmlNodeDialog : IAddXmlNodeDialog { DialogResult dialogResult = DialogResult.OK; - List elementNames = new List(); + List names = new List(); /// - /// Specifies the element names to return from the - /// IAddElementDialog.ElementNames property. + /// Specifies the names to return from the + /// IAddXmlNodeDialog.GetNames method. /// - public void SetElementNamesToReturn(string[] names) + public void SetNamesToReturn(string[] names) { - elementNames.Clear(); + this.names.Clear(); foreach (string name in names) { - elementNames.Add(name); + this.names.Add(name); } } /// /// Specifies the dialog result to return from the - /// IAddElementDialog.ShowDialog method. + /// IAddXmlNodeDialog.ShowDialog method. /// public void SetDialogResult(DialogResult result) { dialogResult = result; } - #region IAddElementDialog implementation + #region IAddXmlNodeDialog implementation - public string[] ElementNames { - get { - return elementNames.ToArray(); - } + public string[] GetNames() + { + return names.ToArray(); } public DialogResult ShowDialog() diff --git a/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj b/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj index 2cbe0d8c15..ad18bb17cb 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj +++ b/src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj @@ -72,6 +72,7 @@ + @@ -89,10 +90,10 @@ + - - + diff --git a/src/AddIns/DisplayBindings/XmlEditor/XmlEditor.sln b/src/AddIns/DisplayBindings/XmlEditor/XmlEditor.sln index 1508b739dc..8139c0f32f 100644 --- a/src/AddIns/DisplayBindings/XmlEditor/XmlEditor.sln +++ b/src/AddIns/DisplayBindings/XmlEditor/XmlEditor.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -# SharpDevelop 2.1.0.2147 +# SharpDevelop 2.1.0.2169 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlEditor", "Project\XmlEditor.csproj", "{6B717BD1-CD5E-498C-A42E-9E6A4584DC48}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlEditor.Tests", "Test\XmlEditor.Tests.csproj", "{FC0FE702-A87D-4D70-A9B6-1ECCD611125F}"