From 0ee962c4c8431f96dd57fa339cc719bb8d3dc3b4 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Sat, 6 Sep 2025 17:43:59 +0200 Subject: [PATCH 01/29] Adding custom argument model and the add/edit dialog. --- AddOrEditCustomArgument.Designer.cs | 122 +++++++++++++++++++++++ AddOrEditCustomArgument.cs | 51 ++++++++++ AddOrEditCustomArgument.resx | 145 ++++++++++++++++++++++++++++ SSMSObjectExplorerMenu.csproj | 11 +++ enums/CustomArgumentType.cs | 9 ++ objects/CustomArgument.cs | 44 +++++++++ 6 files changed, 382 insertions(+) create mode 100644 AddOrEditCustomArgument.Designer.cs create mode 100644 AddOrEditCustomArgument.cs create mode 100644 AddOrEditCustomArgument.resx create mode 100644 enums/CustomArgumentType.cs create mode 100644 objects/CustomArgument.cs diff --git a/AddOrEditCustomArgument.Designer.cs b/AddOrEditCustomArgument.Designer.cs new file mode 100644 index 0000000..e27cad0 --- /dev/null +++ b/AddOrEditCustomArgument.Designer.cs @@ -0,0 +1,122 @@ +namespace SSMSObjectExplorerMenu +{ + partial class AddOrEditCustomArgument + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddOrEditCustomArgument)); + this.textBoxArgumentName = new System.Windows.Forms.TextBox(); + this.comboBoxArgumentType = new System.Windows.Forms.ComboBox(); + this.labelArgumentName = new System.Windows.Forms.Label(); + this.labelArgumentType = new System.Windows.Forms.Label(); + this.buttonSave = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // textBoxArgumentName + // + this.textBoxArgumentName.Location = new System.Drawing.Point(103, 24); + this.textBoxArgumentName.Name = "textBoxArgumentName"; + this.textBoxArgumentName.Size = new System.Drawing.Size(170, 20); + this.textBoxArgumentName.TabIndex = 0; + // + // comboBoxArgumentType + // + this.comboBoxArgumentType.FormattingEnabled = true; + this.comboBoxArgumentType.Location = new System.Drawing.Point(103, 66); + this.comboBoxArgumentType.Name = "comboBoxArgumentType"; + this.comboBoxArgumentType.Size = new System.Drawing.Size(170, 21); + this.comboBoxArgumentType.TabIndex = 1; + // + // labelArgumentName + // + this.labelArgumentName.AutoSize = true; + this.labelArgumentName.Location = new System.Drawing.Point(13, 24); + this.labelArgumentName.Name = "labelArgumentName"; + this.labelArgumentName.Size = new System.Drawing.Size(84, 13); + this.labelArgumentName.TabIndex = 2; + this.labelArgumentName.Text = "Argument name:"; + // + // labelArgumentType + // + this.labelArgumentType.AutoSize = true; + this.labelArgumentType.Location = new System.Drawing.Point(13, 66); + this.labelArgumentType.Name = "labelArgumentType"; + this.labelArgumentType.Size = new System.Drawing.Size(78, 13); + this.labelArgumentType.TabIndex = 3; + this.labelArgumentType.Text = "Argument type:"; + // + // buttonSave + // + this.buttonSave.Location = new System.Drawing.Point(103, 126); + this.buttonSave.Name = "buttonSave"; + this.buttonSave.Size = new System.Drawing.Size(75, 23); + this.buttonSave.TabIndex = 4; + this.buttonSave.Text = "Save"; + this.buttonSave.UseVisualStyleBackColor = true; + this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click); + // + // buttonCancel + // + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(198, 126); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 5; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // AddOrEditCustomArgument + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(285, 164); + this.ControlBox = false; + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonSave); + this.Controls.Add(this.labelArgumentType); + this.Controls.Add(this.labelArgumentName); + this.Controls.Add(this.comboBoxArgumentType); + this.Controls.Add(this.textBoxArgumentName); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "AddOrEditCustomArgument"; + this.Text = "AddOrEditCustomArgument"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBoxArgumentName; + private System.Windows.Forms.ComboBox comboBoxArgumentType; + private System.Windows.Forms.Label labelArgumentName; + private System.Windows.Forms.Label labelArgumentType; + private System.Windows.Forms.Button buttonSave; + private System.Windows.Forms.Button buttonCancel; + } +} \ No newline at end of file diff --git a/AddOrEditCustomArgument.cs b/AddOrEditCustomArgument.cs new file mode 100644 index 0000000..727b064 --- /dev/null +++ b/AddOrEditCustomArgument.cs @@ -0,0 +1,51 @@ +using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.objects; +using System; +using System.Windows.Forms; + +namespace SSMSObjectExplorerMenu +{ + public partial class AddOrEditCustomArgument : Form + { + private bool _editing; + + public CustomArgument CustomArgument { get; private set; } + + public AddOrEditCustomArgument(bool edit = false, CustomArgument argumentToEdit = null) + { + _editing = edit; + if(_editing && argumentToEdit is null) + { + throw new ArgumentException($"{nameof(argumentToEdit)} cannot be null if the dialog is in edit mode.", nameof(argumentToEdit)); + } + + CustomArgument = new CustomArgument + { + Name = _editing ? argumentToEdit.Name : string.Empty, + Type = _editing ? argumentToEdit.Type : CustomArgumentType.UniqueIdentifier + }; + + this.Text = $"{(_editing ? "Editing" : "Adding new")} custom argument..."; + + this.textBoxArgumentName.MaxLength = CustomArgument.NAME_MAX_LENGTH; + this.textBoxArgumentName.DataBindings.Add(nameof(textBoxArgumentName.Text), CustomArgument, nameof(CustomArgument.Name)); + + this.comboBoxArgumentType.DataSource = Enum.GetNames(typeof(CustomArgumentType)); + this.comboBoxArgumentType.SelectedIndex = 0; + this.comboBoxArgumentType.DataBindings.Add(nameof(comboBoxArgumentType.SelectedValue), CustomArgument, nameof(CustomArgument.Type)); + + InitializeComponent(); + } + + private void buttonSave_Click(object sender, EventArgs e) + { + if(string.IsNullOrWhiteSpace(this.textBoxArgumentName.Text)) + { + MessageBox.Show("You have to provide a name!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this.DialogResult = DialogResult.OK; + } + } +} diff --git a/AddOrEditCustomArgument.resx b/AddOrEditCustomArgument.resx new file mode 100644 index 0000000..d729beb --- /dev/null +++ b/AddOrEditCustomArgument.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAA + AACTlZX/hoiJ/5GTlP+PkZL/kJGS/5CRkv+QkZL/kJGS/5CRk/+QkZL/kJGS/5CRkv+PkZL/kZOU/4aI + if+SlJX/goSF/+Pk5P/5+fn/9fX1//X29v/19fb/9fX2//f39f/39/X/9fX2//X29v/19vb/9fX1//n5 + +f/k5OX/g4WG/46Qkf/4+Pj///////////////////////7+/v9XSa7/Vkit//79/f////////7///// + ////////+Pj4/4+Rkv+Nj5D/9/f3///////+/v7//v7+///////9/f3/Khua/ygamP/8/Pz///////7+ + /v/+/v7///////f39/+Oj5H/jY+Q//f4+P///////v7+//7+/v///////f3+/zQjn/8yIZ3//Pz9//// + ///+/v7//v7+///////4+Pj/jpCR/42PkP/3+Pj////////////+/v////////7+/v8yIZ7/MB+c//39 + /f///////v7/////////////+Pj4/46Qkf+Nj5D/9/j4//////////7//v7////////+/v7/MiGe/zAf + nP/9/f3///////7+//////7///////j4+P+OkJH/jpCQ//f39/9XSa//Lh2c/zgnoP82JqD/NiWg/xwJ + lP8cCZT/NiWg/zYmoP83J6D/Lx6c/1ZIr//39/f/j5CR/46QkP/39/f/T0Cr/yUTmP8uHZz/LRub/y0b + m/8bCJT/GwiU/y0bm/8tG5v/Lh2c/yUTmP9OP6v/9/f3/4+Qkf+Nj5D/9/j4//79///7+vz/+/r8//z8 + /f/6+fz/MiCd/zAfnP/5+fv//Pz9//v6/P/7+vz//f3///j4+P+OkJH/jY+Q//f4+P////////////7+ + /////////v7+/zIhnv8xH5z//f39///////+/v/////////////4+Pj/jpCR/42PkP/3+Pj///////7+ + /v/+/v7///////39/v80Ip7/MiGd//z8/f///////v7+//7+/v//////+Pj4/46Qkf+Nj5D/9/f3//// + ///+/v7//v7+///////9/f7/Kxyb/ykamf/8/P3///////7+/v/+/v7///////f3+P+Oj5H/jpCR//j4 + +P/////////////+/////////v7+/09Aqv9OP6n//f39/////////v/////////////4+Pj/j5CS/4SG + h//o6Oj//f39//n5+f/5+fn/+fn5//n5+f/39/f/9/b3//n5+f/5+vn/+fn5//n5+f/9/f3/6Onp/4SG + h/+OkJH/hYeI/5KTlP+QkZL/kJKS/5CSkv+QkpL/kZOT/5GTk/+QkpL/kJKS/5CSkv+QkZL/kpOU/4WH + iP+Nj5D/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAA== + + + \ No newline at end of file diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index fe7a5a7..bd082b9 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -65,7 +65,15 @@ AddMenuItem.cs + + Form + + + AddOrEditCustomArgument.cs + + + @@ -135,6 +143,9 @@ AddMenuItem.cs Designer + + AddOrEditCustomArgument.cs + ResXFileCodeGenerator Resources.Designer.cs diff --git a/enums/CustomArgumentType.cs b/enums/CustomArgumentType.cs new file mode 100644 index 0000000..69871f4 --- /dev/null +++ b/enums/CustomArgumentType.cs @@ -0,0 +1,9 @@ +namespace SSMSObjectExplorerMenu.enums +{ + public enum CustomArgumentType : byte + { + UniqueIdentifier, + Int, + Nvarchar + } +} diff --git a/objects/CustomArgument.cs b/objects/CustomArgument.cs new file mode 100644 index 0000000..0753c7c --- /dev/null +++ b/objects/CustomArgument.cs @@ -0,0 +1,44 @@ +using Microsoft.Internal.VisualStudio.Shell; +using SSMSObjectExplorerMenu.enums; +using System; + +namespace SSMSObjectExplorerMenu.objects +{ + public class CustomArgument + { + public const short NAME_MAX_LENGTH = 128; + + public string Name { get; set; } + + public CustomArgumentType Type { get; set; } + + public override bool Equals(object other) + { + var otherAsCustomArg = other as CustomArgument; + + if (otherAsCustomArg is null) return false; + + return StringComparer.OrdinalIgnoreCase.Equals(Name, otherAsCustomArg.Name) && Type == otherAsCustomArg.Type; + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = 13; + hashCode = hashCode * 41 + (Name?.GetHashCode() ?? 0); + hashCode = hashCode * 41 + Type.GetHashCode(); + return hashCode; + } + } + + public static bool operator ==(CustomArgument left, CustomArgument right) + { + if (ReferenceEquals(left, right)) return true; + if (left is null || right is null) return false; + return left.Equals(right); + } + + public static bool operator !=(CustomArgument left, CustomArgument right) => !(left == right); + } +} From 2039441c19f83889989d43f8ec334cdc79e9f81e Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Sat, 6 Sep 2025 18:36:58 +0200 Subject: [PATCH 02/29] AddOrEditCustomArgument dialog: additional validation. Remove unnecessary using from CustomArgument.cs file. --- AddOrEditCustomArgument.cs | 29 +++++++++++++++++++++++++---- objects/CustomArgument.cs | 3 +-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/AddOrEditCustomArgument.cs b/AddOrEditCustomArgument.cs index 727b064..6abb973 100644 --- a/AddOrEditCustomArgument.cs +++ b/AddOrEditCustomArgument.cs @@ -1,6 +1,8 @@ using SSMSObjectExplorerMenu.enums; using SSMSObjectExplorerMenu.objects; using System; +using System.Collections.Generic; +using System.Linq; using System.Windows.Forms; namespace SSMSObjectExplorerMenu @@ -8,11 +10,24 @@ namespace SSMSObjectExplorerMenu public partial class AddOrEditCustomArgument : Form { private bool _editing; + private IEnumerable _argumentNamesInUse; + private CustomArgument _argument; - public CustomArgument CustomArgument { get; private set; } + public CustomArgument CustomArgument { + get + { + if(this.DialogResult != DialogResult.OK) + { + throw new InvalidOperationException("Cannot get argument value from dialog without any user inter interaction."); + } + return _argument; + } + private set { _argument = value; } + } - public AddOrEditCustomArgument(bool edit = false, CustomArgument argumentToEdit = null) + public AddOrEditCustomArgument(IEnumerable argumentNamesInUse, bool edit = false, CustomArgument argumentToEdit = null) { + _argumentNamesInUse = argumentNamesInUse; _editing = edit; if(_editing && argumentToEdit is null) { @@ -39,9 +54,15 @@ public AddOrEditCustomArgument(bool edit = false, CustomArgument argumentToEdit private void buttonSave_Click(object sender, EventArgs e) { - if(string.IsNullOrWhiteSpace(this.textBoxArgumentName.Text)) + var argumentNameToAdd = this.textBoxArgumentName.Text; + if (string.IsNullOrWhiteSpace(argumentNameToAdd)) + { + MessageBox.Show("You must choose a name for the argument!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + if (_argumentNamesInUse.Any(argumentName => StringComparer.OrdinalIgnoreCase.Equals(argumentName, argumentNameToAdd))) { - MessageBox.Show("You have to provide a name!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show($"Name '{argumentNameToAdd}' is already in use! Choose a different one!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } diff --git a/objects/CustomArgument.cs b/objects/CustomArgument.cs index 0753c7c..8a6ce39 100644 --- a/objects/CustomArgument.cs +++ b/objects/CustomArgument.cs @@ -1,5 +1,4 @@ -using Microsoft.Internal.VisualStudio.Shell; -using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.enums; using System; namespace SSMSObjectExplorerMenu.objects From 4288421fda03db7568faa999b606864e00421d85 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 8 Sep 2025 10:46:53 +0200 Subject: [PATCH 03/29] Rename CustomArgument to UserDefinedArgument in types. Extending AddMenuItem window with controls for adding user-defined arguments. --- AddMenuItem.Designer.cs | 464 ++++++++++-------- AddMenuItem.cs | 36 +- ...> AddOrEditUserDefinedArgument.Designer.cs | 4 +- ...ment.cs => AddOrEditUserDefinedArgument.cs | 29 +- ....resx => AddOrEditUserDefinedArgument.resx | 0 SSMSObjectExplorerMenu.csproj | 15 +- Utils.cs | 23 + ...mentType.cs => UserDefinedArgumentType.cs} | 2 +- objects/MenuItem.cs | 19 +- ...stomArgument.cs => UserDefinedArgument.cs} | 10 +- 10 files changed, 364 insertions(+), 238 deletions(-) rename AddOrEditCustomArgument.Designer.cs => AddOrEditUserDefinedArgument.Designer.cs (98%) rename AddOrEditCustomArgument.cs => AddOrEditUserDefinedArgument.cs (69%) rename AddOrEditCustomArgument.resx => AddOrEditUserDefinedArgument.resx (100%) create mode 100644 Utils.cs rename enums/{CustomArgumentType.cs => UserDefinedArgumentType.cs} (70%) rename objects/{CustomArgument.cs => UserDefinedArgument.cs} (72%) diff --git a/AddMenuItem.Designer.cs b/AddMenuItem.Designer.cs index 122f4b7..77b0ed4 100644 --- a/AddMenuItem.Designer.cs +++ b/AddMenuItem.Designer.cs @@ -28,65 +28,68 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddMenuItem)); - this.buttonCancel = new System.Windows.Forms.Button(); - this.buttonOK = new System.Windows.Forms.Button(); - this.textName = new System.Windows.Forms.TextBox(); - this.comboContext = new System.Windows.Forms.ComboBox(); - this.checkExecute = new System.Windows.Forms.CheckBox(); - this.checkConfirm = new System.Windows.Forms.CheckBox(); - this.textPath = new System.Windows.Forms.TextBox(); - this.labelName = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.radioPath = new System.Windows.Forms.RadioButton(); - this.radioScript = new System.Windows.Forms.RadioButton(); - this.buttonOpen = new System.Windows.Forms.Button(); - this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); - this.labelVersion = new System.Windows.Forms.Label(); - this.SuspendLayout(); - // - // buttonCancel - // - this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(682, 425); - this.buttonCancel.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(112, 35); - this.buttonCancel.TabIndex = 6; - this.buttonCancel.Text = "Cancel"; - this.buttonCancel.UseVisualStyleBackColor = true; - // - // buttonOK - // - this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.buttonOK.Enabled = false; - this.buttonOK.Location = new System.Drawing.Point(561, 425); - this.buttonOK.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.buttonOK.Name = "buttonOK"; - this.buttonOK.Size = new System.Drawing.Size(112, 35); - this.buttonOK.TabIndex = 5; - this.buttonOK.Text = "OK"; - this.buttonOK.UseVisualStyleBackColor = true; - // - // textName - // - this.textName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddMenuItem)); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.textName = new System.Windows.Forms.TextBox(); + this.comboContext = new System.Windows.Forms.ComboBox(); + this.checkExecute = new System.Windows.Forms.CheckBox(); + this.checkConfirm = new System.Windows.Forms.CheckBox(); + this.textPath = new System.Windows.Forms.TextBox(); + this.labelName = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.radioPath = new System.Windows.Forms.RadioButton(); + this.radioScript = new System.Windows.Forms.RadioButton(); + this.buttonOpen = new System.Windows.Forms.Button(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.labelVersion = new System.Windows.Forms.Label(); + this.listViewCustomArgs = new System.Windows.Forms.ListView(); + this.ArgumentName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ArgumentType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.buttonAddCustomArg = new System.Windows.Forms.Button(); + this.buttonRemoveCustomArg = new System.Windows.Forms.Button(); + this.labelCustomArgs = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(455, 440); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 6; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOK.Enabled = false; + this.buttonOK.Location = new System.Drawing.Point(374, 440); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 5; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + // + // textName + // + this.textName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textName.Location = new System.Drawing.Point(132, 18); - this.textName.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.textName.Name = "textName"; - this.textName.Size = new System.Drawing.Size(661, 26); - this.textName.TabIndex = 0; - this.textName.TextChanged += new System.EventHandler(this.textName_TextChanged); - // - // comboContext - // - this.comboContext.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.textName.Location = new System.Drawing.Point(88, 12); + this.textName.Name = "textName"; + this.textName.Size = new System.Drawing.Size(442, 20); + this.textName.TabIndex = 0; + this.textName.TextChanged += new System.EventHandler(this.textName_TextChanged); + // + // comboContext + // + this.comboContext.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.comboContext.FormattingEnabled = true; - this.comboContext.Items.AddRange(new object[] { + this.comboContext.FormattingEnabled = true; + this.comboContext.Items.AddRange(new object[] { "All", "Server", "Server/DatabasesFolder", @@ -99,154 +102,201 @@ private void InitializeComponent() "Server/JobServer", "Server/JobServer/JobsFolder", "Server/JobServer/Job"}); - this.comboContext.Location = new System.Drawing.Point(132, 58); - this.comboContext.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.comboContext.Name = "comboContext"; - this.comboContext.Size = new System.Drawing.Size(661, 28); - this.comboContext.TabIndex = 1; - // - // checkExecute - // - this.checkExecute.AutoSize = true; - this.checkExecute.Location = new System.Drawing.Point(132, 100); - this.checkExecute.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.checkExecute.Name = "checkExecute"; - this.checkExecute.Size = new System.Drawing.Size(93, 24); - this.checkExecute.TabIndex = 2; - this.checkExecute.Text = "Execute"; - this.checkExecute.UseVisualStyleBackColor = true; - this.checkExecute.CheckedChanged += new System.EventHandler(this.checkExecute_CheckedChanged); - // - // checkConfirm - // - this.checkConfirm.AutoSize = true; - this.checkConfirm.Location = new System.Drawing.Point(132, 135); - this.checkConfirm.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.checkConfirm.Name = "checkConfirm"; - this.checkConfirm.Size = new System.Drawing.Size(200, 24); - this.checkConfirm.TabIndex = 3; - this.checkConfirm.Text = "Confirm before execute"; - this.checkConfirm.UseVisualStyleBackColor = true; - this.checkConfirm.CheckedChanged += new System.EventHandler(this.checkConfirm_CheckedChanged); - // - // textPath - // - this.textPath.AcceptsReturn = true; - this.textPath.AcceptsTab = true; - this.textPath.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.comboContext.Location = new System.Drawing.Point(88, 38); + this.comboContext.Name = "comboContext"; + this.comboContext.Size = new System.Drawing.Size(442, 21); + this.comboContext.TabIndex = 1; + // + // checkExecute + // + this.checkExecute.AutoSize = true; + this.checkExecute.Location = new System.Drawing.Point(88, 65); + this.checkExecute.Name = "checkExecute"; + this.checkExecute.Size = new System.Drawing.Size(65, 17); + this.checkExecute.TabIndex = 2; + this.checkExecute.Text = "Execute"; + this.checkExecute.UseVisualStyleBackColor = true; + this.checkExecute.CheckedChanged += new System.EventHandler(this.checkExecute_CheckedChanged); + // + // checkConfirm + // + this.checkConfirm.AutoSize = true; + this.checkConfirm.Location = new System.Drawing.Point(88, 88); + this.checkConfirm.Name = "checkConfirm"; + this.checkConfirm.Size = new System.Drawing.Size(135, 17); + this.checkConfirm.TabIndex = 3; + this.checkConfirm.Text = "Confirm before execute"; + this.checkConfirm.UseVisualStyleBackColor = true; + this.checkConfirm.CheckedChanged += new System.EventHandler(this.checkConfirm_CheckedChanged); + // + // textPath + // + this.textPath.AcceptsReturn = true; + this.textPath.AcceptsTab = true; + this.textPath.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.textPath.Location = new System.Drawing.Point(132, 206); - this.textPath.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.textPath.Multiline = true; - this.textPath.Name = "textPath"; - this.textPath.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.textPath.Size = new System.Drawing.Size(661, 207); - this.textPath.TabIndex = 4; - this.textPath.Text = resources.GetString("textPath.Text"); - this.textPath.WordWrap = false; - this.textPath.TextChanged += new System.EventHandler(this.textPath_TextChanged); - // - // labelName - // - this.labelName.AutoSize = true; - this.labelName.Location = new System.Drawing.Point(18, 23); - this.labelName.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.labelName.Name = "labelName"; - this.labelName.Size = new System.Drawing.Size(51, 20); - this.labelName.TabIndex = 7; - this.labelName.Text = "Name"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(18, 63); - this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(64, 20); - this.label1.TabIndex = 8; - this.label1.Text = "Context"; - // - // radioPath - // - this.radioPath.AutoSize = true; - this.radioPath.Location = new System.Drawing.Point(219, 171); - this.radioPath.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.radioPath.Name = "radioPath"; - this.radioPath.Size = new System.Drawing.Size(67, 24); - this.radioPath.TabIndex = 10; - this.radioPath.Text = "Path"; - this.radioPath.UseVisualStyleBackColor = true; - this.radioPath.CheckedChanged += new System.EventHandler(this.radioPath_CheckedChanged); - // - // radioScript - // - this.radioScript.AutoSize = true; - this.radioScript.Checked = true; - this.radioScript.Location = new System.Drawing.Point(132, 171); - this.radioScript.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.radioScript.Name = "radioScript"; - this.radioScript.Size = new System.Drawing.Size(75, 24); - this.radioScript.TabIndex = 11; - this.radioScript.TabStop = true; - this.radioScript.Text = "Script"; - this.radioScript.UseVisualStyleBackColor = true; - this.radioScript.CheckedChanged += new System.EventHandler(this.radioScript_CheckedChanged); - // - // buttonOpen - // - this.buttonOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonOpen.Location = new System.Drawing.Point(758, 166); - this.buttonOpen.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.buttonOpen.Name = "buttonOpen"; - this.buttonOpen.Size = new System.Drawing.Size(38, 35); - this.buttonOpen.TabIndex = 12; - this.buttonOpen.Text = "..."; - this.buttonOpen.UseVisualStyleBackColor = true; - this.buttonOpen.Click += new System.EventHandler(this.buttonOpen_Click); - // - // openFileDialog - // - this.openFileDialog.DefaultExt = "sql"; - this.openFileDialog.FileName = "openFileDialog"; - this.openFileDialog.Filter = "SQL Server files (*.sql)|*.sql"; - // - // labelVersion - // - this.labelVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.labelVersion.AutoSize = true; - this.labelVersion.Location = new System.Drawing.Point(18, 432); - this.labelVersion.Name = "labelVersion"; - this.labelVersion.Size = new System.Drawing.Size(44, 20); - this.labelVersion.TabIndex = 13; - this.labelVersion.Text = "0.0.0"; - // - // AddMenuItem - // - this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(813, 478); - this.Controls.Add(this.labelVersion); - this.Controls.Add(this.buttonOpen); - this.Controls.Add(this.radioScript); - this.Controls.Add(this.radioPath); - this.Controls.Add(this.label1); - this.Controls.Add(this.labelName); - this.Controls.Add(this.textPath); - this.Controls.Add(this.checkConfirm); - this.Controls.Add(this.checkExecute); - this.Controls.Add(this.comboContext); - this.Controls.Add(this.textName); - this.Controls.Add(this.buttonOK); - this.Controls.Add(this.buttonCancel); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.Name = "AddMenuItem"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "SSMS Object Explorer Menu | New menu item"; - this.ResumeLayout(false); - this.PerformLayout(); + this.textPath.Location = new System.Drawing.Point(88, 245); + this.textPath.Multiline = true; + this.textPath.Name = "textPath"; + this.textPath.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textPath.Size = new System.Drawing.Size(442, 189); + this.textPath.TabIndex = 4; + this.textPath.Text = resources.GetString("textPath.Text"); + this.textPath.WordWrap = false; + this.textPath.TextChanged += new System.EventHandler(this.textPath_TextChanged); + // + // labelName + // + this.labelName.AutoSize = true; + this.labelName.Location = new System.Drawing.Point(12, 15); + this.labelName.Name = "labelName"; + this.labelName.Size = new System.Drawing.Size(35, 13); + this.labelName.TabIndex = 7; + this.labelName.Text = "Name"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 41); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(43, 13); + this.label1.TabIndex = 8; + this.label1.Text = "Context"; + // + // radioPath + // + this.radioPath.AutoSize = true; + this.radioPath.Location = new System.Drawing.Point(146, 222); + this.radioPath.Name = "radioPath"; + this.radioPath.Size = new System.Drawing.Size(47, 17); + this.radioPath.TabIndex = 10; + this.radioPath.Text = "Path"; + this.radioPath.UseVisualStyleBackColor = true; + this.radioPath.CheckedChanged += new System.EventHandler(this.radioPath_CheckedChanged); + // + // radioScript + // + this.radioScript.AutoSize = true; + this.radioScript.Checked = true; + this.radioScript.Location = new System.Drawing.Point(88, 222); + this.radioScript.Name = "radioScript"; + this.radioScript.Size = new System.Drawing.Size(52, 17); + this.radioScript.TabIndex = 11; + this.radioScript.TabStop = true; + this.radioScript.Text = "Script"; + this.radioScript.UseVisualStyleBackColor = true; + this.radioScript.CheckedChanged += new System.EventHandler(this.radioScript_CheckedChanged); + // + // buttonOpen + // + this.buttonOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOpen.Location = new System.Drawing.Point(505, 219); + this.buttonOpen.Name = "buttonOpen"; + this.buttonOpen.Size = new System.Drawing.Size(25, 23); + this.buttonOpen.TabIndex = 12; + this.buttonOpen.Text = "..."; + this.buttonOpen.UseVisualStyleBackColor = true; + this.buttonOpen.Click += new System.EventHandler(this.buttonOpen_Click); + // + // openFileDialog + // + this.openFileDialog.DefaultExt = "sql"; + this.openFileDialog.FileName = "openFileDialog"; + this.openFileDialog.Filter = "SQL Server files (*.sql)|*.sql"; + // + // labelVersion + // + this.labelVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.labelVersion.AutoSize = true; + this.labelVersion.Location = new System.Drawing.Point(12, 445); + this.labelVersion.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(31, 13); + this.labelVersion.TabIndex = 13; + this.labelVersion.Text = "0.0.0"; + // + // listViewCustomArgs + // + this.listViewCustomArgs.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.ArgumentName, + this.ArgumentType}); + this.listViewCustomArgs.HideSelection = false; + this.listViewCustomArgs.Location = new System.Drawing.Point(88, 135); + this.listViewCustomArgs.Name = "listViewCustomArgs"; + this.listViewCustomArgs.Size = new System.Drawing.Size(275, 75); + this.listViewCustomArgs.TabIndex = 15; + this.listViewCustomArgs.UseCompatibleStateImageBehavior = false; + this.listViewCustomArgs.View = System.Windows.Forms.View.Details; + // + // ArgumentName + // + this.ArgumentName.Text = "Argument name"; + this.ArgumentName.Width = 160; + // + // ArgumentType + // + this.ArgumentType.Text = "Argument type"; + this.ArgumentType.Width = 106; + // + // buttonAddCustomArg + // + this.buttonAddCustomArg.Location = new System.Drawing.Point(374, 135); + this.buttonAddCustomArg.Name = "buttonAddCustomArg"; + this.buttonAddCustomArg.Size = new System.Drawing.Size(75, 23); + this.buttonAddCustomArg.TabIndex = 16; + this.buttonAddCustomArg.Text = "Add"; + this.buttonAddCustomArg.UseVisualStyleBackColor = true; + this.buttonAddCustomArg.Click += new System.EventHandler(this.buttonAddCustomArg_Click); + // + // buttonRemoveCustomArg + // + this.buttonRemoveCustomArg.Location = new System.Drawing.Point(374, 164); + this.buttonRemoveCustomArg.Name = "buttonRemoveCustomArg"; + this.buttonRemoveCustomArg.Size = new System.Drawing.Size(75, 23); + this.buttonRemoveCustomArg.TabIndex = 18; + this.buttonRemoveCustomArg.Text = "Remove"; + this.buttonRemoveCustomArg.UseVisualStyleBackColor = true; + this.buttonRemoveCustomArg.Click += new System.EventHandler(this.buttonRemoveCustomArg_Click); + // + // labelCustomArgs + // + this.labelCustomArgs.AutoSize = true; + this.labelCustomArgs.Location = new System.Drawing.Point(91, 117); + this.labelCustomArgs.Name = "labelCustomArgs"; + this.labelCustomArgs.Size = new System.Drawing.Size(151, 13); + this.labelCustomArgs.TabIndex = 19; + this.labelCustomArgs.Text = "List of user-defined arguments:"; + // + // AddMenuItem + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(542, 475); + this.Controls.Add(this.labelCustomArgs); + this.Controls.Add(this.buttonRemoveCustomArg); + this.Controls.Add(this.buttonAddCustomArg); + this.Controls.Add(this.listViewCustomArgs); + this.Controls.Add(this.labelVersion); + this.Controls.Add(this.buttonOpen); + this.Controls.Add(this.radioScript); + this.Controls.Add(this.radioPath); + this.Controls.Add(this.label1); + this.Controls.Add(this.labelName); + this.Controls.Add(this.textPath); + this.Controls.Add(this.checkConfirm); + this.Controls.Add(this.checkExecute); + this.Controls.Add(this.comboContext); + this.Controls.Add(this.textName); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "AddMenuItem"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "SSMS Object Explorer Menu | New menu item"; + this.ResumeLayout(false); + this.PerformLayout(); } @@ -266,5 +316,11 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonOpen; private System.Windows.Forms.OpenFileDialog openFileDialog; private System.Windows.Forms.Label labelVersion; - } + private System.Windows.Forms.ListView listViewCustomArgs; + private System.Windows.Forms.ColumnHeader ArgumentName; + private System.Windows.Forms.ColumnHeader ArgumentType; + private System.Windows.Forms.Button buttonAddCustomArg; + private System.Windows.Forms.Button buttonRemoveCustomArg; + private System.Windows.Forms.Label labelCustomArgs; + } } \ No newline at end of file diff --git a/AddMenuItem.cs b/AddMenuItem.cs index f8ca27e..575b9da 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -1,5 +1,7 @@ -using SSMSObjectExplorerMenu.objects; +using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.objects; using System; +using System.Linq; using System.Reflection; using System.Windows.Forms; using MenuItem = SSMSObjectExplorerMenu.objects.MenuItem; @@ -86,5 +88,35 @@ private void checkExecute_CheckedChanged(object sender, EventArgs e) checkConfirm.Checked = false; } } - } + + private void buttonAddCustomArg_Click(object sender, EventArgs e) + { + var argumentNamesInUse = this.listViewCustomArgs.Items.Cast().Select(item => item.Text); + var addDialog = new AddOrEditUserDefinedArgument(argumentNamesInUse); + if(addDialog.ShowDialog() == DialogResult.OK) + { + var newArgument = addDialog.Argument; + var newListViewItem = new ListViewItem { Text = newArgument.Name }; + newListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem { Text = Enum.GetName(typeof(UserDefinedArgumentType), newArgument.Type) }); + listViewCustomArgs.Items.Add(newListViewItem); + } + } + + private void buttonRemoveCustomArg_Click(object sender, EventArgs e) + { + var selectedItems = this.listViewCustomArgs.Items.Cast().Where(item => item.Selected); + if (selectedItems.Any() && + DialogResult.Yes == MessageBox.Show("Are you sure?", "Deleting arguments", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) + { + foreach (var item in selectedItems) + { + this.listViewCustomArgs.Items.Remove(item); + } + } + else + { + MessageBox.Show("You must select an item to delete.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } } diff --git a/AddOrEditCustomArgument.Designer.cs b/AddOrEditUserDefinedArgument.Designer.cs similarity index 98% rename from AddOrEditCustomArgument.Designer.cs rename to AddOrEditUserDefinedArgument.Designer.cs index e27cad0..13f4740 100644 --- a/AddOrEditCustomArgument.Designer.cs +++ b/AddOrEditUserDefinedArgument.Designer.cs @@ -1,6 +1,6 @@ namespace SSMSObjectExplorerMenu { - partial class AddOrEditCustomArgument + partial class AddOrEditUserDefinedArgument { /// /// Required designer variable. @@ -28,7 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddOrEditCustomArgument)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddOrEditUserDefinedArgument)); this.textBoxArgumentName = new System.Windows.Forms.TextBox(); this.comboBoxArgumentType = new System.Windows.Forms.ComboBox(); this.labelArgumentName = new System.Windows.Forms.Label(); diff --git a/AddOrEditCustomArgument.cs b/AddOrEditUserDefinedArgument.cs similarity index 69% rename from AddOrEditCustomArgument.cs rename to AddOrEditUserDefinedArgument.cs index 6abb973..adda924 100644 --- a/AddOrEditCustomArgument.cs +++ b/AddOrEditUserDefinedArgument.cs @@ -7,13 +7,13 @@ namespace SSMSObjectExplorerMenu { - public partial class AddOrEditCustomArgument : Form + public partial class AddOrEditUserDefinedArgument : Form { private bool _editing; private IEnumerable _argumentNamesInUse; - private CustomArgument _argument; + private UserDefinedArgument _argument; - public CustomArgument CustomArgument { + public UserDefinedArgument Argument { get { if(this.DialogResult != DialogResult.OK) @@ -22,34 +22,35 @@ public CustomArgument CustomArgument { } return _argument; } - private set { _argument = value; } } - public AddOrEditCustomArgument(IEnumerable argumentNamesInUse, bool edit = false, CustomArgument argumentToEdit = null) + public AddOrEditUserDefinedArgument(IEnumerable argumentNamesInUse, bool edit = false, UserDefinedArgument argumentToEdit = null) { - _argumentNamesInUse = argumentNamesInUse; + InitializeComponent(); + + // Can't add arguments already added by the user once or coming from the execution context... + _argumentNamesInUse = argumentNamesInUse.Concat(Utils.ArgumentsFromContext); _editing = edit; if(_editing && argumentToEdit is null) { throw new ArgumentException($"{nameof(argumentToEdit)} cannot be null if the dialog is in edit mode.", nameof(argumentToEdit)); } - CustomArgument = new CustomArgument + _argument = new UserDefinedArgument { Name = _editing ? argumentToEdit.Name : string.Empty, - Type = _editing ? argumentToEdit.Type : CustomArgumentType.UniqueIdentifier + Type = _editing ? argumentToEdit.Type : UserDefinedArgumentType.UniqueIdentifier }; this.Text = $"{(_editing ? "Editing" : "Adding new")} custom argument..."; - this.textBoxArgumentName.MaxLength = CustomArgument.NAME_MAX_LENGTH; - this.textBoxArgumentName.DataBindings.Add(nameof(textBoxArgumentName.Text), CustomArgument, nameof(CustomArgument.Name)); + this.textBoxArgumentName.MaxLength = UserDefinedArgument.NAME_MAX_LENGTH; + this.textBoxArgumentName.DataBindings.Add(nameof(textBoxArgumentName.Text), _argument, nameof(_argument.Name)); - this.comboBoxArgumentType.DataSource = Enum.GetNames(typeof(CustomArgumentType)); + this.comboBoxArgumentType.DataSource = Enum.GetNames(typeof(UserDefinedArgumentType)); this.comboBoxArgumentType.SelectedIndex = 0; - this.comboBoxArgumentType.DataBindings.Add(nameof(comboBoxArgumentType.SelectedValue), CustomArgument, nameof(CustomArgument.Type)); - - InitializeComponent(); + this.comboBoxArgumentType.ValueMember = "."; + this.comboBoxArgumentType.DataBindings.Add(nameof(comboBoxArgumentType.SelectedValue), _argument, nameof(_argument.Type)); } private void buttonSave_Click(object sender, EventArgs e) diff --git a/AddOrEditCustomArgument.resx b/AddOrEditUserDefinedArgument.resx similarity index 100% rename from AddOrEditCustomArgument.resx rename to AddOrEditUserDefinedArgument.resx diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index bd082b9..19137e9 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -65,18 +65,19 @@ AddMenuItem.cs - + Form - - AddOrEditCustomArgument.cs + + AddOrEditUserDefinedArgument.cs - + - + + Component @@ -143,8 +144,8 @@ AddMenuItem.cs Designer - - AddOrEditCustomArgument.cs + + AddOrEditUserDefinedArgument.cs ResXFileCodeGenerator diff --git a/Utils.cs b/Utils.cs new file mode 100644 index 0000000..ade6ed8 --- /dev/null +++ b/Utils.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace SSMSObjectExplorerMenu +{ + public static class Utils + { + public static IEnumerable ArgumentsFromContext = new string[] + { + "{OBJECT}", + "{SERVER}", + "{DATABASE}", + "{TABLE}", + "{VIEW}", + "{STORED_PROCEDURE}", + "{FUNCTION}", + "{SCHEMA}", + "{JOB}", + "{YYYY-MM-DD}", + "{HH:mm:ss}", + "{YYYY-MM-DD HH:mm:ss}" + }; + } +} diff --git a/enums/CustomArgumentType.cs b/enums/UserDefinedArgumentType.cs similarity index 70% rename from enums/CustomArgumentType.cs rename to enums/UserDefinedArgumentType.cs index 69871f4..f02c68e 100644 --- a/enums/CustomArgumentType.cs +++ b/enums/UserDefinedArgumentType.cs @@ -1,6 +1,6 @@ namespace SSMSObjectExplorerMenu.enums { - public enum CustomArgumentType : byte + public enum UserDefinedArgumentType : byte { UniqueIdentifier, Int, diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index 8329793..001d245 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -1,7 +1,10 @@ -using System; +using SSMSObjectExplorerMenu.enums; +using System; +using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing.Design; +using System.Linq; namespace SSMSObjectExplorerMenu.objects { @@ -51,21 +54,31 @@ public string Script [DefaultValue("All")] public string Context { get; set; } = "All"; + [Category("Menu item")] + [DisplayName("User-defined arguments")] + [Description("List of user-deifned arguments can be used in the T-SQL script.")] + [DefaultValue("All")] + public IEnumerable UserDefinedArguments { get; private set; } = Enumerable.Empty(); public MenuItem() { } - public MenuItem(bool enabled, string context, string name, string script, bool execute, bool confirm) + public MenuItem(bool enabled, string context, string name, string script, bool execute, bool confirm, IEnumerable customArguments = null) { - Enabled = enabled; + Enabled = enabled; Context = context; Name = name; Script = script; Execute = execute; Confirm = confirm; + if(customArguments != null) + { + UserDefinedArguments = customArguments; + } + if (Confirm) { Execute = true; } diff --git a/objects/CustomArgument.cs b/objects/UserDefinedArgument.cs similarity index 72% rename from objects/CustomArgument.cs rename to objects/UserDefinedArgument.cs index 8a6ce39..f4d82d9 100644 --- a/objects/CustomArgument.cs +++ b/objects/UserDefinedArgument.cs @@ -3,17 +3,17 @@ namespace SSMSObjectExplorerMenu.objects { - public class CustomArgument + public class UserDefinedArgument { public const short NAME_MAX_LENGTH = 128; public string Name { get; set; } - public CustomArgumentType Type { get; set; } + public UserDefinedArgumentType Type { get; set; } public override bool Equals(object other) { - var otherAsCustomArg = other as CustomArgument; + var otherAsCustomArg = other as UserDefinedArgument; if (otherAsCustomArg is null) return false; @@ -31,13 +31,13 @@ public override int GetHashCode() } } - public static bool operator ==(CustomArgument left, CustomArgument right) + public static bool operator ==(UserDefinedArgument left, UserDefinedArgument right) { if (ReferenceEquals(left, right)) return true; if (left is null || right is null) return false; return left.Equals(right); } - public static bool operator !=(CustomArgument left, CustomArgument right) => !(left == right); + public static bool operator !=(UserDefinedArgument left, UserDefinedArgument right) => !(left == right); } } From 098734be7a02871cc3562cbc600c0bacdec34a31 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 8 Sep 2025 13:56:27 +0200 Subject: [PATCH 04/29] Displaying user-defined arguments in Options grid for view and edit. Fixing data binding in AddOrEditUserDefinedArgument dialog. --- AddOrEditUserDefinedArgument.cs | 12 +++++------- objects/MenuItem.cs | 13 ++++++++----- objects/UserDefinedArgument.cs | 7 +++++++ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/AddOrEditUserDefinedArgument.cs b/AddOrEditUserDefinedArgument.cs index adda924..753ff48 100644 --- a/AddOrEditUserDefinedArgument.cs +++ b/AddOrEditUserDefinedArgument.cs @@ -45,25 +45,23 @@ public AddOrEditUserDefinedArgument(IEnumerable argumentNamesInUse, bool this.Text = $"{(_editing ? "Editing" : "Adding new")} custom argument..."; this.textBoxArgumentName.MaxLength = UserDefinedArgument.NAME_MAX_LENGTH; - this.textBoxArgumentName.DataBindings.Add(nameof(textBoxArgumentName.Text), _argument, nameof(_argument.Name)); + this.textBoxArgumentName.DataBindings.Add(nameof(textBoxArgumentName.Text), _argument, nameof(_argument.Name), true, DataSourceUpdateMode.OnPropertyChanged); this.comboBoxArgumentType.DataSource = Enum.GetNames(typeof(UserDefinedArgumentType)); this.comboBoxArgumentType.SelectedIndex = 0; - this.comboBoxArgumentType.ValueMember = "."; - this.comboBoxArgumentType.DataBindings.Add(nameof(comboBoxArgumentType.SelectedValue), _argument, nameof(_argument.Type)); + this.comboBoxArgumentType.DataBindings.Add(nameof(comboBoxArgumentType.SelectedItem), _argument, nameof(_argument.Type), true, DataSourceUpdateMode.OnPropertyChanged); } private void buttonSave_Click(object sender, EventArgs e) { - var argumentNameToAdd = this.textBoxArgumentName.Text; - if (string.IsNullOrWhiteSpace(argumentNameToAdd)) + if (string.IsNullOrWhiteSpace(_argument.Name)) { MessageBox.Show("You must choose a name for the argument!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - if (_argumentNamesInUse.Any(argumentName => StringComparer.OrdinalIgnoreCase.Equals(argumentName, argumentNameToAdd))) + if (_argumentNamesInUse.Any(argumentName => StringComparer.OrdinalIgnoreCase.Equals(argumentName, _argument.Name))) { - MessageBox.Show($"Name '{argumentNameToAdd}' is already in use! Choose a different one!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show($"Name '{_argument.Name}' is already in use! Choose a different one!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index 001d245..49cf948 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -57,15 +57,15 @@ public string Script [Category("Menu item")] [DisplayName("User-defined arguments")] [Description("List of user-deifned arguments can be used in the T-SQL script.")] - [DefaultValue("All")] - public IEnumerable UserDefinedArguments { get; private set; } = Enumerable.Empty(); + [Editor(typeof(CollectionEditor), typeof(UITypeEditor))] + public BindingList UserDefinedArguments { get; private set; } = new BindingList(); public MenuItem() { } - public MenuItem(bool enabled, string context, string name, string script, bool execute, bool confirm, IEnumerable customArguments = null) + public MenuItem(bool enabled, string context, string name, string script, bool execute, bool confirm, IEnumerable userDefinedArguments = null) { Enabled = enabled; Context = context; @@ -74,9 +74,12 @@ public MenuItem(bool enabled, string context, string name, string script, bool e Execute = execute; Confirm = confirm; - if(customArguments != null) + if(userDefinedArguments != null) { - UserDefinedArguments = customArguments; + foreach(var arg in userDefinedArguments) + { + UserDefinedArguments.Add(arg); + } } if (Confirm) { diff --git a/objects/UserDefinedArgument.cs b/objects/UserDefinedArgument.cs index f4d82d9..e57663e 100644 --- a/objects/UserDefinedArgument.cs +++ b/objects/UserDefinedArgument.cs @@ -1,14 +1,21 @@ using SSMSObjectExplorerMenu.enums; using System; +using System.ComponentModel; namespace SSMSObjectExplorerMenu.objects { + + [TypeConverter(typeof(ExpandableObjectConverter))] public class UserDefinedArgument { public const short NAME_MAX_LENGTH = 128; + [DisplayName("Name")] + [Description("Name of the user-defined argument")] public string Name { get; set; } + [DisplayName("Data type")] + [Description("Data type of the user-defined argument")] public UserDefinedArgumentType Type { get; set; } public override bool Equals(object other) From f438a208f3b2c1e2b84586a4a6dd47d0920b4113 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 8 Sep 2025 13:59:37 +0200 Subject: [PATCH 05/29] Renaming AddOrEditUserDefinedArgument to AddUserDefinedArgument. --- AddMenuItem.cs | 2 +- ...t.Designer.cs => AddUserDefinedArgument.Designer.cs | 4 ++-- ...UserDefinedArgument.cs => AddUserDefinedArgument.cs | 4 ++-- ...DefinedArgument.resx => AddUserDefinedArgument.resx | 0 SSMSObjectExplorerMenu.csproj | 10 +++++----- 5 files changed, 10 insertions(+), 10 deletions(-) rename AddOrEditUserDefinedArgument.Designer.cs => AddUserDefinedArgument.Designer.cs (98%) rename AddOrEditUserDefinedArgument.cs => AddUserDefinedArgument.cs (93%) rename AddOrEditUserDefinedArgument.resx => AddUserDefinedArgument.resx (100%) diff --git a/AddMenuItem.cs b/AddMenuItem.cs index 575b9da..aa40e39 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -92,7 +92,7 @@ private void checkExecute_CheckedChanged(object sender, EventArgs e) private void buttonAddCustomArg_Click(object sender, EventArgs e) { var argumentNamesInUse = this.listViewCustomArgs.Items.Cast().Select(item => item.Text); - var addDialog = new AddOrEditUserDefinedArgument(argumentNamesInUse); + var addDialog = new AddUserDefinedArgument(argumentNamesInUse); if(addDialog.ShowDialog() == DialogResult.OK) { var newArgument = addDialog.Argument; diff --git a/AddOrEditUserDefinedArgument.Designer.cs b/AddUserDefinedArgument.Designer.cs similarity index 98% rename from AddOrEditUserDefinedArgument.Designer.cs rename to AddUserDefinedArgument.Designer.cs index 13f4740..140601b 100644 --- a/AddOrEditUserDefinedArgument.Designer.cs +++ b/AddUserDefinedArgument.Designer.cs @@ -1,6 +1,6 @@ namespace SSMSObjectExplorerMenu { - partial class AddOrEditUserDefinedArgument + partial class AddUserDefinedArgument { /// /// Required designer variable. @@ -28,7 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddOrEditUserDefinedArgument)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddUserDefinedArgument)); this.textBoxArgumentName = new System.Windows.Forms.TextBox(); this.comboBoxArgumentType = new System.Windows.Forms.ComboBox(); this.labelArgumentName = new System.Windows.Forms.Label(); diff --git a/AddOrEditUserDefinedArgument.cs b/AddUserDefinedArgument.cs similarity index 93% rename from AddOrEditUserDefinedArgument.cs rename to AddUserDefinedArgument.cs index 753ff48..fb90c8b 100644 --- a/AddOrEditUserDefinedArgument.cs +++ b/AddUserDefinedArgument.cs @@ -7,7 +7,7 @@ namespace SSMSObjectExplorerMenu { - public partial class AddOrEditUserDefinedArgument : Form + public partial class AddUserDefinedArgument : Form { private bool _editing; private IEnumerable _argumentNamesInUse; @@ -24,7 +24,7 @@ public UserDefinedArgument Argument { } } - public AddOrEditUserDefinedArgument(IEnumerable argumentNamesInUse, bool edit = false, UserDefinedArgument argumentToEdit = null) + public AddUserDefinedArgument(IEnumerable argumentNamesInUse, bool edit = false, UserDefinedArgument argumentToEdit = null) { InitializeComponent(); diff --git a/AddOrEditUserDefinedArgument.resx b/AddUserDefinedArgument.resx similarity index 100% rename from AddOrEditUserDefinedArgument.resx rename to AddUserDefinedArgument.resx diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index 19137e9..097e038 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -65,11 +65,11 @@ AddMenuItem.cs - + Form - - AddOrEditUserDefinedArgument.cs + + AddUserDefinedArgument.cs @@ -144,8 +144,8 @@ AddMenuItem.cs Designer - - AddOrEditUserDefinedArgument.cs + + AddUserDefinedArgument.cs ResXFileCodeGenerator From d321ad473f06237d01c67836e79c82aa54965cee Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 8 Sep 2025 14:03:44 +0200 Subject: [PATCH 06/29] Removing editing scenaro from AddUserDefinedArgument dialog's code. --- AddUserDefinedArgument.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/AddUserDefinedArgument.cs b/AddUserDefinedArgument.cs index fb90c8b..ffeb724 100644 --- a/AddUserDefinedArgument.cs +++ b/AddUserDefinedArgument.cs @@ -9,7 +9,6 @@ namespace SSMSObjectExplorerMenu { public partial class AddUserDefinedArgument : Form { - private bool _editing; private IEnumerable _argumentNamesInUse; private UserDefinedArgument _argument; @@ -24,25 +23,20 @@ public UserDefinedArgument Argument { } } - public AddUserDefinedArgument(IEnumerable argumentNamesInUse, bool edit = false, UserDefinedArgument argumentToEdit = null) + public AddUserDefinedArgument(IEnumerable argumentNamesInUse) { InitializeComponent(); // Can't add arguments already added by the user once or coming from the execution context... _argumentNamesInUse = argumentNamesInUse.Concat(Utils.ArgumentsFromContext); - _editing = edit; - if(_editing && argumentToEdit is null) - { - throw new ArgumentException($"{nameof(argumentToEdit)} cannot be null if the dialog is in edit mode.", nameof(argumentToEdit)); - } _argument = new UserDefinedArgument { - Name = _editing ? argumentToEdit.Name : string.Empty, - Type = _editing ? argumentToEdit.Type : UserDefinedArgumentType.UniqueIdentifier + Name = string.Empty, + Type = UserDefinedArgumentType.UniqueIdentifier }; - this.Text = $"{(_editing ? "Editing" : "Adding new")} custom argument..."; + this.Text = "Adding new custom argument..."; this.textBoxArgumentName.MaxLength = UserDefinedArgument.NAME_MAX_LENGTH; this.textBoxArgumentName.DataBindings.Add(nameof(textBoxArgumentName.Text), _argument, nameof(_argument.Name), true, DataSourceUpdateMode.OnPropertyChanged); From 71dbc255eef0e0be87a647ab4a0cf4fdb543d78d Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 8 Sep 2025 16:50:29 +0200 Subject: [PATCH 07/29] Refactoring & fixes: - Renaming everything (types, variables) contains "argument", "arg" to "parameter", "param". - Moving extensions under own folder/namespace. - Fix for AddMenuItem dialog: not saved user-defined parameters with the command. --- AddMenuItem.Designer.cs | 112 +++++++++--------- AddMenuItem.cs | 45 +++---- AddUserDefinedArgument.cs | 65 ---------- ....cs => AddUserDefinedParameter.Designer.cs | 84 ++++++------- AddUserDefinedParameter.cs | 65 ++++++++++ ...ument.resx => AddUserDefinedParameter.resx | 0 OptionsDialogPage.cs | 1 + SSMSObjectExplorerMenu.cs | 4 +- SSMSObjectExplorerMenu.csproj | 13 +- Utils.cs | 2 +- enums/UserDefinedArgumentType.cs | 2 +- Extensions.cs => extensions/Extensions.cs | 2 +- extensions/UIExtensions.cs | 23 ++++ objects/MenuItem.cs | 20 ++-- objects/UserDefinedArgument.cs | 19 ++- 15 files changed, 238 insertions(+), 219 deletions(-) delete mode 100644 AddUserDefinedArgument.cs rename AddUserDefinedArgument.Designer.cs => AddUserDefinedParameter.Designer.cs (54%) create mode 100644 AddUserDefinedParameter.cs rename AddUserDefinedArgument.resx => AddUserDefinedParameter.resx (100%) rename Extensions.cs => extensions/Extensions.cs (98%) create mode 100644 extensions/UIExtensions.cs diff --git a/AddMenuItem.Designer.cs b/AddMenuItem.Designer.cs index 77b0ed4..54dc8b4 100644 --- a/AddMenuItem.Designer.cs +++ b/AddMenuItem.Designer.cs @@ -43,12 +43,12 @@ private void InitializeComponent() this.buttonOpen = new System.Windows.Forms.Button(); this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); this.labelVersion = new System.Windows.Forms.Label(); - this.listViewCustomArgs = new System.Windows.Forms.ListView(); - this.ArgumentName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.ArgumentType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.buttonAddCustomArg = new System.Windows.Forms.Button(); - this.buttonRemoveCustomArg = new System.Windows.Forms.Button(); - this.labelCustomArgs = new System.Windows.Forms.Label(); + this.listViewUserDefinedParam = new System.Windows.Forms.ListView(); + this.ParameterName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ParameterType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.buttonAddUserDefinedParam = new System.Windows.Forms.Button(); + this.buttonRemoveUserDefinedParam = new System.Windows.Forms.Button(); + this.labelUserDefinedParameters = new System.Windows.Forms.Label(); this.SuspendLayout(); // // buttonCancel @@ -216,67 +216,67 @@ private void InitializeComponent() this.labelVersion.TabIndex = 13; this.labelVersion.Text = "0.0.0"; // - // listViewCustomArgs + // listViewUserDefinedParam // - this.listViewCustomArgs.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.ArgumentName, - this.ArgumentType}); - this.listViewCustomArgs.HideSelection = false; - this.listViewCustomArgs.Location = new System.Drawing.Point(88, 135); - this.listViewCustomArgs.Name = "listViewCustomArgs"; - this.listViewCustomArgs.Size = new System.Drawing.Size(275, 75); - this.listViewCustomArgs.TabIndex = 15; - this.listViewCustomArgs.UseCompatibleStateImageBehavior = false; - this.listViewCustomArgs.View = System.Windows.Forms.View.Details; + this.listViewUserDefinedParam.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.ParameterName, + this.ParameterType}); + this.listViewUserDefinedParam.HideSelection = false; + this.listViewUserDefinedParam.Location = new System.Drawing.Point(88, 135); + this.listViewUserDefinedParam.Name = "listViewUserDefinedParam"; + this.listViewUserDefinedParam.Size = new System.Drawing.Size(275, 75); + this.listViewUserDefinedParam.TabIndex = 15; + this.listViewUserDefinedParam.UseCompatibleStateImageBehavior = false; + this.listViewUserDefinedParam.View = System.Windows.Forms.View.Details; // - // ArgumentName + // ParameterName // - this.ArgumentName.Text = "Argument name"; - this.ArgumentName.Width = 160; + this.ParameterName.Text = "Parameter name"; + this.ParameterName.Width = 160; // - // ArgumentType + // ParameterType // - this.ArgumentType.Text = "Argument type"; - this.ArgumentType.Width = 106; + this.ParameterType.Text = "Parameter type"; + this.ParameterType.Width = 106; // - // buttonAddCustomArg + // buttonAddUserDefinedParam // - this.buttonAddCustomArg.Location = new System.Drawing.Point(374, 135); - this.buttonAddCustomArg.Name = "buttonAddCustomArg"; - this.buttonAddCustomArg.Size = new System.Drawing.Size(75, 23); - this.buttonAddCustomArg.TabIndex = 16; - this.buttonAddCustomArg.Text = "Add"; - this.buttonAddCustomArg.UseVisualStyleBackColor = true; - this.buttonAddCustomArg.Click += new System.EventHandler(this.buttonAddCustomArg_Click); + this.buttonAddUserDefinedParam.Location = new System.Drawing.Point(374, 135); + this.buttonAddUserDefinedParam.Name = "buttonAddUserDefinedParam"; + this.buttonAddUserDefinedParam.Size = new System.Drawing.Size(75, 23); + this.buttonAddUserDefinedParam.TabIndex = 16; + this.buttonAddUserDefinedParam.Text = "Add"; + this.buttonAddUserDefinedParam.UseVisualStyleBackColor = true; + this.buttonAddUserDefinedParam.Click += new System.EventHandler(this.buttonAddUserDefinedParam_Click); // - // buttonRemoveCustomArg + // buttonRemoveUserDefinedParam // - this.buttonRemoveCustomArg.Location = new System.Drawing.Point(374, 164); - this.buttonRemoveCustomArg.Name = "buttonRemoveCustomArg"; - this.buttonRemoveCustomArg.Size = new System.Drawing.Size(75, 23); - this.buttonRemoveCustomArg.TabIndex = 18; - this.buttonRemoveCustomArg.Text = "Remove"; - this.buttonRemoveCustomArg.UseVisualStyleBackColor = true; - this.buttonRemoveCustomArg.Click += new System.EventHandler(this.buttonRemoveCustomArg_Click); + this.buttonRemoveUserDefinedParam.Location = new System.Drawing.Point(374, 164); + this.buttonRemoveUserDefinedParam.Name = "buttonRemoveUserDefinedParam"; + this.buttonRemoveUserDefinedParam.Size = new System.Drawing.Size(75, 23); + this.buttonRemoveUserDefinedParam.TabIndex = 18; + this.buttonRemoveUserDefinedParam.Text = "Remove"; + this.buttonRemoveUserDefinedParam.UseVisualStyleBackColor = true; + this.buttonRemoveUserDefinedParam.Click += new System.EventHandler(this.buttonRemoveUserDefinedParam_Click); // - // labelCustomArgs + // labelUserDefinedParameters // - this.labelCustomArgs.AutoSize = true; - this.labelCustomArgs.Location = new System.Drawing.Point(91, 117); - this.labelCustomArgs.Name = "labelCustomArgs"; - this.labelCustomArgs.Size = new System.Drawing.Size(151, 13); - this.labelCustomArgs.TabIndex = 19; - this.labelCustomArgs.Text = "List of user-defined arguments:"; + this.labelUserDefinedParameters.AutoSize = true; + this.labelUserDefinedParameters.Location = new System.Drawing.Point(91, 117); + this.labelUserDefinedParameters.Name = "labelUserDefinedParameters"; + this.labelUserDefinedParameters.Size = new System.Drawing.Size(154, 13); + this.labelUserDefinedParameters.TabIndex = 19; + this.labelUserDefinedParameters.Text = "List of user-defined parameters:"; // // AddMenuItem // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(542, 475); - this.Controls.Add(this.labelCustomArgs); - this.Controls.Add(this.buttonRemoveCustomArg); - this.Controls.Add(this.buttonAddCustomArg); - this.Controls.Add(this.listViewCustomArgs); + this.Controls.Add(this.labelUserDefinedParameters); + this.Controls.Add(this.buttonRemoveUserDefinedParam); + this.Controls.Add(this.buttonAddUserDefinedParam); + this.Controls.Add(this.listViewUserDefinedParam); this.Controls.Add(this.labelVersion); this.Controls.Add(this.buttonOpen); this.Controls.Add(this.radioScript); @@ -316,11 +316,11 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonOpen; private System.Windows.Forms.OpenFileDialog openFileDialog; private System.Windows.Forms.Label labelVersion; - private System.Windows.Forms.ListView listViewCustomArgs; - private System.Windows.Forms.ColumnHeader ArgumentName; - private System.Windows.Forms.ColumnHeader ArgumentType; - private System.Windows.Forms.Button buttonAddCustomArg; - private System.Windows.Forms.Button buttonRemoveCustomArg; - private System.Windows.Forms.Label labelCustomArgs; + private System.Windows.Forms.ListView listViewUserDefinedParam; + private System.Windows.Forms.ColumnHeader ParameterName; + private System.Windows.Forms.ColumnHeader ParameterType; + private System.Windows.Forms.Button buttonAddUserDefinedParam; + private System.Windows.Forms.Button buttonRemoveUserDefinedParam; + private System.Windows.Forms.Label labelUserDefinedParameters; } } \ No newline at end of file diff --git a/AddMenuItem.cs b/AddMenuItem.cs index aa40e39..6efa452 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -1,4 +1,5 @@ using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.extensions; using SSMSObjectExplorerMenu.objects; using System; using System.Linq; @@ -22,7 +23,7 @@ public AddMenuItem(NodeInfo nodeInfo) public MenuItem GetMenuItem() { - return new MenuItem(true, comboContext.Text, textName.Text, textPath.Text, checkExecute.Checked, checkConfirm.Checked); + return new MenuItem(true, comboContext.Text, textName.Text, textPath.Text, checkExecute.Checked, checkConfirm.Checked, listViewUserDefinedParam.GetUserDefinedParams()); } @@ -89,33 +90,33 @@ private void checkExecute_CheckedChanged(object sender, EventArgs e) } } - private void buttonAddCustomArg_Click(object sender, EventArgs e) + private void buttonAddUserDefinedParam_Click(object sender, EventArgs e) { - var argumentNamesInUse = this.listViewCustomArgs.Items.Cast().Select(item => item.Text); - var addDialog = new AddUserDefinedArgument(argumentNamesInUse); - if(addDialog.ShowDialog() == DialogResult.OK) - { - var newArgument = addDialog.Argument; - var newListViewItem = new ListViewItem { Text = newArgument.Name }; - newListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem { Text = Enum.GetName(typeof(UserDefinedArgumentType), newArgument.Type) }); - listViewCustomArgs.Items.Add(newListViewItem); + var argumentNamesInUse = this.listViewUserDefinedParam.Items.Cast().Select(item => item.Text); + var addDialog = new AddUserDefinedParameter(argumentNamesInUse); + if (addDialog.ShowDialog() == DialogResult.OK) + { + var newParam = addDialog.Parameter; + var newListViewItem = new ListViewItem { Text = newParam.Name }; + newListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem { Text = Enum.GetName(typeof(UserDefinedParameterType), newParam.Type), Tag = newParam.Type }); + listViewUserDefinedParam.Items.Add(newListViewItem); } } - private void buttonRemoveCustomArg_Click(object sender, EventArgs e) + private void buttonRemoveUserDefinedParam_Click(object sender, EventArgs e) { - var selectedItems = this.listViewCustomArgs.Items.Cast().Where(item => item.Selected); - if (selectedItems.Any() && - DialogResult.Yes == MessageBox.Show("Are you sure?", "Deleting arguments", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) - { - foreach (var item in selectedItems) - { - this.listViewCustomArgs.Items.Remove(item); + var selectedItems = this.listViewUserDefinedParam.Items.Cast().Where(item => item.Selected); + if (selectedItems.Any() && + DialogResult.Yes == MessageBox.Show("Are you sure?", "Deleting parameter", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) + { + foreach (var item in selectedItems) + { + this.listViewUserDefinedParam.Items.Remove(item); } - } - else - { - MessageBox.Show("You must select an item to delete.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + else + { + MessageBox.Show("You must select an item to delete.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } diff --git a/AddUserDefinedArgument.cs b/AddUserDefinedArgument.cs deleted file mode 100644 index ffeb724..0000000 --- a/AddUserDefinedArgument.cs +++ /dev/null @@ -1,65 +0,0 @@ -using SSMSObjectExplorerMenu.enums; -using SSMSObjectExplorerMenu.objects; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Forms; - -namespace SSMSObjectExplorerMenu -{ - public partial class AddUserDefinedArgument : Form - { - private IEnumerable _argumentNamesInUse; - private UserDefinedArgument _argument; - - public UserDefinedArgument Argument { - get - { - if(this.DialogResult != DialogResult.OK) - { - throw new InvalidOperationException("Cannot get argument value from dialog without any user inter interaction."); - } - return _argument; - } - } - - public AddUserDefinedArgument(IEnumerable argumentNamesInUse) - { - InitializeComponent(); - - // Can't add arguments already added by the user once or coming from the execution context... - _argumentNamesInUse = argumentNamesInUse.Concat(Utils.ArgumentsFromContext); - - _argument = new UserDefinedArgument - { - Name = string.Empty, - Type = UserDefinedArgumentType.UniqueIdentifier - }; - - this.Text = "Adding new custom argument..."; - - this.textBoxArgumentName.MaxLength = UserDefinedArgument.NAME_MAX_LENGTH; - this.textBoxArgumentName.DataBindings.Add(nameof(textBoxArgumentName.Text), _argument, nameof(_argument.Name), true, DataSourceUpdateMode.OnPropertyChanged); - - this.comboBoxArgumentType.DataSource = Enum.GetNames(typeof(UserDefinedArgumentType)); - this.comboBoxArgumentType.SelectedIndex = 0; - this.comboBoxArgumentType.DataBindings.Add(nameof(comboBoxArgumentType.SelectedItem), _argument, nameof(_argument.Type), true, DataSourceUpdateMode.OnPropertyChanged); - } - - private void buttonSave_Click(object sender, EventArgs e) - { - if (string.IsNullOrWhiteSpace(_argument.Name)) - { - MessageBox.Show("You must choose a name for the argument!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - if (_argumentNamesInUse.Any(argumentName => StringComparer.OrdinalIgnoreCase.Equals(argumentName, _argument.Name))) - { - MessageBox.Show($"Name '{_argument.Name}' is already in use! Choose a different one!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - this.DialogResult = DialogResult.OK; - } - } -} diff --git a/AddUserDefinedArgument.Designer.cs b/AddUserDefinedParameter.Designer.cs similarity index 54% rename from AddUserDefinedArgument.Designer.cs rename to AddUserDefinedParameter.Designer.cs index 140601b..59d18ce 100644 --- a/AddUserDefinedArgument.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -1,6 +1,6 @@ namespace SSMSObjectExplorerMenu { - partial class AddUserDefinedArgument + partial class AddUserDefinedParameter { /// /// Required designer variable. @@ -28,47 +28,47 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddUserDefinedArgument)); - this.textBoxArgumentName = new System.Windows.Forms.TextBox(); - this.comboBoxArgumentType = new System.Windows.Forms.ComboBox(); - this.labelArgumentName = new System.Windows.Forms.Label(); - this.labelArgumentType = new System.Windows.Forms.Label(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddUserDefinedParameter)); + this.textBoxParameterName = new System.Windows.Forms.TextBox(); + this.comboBoxParameterType = new System.Windows.Forms.ComboBox(); + this.labelParameterName = new System.Windows.Forms.Label(); + this.labelParameterType = new System.Windows.Forms.Label(); this.buttonSave = new System.Windows.Forms.Button(); this.buttonCancel = new System.Windows.Forms.Button(); this.SuspendLayout(); // - // textBoxArgumentName + // textBoxParameterName // - this.textBoxArgumentName.Location = new System.Drawing.Point(103, 24); - this.textBoxArgumentName.Name = "textBoxArgumentName"; - this.textBoxArgumentName.Size = new System.Drawing.Size(170, 20); - this.textBoxArgumentName.TabIndex = 0; + this.textBoxParameterName.Location = new System.Drawing.Point(103, 24); + this.textBoxParameterName.Name = "textBoxParameterName"; + this.textBoxParameterName.Size = new System.Drawing.Size(170, 20); + this.textBoxParameterName.TabIndex = 0; // - // comboBoxArgumentType + // comboBoxParameterType // - this.comboBoxArgumentType.FormattingEnabled = true; - this.comboBoxArgumentType.Location = new System.Drawing.Point(103, 66); - this.comboBoxArgumentType.Name = "comboBoxArgumentType"; - this.comboBoxArgumentType.Size = new System.Drawing.Size(170, 21); - this.comboBoxArgumentType.TabIndex = 1; + this.comboBoxParameterType.FormattingEnabled = true; + this.comboBoxParameterType.Location = new System.Drawing.Point(103, 66); + this.comboBoxParameterType.Name = "comboBoxParameterType"; + this.comboBoxParameterType.Size = new System.Drawing.Size(170, 21); + this.comboBoxParameterType.TabIndex = 1; // - // labelArgumentName + // labelParameterName // - this.labelArgumentName.AutoSize = true; - this.labelArgumentName.Location = new System.Drawing.Point(13, 24); - this.labelArgumentName.Name = "labelArgumentName"; - this.labelArgumentName.Size = new System.Drawing.Size(84, 13); - this.labelArgumentName.TabIndex = 2; - this.labelArgumentName.Text = "Argument name:"; + this.labelParameterName.AutoSize = true; + this.labelParameterName.Location = new System.Drawing.Point(13, 24); + this.labelParameterName.Name = "labelParameterName"; + this.labelParameterName.Size = new System.Drawing.Size(87, 13); + this.labelParameterName.TabIndex = 2; + this.labelParameterName.Text = "Parameter name:"; // - // labelArgumentType + // labelParameterType // - this.labelArgumentType.AutoSize = true; - this.labelArgumentType.Location = new System.Drawing.Point(13, 66); - this.labelArgumentType.Name = "labelArgumentType"; - this.labelArgumentType.Size = new System.Drawing.Size(78, 13); - this.labelArgumentType.TabIndex = 3; - this.labelArgumentType.Text = "Argument type:"; + this.labelParameterType.AutoSize = true; + this.labelParameterType.Location = new System.Drawing.Point(13, 66); + this.labelParameterType.Name = "labelParameterType"; + this.labelParameterType.Size = new System.Drawing.Size(81, 13); + this.labelParameterType.TabIndex = 3; + this.labelParameterType.Text = "Parameter type:"; // // buttonSave // @@ -90,7 +90,7 @@ private void InitializeComponent() this.buttonCancel.Text = "Cancel"; this.buttonCancel.UseVisualStyleBackColor = true; // - // AddOrEditCustomArgument + // AddUserDefinedParameter // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; @@ -98,13 +98,13 @@ private void InitializeComponent() this.ControlBox = false; this.Controls.Add(this.buttonCancel); this.Controls.Add(this.buttonSave); - this.Controls.Add(this.labelArgumentType); - this.Controls.Add(this.labelArgumentName); - this.Controls.Add(this.comboBoxArgumentType); - this.Controls.Add(this.textBoxArgumentName); + this.Controls.Add(this.labelParameterType); + this.Controls.Add(this.labelParameterName); + this.Controls.Add(this.comboBoxParameterType); + this.Controls.Add(this.textBoxParameterName); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.Name = "AddOrEditCustomArgument"; - this.Text = "AddOrEditCustomArgument"; + this.Name = "AddUserDefinedParameter"; + this.Text = "AddUserDefinedParameter"; this.ResumeLayout(false); this.PerformLayout(); @@ -112,10 +112,10 @@ private void InitializeComponent() #endregion - private System.Windows.Forms.TextBox textBoxArgumentName; - private System.Windows.Forms.ComboBox comboBoxArgumentType; - private System.Windows.Forms.Label labelArgumentName; - private System.Windows.Forms.Label labelArgumentType; + private System.Windows.Forms.TextBox textBoxParameterName; + private System.Windows.Forms.ComboBox comboBoxParameterType; + private System.Windows.Forms.Label labelParameterName; + private System.Windows.Forms.Label labelParameterType; private System.Windows.Forms.Button buttonSave; private System.Windows.Forms.Button buttonCancel; } diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs new file mode 100644 index 0000000..26cddf8 --- /dev/null +++ b/AddUserDefinedParameter.cs @@ -0,0 +1,65 @@ +using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.objects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace SSMSObjectExplorerMenu +{ + public partial class AddUserDefinedParameter : Form + { + private IEnumerable _paramNamesInUse; + private UserDefinedParameter _parameter; + + public UserDefinedParameter Parameter { + get + { + if(this.DialogResult != DialogResult.OK) + { + throw new InvalidOperationException("Cannot get parameter from dialog without any user inter interaction."); + } + return _parameter; + } + } + + public AddUserDefinedParameter(IEnumerable paramNamesInUse) + { + InitializeComponent(); + + // Can't add parameters already added by the user once or coming from the execution context... + _paramNamesInUse = paramNamesInUse.Concat(Utils.ParametersFromContext); + + _parameter = new UserDefinedParameter + { + Name = string.Empty, + Type = UserDefinedParameterType.UniqueIdentifier + }; + + this.Text = "Adding new user-defined parameter..."; + + this.textBoxParameterName.MaxLength = UserDefinedParameter.NAME_MAX_LENGTH; + this.textBoxParameterName.DataBindings.Add(nameof(textBoxParameterName.Text), _parameter, nameof(_parameter.Name), true, DataSourceUpdateMode.OnPropertyChanged); + + this.comboBoxParameterType.DataSource = Enum.GetNames(typeof(UserDefinedParameterType)); + this.comboBoxParameterType.SelectedIndex = 0; + this.comboBoxParameterType.DataBindings.Add(nameof(comboBoxParameterType.SelectedItem), _parameter, nameof(_parameter.Type), true, DataSourceUpdateMode.OnPropertyChanged); + } + + private void buttonSave_Click(object sender, EventArgs e) + { + if (string.IsNullOrWhiteSpace(_parameter.Name)) + { + MessageBox.Show("You must choose a name for the parameter!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + if (_paramNamesInUse.Any(paramName => StringComparer.OrdinalIgnoreCase.Equals(paramName, _parameter.Name))) + { + MessageBox.Show($"Name '{_parameter.Name}' is already in use! Choose a different one!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this.DialogResult = DialogResult.OK; + } + } +} diff --git a/AddUserDefinedArgument.resx b/AddUserDefinedParameter.resx similarity index 100% rename from AddUserDefinedArgument.resx rename to AddUserDefinedParameter.resx diff --git a/OptionsDialogPage.cs b/OptionsDialogPage.cs index bcebbde..69f0cc7 100644 --- a/OptionsDialogPage.cs +++ b/OptionsDialogPage.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.Shell; +using SSMSObjectExplorerMenu.extensions; using SSMSObjectExplorerMenu.objects; using System.Collections.Generic; using System.ComponentModel; diff --git a/SSMSObjectExplorerMenu.cs b/SSMSObjectExplorerMenu.cs index 382f640..88b88de 100644 --- a/SSMSObjectExplorerMenu.cs +++ b/SSMSObjectExplorerMenu.cs @@ -3,16 +3,14 @@ using Microsoft.SqlServer.Management.UI.VSIntegration; using Microsoft.SqlServer.Management.UI.VSIntegration.Editors; using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer; -using Microsoft.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Threading; -using Microsoft.VisualStudio.VCProjectEngine; +using SSMSObjectExplorerMenu.extensions; using SSMSObjectExplorerMenu.objects; using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index 097e038..3f94581 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -65,14 +65,15 @@ AddMenuItem.cs - + Form - - AddUserDefinedArgument.cs + + AddUserDefinedParameter.cs - + + @@ -144,8 +145,8 @@ AddMenuItem.cs Designer - - AddUserDefinedArgument.cs + + AddUserDefinedParameter.cs ResXFileCodeGenerator diff --git a/Utils.cs b/Utils.cs index ade6ed8..3bdfd55 100644 --- a/Utils.cs +++ b/Utils.cs @@ -4,7 +4,7 @@ namespace SSMSObjectExplorerMenu { public static class Utils { - public static IEnumerable ArgumentsFromContext = new string[] + public static IEnumerable ParametersFromContext = new string[] { "{OBJECT}", "{SERVER}", diff --git a/enums/UserDefinedArgumentType.cs b/enums/UserDefinedArgumentType.cs index f02c68e..3e15e92 100644 --- a/enums/UserDefinedArgumentType.cs +++ b/enums/UserDefinedArgumentType.cs @@ -1,6 +1,6 @@ namespace SSMSObjectExplorerMenu.enums { - public enum UserDefinedArgumentType : byte + public enum UserDefinedParameterType : byte { UniqueIdentifier, Int, diff --git a/Extensions.cs b/extensions/Extensions.cs similarity index 98% rename from Extensions.cs rename to extensions/Extensions.cs index 9065efc..fc1f88f 100644 --- a/Extensions.cs +++ b/extensions/Extensions.cs @@ -4,7 +4,7 @@ using System.IO; using System.Xml.Serialization; -namespace SSMSObjectExplorerMenu +namespace SSMSObjectExplorerMenu.extensions { public static class Extensions { diff --git a/extensions/UIExtensions.cs b/extensions/UIExtensions.cs new file mode 100644 index 0000000..fab6cb7 --- /dev/null +++ b/extensions/UIExtensions.cs @@ -0,0 +1,23 @@ +using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.objects; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace SSMSObjectExplorerMenu.extensions +{ + internal static class UIExtensions + { + public static IEnumerable GetUserDefinedParams(this ListView listView) + { + foreach (ListViewItem item in listView.Items) + { + yield return new UserDefinedParameter + { + Name = item.Text, + Type = (UserDefinedParameterType)item.SubItems.Cast().Last().Tag + }; + } + } + } +} diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index 49cf948..d7bde11 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -1,5 +1,4 @@ -using SSMSObjectExplorerMenu.enums; -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; @@ -55,17 +54,17 @@ public string Script public string Context { get; set; } = "All"; [Category("Menu item")] - [DisplayName("User-defined arguments")] - [Description("List of user-deifned arguments can be used in the T-SQL script.")] + [DisplayName("User-defined parameters")] + [Description("List of user-deifned parameters can be used in the T-SQL script.")] [Editor(typeof(CollectionEditor), typeof(UITypeEditor))] - public BindingList UserDefinedArguments { get; private set; } = new BindingList(); + public BindingList UserDefinedParameters { get; private set; } = new BindingList(); public MenuItem() { } - public MenuItem(bool enabled, string context, string name, string script, bool execute, bool confirm, IEnumerable userDefinedArguments = null) + public MenuItem(bool enabled, string context, string name, string script, bool execute, bool confirm, IEnumerable userDefinedParams = null) { Enabled = enabled; Context = context; @@ -74,12 +73,9 @@ public MenuItem(bool enabled, string context, string name, string script, bool e Execute = execute; Confirm = confirm; - if(userDefinedArguments != null) - { - foreach(var arg in userDefinedArguments) - { - UserDefinedArguments.Add(arg); - } + foreach (var param in userDefinedParams ?? Enumerable.Empty()) + { + UserDefinedParameters.Add(param); } if (Confirm) { diff --git a/objects/UserDefinedArgument.cs b/objects/UserDefinedArgument.cs index e57663e..8ef9d2b 100644 --- a/objects/UserDefinedArgument.cs +++ b/objects/UserDefinedArgument.cs @@ -4,27 +4,26 @@ namespace SSMSObjectExplorerMenu.objects { - [TypeConverter(typeof(ExpandableObjectConverter))] - public class UserDefinedArgument + public class UserDefinedParameter { public const short NAME_MAX_LENGTH = 128; [DisplayName("Name")] - [Description("Name of the user-defined argument")] + [Description("Name of the user-defined parameter")] public string Name { get; set; } [DisplayName("Data type")] - [Description("Data type of the user-defined argument")] - public UserDefinedArgumentType Type { get; set; } + [Description("Data type of the user-defined parameter")] + public UserDefinedParameterType Type { get; set; } public override bool Equals(object other) { - var otherAsCustomArg = other as UserDefinedArgument; + var otherAsParam = other as UserDefinedParameter; - if (otherAsCustomArg is null) return false; + if (otherAsParam is null) return false; - return StringComparer.OrdinalIgnoreCase.Equals(Name, otherAsCustomArg.Name) && Type == otherAsCustomArg.Type; + return StringComparer.OrdinalIgnoreCase.Equals(Name, otherAsParam.Name) && Type == otherAsParam.Type; } public override int GetHashCode() @@ -38,13 +37,13 @@ public override int GetHashCode() } } - public static bool operator ==(UserDefinedArgument left, UserDefinedArgument right) + public static bool operator ==(UserDefinedParameter left, UserDefinedParameter right) { if (ReferenceEquals(left, right)) return true; if (left is null || right is null) return false; return left.Equals(right); } - public static bool operator !=(UserDefinedArgument left, UserDefinedArgument right) => !(left == right); + public static bool operator !=(UserDefinedParameter left, UserDefinedParameter right) => !(left == right); } } From e80762e77e8f28a03ca2a91d4c2d3e70f5afd1e0 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Wed, 10 Sep 2025 18:08:12 +0200 Subject: [PATCH 08/29] Enabling user-defined parameters in T-SQL scripts. See details below. AddMenuItem: passing parameters coming from (execution) context as part of parameter names in use. AddUserDefinedParameter: refactored validation. Modified exception message in Parameter getter. OptionsDialogPage: adding validation for MenuItems when user clicks OK on Options page. Changes will be discarded if user clicks on Cancel or closes the Options page. SSMSObjectExplorerMenu: replacing user-defined parameters in T-SQL script of the MenuItem/command. Utils: fix context parameter names. Extensions: added ReplaceRange extension method. Removed unnecessary empty lines. UIExtensions: added ToUserDefinedArgument extension method. MenuItem: added validation. UserDefinedArgument added. ArgumentControl: new control for entering value for a user-defined parameter. EnterUserDefinedArgument: new dialog for entering parameter values before executing the T-SQL script of the MenuItem/command. --- AddMenuItem.cs | 3 +- AddUserDefinedParameter.Designer.cs | 2 +- AddUserDefinedParameter.cs | 54 ++++++---- ArgumentControl.Designer.cs | 44 ++++++++ ArgumentControl.cs | 96 +++++++++++++++++ ArgumentControl.resx | 120 +++++++++++++++++++++ EnterUserDefinedArguments.Designer.cs | 105 ++++++++++++++++++ EnterUserDefinedArguments.cs | 60 +++++++++++ EnterUserDefinedArguments.resx | 148 ++++++++++++++++++++++++++ OptionsDialogPage.cs | 52 ++++++++- SSMSObjectExplorerMenu.cs | 44 +++++--- SSMSObjectExplorerMenu.csproj | 20 ++++ Utils.cs | 24 ++--- extensions/Extensions.cs | 18 ++-- extensions/UIExtensions.cs | 3 + objects/MenuItem.cs | 21 ++++ objects/MenuItemErrorModel.cs | 9 ++ objects/UserDefinedArgument.cs | 52 ++++----- objects/UserDefinedParameter.cs | 38 +++++++ 19 files changed, 821 insertions(+), 92 deletions(-) create mode 100644 ArgumentControl.Designer.cs create mode 100644 ArgumentControl.cs create mode 100644 ArgumentControl.resx create mode 100644 EnterUserDefinedArguments.Designer.cs create mode 100644 EnterUserDefinedArguments.cs create mode 100644 EnterUserDefinedArguments.resx create mode 100644 objects/MenuItemErrorModel.cs create mode 100644 objects/UserDefinedParameter.cs diff --git a/AddMenuItem.cs b/AddMenuItem.cs index 6efa452..4e05291 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -92,7 +92,8 @@ private void checkExecute_CheckedChanged(object sender, EventArgs e) private void buttonAddUserDefinedParam_Click(object sender, EventArgs e) { - var argumentNamesInUse = this.listViewUserDefinedParam.Items.Cast().Select(item => item.Text); + var argumentNamesInUse = this.listViewUserDefinedParam.Items.Cast().Select(item => item.Text) + .Concat(Utils.ParametersFromContext); var addDialog = new AddUserDefinedParameter(argumentNamesInUse); if (addDialog.ShowDialog() == DialogResult.OK) { diff --git a/AddUserDefinedParameter.Designer.cs b/AddUserDefinedParameter.Designer.cs index 59d18ce..026de20 100644 --- a/AddUserDefinedParameter.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -104,7 +104,7 @@ private void InitializeComponent() this.Controls.Add(this.textBoxParameterName); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "AddUserDefinedParameter"; - this.Text = "AddUserDefinedParameter"; + this.Text = "Adding new user-defined parameter..."; this.ResumeLayout(false); this.PerformLayout(); diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs index 26cddf8..316b0d4 100644 --- a/AddUserDefinedParameter.cs +++ b/AddUserDefinedParameter.cs @@ -2,7 +2,6 @@ using SSMSObjectExplorerMenu.objects; using System; using System.Collections.Generic; -using System.Linq; using System.Windows.Forms; namespace SSMSObjectExplorerMenu @@ -10,16 +9,17 @@ namespace SSMSObjectExplorerMenu public partial class AddUserDefinedParameter : Form { private IEnumerable _paramNamesInUse; - private UserDefinedParameter _parameter; + private ParameterItem _parameter; - public UserDefinedParameter Parameter { + public UserDefinedParameter Parameter + { get { - if(this.DialogResult != DialogResult.OK) + if (!TryValidate(out string _) || this.DialogResult != DialogResult.OK) { - throw new InvalidOperationException("Cannot get parameter from dialog without any user inter interaction."); + throw new InvalidOperationException("Dialog is invalid state."); } - return _parameter; + return new UserDefinedParameter { Name = _parameter.Name, Type = _parameter.Type }; } } @@ -27,16 +27,8 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse) { InitializeComponent(); - // Can't add parameters already added by the user once or coming from the execution context... - _paramNamesInUse = paramNamesInUse.Concat(Utils.ParametersFromContext); - - _parameter = new UserDefinedParameter - { - Name = string.Empty, - Type = UserDefinedParameterType.UniqueIdentifier - }; - - this.Text = "Adding new user-defined parameter..."; + _parameter = new ParameterItem { Name = string.Empty, Type = UserDefinedParameterType.UniqueIdentifier }; + _paramNamesInUse = paramNamesInUse; this.textBoxParameterName.MaxLength = UserDefinedParameter.NAME_MAX_LENGTH; this.textBoxParameterName.DataBindings.Add(nameof(textBoxParameterName.Text), _parameter, nameof(_parameter.Name), true, DataSourceUpdateMode.OnPropertyChanged); @@ -48,18 +40,36 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse) private void buttonSave_Click(object sender, EventArgs e) { - if (string.IsNullOrWhiteSpace(_parameter.Name)) + if (!TryValidate(out string validationErrorMessage)) { - MessageBox.Show("You must choose a name for the parameter!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(validationErrorMessage, "Invalid parameter", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - if (_paramNamesInUse.Any(paramName => StringComparer.OrdinalIgnoreCase.Equals(paramName, _parameter.Name))) + + this.DialogResult = DialogResult.OK; + } + + private bool TryValidate(out string validationErrorMessage) + { + try + { + // Can't add parameters already added by the user once or coming from the execution context... + UserDefinedParameter.ValidateName(_parameter.Name, _paramNamesInUse); + } + catch (ArgumentException ex) { - MessageBox.Show($"Name '{_parameter.Name}' is already in use! Choose a different one!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; + validationErrorMessage = ex.Message; + return false; } - this.DialogResult = DialogResult.OK; + validationErrorMessage = null; + return true; + } + + class ParameterItem + { + public string Name { get; set; } + public UserDefinedParameterType Type { get; set; } } } } diff --git a/ArgumentControl.Designer.cs b/ArgumentControl.Designer.cs new file mode 100644 index 0000000..a631577 --- /dev/null +++ b/ArgumentControl.Designer.cs @@ -0,0 +1,44 @@ +namespace SSMSObjectExplorerMenu +{ + partial class ArgumentControl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // ArgumentControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "ArgumentControl"; + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/ArgumentControl.cs b/ArgumentControl.cs new file mode 100644 index 0000000..c501b47 --- /dev/null +++ b/ArgumentControl.cs @@ -0,0 +1,96 @@ +using SSMSObjectExplorerMenu.enums; +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace SSMSObjectExplorerMenu +{ + public partial class ArgumentControl : UserControl + { + private const int HEIGHT_LABEL = 15; + private const int HEIGHT_VALUECONTROL = 20; + private const byte UNIQUEIDENTIFIER_LENGTH = 36; + + private Label _labelParameterName; + private Control _valueControl; + + public string ParameterName { get; private set; } + public UserDefinedParameterType ParameterType { get; private set; } + public string ParameterValueString => _valueControl.Text; + + public Func Validator { get; private set; } + + public ArgumentControl(string parameterName, UserDefinedParameterType parameterType, int width) + { + if(string.IsNullOrWhiteSpace(parameterName)) + { + throw new ArgumentException("Parameter name cannot be null or whitespace.", nameof(parameterName)); + } + + if (width < 0) + { + throw new ArgumentException("Width cannot be negative.", nameof(width)); + } + + ParameterName = parameterName; + ParameterType = parameterType; + + InitializeComponent(); + + this.Size = new Size(width, HEIGHT_LABEL + HEIGHT_VALUECONTROL); + + switch (parameterType) + { + case UserDefinedParameterType.UniqueIdentifier: + Init_Uniqueidentifier(); + break; + case UserDefinedParameterType.Nvarchar: + Init_Nvarchar(); + break; + case UserDefinedParameterType.Int: + Init_Int(); + break; + default: + throw new ArgumentException("Parameter type is not known.", nameof(parameterType)); + } + this._valueControl.Location = new Point(0, HEIGHT_LABEL); + this._valueControl.Size = new Size(this.Size.Width, HEIGHT_VALUECONTROL); + this.Controls.Add(this._valueControl); + + this._labelParameterName = new Label(); + this._labelParameterName.Location = Point.Empty; + this._labelParameterName.Size = new Size(this.Size.Width, HEIGHT_LABEL); + this._labelParameterName.Text = $"{parameterName} ({parameterType}):"; + this.Controls.Add(this._labelParameterName); + } + + private void Init_Uniqueidentifier() + { + var guidTextBox = new TextBox(); + guidTextBox.MaxLength = UNIQUEIDENTIFIER_LENGTH; + guidTextBox.Text = string.Empty; + + _valueControl = guidTextBox; + Validator = Validate_Uniqueidentifier; + } + + private void Init_Nvarchar() + { + var textBox = new TextBox(); + textBox.Text = string.Empty; + + _valueControl = textBox; + Validator = Validate_Nvarchar; + } + + private void Init_Int() + { + _valueControl = new NumericUpDown(); + Validator = () => true; + } + + private bool Validate_Uniqueidentifier() => Guid.TryParse(_valueControl.Text, out _); + + private bool Validate_Nvarchar() => !string.IsNullOrWhiteSpace(_valueControl.Text); + } +} diff --git a/ArgumentControl.resx b/ArgumentControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/ArgumentControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/EnterUserDefinedArguments.Designer.cs b/EnterUserDefinedArguments.Designer.cs new file mode 100644 index 0000000..cfa3ecd --- /dev/null +++ b/EnterUserDefinedArguments.Designer.cs @@ -0,0 +1,105 @@ +namespace SSMSObjectExplorerMenu +{ + partial class EnterUserDefinedArguments + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EnterUserDefinedArguments)); + this.label1 = new System.Windows.Forms.Label(); + this.flowLayoutPanelArguments = new System.Windows.Forms.FlowLayoutPanel(); + this.buttonOK = new System.Windows.Forms.Button(); + this.dialogPage1 = new Microsoft.VisualStudio.Shell.DialogPage(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(222, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Please enter values for the parameters below."; + // + // flowLayoutPanelArguments + // + this.flowLayoutPanelArguments.AutoScroll = true; + this.flowLayoutPanelArguments.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowLayoutPanelArguments.Location = new System.Drawing.Point(15, 26); + this.flowLayoutPanelArguments.Name = "flowLayoutPanelArguments"; + this.flowLayoutPanelArguments.Size = new System.Drawing.Size(300, 150); + this.flowLayoutPanelArguments.TabIndex = 1; + // + // buttonOK + // + this.buttonOK.Location = new System.Drawing.Point(159, 182); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 2; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(240, 182); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 3; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // EnterUserDefinedArguments + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.buttonCancel; + this.ClientSize = new System.Drawing.Size(329, 216); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.flowLayoutPanelArguments); + this.Controls.Add(this.label1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "EnterUserDefinedArguments"; + this.Text = "Enter script arguments..."; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanelArguments; + private System.Windows.Forms.Button buttonOK; + private Microsoft.VisualStudio.Shell.DialogPage dialogPage1; + private System.Windows.Forms.Button buttonCancel; + } +} \ No newline at end of file diff --git a/EnterUserDefinedArguments.cs b/EnterUserDefinedArguments.cs new file mode 100644 index 0000000..ee3d01c --- /dev/null +++ b/EnterUserDefinedArguments.cs @@ -0,0 +1,60 @@ +using SSMSObjectExplorerMenu.extensions; +using SSMSObjectExplorerMenu.objects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace SSMSObjectExplorerMenu +{ + public partial class EnterUserDefinedArguments : Form + { + private readonly ArgumentControl[] _argumentControls; + + public IEnumerable UserDefinedArguments { + get + { + if(!TryValidate(out string _) || this.DialogResult != DialogResult.OK) + { + throw new InvalidOperationException("Dialog is in invalid state."); + } + return _argumentControls.Select(ac => ac.ToUserDefinedArgument()); + } + } + + public EnterUserDefinedArguments(IEnumerable parameters) + { + InitializeComponent(); + + int argumentControlWidth = this.flowLayoutPanelArguments.ClientSize.Width - SystemInformation.VerticalScrollBarWidth; + _argumentControls = parameters.Select(p => new ArgumentControl(p.Name, p.Type, argumentControlWidth)).ToArray(); + this.flowLayoutPanelArguments.Controls.AddRange(_argumentControls); + } + + private void buttonOK_Click(object sender, System.EventArgs e) + { + if(!TryValidate(out string validationErrorMessage)) + { + MessageBox.Show(this, validationErrorMessage, "Invalid parameter value", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this.DialogResult = DialogResult.OK; + } + + private bool TryValidate(out string validationErrorMessage) + { + foreach (var ac in _argumentControls) + { + if (!ac.Validator()) + { + validationErrorMessage = $"The value for parameter '{ac.ParameterName}' ({ac.ParameterType}) is not valid!"; + return false; + } + } + + validationErrorMessage = null; + return true; + } + } +} diff --git a/EnterUserDefinedArguments.resx b/EnterUserDefinedArguments.resx new file mode 100644 index 0000000..a92f93f --- /dev/null +++ b/EnterUserDefinedArguments.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAA + AACTlZX/hoiJ/5GTlP+PkZL/kJGS/5CRkv+QkZL/kJGS/5CRk/+QkZL/kJGS/5CRkv+PkZL/kZOU/4aI + if+SlJX/goSF/+Pk5P/5+fn/9fX1//X29v/19fb/9fX2//f39f/39/X/9fX2//X29v/19vb/9fX1//n5 + +f/k5OX/g4WG/46Qkf/4+Pj///////////////////////7+/v9XSa7/Vkit//79/f////////7///// + ////////+Pj4/4+Rkv+Nj5D/9/f3///////+/v7//v7+///////9/f3/Khua/ygamP/8/Pz///////7+ + /v/+/v7///////f39/+Oj5H/jY+Q//f4+P///////v7+//7+/v///////f3+/zQjn/8yIZ3//Pz9//// + ///+/v7//v7+///////4+Pj/jpCR/42PkP/3+Pj////////////+/v////////7+/v8yIZ7/MB+c//39 + /f///////v7/////////////+Pj4/46Qkf+Nj5D/9/j4//////////7//v7////////+/v7/MiGe/zAf + nP/9/f3///////7+//////7///////j4+P+OkJH/jpCQ//f39/9XSa//Lh2c/zgnoP82JqD/NiWg/xwJ + lP8cCZT/NiWg/zYmoP83J6D/Lx6c/1ZIr//39/f/j5CR/46QkP/39/f/T0Cr/yUTmP8uHZz/LRub/y0b + m/8bCJT/GwiU/y0bm/8tG5v/Lh2c/yUTmP9OP6v/9/f3/4+Qkf+Nj5D/9/j4//79///7+vz/+/r8//z8 + /f/6+fz/MiCd/zAfnP/5+fv//Pz9//v6/P/7+vz//f3///j4+P+OkJH/jY+Q//f4+P////////////7+ + /////////v7+/zIhnv8xH5z//f39///////+/v/////////////4+Pj/jpCR/42PkP/3+Pj///////7+ + /v/+/v7///////39/v80Ip7/MiGd//z8/f///////v7+//7+/v//////+Pj4/46Qkf+Nj5D/9/f3//// + ///+/v7//v7+///////9/f7/Kxyb/ykamf/8/P3///////7+/v/+/v7///////f3+P+Oj5H/jpCR//j4 + +P/////////////+/////////v7+/09Aqv9OP6n//f39/////////v/////////////4+Pj/j5CS/4SG + h//o6Oj//f39//n5+f/5+fn/+fn5//n5+f/39/f/9/b3//n5+f/5+vn/+fn5//n5+f/9/f3/6Onp/4SG + h/+OkJH/hYeI/5KTlP+QkZL/kJKS/5CSkv+QkpL/kZOT/5GTk/+QkpL/kJKS/5CSkv+QkZL/kpOU/4WH + iP+Nj5D/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAA== + + + \ No newline at end of file diff --git a/OptionsDialogPage.cs b/OptionsDialogPage.cs index 69f0cc7..27419a8 100644 --- a/OptionsDialogPage.cs +++ b/OptionsDialogPage.cs @@ -1,8 +1,14 @@ using Microsoft.VisualStudio.Shell; using SSMSObjectExplorerMenu.extensions; using SSMSObjectExplorerMenu.objects; +using System; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; +using System.Text; +using MessageBox = System.Windows.Forms.MessageBox; +using MessageBoxButtons = System.Windows.Forms.MessageBoxButtons; +using MessageBoxIcon = System.Windows.Forms.MessageBoxIcon; namespace SSMSObjectExplorerMenu { @@ -61,7 +67,7 @@ public override void LoadSettingsFromStorage() { base.LoadSettingsFromStorage(); - if (MenuItems.Count == 0 && MenuItemsXml.Length > 0) + if (MenuItemsXml.Length > 0) { try { @@ -91,5 +97,47 @@ public override void SaveSettingsToStorage() base.SaveSettingsToStorage(); } - } + protected override void OnApply(PageApplyEventArgs e) + { + if(!TryValidate(out IEnumerable validationErrors)) + { + ShowValidationErrorDialog(validationErrors); + e.ApplyBehavior = ApplyKind.CancelNoNavigate; + return; + } + + // Calls SaveSettingsToStorage + base.OnApply(e); + } + + private bool TryValidate(out IEnumerable validationErrors) + { + var errorList = new List(); + foreach (var menuItem in MenuItems) + { + if (!menuItem.TryValidate(out IEnumerable errors)) + { + errorList.AddRange(errors); + } + } + validationErrors = errorList; + return !errorList.Any(); + } + + private void ShowValidationErrorDialog(IEnumerable validationErrors) + { + if(validationErrors.Any()) + { + StringBuilder builder = new StringBuilder(); + + builder.AppendLine($"One or more validation errors occurred:{Environment.NewLine}"); + foreach (var error in validationErrors) + { + builder.AppendLine($"Menu item '{error.MenuItemName}': {error.ErrorMessage}"); + } + // TODO: more advanced error dialog? + MessageBox.Show(builder.ToString(), "SSMS Object Explorer Menu - Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } } diff --git a/SSMSObjectExplorerMenu.cs b/SSMSObjectExplorerMenu.cs index 88b88de..389221f 100644 --- a/SSMSObjectExplorerMenu.cs +++ b/SSMSObjectExplorerMenu.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -323,23 +324,36 @@ private async Task Menu_ClickAsync(object sender, EventArgs e) script = itemInstance.MenuItem.Script; } + var contextDefinedArgs = new (string Parameter, string Value)[] + { + ("{OBJECT}", itemInstance.Name), + ("{SERVER}", itemInstance.NodeInfo.Server), + ("{DATABASE}", itemInstance.NodeInfo.Database), + ("{TABLE}", itemInstance.NodeInfo.Table), + ("{VIEW}", itemInstance.NodeInfo.View), + ("{STORED_PROCEDURE}", itemInstance.NodeInfo.StoredProcedure), + ("{FUNCTION}", itemInstance.NodeInfo.Function), + ("{SCHEMA}", itemInstance.NodeInfo.Schema), + ("{JOB}", itemInstance.NodeInfo.Job), + ("{YYYY-MM-DD}", DateTime.Now.ToString("yyyy-MM-dd")), + ("{HH:mm:ss}", DateTime.Now.ToString("HH:mm:ss")), + ("{YYYY-MM-DD HH:mm:ss}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) + }; - script = script - .Replace("{OBJECT}", itemInstance.Name) - .Replace("{SERVER}", itemInstance.NodeInfo.Server) - .Replace("{DATABASE}", itemInstance.NodeInfo.Database) - .Replace("{TABLE}", itemInstance.NodeInfo.Table) - .Replace("{VIEW}", itemInstance.NodeInfo.View) - .Replace("{STORED_PROCEDURE}", itemInstance.NodeInfo.StoredProcedure) - .Replace("{FUNCTION}", itemInstance.NodeInfo.Function) - .Replace("{SCHEMA}", itemInstance.NodeInfo.Schema) - .Replace("{JOB}", itemInstance.NodeInfo.Job) - .Replace("{YYYY-MM-DD}", DateTime.Now.ToString("yyyy-MM-dd")) - .Replace("{HH:mm:ss}", DateTime.Now.ToString("HH:mm:ss")) - .Replace("{YYYY-MM-DD HH:mm:ss}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); - - + IEnumerable<(string Parameter, string Value)> userDefinedArgs = Enumerable.Empty<(string, string)>(); + var userDefinedParams = itemInstance.MenuItem.UserDefinedParameters; + if (userDefinedParams?.Any() ?? false) + { + var enterArgumentsDialog = new EnterUserDefinedArguments(userDefinedParams); + if (DialogResult.OK == enterArgumentsDialog.ShowDialog()) + { + userDefinedArgs = enterArgumentsDialog.UserDefinedArguments.Select(arg => ($"{{{arg.Name}}}", arg.ValueAsString)); + } + // Abort in case the user pressed on Cancel + else return; + } + script = script.ReplaceRange(contextDefinedArgs.Concat(userDefinedArgs)); DTE2 dte = (DTE2)await this.GetServiceAsync(typeof(DTE)); if (dte == null) diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index 3f94581..4780f59 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -71,10 +71,24 @@ AddUserDefinedParameter.cs + + UserControl + + + ArgumentControl.cs + + + Form + + + EnterUserDefinedArguments.cs + + + @@ -148,6 +162,12 @@ AddUserDefinedParameter.cs + + ArgumentControl.cs + + + EnterUserDefinedArguments.cs + ResXFileCodeGenerator Resources.Designer.cs diff --git a/Utils.cs b/Utils.cs index 3bdfd55..bf1e9a2 100644 --- a/Utils.cs +++ b/Utils.cs @@ -6,18 +6,18 @@ public static class Utils { public static IEnumerable ParametersFromContext = new string[] { - "{OBJECT}", - "{SERVER}", - "{DATABASE}", - "{TABLE}", - "{VIEW}", - "{STORED_PROCEDURE}", - "{FUNCTION}", - "{SCHEMA}", - "{JOB}", - "{YYYY-MM-DD}", - "{HH:mm:ss}", - "{YYYY-MM-DD HH:mm:ss}" + "OBJECT", + "SERVER", + "DATABASE", + "TABLE", + "VIEW", + "STORED_PROCEDURE", + "FUNCTION", + "SCHEMA", + "JOB", + "YYYY-MM-DD", + "HHmm:ss", + "YYYY-MM-DD HH:mm:ss" }; } } diff --git a/extensions/Extensions.cs b/extensions/Extensions.cs index fc1f88f..6157f2b 100644 --- a/extensions/Extensions.cs +++ b/extensions/Extensions.cs @@ -1,6 +1,8 @@ using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer; using SSMSObjectExplorerMenu.objects; using System; +using System.Collections; +using System.Collections.Generic; using System.IO; using System.Xml.Serialization; @@ -28,7 +30,6 @@ public static string SerializeObject(this T toSerialize) } } - public static NodeInfo GetInfo(this INodeInformation node) { NodeInfo info = new NodeInfo @@ -77,8 +78,6 @@ public static NodeInfo GetInfo(this INodeInformation node) continue; } - - if (s.StartsWith("StoredProcedure[@Name='")) { string[] t = s.Replace("StoredProcedure[@Name='", "").Replace("' and @Schema='", "|").Replace("']", "").Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); @@ -115,11 +114,18 @@ public static NodeInfo GetInfo(this INodeInformation node) } } - return info; } - - + public static string ReplaceRange(this string original, IEnumerable<(string Phrase, string Value)> elements) + { + // TODO: replacement case-insensitive? + string result = original; + foreach ((string Phrase, string Value) in elements) + { + result = result.Replace(Phrase, Value); + } + return result; + } } } diff --git a/extensions/UIExtensions.cs b/extensions/UIExtensions.cs index fab6cb7..31df945 100644 --- a/extensions/UIExtensions.cs +++ b/extensions/UIExtensions.cs @@ -19,5 +19,8 @@ public static IEnumerable GetUserDefinedParams(this ListVi }; } } + + public static UserDefinedArgument ToUserDefinedArgument(this ArgumentControl control) + => new UserDefinedArgument(control.ParameterName, control.ParameterType, control.ParameterValueString); } } diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index d7bde11..6683ee4 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -82,5 +82,26 @@ public MenuItem(bool enabled, string context, string name, string script, bool e Execute = true; } } + + public bool TryValidate(out IEnumerable validationErrors) + { + var errorList = new List(); + + foreach(var param in UserDefinedParameters) + { + try + { + var otherParamNames = UserDefinedParameters.Where(p => p != param).Select(p => p.Name); + UserDefinedParameter.ValidateName(param.Name, Utils.ParametersFromContext.Concat(otherParamNames)); + } + catch (ArgumentException ex) + { + errorList.Add(new MenuItemErrorModel { MenuItemName = Name, ErrorMessage = ex.Message }); + } + } + + validationErrors = errorList; + return !errorList.Any(); + } } } diff --git a/objects/MenuItemErrorModel.cs b/objects/MenuItemErrorModel.cs new file mode 100644 index 0000000..46fe77c --- /dev/null +++ b/objects/MenuItemErrorModel.cs @@ -0,0 +1,9 @@ +namespace SSMSObjectExplorerMenu.objects +{ + public class MenuItemErrorModel + { + public string MenuItemName { get; set; } + + public string ErrorMessage { get; set; } + } +} diff --git a/objects/UserDefinedArgument.cs b/objects/UserDefinedArgument.cs index 8ef9d2b..c2c9745 100644 --- a/objects/UserDefinedArgument.cs +++ b/objects/UserDefinedArgument.cs @@ -1,49 +1,35 @@ -using SSMSObjectExplorerMenu.enums; +using Microsoft.Internal.VisualStudio.Shell; +using SSMSObjectExplorerMenu.enums; using System; -using System.ComponentModel; namespace SSMSObjectExplorerMenu.objects { - [TypeConverter(typeof(ExpandableObjectConverter))] - public class UserDefinedParameter + public class UserDefinedArgument : UserDefinedParameter { - public const short NAME_MAX_LENGTH = 128; + private string _valueStr; - [DisplayName("Name")] - [Description("Name of the user-defined parameter")] - public string Name { get; set; } - - [DisplayName("Data type")] - [Description("Data type of the user-defined parameter")] - public UserDefinedParameterType Type { get; set; } + public string ValueAsString { + get => _valueStr; + private set + { + ValidateValue(value); + _valueStr = value; + } + } - public override bool Equals(object other) + public UserDefinedArgument(string name, UserDefinedParameterType type, string value) { - var otherAsParam = other as UserDefinedParameter; - - if (otherAsParam is null) return false; - - return StringComparer.OrdinalIgnoreCase.Equals(Name, otherAsParam.Name) && Type == otherAsParam.Type; + Name = name; + Type = type; + ValueAsString = value; } - public override int GetHashCode() + private static void ValidateValue(string value) { - unchecked + if (value is null) { - int hashCode = 13; - hashCode = hashCode * 41 + (Name?.GetHashCode() ?? 0); - hashCode = hashCode * 41 + Type.GetHashCode(); - return hashCode; + throw new ArgumentNullException(nameof(value), "Value cannot be null."); } } - - public static bool operator ==(UserDefinedParameter left, UserDefinedParameter right) - { - if (ReferenceEquals(left, right)) return true; - if (left is null || right is null) return false; - return left.Equals(right); - } - - public static bool operator !=(UserDefinedParameter left, UserDefinedParameter right) => !(left == right); } } diff --git a/objects/UserDefinedParameter.cs b/objects/UserDefinedParameter.cs new file mode 100644 index 0000000..51f9913 --- /dev/null +++ b/objects/UserDefinedParameter.cs @@ -0,0 +1,38 @@ +using SSMSObjectExplorerMenu.enums; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace SSMSObjectExplorerMenu.objects +{ + [TypeConverter(typeof(ExpandableObjectConverter))] + public class UserDefinedParameter + { + public const short NAME_MAX_LENGTH = 64; + + [DisplayName("Name")] + [Description("Name of the user-defined parameter. Cannot be empty or contain only whitespace characters.")] + public string Name { get; set; } + + [DisplayName("Data type")] + [Description("Data type of the user-defined parameter.")] + public UserDefinedParameterType Type { get; set; } + + public static void ValidateName(string parameterName, IEnumerable reservedNames = null) + { + if (string.IsNullOrWhiteSpace(parameterName)) + { + throw new ArgumentException("User-defined parameter name cannot be null or whitespace."); + } + if (parameterName.Length > NAME_MAX_LENGTH) + { + throw new ArgumentException($"User-defined parameter name cannot be longer than {NAME_MAX_LENGTH} characters."); + } + if (reservedNames?.Any(reservedName => StringComparer.OrdinalIgnoreCase.Equals(reservedName, parameterName)) ?? false) + { + throw new ArgumentException($"Parameter name '{parameterName}' is reserved or duplicated."); + } + } + } +} From 9e3a5c989cd44162dee7f1c1fa520f7cc11a646a Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 11 Sep 2025 13:30:04 +0200 Subject: [PATCH 09/29] UI fixes: - AddMenuItem: making user-defined parameter listview larger & resizeable. Increasing window & control sizes. - AddUserDefinedParameter: displaying window in center of parent, modify sytle. - EnterUserDefinedArgument: displaying window in center of parent, modify sytle. Auto-sized flowLayoutPanel. --- AddMenuItem.Designer.cs | 36 +++++++++++++++------------ AddUserDefinedParameter.Designer.cs | 5 +++- EnterUserDefinedArguments.Designer.cs | 19 +++++++++++--- EnterUserDefinedArguments.cs | 7 +++++- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/AddMenuItem.Designer.cs b/AddMenuItem.Designer.cs index 54dc8b4..38f23b7 100644 --- a/AddMenuItem.Designer.cs +++ b/AddMenuItem.Designer.cs @@ -55,7 +55,7 @@ private void InitializeComponent() // this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(455, 440); + this.buttonCancel.Location = new System.Drawing.Point(444, 502); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(75, 23); this.buttonCancel.TabIndex = 6; @@ -67,7 +67,7 @@ private void InitializeComponent() this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; this.buttonOK.Enabled = false; - this.buttonOK.Location = new System.Drawing.Point(374, 440); + this.buttonOK.Location = new System.Drawing.Point(363, 502); this.buttonOK.Name = "buttonOK"; this.buttonOK.Size = new System.Drawing.Size(75, 23); this.buttonOK.TabIndex = 5; @@ -80,7 +80,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.textName.Location = new System.Drawing.Point(88, 12); this.textName.Name = "textName"; - this.textName.Size = new System.Drawing.Size(442, 20); + this.textName.Size = new System.Drawing.Size(431, 20); this.textName.TabIndex = 0; this.textName.TextChanged += new System.EventHandler(this.textName_TextChanged); // @@ -104,7 +104,7 @@ private void InitializeComponent() "Server/JobServer/Job"}); this.comboContext.Location = new System.Drawing.Point(88, 38); this.comboContext.Name = "comboContext"; - this.comboContext.Size = new System.Drawing.Size(442, 21); + this.comboContext.Size = new System.Drawing.Size(431, 21); this.comboContext.TabIndex = 1; // // checkExecute @@ -136,11 +136,11 @@ private void InitializeComponent() this.textPath.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.textPath.Location = new System.Drawing.Point(88, 245); + this.textPath.Location = new System.Drawing.Point(89, 284); this.textPath.Multiline = true; this.textPath.Name = "textPath"; this.textPath.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.textPath.Size = new System.Drawing.Size(442, 189); + this.textPath.Size = new System.Drawing.Size(431, 210); this.textPath.TabIndex = 4; this.textPath.Text = resources.GetString("textPath.Text"); this.textPath.WordWrap = false; @@ -167,7 +167,7 @@ private void InitializeComponent() // radioPath // this.radioPath.AutoSize = true; - this.radioPath.Location = new System.Drawing.Point(146, 222); + this.radioPath.Location = new System.Drawing.Point(146, 261); this.radioPath.Name = "radioPath"; this.radioPath.Size = new System.Drawing.Size(47, 17); this.radioPath.TabIndex = 10; @@ -179,7 +179,7 @@ private void InitializeComponent() // this.radioScript.AutoSize = true; this.radioScript.Checked = true; - this.radioScript.Location = new System.Drawing.Point(88, 222); + this.radioScript.Location = new System.Drawing.Point(88, 261); this.radioScript.Name = "radioScript"; this.radioScript.Size = new System.Drawing.Size(52, 17); this.radioScript.TabIndex = 11; @@ -191,7 +191,7 @@ private void InitializeComponent() // buttonOpen // this.buttonOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonOpen.Location = new System.Drawing.Point(505, 219); + this.buttonOpen.Location = new System.Drawing.Point(495, 255); this.buttonOpen.Name = "buttonOpen"; this.buttonOpen.Size = new System.Drawing.Size(25, 23); this.buttonOpen.TabIndex = 12; @@ -209,7 +209,7 @@ private void InitializeComponent() // this.labelVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.labelVersion.AutoSize = true; - this.labelVersion.Location = new System.Drawing.Point(12, 445); + this.labelVersion.Location = new System.Drawing.Point(12, 510); this.labelVersion.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); this.labelVersion.Name = "labelVersion"; this.labelVersion.Size = new System.Drawing.Size(31, 13); @@ -218,13 +218,15 @@ private void InitializeComponent() // // listViewUserDefinedParam // + this.listViewUserDefinedParam.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.listViewUserDefinedParam.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.ParameterName, this.ParameterType}); this.listViewUserDefinedParam.HideSelection = false; this.listViewUserDefinedParam.Location = new System.Drawing.Point(88, 135); this.listViewUserDefinedParam.Name = "listViewUserDefinedParam"; - this.listViewUserDefinedParam.Size = new System.Drawing.Size(275, 75); + this.listViewUserDefinedParam.Size = new System.Drawing.Size(350, 120); this.listViewUserDefinedParam.TabIndex = 15; this.listViewUserDefinedParam.UseCompatibleStateImageBehavior = false; this.listViewUserDefinedParam.View = System.Windows.Forms.View.Details; @@ -232,16 +234,17 @@ private void InitializeComponent() // ParameterName // this.ParameterName.Text = "Parameter name"; - this.ParameterName.Width = 160; + this.ParameterName.Width = 197; // // ParameterType // this.ParameterType.Text = "Parameter type"; - this.ParameterType.Width = 106; + this.ParameterType.Width = 109; // // buttonAddUserDefinedParam // - this.buttonAddUserDefinedParam.Location = new System.Drawing.Point(374, 135); + this.buttonAddUserDefinedParam.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonAddUserDefinedParam.Location = new System.Drawing.Point(444, 135); this.buttonAddUserDefinedParam.Name = "buttonAddUserDefinedParam"; this.buttonAddUserDefinedParam.Size = new System.Drawing.Size(75, 23); this.buttonAddUserDefinedParam.TabIndex = 16; @@ -251,7 +254,8 @@ private void InitializeComponent() // // buttonRemoveUserDefinedParam // - this.buttonRemoveUserDefinedParam.Location = new System.Drawing.Point(374, 164); + this.buttonRemoveUserDefinedParam.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonRemoveUserDefinedParam.Location = new System.Drawing.Point(444, 164); this.buttonRemoveUserDefinedParam.Name = "buttonRemoveUserDefinedParam"; this.buttonRemoveUserDefinedParam.Size = new System.Drawing.Size(75, 23); this.buttonRemoveUserDefinedParam.TabIndex = 18; @@ -272,7 +276,7 @@ private void InitializeComponent() // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(542, 475); + this.ClientSize = new System.Drawing.Size(531, 540); this.Controls.Add(this.labelUserDefinedParameters); this.Controls.Add(this.buttonRemoveUserDefinedParam); this.Controls.Add(this.buttonAddUserDefinedParam); diff --git a/AddUserDefinedParameter.Designer.cs b/AddUserDefinedParameter.Designer.cs index 026de20..09c78dc 100644 --- a/AddUserDefinedParameter.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -95,15 +95,18 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(285, 164); - this.ControlBox = false; this.Controls.Add(this.buttonCancel); this.Controls.Add(this.buttonSave); this.Controls.Add(this.labelParameterType); this.Controls.Add(this.labelParameterName); this.Controls.Add(this.comboBoxParameterType); this.Controls.Add(this.textBoxParameterName); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; this.Name = "AddUserDefinedParameter"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Adding new user-defined parameter..."; this.ResumeLayout(false); this.PerformLayout(); diff --git a/EnterUserDefinedArguments.Designer.cs b/EnterUserDefinedArguments.Designer.cs index cfa3ecd..9880dcf 100644 --- a/EnterUserDefinedArguments.Designer.cs +++ b/EnterUserDefinedArguments.Designer.cs @@ -47,16 +47,23 @@ private void InitializeComponent() // // flowLayoutPanelArguments // + this.flowLayoutPanelArguments.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.flowLayoutPanelArguments.AutoScroll = true; + this.flowLayoutPanelArguments.AutoSize = true; this.flowLayoutPanelArguments.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; this.flowLayoutPanelArguments.Location = new System.Drawing.Point(15, 26); + this.flowLayoutPanelArguments.MaximumSize = new System.Drawing.Size(300, 200); this.flowLayoutPanelArguments.Name = "flowLayoutPanelArguments"; - this.flowLayoutPanelArguments.Size = new System.Drawing.Size(300, 150); + this.flowLayoutPanelArguments.Size = new System.Drawing.Size(300, 50); this.flowLayoutPanelArguments.TabIndex = 1; + this.flowLayoutPanelArguments.WrapContents = false; // // buttonOK // - this.buttonOK.Location = new System.Drawing.Point(159, 182); + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.Location = new System.Drawing.Point(159, 82); this.buttonOK.Name = "buttonOK"; this.buttonOK.Size = new System.Drawing.Size(75, 23); this.buttonOK.TabIndex = 2; @@ -66,8 +73,9 @@ private void InitializeComponent() // // buttonCancel // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(240, 182); + this.buttonCancel.Location = new System.Drawing.Point(240, 82); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(75, 23); this.buttonCancel.TabIndex = 3; @@ -78,16 +86,19 @@ private void InitializeComponent() // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; this.CancelButton = this.buttonCancel; - this.ClientSize = new System.Drawing.Size(329, 216); + this.ClientSize = new System.Drawing.Size(329, 111); this.Controls.Add(this.buttonCancel); this.Controls.Add(this.buttonOK); this.Controls.Add(this.flowLayoutPanelArguments); this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "EnterUserDefinedArguments"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Enter script arguments..."; this.ResumeLayout(false); this.PerformLayout(); diff --git a/EnterUserDefinedArguments.cs b/EnterUserDefinedArguments.cs index ee3d01c..0d7db59 100644 --- a/EnterUserDefinedArguments.cs +++ b/EnterUserDefinedArguments.cs @@ -9,6 +9,11 @@ namespace SSMSObjectExplorerMenu { public partial class EnterUserDefinedArguments : Form { + /// + /// Space for the vertical scrollbar and some padding. + /// + private const int FLOWLAYOUTPANEL_PADDING = 25; + private readonly ArgumentControl[] _argumentControls; public IEnumerable UserDefinedArguments { @@ -26,7 +31,7 @@ public EnterUserDefinedArguments(IEnumerable parameters) { InitializeComponent(); - int argumentControlWidth = this.flowLayoutPanelArguments.ClientSize.Width - SystemInformation.VerticalScrollBarWidth; + int argumentControlWidth = this.flowLayoutPanelArguments.ClientSize.Width - FLOWLAYOUTPANEL_PADDING; _argumentControls = parameters.Select(p => new ArgumentControl(p.Name, p.Type, argumentControlWidth)).ToArray(); this.flowLayoutPanelArguments.Controls.AddRange(_argumentControls); } From ace535545b073a134e36dc2f09f7bd113140eb83 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 11 Sep 2025 13:59:51 +0200 Subject: [PATCH 10/29] Making parameter name replacement case-insensitive. --- extensions/Extensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/Extensions.cs b/extensions/Extensions.cs index 6157f2b..e8fdfd2 100644 --- a/extensions/Extensions.cs +++ b/extensions/Extensions.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using System.Xml.Serialization; namespace SSMSObjectExplorerMenu.extensions @@ -119,11 +120,11 @@ public static NodeInfo GetInfo(this INodeInformation node) public static string ReplaceRange(this string original, IEnumerable<(string Phrase, string Value)> elements) { - // TODO: replacement case-insensitive? string result = original; foreach ((string Phrase, string Value) in elements) { - result = result.Replace(Phrase, Value); + var replacementRegex = Regex.Escape(Phrase); + result = Regex.Replace(result, replacementRegex, Value, RegexOptions.IgnoreCase); } return result; } From 0434c7e23236b6e2245168662decbdc331d2a577 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Fri, 12 Sep 2025 10:53:07 +0200 Subject: [PATCH 11/29] Adding bit (boolean) parameter type. --- ArgumentControl.cs | 21 ++++++++++++++++++++- SSMSObjectExplorerMenu.csproj | 1 + enums/UserDefinedArgumentType.cs | 3 ++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/ArgumentControl.cs b/ArgumentControl.cs index c501b47..a9c6eef 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -16,7 +16,17 @@ public partial class ArgumentControl : UserControl public string ParameterName { get; private set; } public UserDefinedParameterType ParameterType { get; private set; } - public string ParameterValueString => _valueControl.Text; + public string ParameterValueString + { + get + { + if(ParameterType == UserDefinedParameterType.Bit) + { + return ((CheckBox)_valueControl).Checked ? "1" : "0"; + } + else return _valueControl.Text; + } + } public Func Validator { get; private set; } @@ -50,6 +60,9 @@ public ArgumentControl(string parameterName, UserDefinedParameterType parameterT case UserDefinedParameterType.Int: Init_Int(); break; + case UserDefinedParameterType.Bit: + Init_Bit(); + break; default: throw new ArgumentException("Parameter type is not known.", nameof(parameterType)); } @@ -89,6 +102,12 @@ private void Init_Int() Validator = () => true; } + private void Init_Bit() + { + _valueControl = new CheckBox(); + Validator = () => true; + } + private bool Validate_Uniqueidentifier() => Guid.TryParse(_valueControl.Text, out _); private bool Validate_Nvarchar() => !string.IsNullOrWhiteSpace(_valueControl.Text); diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index 4780f59..10d1328 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -129,6 +129,7 @@ False + diff --git a/enums/UserDefinedArgumentType.cs b/enums/UserDefinedArgumentType.cs index 3e15e92..b2ace6b 100644 --- a/enums/UserDefinedArgumentType.cs +++ b/enums/UserDefinedArgumentType.cs @@ -4,6 +4,7 @@ public enum UserDefinedParameterType : byte { UniqueIdentifier, Int, - Nvarchar + Nvarchar, + Bit } } From 0fe7b12060973ef78186294e8c63605fe720094c Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Fri, 12 Sep 2025 17:24:36 +0200 Subject: [PATCH 12/29] Adding CustomList parameter type. Refactoring in validation. --- AddMenuItem.cs | 4 +- AddUserDefinedParameter.Designer.cs | 83 ++++++++++++++++++++++++++--- AddUserDefinedParameter.cs | 82 +++++++++++++++++++++------- ArgumentControl.cs | 35 +++++++----- EnterUserDefinedArguments.cs | 6 +-- OptionsDialogPage.cs | 17 +++--- SSMSObjectExplorerMenu.csproj | 1 + enums/UserDefinedArgumentType.cs | 6 ++- extensions/UIExtensions.cs | 20 +++---- objects/MenuItem.cs | 12 ++--- objects/MenuItemErrorModel.cs | 6 ++- objects/StringListItem.cs | 61 +++++++++++++++++++++ objects/UserDefinedParameter.cs | 51 ++++++++++++++++-- 13 files changed, 308 insertions(+), 76 deletions(-) create mode 100644 objects/StringListItem.cs diff --git a/AddMenuItem.cs b/AddMenuItem.cs index 4e05291..9ffb71a 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -98,8 +98,8 @@ private void buttonAddUserDefinedParam_Click(object sender, EventArgs e) if (addDialog.ShowDialog() == DialogResult.OK) { var newParam = addDialog.Parameter; - var newListViewItem = new ListViewItem { Text = newParam.Name }; - newListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem { Text = Enum.GetName(typeof(UserDefinedParameterType), newParam.Type), Tag = newParam.Type }); + var newListViewItem = new ListViewItem { Text = newParam.Name, Tag = newParam }; + newListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem { Text = Enum.GetName(typeof(UserDefinedParameterType), newParam.Type) }); listViewUserDefinedParam.Items.Add(newListViewItem); } } diff --git a/AddUserDefinedParameter.Designer.cs b/AddUserDefinedParameter.Designer.cs index 09c78dc..39ce8b3 100644 --- a/AddUserDefinedParameter.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -35,11 +35,17 @@ private void InitializeComponent() this.labelParameterType = new System.Windows.Forms.Label(); this.buttonSave = new System.Windows.Forms.Button(); this.buttonCancel = new System.Windows.Forms.Button(); + this.listViewCustomList = new System.Windows.Forms.ListView(); + this.buttonAddCustomList = new System.Windows.Forms.Button(); + this.buttonRemoveCustomList = new System.Windows.Forms.Button(); + this.labelCustomList = new System.Windows.Forms.Label(); + this.panelCustomList = new System.Windows.Forms.Panel(); + this.panelCustomList.SuspendLayout(); this.SuspendLayout(); // // textBoxParameterName // - this.textBoxParameterName.Location = new System.Drawing.Point(103, 24); + this.textBoxParameterName.Location = new System.Drawing.Point(103, 14); this.textBoxParameterName.Name = "textBoxParameterName"; this.textBoxParameterName.Size = new System.Drawing.Size(170, 20); this.textBoxParameterName.TabIndex = 0; @@ -47,15 +53,16 @@ private void InitializeComponent() // comboBoxParameterType // this.comboBoxParameterType.FormattingEnabled = true; - this.comboBoxParameterType.Location = new System.Drawing.Point(103, 66); + this.comboBoxParameterType.Location = new System.Drawing.Point(103, 56); this.comboBoxParameterType.Name = "comboBoxParameterType"; this.comboBoxParameterType.Size = new System.Drawing.Size(170, 21); this.comboBoxParameterType.TabIndex = 1; + this.comboBoxParameterType.SelectedValueChanged += new System.EventHandler(this.comboBoxParameterType_SelectedValueChanged); // // labelParameterName // this.labelParameterName.AutoSize = true; - this.labelParameterName.Location = new System.Drawing.Point(13, 24); + this.labelParameterName.Location = new System.Drawing.Point(13, 14); this.labelParameterName.Name = "labelParameterName"; this.labelParameterName.Size = new System.Drawing.Size(87, 13); this.labelParameterName.TabIndex = 2; @@ -64,7 +71,7 @@ private void InitializeComponent() // labelParameterType // this.labelParameterType.AutoSize = true; - this.labelParameterType.Location = new System.Drawing.Point(13, 66); + this.labelParameterType.Location = new System.Drawing.Point(13, 56); this.labelParameterType.Name = "labelParameterType"; this.labelParameterType.Size = new System.Drawing.Size(81, 13); this.labelParameterType.TabIndex = 3; @@ -72,7 +79,8 @@ private void InitializeComponent() // // buttonSave // - this.buttonSave.Location = new System.Drawing.Point(103, 126); + this.buttonSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSave.Location = new System.Drawing.Point(117, 203); this.buttonSave.Name = "buttonSave"; this.buttonSave.Size = new System.Drawing.Size(75, 23); this.buttonSave.TabIndex = 4; @@ -82,19 +90,73 @@ private void InitializeComponent() // // buttonCancel // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(198, 126); + this.buttonCancel.Location = new System.Drawing.Point(198, 203); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(75, 23); this.buttonCancel.TabIndex = 5; this.buttonCancel.Text = "Cancel"; this.buttonCancel.UseVisualStyleBackColor = true; // + // listViewCustomList + // + this.listViewCustomList.HideSelection = false; + this.listViewCustomList.LabelEdit = true; + this.listViewCustomList.Location = new System.Drawing.Point(0, 18); + this.listViewCustomList.Name = "listViewCustomList"; + this.listViewCustomList.Size = new System.Drawing.Size(228, 79); + this.listViewCustomList.TabIndex = 6; + this.listViewCustomList.UseCompatibleStateImageBehavior = false; + // + // buttonAddCustomList + // + this.buttonAddCustomList.Location = new System.Drawing.Point(234, 16); + this.buttonAddCustomList.Name = "buttonAddCustomList"; + this.buttonAddCustomList.Size = new System.Drawing.Size(23, 23); + this.buttonAddCustomList.TabIndex = 7; + this.buttonAddCustomList.Text = "+"; + this.buttonAddCustomList.UseVisualStyleBackColor = true; + this.buttonAddCustomList.Click += new System.EventHandler(this.buttonAddCustomList_Click); + // + // buttonRemoveCustomList + // + this.buttonRemoveCustomList.Location = new System.Drawing.Point(234, 45); + this.buttonRemoveCustomList.Name = "buttonRemoveCustomList"; + this.buttonRemoveCustomList.Size = new System.Drawing.Size(23, 23); + this.buttonRemoveCustomList.TabIndex = 8; + this.buttonRemoveCustomList.Text = "-"; + this.buttonRemoveCustomList.UseVisualStyleBackColor = true; + this.buttonRemoveCustomList.Click += new System.EventHandler(this.buttonRemoveCustomList_Click); + // + // labelCustomList + // + this.labelCustomList.AutoSize = true; + this.labelCustomList.Location = new System.Drawing.Point(3, 2); + this.labelCustomList.Name = "labelCustomList"; + this.labelCustomList.Size = new System.Drawing.Size(113, 13); + this.labelCustomList.TabIndex = 9; + this.labelCustomList.Text = "List of possible values:"; + // + // panelCustomList + // + this.panelCustomList.Controls.Add(this.labelCustomList); + this.panelCustomList.Controls.Add(this.buttonRemoveCustomList); + this.panelCustomList.Controls.Add(this.buttonAddCustomList); + this.panelCustomList.Controls.Add(this.listViewCustomList); + this.panelCustomList.Location = new System.Drawing.Point(16, 95); + this.panelCustomList.Name = "panelCustomList"; + this.panelCustomList.Size = new System.Drawing.Size(257, 100); + this.panelCustomList.TabIndex = 10; + // // AddUserDefinedParameter // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(285, 164); + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(285, 238); + this.Controls.Add(this.panelCustomList); this.Controls.Add(this.buttonCancel); this.Controls.Add(this.buttonSave); this.Controls.Add(this.labelParameterType); @@ -108,6 +170,8 @@ private void InitializeComponent() this.Name = "AddUserDefinedParameter"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Adding new user-defined parameter..."; + this.panelCustomList.ResumeLayout(false); + this.panelCustomList.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -121,5 +185,10 @@ private void InitializeComponent() private System.Windows.Forms.Label labelParameterType; private System.Windows.Forms.Button buttonSave; private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.ListView listViewCustomList; + private System.Windows.Forms.Button buttonAddCustomList; + private System.Windows.Forms.Button buttonRemoveCustomList; + private System.Windows.Forms.Label labelCustomList; + private System.Windows.Forms.Panel panelCustomList; } } \ No newline at end of file diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs index 316b0d4..d1d12a2 100644 --- a/AddUserDefinedParameter.cs +++ b/AddUserDefinedParameter.cs @@ -1,7 +1,11 @@ using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.extensions; using SSMSObjectExplorerMenu.objects; using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; using System.Windows.Forms; namespace SSMSObjectExplorerMenu @@ -15,11 +19,20 @@ public UserDefinedParameter Parameter { get { - if (!TryValidate(out string _) || this.DialogResult != DialogResult.OK) + if (!TryValidate(out List _) || this.DialogResult != DialogResult.OK) { - throw new InvalidOperationException("Dialog is invalid state."); + throw new InvalidOperationException("Dialog is in invalid state."); } - return new UserDefinedParameter { Name = _parameter.Name, Type = _parameter.Type }; + return new UserDefinedParameter + { + Name = _parameter.Name, + Type = _parameter.Type, + ValueSetOfCustomList = new BindingList( + _parameter.Type == UserDefinedParameterType.CustomList ? + this.listViewCustomList.Items.Cast().Select(item => new StringListItem(item.Text)).ToList() : + new List() + ) + }; } } @@ -33,43 +46,76 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse) this.textBoxParameterName.MaxLength = UserDefinedParameter.NAME_MAX_LENGTH; this.textBoxParameterName.DataBindings.Add(nameof(textBoxParameterName.Text), _parameter, nameof(_parameter.Name), true, DataSourceUpdateMode.OnPropertyChanged); - this.comboBoxParameterType.DataSource = Enum.GetNames(typeof(UserDefinedParameterType)); - this.comboBoxParameterType.SelectedIndex = 0; - this.comboBoxParameterType.DataBindings.Add(nameof(comboBoxParameterType.SelectedItem), _parameter, nameof(_parameter.Type), true, DataSourceUpdateMode.OnPropertyChanged); + this.comboBoxParameterType.DataSource = + Enum.GetValues(typeof(UserDefinedParameterType)) + .Cast() + .Select(type => new ComboBoxItem { Displayed = Enum.GetName(typeof(UserDefinedParameterType), type), Value = type }).ToList(); + this.comboBoxParameterType.DisplayMember = nameof(ComboBoxItem.Displayed); + this.comboBoxParameterType.ValueMember = nameof(ComboBoxItem.Value); + this.comboBoxParameterType.DataBindings.Add(nameof(comboBoxParameterType.SelectedValue), _parameter, nameof(_parameter.Type), true, DataSourceUpdateMode.OnPropertyChanged); } private void buttonSave_Click(object sender, EventArgs e) { - if (!TryValidate(out string validationErrorMessage)) + if (!TryValidate(out List validationErrors)) { - MessageBox.Show(validationErrorMessage, "Invalid parameter", MessageBoxButtons.OK, MessageBoxIcon.Error); + var errorMessageBuilder = new StringBuilder(); + validationErrors.ForEach(error => errorMessageBuilder.AppendLine(error)); + MessageBox.Show(errorMessageBuilder.ToString(), "Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } this.DialogResult = DialogResult.OK; } - private bool TryValidate(out string validationErrorMessage) + private bool TryValidate(out List validationErros) { - try + var paramBuiltFromDialog = new UserDefinedParameter { - // Can't add parameters already added by the user once or coming from the execution context... - UserDefinedParameter.ValidateName(_parameter.Name, _paramNamesInUse); - } - catch (ArgumentException ex) + Name = _parameter.Name, + Type = _parameter.Type, + ValueSetOfCustomList = new BindingList( + _parameter.Type == UserDefinedParameterType.CustomList ? + this.listViewCustomList.Items.Cast().Select(item => new StringListItem(item.Text)).ToList() : + new List() + ) + }; + + validationErros = !paramBuiltFromDialog.TryValidate(out IEnumerable errors, _paramNamesInUse) ? errors.ToList() : new List(); + return !validationErros.Any(); + } + + private void comboBoxParameterType_SelectedValueChanged(object sender, EventArgs e) + { + var selectedValue = comboBoxParameterType.SelectedValue as UserDefinedParameterType?; + if(selectedValue != null) { - validationErrorMessage = ex.Message; - return false; + this.panelCustomList.Enabled = selectedValue == UserDefinedParameterType.CustomList; } + } - validationErrorMessage = null; - return true; + private void buttonAddCustomList_Click(object sender, EventArgs e) + { + this.listViewCustomList.Items.Add("New value (click to edit)..."); + } + + private void buttonRemoveCustomList_Click(object sender, EventArgs e) + { + var selectedItems = this.listViewCustomList.Items.Cast().Where(item => item.Selected); + this.listViewCustomList.Items.RemoveRange(selectedItems); } class ParameterItem { public string Name { get; set; } public UserDefinedParameterType Type { get; set; } + public ISet ValueSetOfCustomList { get; set; } + } + + class ComboBoxItem + { + public string Displayed { get; set; } + public UserDefinedParameterType Value { get; set; } } } } diff --git a/ArgumentControl.cs b/ArgumentControl.cs index a9c6eef..23ee9ab 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -1,5 +1,7 @@ using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.objects; using System; +using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; @@ -14,13 +16,12 @@ public partial class ArgumentControl : UserControl private Label _labelParameterName; private Control _valueControl; - public string ParameterName { get; private set; } - public UserDefinedParameterType ParameterType { get; private set; } + public UserDefinedParameter Parameter { get; private set; } public string ParameterValueString { get { - if(ParameterType == UserDefinedParameterType.Bit) + if(Parameter.Type == UserDefinedParameterType.Bit) { return ((CheckBox)_valueControl).Checked ? "1" : "0"; } @@ -30,26 +31,23 @@ public string ParameterValueString public Func Validator { get; private set; } - public ArgumentControl(string parameterName, UserDefinedParameterType parameterType, int width) + public ArgumentControl(UserDefinedParameter parameter, int width) { - if(string.IsNullOrWhiteSpace(parameterName)) + if(!parameter.TryValidate(out IEnumerable _)) { - throw new ArgumentException("Parameter name cannot be null or whitespace.", nameof(parameterName)); + throw new ArgumentException("Parameter validation has failed.", nameof(parameter)); } - if (width < 0) { throw new ArgumentException("Width cannot be negative.", nameof(width)); } - ParameterName = parameterName; - ParameterType = parameterType; + Parameter = parameter; InitializeComponent(); - this.Size = new Size(width, HEIGHT_LABEL + HEIGHT_VALUECONTROL); - switch (parameterType) + switch (Parameter.Type) { case UserDefinedParameterType.UniqueIdentifier: Init_Uniqueidentifier(); @@ -63,8 +61,11 @@ public ArgumentControl(string parameterName, UserDefinedParameterType parameterT case UserDefinedParameterType.Bit: Init_Bit(); break; + case UserDefinedParameterType.CustomList: + Init_CustomList(); + break; default: - throw new ArgumentException("Parameter type is not known.", nameof(parameterType)); + throw new ArgumentException("Parameter type is not known.", nameof(Parameter.Type)); } this._valueControl.Location = new Point(0, HEIGHT_LABEL); this._valueControl.Size = new Size(this.Size.Width, HEIGHT_VALUECONTROL); @@ -73,7 +74,7 @@ public ArgumentControl(string parameterName, UserDefinedParameterType parameterT this._labelParameterName = new Label(); this._labelParameterName.Location = Point.Empty; this._labelParameterName.Size = new Size(this.Size.Width, HEIGHT_LABEL); - this._labelParameterName.Text = $"{parameterName} ({parameterType}):"; + this._labelParameterName.Text = $"{Parameter.Name} ({Parameter.Type}):"; this.Controls.Add(this._labelParameterName); } @@ -107,6 +108,14 @@ private void Init_Bit() _valueControl = new CheckBox(); Validator = () => true; } + private void Init_CustomList() + { + var comboBox = new ComboBox(); + comboBox.DataSource = Parameter.ValueSetOfCustomList; + + _valueControl = comboBox; + Validator = () => true; + } private bool Validate_Uniqueidentifier() => Guid.TryParse(_valueControl.Text, out _); diff --git a/EnterUserDefinedArguments.cs b/EnterUserDefinedArguments.cs index 0d7db59..744f1f0 100644 --- a/EnterUserDefinedArguments.cs +++ b/EnterUserDefinedArguments.cs @@ -32,11 +32,11 @@ public EnterUserDefinedArguments(IEnumerable parameters) InitializeComponent(); int argumentControlWidth = this.flowLayoutPanelArguments.ClientSize.Width - FLOWLAYOUTPANEL_PADDING; - _argumentControls = parameters.Select(p => new ArgumentControl(p.Name, p.Type, argumentControlWidth)).ToArray(); + _argumentControls = parameters.Select(p => new ArgumentControl(p, argumentControlWidth)).ToArray(); this.flowLayoutPanelArguments.Controls.AddRange(_argumentControls); } - private void buttonOK_Click(object sender, System.EventArgs e) + private void buttonOK_Click(object sender, EventArgs e) { if(!TryValidate(out string validationErrorMessage)) { @@ -53,7 +53,7 @@ private bool TryValidate(out string validationErrorMessage) { if (!ac.Validator()) { - validationErrorMessage = $"The value for parameter '{ac.ParameterName}' ({ac.ParameterType}) is not valid!"; + validationErrorMessage = $"The value for parameter '{ac.Parameter.Name}' ({ac.Parameter.Type}) is not valid!"; return false; } } diff --git a/OptionsDialogPage.cs b/OptionsDialogPage.cs index 27419a8..12a42ed 100644 --- a/OptionsDialogPage.cs +++ b/OptionsDialogPage.cs @@ -99,7 +99,7 @@ public override void SaveSettingsToStorage() protected override void OnApply(PageApplyEventArgs e) { - if(!TryValidate(out IEnumerable validationErrors)) + if(!TryValidate(out List validationErrors)) { ShowValidationErrorDialog(validationErrors); e.ApplyBehavior = ApplyKind.CancelNoNavigate; @@ -110,28 +110,27 @@ protected override void OnApply(PageApplyEventArgs e) base.OnApply(e); } - private bool TryValidate(out IEnumerable validationErrors) + private bool TryValidate(out List validationErrors) { - var errorList = new List(); + validationErrors = new List(); foreach (var menuItem in MenuItems) { if (!menuItem.TryValidate(out IEnumerable errors)) { - errorList.AddRange(errors); + validationErrors.AddRange(errors); } } - validationErrors = errorList; - return !errorList.Any(); + return !validationErrors.Any(); } - private void ShowValidationErrorDialog(IEnumerable validationErrors) + private void ShowValidationErrorDialog(List validationErrors) { if(validationErrors.Any()) { - StringBuilder builder = new StringBuilder(); + var builder = new StringBuilder(); builder.AppendLine($"One or more validation errors occurred:{Environment.NewLine}"); - foreach (var error in validationErrors) + foreach (var error in validationErrors.SelectMany(e => e.ErrorMessages, (m, e) => new { m.MenuItemName, ErrorMessage = e})) { builder.AppendLine($"Menu item '{error.MenuItemName}': {error.ErrorMessage}"); } diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index 10d1328..c767aa0 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -87,6 +87,7 @@ + diff --git a/enums/UserDefinedArgumentType.cs b/enums/UserDefinedArgumentType.cs index b2ace6b..3bcb568 100644 --- a/enums/UserDefinedArgumentType.cs +++ b/enums/UserDefinedArgumentType.cs @@ -5,6 +5,10 @@ public enum UserDefinedParameterType : byte UniqueIdentifier, Int, Nvarchar, - Bit + Bit, + /// + /// This is not a SQL Server data type. Represents a list of custom values defined by the user. + /// + CustomList } } diff --git a/extensions/UIExtensions.cs b/extensions/UIExtensions.cs index 31df945..de113ea 100644 --- a/extensions/UIExtensions.cs +++ b/extensions/UIExtensions.cs @@ -1,7 +1,5 @@ -using SSMSObjectExplorerMenu.enums; -using SSMSObjectExplorerMenu.objects; +using SSMSObjectExplorerMenu.objects; using System.Collections.Generic; -using System.Linq; using System.Windows.Forms; namespace SSMSObjectExplorerMenu.extensions @@ -12,15 +10,19 @@ public static IEnumerable GetUserDefinedParams(this ListVi { foreach (ListViewItem item in listView.Items) { - yield return new UserDefinedParameter - { - Name = item.Text, - Type = (UserDefinedParameterType)item.SubItems.Cast().Last().Tag - }; + yield return item.Tag as UserDefinedParameter; } } public static UserDefinedArgument ToUserDefinedArgument(this ArgumentControl control) - => new UserDefinedArgument(control.ParameterName, control.ParameterType, control.ParameterValueString); + => new UserDefinedArgument(control.Parameter.Name, control.Parameter.Type, control.ParameterValueString); + + public static void RemoveRange(this ListView.ListViewItemCollection litViewItems, IEnumerable itemsToRemove) + { + foreach (var item in itemsToRemove) + { + litViewItems.Remove(item); + } + } } } diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index 6683ee4..e6fb76e 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -89,15 +89,11 @@ public bool TryValidate(out IEnumerable validationErrors) foreach(var param in UserDefinedParameters) { - try + var otherParamNames = UserDefinedParameters.Where(p => p != param).Select(p => p.Name); + if(!param.TryValidate(out IEnumerable paramErrors, Utils.ParametersFromContext.Concat(otherParamNames))) { - var otherParamNames = UserDefinedParameters.Where(p => p != param).Select(p => p.Name); - UserDefinedParameter.ValidateName(param.Name, Utils.ParametersFromContext.Concat(otherParamNames)); - } - catch (ArgumentException ex) - { - errorList.Add(new MenuItemErrorModel { MenuItemName = Name, ErrorMessage = ex.Message }); - } + errorList.Add(new MenuItemErrorModel { MenuItemName = Name, ErrorMessages = paramErrors }); + } } validationErrors = errorList; diff --git a/objects/MenuItemErrorModel.cs b/objects/MenuItemErrorModel.cs index 46fe77c..cb6ffc0 100644 --- a/objects/MenuItemErrorModel.cs +++ b/objects/MenuItemErrorModel.cs @@ -1,9 +1,11 @@ -namespace SSMSObjectExplorerMenu.objects +using System.Collections.Generic; + +namespace SSMSObjectExplorerMenu.objects { public class MenuItemErrorModel { public string MenuItemName { get; set; } - public string ErrorMessage { get; set; } + public IEnumerable ErrorMessages { get; set; } } } diff --git a/objects/StringListItem.cs b/objects/StringListItem.cs new file mode 100644 index 0000000..70d64e0 --- /dev/null +++ b/objects/StringListItem.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; + +namespace SSMSObjectExplorerMenu.objects +{ + /// + /// This class is a wrapper for using it with in property grid. + /// calls the default constructor when adding a new item to the collection. + /// does not have a default parameterless constructor. + /// + public class StringListItem + { + public string Value { get; set; } = string.Empty; + + public StringListItem() { } + public StringListItem(string value) { Value = value; } + + public override string ToString() => Value; + + public static implicit operator string(StringListItem item) => item?.Value; + + public static implicit operator StringListItem(string value) => new StringListItem(value); + } + + public class StringListItemComparer : IEqualityComparer + { + private StringComparison? _comparison; + + public StringListItemComparer() { } + + public StringListItemComparer(StringComparison comparison) => _comparison = comparison; + + public bool Equals(StringListItem x, StringListItem y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null) return false; + return _comparison.HasValue ? string.Equals(x.Value, y.Value, _comparison.Value) : string.Equals(x.Value, y.Value); + } + + public int GetHashCode(StringListItem obj) + { + if (obj?.Value == null) return 0; + + switch (_comparison) + { + case StringComparison.OrdinalIgnoreCase: + return obj.Value.ToLowerInvariant().GetHashCode(); + case StringComparison.CurrentCultureIgnoreCase: + return obj.Value.ToLower(System.Globalization.CultureInfo.CurrentCulture).GetHashCode(); + case StringComparison.InvariantCultureIgnoreCase: + return obj.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture).GetHashCode(); + case StringComparison.Ordinal: + case StringComparison.CurrentCulture: + case StringComparison.InvariantCulture: + default: + return obj.Value.GetHashCode(); + } + } + } +} diff --git a/objects/UserDefinedParameter.cs b/objects/UserDefinedParameter.cs index 51f9913..c3fafbb 100644 --- a/objects/UserDefinedParameter.cs +++ b/objects/UserDefinedParameter.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing.Design; using System.Linq; namespace SSMSObjectExplorerMenu.objects @@ -19,20 +21,61 @@ public class UserDefinedParameter [Description("Data type of the user-defined parameter.")] public UserDefinedParameterType Type { get; set; } - public static void ValidateName(string parameterName, IEnumerable reservedNames = null) + /// + /// Populate if is . Otherwise it's ignored. + /// + [DisplayName("List of values")] + [Description("List of selectable values")] + [Editor(typeof(CollectionEditor), typeof(UITypeEditor))] + public BindingList ValueSetOfCustomList { get; set; } + + public bool TryValidate(out IEnumerable validationErrors, IEnumerable reservedNames = null) { + var errors = new List(); + if(!TryValidateName(Name, out IEnumerable nameErrors, reservedNames)) + { + errors.AddRange(nameErrors); + } + + if (Type == UserDefinedParameterType.CustomList) + { + if (ValueSetOfCustomList is null || ValueSetOfCustomList.Count == 0) + { + errors.Add("Value set of CustomList parameter cannot be empty."); + } + if (ValueSetOfCustomList.Any(value => string.IsNullOrWhiteSpace(value))) + { + errors.Add("Value set of CustomList parameter cannot contain empty or whitespace-only elements."); + } + if(ValueSetOfCustomList.Distinct(new StringListItemComparer(StringComparison.OrdinalIgnoreCase)).Count() != ValueSetOfCustomList.Count) + { + errors.Add("Value set of CustomList parameter cannot have duplicate elements."); + } + } + + validationErrors = errors; + return !validationErrors.Any(); + } + + public static bool TryValidateName(string parameterName, out IEnumerable validationErrors, IEnumerable reservedNames = null) + { + var errors = new List(); + if (string.IsNullOrWhiteSpace(parameterName)) { - throw new ArgumentException("User-defined parameter name cannot be null or whitespace."); + errors.Add("User-defined parameter name cannot be null or whitespace."); } if (parameterName.Length > NAME_MAX_LENGTH) { - throw new ArgumentException($"User-defined parameter name cannot be longer than {NAME_MAX_LENGTH} characters."); + errors.Add($"User-defined parameter name cannot be longer than {NAME_MAX_LENGTH} characters."); } if (reservedNames?.Any(reservedName => StringComparer.OrdinalIgnoreCase.Equals(reservedName, parameterName)) ?? false) { - throw new ArgumentException($"Parameter name '{parameterName}' is reserved or duplicated."); + errors.Add($"Parameter name '{parameterName}' is reserved or duplicated."); } + + validationErrors = errors; + return !validationErrors.Any(); } } } From 78289616d449c69aee2c302540b42cc73e150fa6 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 15 Sep 2025 07:43:19 +0200 Subject: [PATCH 13/29] Adding missing inital value of the CustomList collection - fixing not saving value list. --- objects/UserDefinedParameter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objects/UserDefinedParameter.cs b/objects/UserDefinedParameter.cs index c3fafbb..dc6b8b6 100644 --- a/objects/UserDefinedParameter.cs +++ b/objects/UserDefinedParameter.cs @@ -27,7 +27,7 @@ public class UserDefinedParameter [DisplayName("List of values")] [Description("List of selectable values")] [Editor(typeof(CollectionEditor), typeof(UITypeEditor))] - public BindingList ValueSetOfCustomList { get; set; } + public BindingList ValueSetOfCustomList { get; set; } = new BindingList(); public bool TryValidate(out IEnumerable validationErrors, IEnumerable reservedNames = null) { From 6ea15515bd3e98b75f08bc4633029e960f07020f Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 15 Sep 2025 07:53:49 +0200 Subject: [PATCH 14/29] Arranging controls of ArgumentControl - providing more space between controls. --- ArgumentControl.cs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/ArgumentControl.cs b/ArgumentControl.cs index 23ee9ab..c9a58c6 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -9,8 +9,10 @@ namespace SSMSObjectExplorerMenu { public partial class ArgumentControl : UserControl { - private const int HEIGHT_LABEL = 15; - private const int HEIGHT_VALUECONTROL = 20; + /// + /// Padding of the control in pixels. + /// + private const int PADDING_TOP_BOTTOM = 2; private const byte UNIQUEIDENTIFIER_LENGTH = 36; private Label _labelParameterName; @@ -45,7 +47,6 @@ public ArgumentControl(UserDefinedParameter parameter, int width) Parameter = parameter; InitializeComponent(); - this.Size = new Size(width, HEIGHT_LABEL + HEIGHT_VALUECONTROL); switch (Parameter.Type) { @@ -67,15 +68,18 @@ public ArgumentControl(UserDefinedParameter parameter, int width) default: throw new ArgumentException("Parameter type is not known.", nameof(Parameter.Type)); } - this._valueControl.Location = new Point(0, HEIGHT_LABEL); - this._valueControl.Size = new Size(this.Size.Width, HEIGHT_VALUECONTROL); - this.Controls.Add(this._valueControl); - this._labelParameterName = new Label(); - this._labelParameterName.Location = Point.Empty; - this._labelParameterName.Size = new Size(this.Size.Width, HEIGHT_LABEL); + + this.Size = new Size(width, (2 * PADDING_TOP_BOTTOM) + this._labelParameterName.Height + this._valueControl.Height); + + this._labelParameterName.Location = new Point(0, PADDING_TOP_BOTTOM); + this._labelParameterName.Width = this.Width; this._labelParameterName.Text = $"{Parameter.Name} ({Parameter.Type}):"; this.Controls.Add(this._labelParameterName); + + this._valueControl.Location = new Point(0, this._labelParameterName.Location.Y + this._labelParameterName.Height); + this._valueControl.Width = this.Size.Width; + this.Controls.Add(this._valueControl); } private void Init_Uniqueidentifier() From ecd31d7cf28d23c7536a29bc8edbdbf3f53ac970 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 15 Sep 2025 10:36:50 +0200 Subject: [PATCH 15/29] Turning MenuItem context into enumeration type. Fixing issues the below issues: - "Server/Database/Table/Column" could not be selected on the AddMenuItem dialog as the new command's context. - In the Options grid, Context property of the command/menu item could be edited via a text box. This was error prone - in case of a typo, the command disappeared from the Object Explorer context menu. Now it can be selected from a dropdown. --- AddMenuItem.Designer.cs | 13 ------------ AddMenuItem.cs | 17 ++++++++++----- AddUserDefinedParameter.cs | 12 +++-------- MenuItemContextConverter.cs | 40 +++++++++++++++++++++++++++++++++++ SSMSObjectExplorerMenu.cs | 3 ++- SSMSObjectExplorerMenu.csproj | 3 +++ enums/MenuItemContext.cs | 36 +++++++++++++++++++++++++++++++ extensions/Extensions.cs | 22 +++++++++++++++++++ objects/ComboBoxItem.cs | 8 +++++++ objects/MenuItem.cs | 10 +++++---- 10 files changed, 132 insertions(+), 32 deletions(-) create mode 100644 MenuItemContextConverter.cs create mode 100644 enums/MenuItemContext.cs create mode 100644 objects/ComboBoxItem.cs diff --git a/AddMenuItem.Designer.cs b/AddMenuItem.Designer.cs index 38f23b7..44be659 100644 --- a/AddMenuItem.Designer.cs +++ b/AddMenuItem.Designer.cs @@ -89,19 +89,6 @@ private void InitializeComponent() this.comboContext.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.comboContext.FormattingEnabled = true; - this.comboContext.Items.AddRange(new object[] { - "All", - "Server", - "Server/DatabasesFolder", - "Server/Database", - "Server/Database/Table", - "Server/Database/UserTablesFolder", - "Server/Database/View", - "Server/Database/StoredProcedure", - "Server/Database/StoredProceduresFolder", - "Server/JobServer", - "Server/JobServer/JobsFolder", - "Server/JobServer/Job"}); this.comboContext.Location = new System.Drawing.Point(88, 38); this.comboContext.Name = "comboContext"; this.comboContext.Size = new System.Drawing.Size(431, 21); diff --git a/AddMenuItem.cs b/AddMenuItem.cs index 9ffb71a..dad89ad 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -16,16 +16,24 @@ public AddMenuItem(NodeInfo nodeInfo) InitializeComponent(); labelVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + comboContext.Text = nodeInfo.UrnPath; - this.ActiveControl = textName; + + this.comboContext.DataSource = + Enum.GetValues(typeof(MenuItemContext)) + .Cast() + .Select(ctx => new { Displayed = ctx.ToStringDescription(), Value = ctx }).ToList(); + this.comboContext.DisplayMember = nameof(ComboBoxItem.Displayed); + this.comboContext.ValueMember = nameof(ComboBoxItem.Value); + + this.ActiveControl = textName; buttonOpen.Visible = false; } public MenuItem GetMenuItem() { - return new MenuItem(true, comboContext.Text, textName.Text, textPath.Text, checkExecute.Checked, checkConfirm.Checked, listViewUserDefinedParam.GetUserDefinedParams()); + return new MenuItem(true, (MenuItemContext)comboContext.SelectedValue, textName.Text, textPath.Text, checkExecute.Checked, checkConfirm.Checked, listViewUserDefinedParam.GetUserDefinedParams()); } - private void textName_TextChanged(object sender, EventArgs e) { @@ -39,8 +47,7 @@ private void textPath_TextChanged(object sender, EventArgs e) private void ValidateInputs() { - if (comboContext.Text.Trim().Length > 0 - && textName.Text.Trim().Length > 0 + if (textName.Text.Trim().Length > 0 && textPath.Text.Trim().Length > 0) { buttonOK.Enabled = true; diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs index d1d12a2..433615d 100644 --- a/AddUserDefinedParameter.cs +++ b/AddUserDefinedParameter.cs @@ -49,9 +49,9 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse) this.comboBoxParameterType.DataSource = Enum.GetValues(typeof(UserDefinedParameterType)) .Cast() - .Select(type => new ComboBoxItem { Displayed = Enum.GetName(typeof(UserDefinedParameterType), type), Value = type }).ToList(); - this.comboBoxParameterType.DisplayMember = nameof(ComboBoxItem.Displayed); - this.comboBoxParameterType.ValueMember = nameof(ComboBoxItem.Value); + .Select(type => new ComboBoxItem { Displayed = Enum.GetName(typeof(UserDefinedParameterType), type), Value = type }).ToList(); + this.comboBoxParameterType.DisplayMember = nameof(ComboBoxItem.Displayed); + this.comboBoxParameterType.ValueMember = nameof(ComboBoxItem.Value); this.comboBoxParameterType.DataBindings.Add(nameof(comboBoxParameterType.SelectedValue), _parameter, nameof(_parameter.Type), true, DataSourceUpdateMode.OnPropertyChanged); } @@ -111,11 +111,5 @@ class ParameterItem public UserDefinedParameterType Type { get; set; } public ISet ValueSetOfCustomList { get; set; } } - - class ComboBoxItem - { - public string Displayed { get; set; } - public UserDefinedParameterType Value { get; set; } - } } } diff --git a/MenuItemContextConverter.cs b/MenuItemContextConverter.cs new file mode 100644 index 0000000..f19768e --- /dev/null +++ b/MenuItemContextConverter.cs @@ -0,0 +1,40 @@ +using SSMSObjectExplorerMenu.enums; +using System; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace SSMSObjectExplorerMenu +{ + public class MenuItemContextConverter : EnumConverter + { + public MenuItemContextConverter() : base(typeof(MenuItemContext)) + { + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (value is MenuItemContext && destinationType == typeof(string)) + { + var field = typeof(MenuItemContext).GetField(value.ToString()); + var desc = field?.GetCustomAttribute(); + return (desc?.Description) ?? throw new ArgumentException($"Unknown {typeof(MenuItemContext)} value", nameof(value)); + } + return base.ConvertTo(context, culture, value, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if(value is string val) + { + var targetField = typeof(MenuItemContext).GetFields() + .SingleOrDefault(f => f.GetCustomAttribute()?.Description == val); + return targetField != null ? + Enum.Parse(typeof(MenuItemContext), targetField.Name) : + throw new ArgumentException($"Unknown {typeof(MenuItemContext)} value", nameof(value)); + } + return base.ConvertFrom(context, culture, value); + } + } +} diff --git a/SSMSObjectExplorerMenu.cs b/SSMSObjectExplorerMenu.cs index 389221f..ad9e000 100644 --- a/SSMSObjectExplorerMenu.cs +++ b/SSMSObjectExplorerMenu.cs @@ -118,7 +118,8 @@ private void TreeView_ContextMenuStripChanged(object sender, EventArgs e) continue; } - if (menuItem.Context == "All" || menuItem.Context == nodes[0].UrnPath) + var menuItemContext = menuItem.Context.ToStringDescription(); + if (menuItemContext == "All" || menuItemContext == nodes[0].UrnPath) { MenuItemInstance instance = new MenuItemInstance(menuItem, nodeInfo, nodes[0].InvariantName); diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index c767aa0..d9f1a93 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -83,9 +83,12 @@ EnterUserDefinedArguments.cs + + + diff --git a/enums/MenuItemContext.cs b/enums/MenuItemContext.cs new file mode 100644 index 0000000..8e940ec --- /dev/null +++ b/enums/MenuItemContext.cs @@ -0,0 +1,36 @@ +using System; +using System.ComponentModel; + +namespace SSMSObjectExplorerMenu.enums +{ + [Flags] + public enum MenuItemContext + { + [Description("Server")] + Server = 1, + [Description("Server/DatabasesFolder")] + DatabasesFolder = 2, + [Description("Server/Database")] + Database = 4, + [Description("Server/Database/Table")] + Table = 8, + [Description("Server/Database/Table/Column")] + Column = 16, + [Description("Server/Database/UserTablesFolder")] + UserTablesFolder = 32, + [Description("Server/Database/View")] + View = 64, + [Description("Server/Database/StoredProceduresFolder")] + StoredProceduresFolder = 128, + [Description("Server/Database/StoredProcedure")] + StoredProcedure = 256, + [Description("Server/JobServer")] + JobServer = 512, + [Description("Server/JobServer/JobsFolder")] + JobsFolder = 1024, + [Description("Server/JobServer/Job")] + Job = 2048, + [Description("All")] + All = Server | DatabasesFolder | Database | Table | Column | UserTablesFolder | View | StoredProceduresFolder | StoredProcedure | JobServer | JobsFolder | Job + } +} diff --git a/extensions/Extensions.cs b/extensions/Extensions.cs index e8fdfd2..5b1d677 100644 --- a/extensions/Extensions.cs +++ b/extensions/Extensions.cs @@ -1,8 +1,11 @@ using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer; +using Newtonsoft.Json.Linq; +using SSMSObjectExplorerMenu.enums; using SSMSObjectExplorerMenu.objects; using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Text.RegularExpressions; using System.Xml.Serialization; @@ -128,5 +131,24 @@ public static string ReplaceRange(this string original, IEnumerable<(string Phra } return result; } + + public static string ToStringDescription(this T context) where T : Enum + { + var enumType = typeof(T); + var name = Enum.GetName(enumType, context); + if (name != null) + { + var field = enumType.GetField(name); + if (field != null) + { + var attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; + if (attr != null) + { + return attr.Description; + } + } + } + throw new ArgumentException($"Unknown {nameof(T)} value.", nameof(context)); + } } } diff --git a/objects/ComboBoxItem.cs b/objects/ComboBoxItem.cs new file mode 100644 index 0000000..1ebd668 --- /dev/null +++ b/objects/ComboBoxItem.cs @@ -0,0 +1,8 @@ +namespace SSMSObjectExplorerMenu.objects +{ + public class ComboBoxItem + { + public string Displayed { get; set; } + public TValue Value { get; set; } + } +} diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index e6fb76e..57f06b9 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -1,4 +1,5 @@ -using System; +using SSMSObjectExplorerMenu.enums; +using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; @@ -50,8 +51,9 @@ public string Script [Category("Menu item")] [DisplayName("Context")] [Description("Tree node level where to display menu item.")] - [DefaultValue("All")] - public string Context { get; set; } = "All"; + [DefaultValue(MenuItemContext.All)] + [TypeConverter(typeof(MenuItemContextConverter))] + public MenuItemContext Context { get; set; } = MenuItemContext.All; [Category("Menu item")] [DisplayName("User-defined parameters")] @@ -64,7 +66,7 @@ public MenuItem() } - public MenuItem(bool enabled, string context, string name, string script, bool execute, bool confirm, IEnumerable userDefinedParams = null) + public MenuItem(bool enabled, MenuItemContext context, string name, string script, bool execute, bool confirm, IEnumerable userDefinedParams = null) { Enabled = enabled; Context = context; From d293da786851cccbe76c2e2526e18dd2ddeaefb2 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 15 Sep 2025 11:04:51 +0200 Subject: [PATCH 16/29] Providing description for UserDefinedParameterType values. --- AddUserDefinedParameter.Designer.cs | 4 ++-- AddUserDefinedParameter.cs | 2 +- MenuItemContextConverter.cs | 25 +++++++++++++++++-------- enums/UserDefinedArgumentType.cs | 11 +++++++++-- objects/UserDefinedParameter.cs | 5 +++-- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/AddUserDefinedParameter.Designer.cs b/AddUserDefinedParameter.Designer.cs index 39ce8b3..269d6de 100644 --- a/AddUserDefinedParameter.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -134,9 +134,9 @@ private void InitializeComponent() this.labelCustomList.AutoSize = true; this.labelCustomList.Location = new System.Drawing.Point(3, 2); this.labelCustomList.Name = "labelCustomList"; - this.labelCustomList.Size = new System.Drawing.Size(113, 13); + this.labelCustomList.Size = new System.Drawing.Size(75, 13); this.labelCustomList.TabIndex = 9; - this.labelCustomList.Text = "List of possible values:"; + this.labelCustomList.Text = "List of options:"; // // panelCustomList // diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs index 433615d..01957f8 100644 --- a/AddUserDefinedParameter.cs +++ b/AddUserDefinedParameter.cs @@ -49,7 +49,7 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse) this.comboBoxParameterType.DataSource = Enum.GetValues(typeof(UserDefinedParameterType)) .Cast() - .Select(type => new ComboBoxItem { Displayed = Enum.GetName(typeof(UserDefinedParameterType), type), Value = type }).ToList(); + .Select(type => new ComboBoxItem { Displayed = type.ToStringDescription(), Value = type }).ToList(); this.comboBoxParameterType.DisplayMember = nameof(ComboBoxItem.Displayed); this.comboBoxParameterType.ValueMember = nameof(ComboBoxItem.Value); this.comboBoxParameterType.DataBindings.Add(nameof(comboBoxParameterType.SelectedValue), _parameter, nameof(_parameter.Type), true, DataSourceUpdateMode.OnPropertyChanged); diff --git a/MenuItemContextConverter.cs b/MenuItemContextConverter.cs index f19768e..c3bd39e 100644 --- a/MenuItemContextConverter.cs +++ b/MenuItemContextConverter.cs @@ -7,19 +7,28 @@ namespace SSMSObjectExplorerMenu { - public class MenuItemContextConverter : EnumConverter + + public class MenuItemContextConverter : EnumConverter + { + } + + public class UserDefinedArgumentTypeConverter : EnumConverter + { + } + + public abstract class EnumConverter : EnumConverter where T : Enum { - public MenuItemContextConverter() : base(typeof(MenuItemContext)) + public EnumConverter() : base(typeof(T)) { } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { - if (value is MenuItemContext && destinationType == typeof(string)) + if (value is T && destinationType == typeof(string)) { - var field = typeof(MenuItemContext).GetField(value.ToString()); + var field = typeof(T).GetField(value.ToString()); var desc = field?.GetCustomAttribute(); - return (desc?.Description) ?? throw new ArgumentException($"Unknown {typeof(MenuItemContext)} value", nameof(value)); + return (desc?.Description) ?? throw new ArgumentException($"Unknown {typeof(T)} value.", nameof(value)); } return base.ConvertTo(context, culture, value, destinationType); } @@ -28,11 +37,11 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c { if(value is string val) { - var targetField = typeof(MenuItemContext).GetFields() + var targetField = typeof(T).GetFields() .SingleOrDefault(f => f.GetCustomAttribute()?.Description == val); return targetField != null ? - Enum.Parse(typeof(MenuItemContext), targetField.Name) : - throw new ArgumentException($"Unknown {typeof(MenuItemContext)} value", nameof(value)); + Enum.Parse(typeof(T), targetField.Name) : + throw new ArgumentException($"Unknown {typeof(T)} value.", nameof(value)); } return base.ConvertFrom(context, culture, value); } diff --git a/enums/UserDefinedArgumentType.cs b/enums/UserDefinedArgumentType.cs index 3bcb568..9d97bc9 100644 --- a/enums/UserDefinedArgumentType.cs +++ b/enums/UserDefinedArgumentType.cs @@ -1,14 +1,21 @@ -namespace SSMSObjectExplorerMenu.enums +using System.ComponentModel; + +namespace SSMSObjectExplorerMenu.enums { public enum UserDefinedParameterType : byte { + [Description("uniqueidentifier")] UniqueIdentifier, + [Description("int")] Int, + [Description("nvarchar")] Nvarchar, + [Description("bit")] Bit, /// - /// This is not a SQL Server data type. Represents a list of custom values defined by the user. + /// This is not a SQL Server data type. Represents a list of options defined by the user. /// + [Description("List of options")] CustomList } } diff --git a/objects/UserDefinedParameter.cs b/objects/UserDefinedParameter.cs index dc6b8b6..0e6028b 100644 --- a/objects/UserDefinedParameter.cs +++ b/objects/UserDefinedParameter.cs @@ -19,13 +19,14 @@ public class UserDefinedParameter [DisplayName("Data type")] [Description("Data type of the user-defined parameter.")] + [TypeConverter(typeof(UserDefinedArgumentTypeConverter))] public UserDefinedParameterType Type { get; set; } /// /// Populate if is . Otherwise it's ignored. /// - [DisplayName("List of values")] - [Description("List of selectable values")] + [DisplayName("List of options")] + [Description("List of options. If the parameter's data type is not \"List of options\", it is ignored.")] [Editor(typeof(CollectionEditor), typeof(UITypeEditor))] public BindingList ValueSetOfCustomList { get; set; } = new BindingList(); From 01f9d59a2a3debf36df9152ff8944751f350710e Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 15 Sep 2025 13:14:17 +0200 Subject: [PATCH 17/29] Changing listview's view mode in AddUserDefinedParameter dialog. --- AddUserDefinedParameter.Designer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AddUserDefinedParameter.Designer.cs b/AddUserDefinedParameter.Designer.cs index 269d6de..74765a0 100644 --- a/AddUserDefinedParameter.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -108,6 +108,7 @@ private void InitializeComponent() this.listViewCustomList.Size = new System.Drawing.Size(228, 79); this.listViewCustomList.TabIndex = 6; this.listViewCustomList.UseCompatibleStateImageBehavior = false; + this.listViewCustomList.View = System.Windows.Forms.View.List; // // buttonAddCustomList // From 3117c4513c6d9e998ba2b9bbb119804e9ed8f2e2 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Tue, 16 Sep 2025 11:47:15 +0200 Subject: [PATCH 18/29] Fixing displayed text in labels, dialogs. Moving enum converters in individual files. --- AddMenuItem.cs | 2 +- AddUserDefinedParameter.cs | 2 +- ArgumentControl.cs | 3 ++- EnterUserDefinedArguments.cs | 2 +- EnumConverter.cs | 39 +++++++++++++++++++++++++++ MenuItemContextConverter.cs | 41 ----------------------------- OptionsDialogPage.cs | 2 +- SSMSObjectExplorerMenu.csproj | 2 ++ UserDefinedArgumentTypeConverter.cs | 8 ++++++ objects/UserDefinedParameter.cs | 6 ++--- 10 files changed, 58 insertions(+), 49 deletions(-) create mode 100644 EnumConverter.cs create mode 100644 UserDefinedArgumentTypeConverter.cs diff --git a/AddMenuItem.cs b/AddMenuItem.cs index dad89ad..324d928 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -115,7 +115,7 @@ private void buttonRemoveUserDefinedParam_Click(object sender, EventArgs e) { var selectedItems = this.listViewUserDefinedParam.Items.Cast().Where(item => item.Selected); if (selectedItems.Any() && - DialogResult.Yes == MessageBox.Show("Are you sure?", "Deleting parameter", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) + DialogResult.Yes == MessageBox.Show("Are you sure?", "Delete parameter", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) { foreach (var item in selectedItems) { diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs index 01957f8..86c3001 100644 --- a/AddUserDefinedParameter.cs +++ b/AddUserDefinedParameter.cs @@ -96,7 +96,7 @@ private void comboBoxParameterType_SelectedValueChanged(object sender, EventArgs private void buttonAddCustomList_Click(object sender, EventArgs e) { - this.listViewCustomList.Items.Add("New value (click to edit)..."); + this.listViewCustomList.Items.Add("New value (double-click to edit)..."); } private void buttonRemoveCustomList_Click(object sender, EventArgs e) diff --git a/ArgumentControl.cs b/ArgumentControl.cs index c9a58c6..c701577 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -1,4 +1,5 @@ using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.extensions; using SSMSObjectExplorerMenu.objects; using System; using System.Collections.Generic; @@ -74,7 +75,7 @@ public ArgumentControl(UserDefinedParameter parameter, int width) this._labelParameterName.Location = new Point(0, PADDING_TOP_BOTTOM); this._labelParameterName.Width = this.Width; - this._labelParameterName.Text = $"{Parameter.Name} ({Parameter.Type}):"; + this._labelParameterName.Text = $"{Parameter.Name} ({Parameter.Type.ToStringDescription()}):"; this.Controls.Add(this._labelParameterName); this._valueControl.Location = new Point(0, this._labelParameterName.Location.Y + this._labelParameterName.Height); diff --git a/EnterUserDefinedArguments.cs b/EnterUserDefinedArguments.cs index 744f1f0..fb5153d 100644 --- a/EnterUserDefinedArguments.cs +++ b/EnterUserDefinedArguments.cs @@ -40,7 +40,7 @@ private void buttonOK_Click(object sender, EventArgs e) { if(!TryValidate(out string validationErrorMessage)) { - MessageBox.Show(this, validationErrorMessage, "Invalid parameter value", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(this, validationErrorMessage, "Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } diff --git a/EnumConverter.cs b/EnumConverter.cs new file mode 100644 index 0000000..9e2445f --- /dev/null +++ b/EnumConverter.cs @@ -0,0 +1,39 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace SSMSObjectExplorerMenu +{ + public abstract class EnumConverter : EnumConverter where T : Enum + { + public EnumConverter() : base(typeof(T)) + { + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (value is T && destinationType == typeof(string)) + { + var field = typeof(T).GetField(value.ToString()); + var desc = field?.GetCustomAttribute(); + return (desc?.Description) ?? throw new ArgumentException($"Unknown {typeof(T)} value.", nameof(value)); + } + return base.ConvertTo(context, culture, value, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string val) + { + var targetField = typeof(T).GetFields() + .SingleOrDefault(f => f.GetCustomAttribute()?.Description == val); + return targetField != null ? + Enum.Parse(typeof(T), targetField.Name) : + throw new ArgumentException($"Unknown {typeof(T)} value.", nameof(value)); + } + return base.ConvertFrom(context, culture, value); + } + } +} diff --git a/MenuItemContextConverter.cs b/MenuItemContextConverter.cs index c3bd39e..4a2ff88 100644 --- a/MenuItemContextConverter.cs +++ b/MenuItemContextConverter.cs @@ -1,49 +1,8 @@ using SSMSObjectExplorerMenu.enums; -using System; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Reflection; namespace SSMSObjectExplorerMenu { - public class MenuItemContextConverter : EnumConverter { } - - public class UserDefinedArgumentTypeConverter : EnumConverter - { - } - - public abstract class EnumConverter : EnumConverter where T : Enum - { - public EnumConverter() : base(typeof(T)) - { - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value is T && destinationType == typeof(string)) - { - var field = typeof(T).GetField(value.ToString()); - var desc = field?.GetCustomAttribute(); - return (desc?.Description) ?? throw new ArgumentException($"Unknown {typeof(T)} value.", nameof(value)); - } - return base.ConvertTo(context, culture, value, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if(value is string val) - { - var targetField = typeof(T).GetFields() - .SingleOrDefault(f => f.GetCustomAttribute()?.Description == val); - return targetField != null ? - Enum.Parse(typeof(T), targetField.Name) : - throw new ArgumentException($"Unknown {typeof(T)} value.", nameof(value)); - } - return base.ConvertFrom(context, culture, value); - } - } } diff --git a/OptionsDialogPage.cs b/OptionsDialogPage.cs index 12a42ed..7ec5619 100644 --- a/OptionsDialogPage.cs +++ b/OptionsDialogPage.cs @@ -135,7 +135,7 @@ private void ShowValidationErrorDialog(List validationErrors builder.AppendLine($"Menu item '{error.MenuItemName}': {error.ErrorMessage}"); } // TODO: more advanced error dialog? - MessageBox.Show(builder.ToString(), "SSMS Object Explorer Menu - Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(builder.ToString(), "SSMS Object Explorer Menu | Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } diff --git a/SSMSObjectExplorerMenu.csproj b/SSMSObjectExplorerMenu.csproj index d9f1a93..cf82128 100644 --- a/SSMSObjectExplorerMenu.csproj +++ b/SSMSObjectExplorerMenu.csproj @@ -83,6 +83,7 @@ EnterUserDefinedArguments.cs + @@ -96,6 +97,7 @@ + diff --git a/UserDefinedArgumentTypeConverter.cs b/UserDefinedArgumentTypeConverter.cs new file mode 100644 index 0000000..ac9299b --- /dev/null +++ b/UserDefinedArgumentTypeConverter.cs @@ -0,0 +1,8 @@ +using SSMSObjectExplorerMenu.enums; + +namespace SSMSObjectExplorerMenu +{ + public class UserDefinedArgumentTypeConverter : EnumConverter + { + } +} diff --git a/objects/UserDefinedParameter.cs b/objects/UserDefinedParameter.cs index 0e6028b..16daebf 100644 --- a/objects/UserDefinedParameter.cs +++ b/objects/UserDefinedParameter.cs @@ -42,15 +42,15 @@ public bool TryValidate(out IEnumerable validationErrors, IEnumerable string.IsNullOrWhiteSpace(value))) { - errors.Add("Value set of CustomList parameter cannot contain empty or whitespace-only elements."); + errors.Add("List of options cannot contain empty or whitespace-only elements."); } if(ValueSetOfCustomList.Distinct(new StringListItemComparer(StringComparison.OrdinalIgnoreCase)).Count() != ValueSetOfCustomList.Count) { - errors.Add("Value set of CustomList parameter cannot have duplicate elements."); + errors.Add("List of options cannot have duplicate elements."); } } From 76c36c53359d1cc812d49438c994ca2d9f92e71c Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Tue, 16 Sep 2025 16:44:40 +0200 Subject: [PATCH 19/29] Enabling/disabling the dialog buttons instead of displaying error popup. Allowin editing parameters on the AddMenuItem dialog. --- AddMenuItem.Designer.cs | 19 ++++++++++++- AddMenuItem.cs | 41 ++++++++++++++++++++++------- AddUserDefinedParameter.Designer.cs | 4 ++- AddUserDefinedParameter.cs | 21 +++++++++++++-- extensions/UIExtensions.cs | 3 +++ 5 files changed, 75 insertions(+), 13 deletions(-) diff --git a/AddMenuItem.Designer.cs b/AddMenuItem.Designer.cs index 44be659..39c5d0a 100644 --- a/AddMenuItem.Designer.cs +++ b/AddMenuItem.Designer.cs @@ -49,6 +49,7 @@ private void InitializeComponent() this.buttonAddUserDefinedParam = new System.Windows.Forms.Button(); this.buttonRemoveUserDefinedParam = new System.Windows.Forms.Button(); this.labelUserDefinedParameters = new System.Windows.Forms.Label(); + this.buttonEditUserDefinedParameter = new System.Windows.Forms.Button(); this.SuspendLayout(); // // buttonCancel @@ -217,6 +218,7 @@ private void InitializeComponent() this.listViewUserDefinedParam.TabIndex = 15; this.listViewUserDefinedParam.UseCompatibleStateImageBehavior = false; this.listViewUserDefinedParam.View = System.Windows.Forms.View.Details; + this.listViewUserDefinedParam.SelectedIndexChanged += new System.EventHandler(this.listViewUserDefinedParam_SelectedIndexChanged); // // ParameterName // @@ -242,7 +244,8 @@ private void InitializeComponent() // buttonRemoveUserDefinedParam // this.buttonRemoveUserDefinedParam.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonRemoveUserDefinedParam.Location = new System.Drawing.Point(444, 164); + this.buttonRemoveUserDefinedParam.Enabled = false; + this.buttonRemoveUserDefinedParam.Location = new System.Drawing.Point(445, 193); this.buttonRemoveUserDefinedParam.Name = "buttonRemoveUserDefinedParam"; this.buttonRemoveUserDefinedParam.Size = new System.Drawing.Size(75, 23); this.buttonRemoveUserDefinedParam.TabIndex = 18; @@ -259,11 +262,24 @@ private void InitializeComponent() this.labelUserDefinedParameters.TabIndex = 19; this.labelUserDefinedParameters.Text = "List of user-defined parameters:"; // + // buttonEditUserDefinedParameter + // + this.buttonEditUserDefinedParameter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonEditUserDefinedParameter.Enabled = false; + this.buttonEditUserDefinedParameter.Location = new System.Drawing.Point(444, 164); + this.buttonEditUserDefinedParameter.Name = "buttonEditUserDefinedParameter"; + this.buttonEditUserDefinedParameter.Size = new System.Drawing.Size(75, 23); + this.buttonEditUserDefinedParameter.TabIndex = 20; + this.buttonEditUserDefinedParameter.Text = "Edit"; + this.buttonEditUserDefinedParameter.UseVisualStyleBackColor = true; + this.buttonEditUserDefinedParameter.Click += new System.EventHandler(this.buttonEditUserDefinedParam_Click); + // // AddMenuItem // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(531, 540); + this.Controls.Add(this.buttonEditUserDefinedParameter); this.Controls.Add(this.labelUserDefinedParameters); this.Controls.Add(this.buttonRemoveUserDefinedParam); this.Controls.Add(this.buttonAddUserDefinedParam); @@ -313,5 +329,6 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonAddUserDefinedParam; private System.Windows.Forms.Button buttonRemoveUserDefinedParam; private System.Windows.Forms.Label labelUserDefinedParameters; + private System.Windows.Forms.Button buttonEditUserDefinedParameter; } } \ No newline at end of file diff --git a/AddMenuItem.cs b/AddMenuItem.cs index 324d928..b5a697b 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -2,6 +2,7 @@ using SSMSObjectExplorerMenu.extensions; using SSMSObjectExplorerMenu.objects; using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Windows.Forms; @@ -99,9 +100,7 @@ private void checkExecute_CheckedChanged(object sender, EventArgs e) private void buttonAddUserDefinedParam_Click(object sender, EventArgs e) { - var argumentNamesInUse = this.listViewUserDefinedParam.Items.Cast().Select(item => item.Text) - .Concat(Utils.ParametersFromContext); - var addDialog = new AddUserDefinedParameter(argumentNamesInUse); + var addDialog = new AddUserDefinedParameter(GetArgumentNamesInUse()); if (addDialog.ShowDialog() == DialogResult.OK) { var newParam = addDialog.Parameter; @@ -111,21 +110,45 @@ private void buttonAddUserDefinedParam_Click(object sender, EventArgs e) } } + private void buttonEditUserDefinedParam_Click(object sender, EventArgs e) + { + var selectedItem = this.listViewUserDefinedParam.GetSelectedItems().SingleOrDefault(); + if (selectedItem != null) + { + var editDialog = new AddUserDefinedParameter(GetArgumentNamesInUse(), true, (UserDefinedParameter)selectedItem.Tag); + if (editDialog.ShowDialog() == DialogResult.OK) + { + var editedParam = editDialog.Parameter; + selectedItem.Text = editedParam.Name; + selectedItem.SubItems[1].Text = Enum.GetName(typeof(UserDefinedParameterType), editedParam.Type); + selectedItem.Tag = editedParam; + } + } + } + private void buttonRemoveUserDefinedParam_Click(object sender, EventArgs e) { - var selectedItems = this.listViewUserDefinedParam.Items.Cast().Where(item => item.Selected); + var selectedItems = this.listViewUserDefinedParam.GetSelectedItems(); if (selectedItems.Any() && - DialogResult.Yes == MessageBox.Show("Are you sure?", "Delete parameter", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) + DialogResult.Yes == MessageBox.Show("Are you sure?", "Delete parameter(s)", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) { foreach (var item in selectedItems) { this.listViewUserDefinedParam.Items.Remove(item); } } - else - { - MessageBox.Show("You must select an item to delete.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } } + + private void listViewUserDefinedParam_SelectedIndexChanged(object sender, EventArgs e) + { + this.BeginInvoke((Action)(() => + { + var selectedItemsCount = this.listViewUserDefinedParam.GetSelectedItems().Count(); + this.buttonEditUserDefinedParameter.Enabled = selectedItemsCount == 1; + this.buttonRemoveUserDefinedParam.Enabled = selectedItemsCount > 0; + })); + } + + private IEnumerable GetArgumentNamesInUse() => this.listViewUserDefinedParam.Items.Cast().Select(item => item.Text).Concat(Utils.ParametersFromContext); } } diff --git a/AddUserDefinedParameter.Designer.cs b/AddUserDefinedParameter.Designer.cs index 74765a0..4d64815 100644 --- a/AddUserDefinedParameter.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -109,6 +109,7 @@ private void InitializeComponent() this.listViewCustomList.TabIndex = 6; this.listViewCustomList.UseCompatibleStateImageBehavior = false; this.listViewCustomList.View = System.Windows.Forms.View.List; + this.listViewCustomList.SelectedIndexChanged += new System.EventHandler(this.listViewCustomList_SelectedIndexChanged); // // buttonAddCustomList // @@ -122,6 +123,7 @@ private void InitializeComponent() // // buttonRemoveCustomList // + this.buttonRemoveCustomList.Enabled = false; this.buttonRemoveCustomList.Location = new System.Drawing.Point(234, 45); this.buttonRemoveCustomList.Name = "buttonRemoveCustomList"; this.buttonRemoveCustomList.Size = new System.Drawing.Size(23, 23); @@ -170,7 +172,7 @@ private void InitializeComponent() this.MinimizeBox = false; this.Name = "AddUserDefinedParameter"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Adding new user-defined parameter..."; + this.Text = "Adding user-defined parameter..."; this.panelCustomList.ResumeLayout(false); this.panelCustomList.PerformLayout(); this.ResumeLayout(false); diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs index 86c3001..872b1b0 100644 --- a/AddUserDefinedParameter.cs +++ b/AddUserDefinedParameter.cs @@ -36,12 +36,17 @@ public UserDefinedParameter Parameter } } - public AddUserDefinedParameter(IEnumerable paramNamesInUse) + public AddUserDefinedParameter(IEnumerable paramNamesInUse, bool edit = false, UserDefinedParameter parameterToEdit = null) { + if(edit && parameterToEdit is null) + { + throw new ArgumentNullException(nameof(parameterToEdit), "Parameter to edit must be provided when edit is true."); + } + InitializeComponent(); _parameter = new ParameterItem { Name = string.Empty, Type = UserDefinedParameterType.UniqueIdentifier }; - _paramNamesInUse = paramNamesInUse; + _paramNamesInUse = !edit ? paramNamesInUse : paramNamesInUse.Except(new[] { parameterToEdit.Name }); this.textBoxParameterName.MaxLength = UserDefinedParameter.NAME_MAX_LENGTH; this.textBoxParameterName.DataBindings.Add(nameof(textBoxParameterName.Text), _parameter, nameof(_parameter.Name), true, DataSourceUpdateMode.OnPropertyChanged); @@ -53,6 +58,14 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse) this.comboBoxParameterType.DisplayMember = nameof(ComboBoxItem.Displayed); this.comboBoxParameterType.ValueMember = nameof(ComboBoxItem.Value); this.comboBoxParameterType.DataBindings.Add(nameof(comboBoxParameterType.SelectedValue), _parameter, nameof(_parameter.Type), true, DataSourceUpdateMode.OnPropertyChanged); + + if(edit) + { + _parameter.Name = parameterToEdit.Name; + _parameter.Type = parameterToEdit.Type; + this.listViewCustomList.Items.AddRange(parameterToEdit.ValueSetOfCustomList.Select(item => new ListViewItem(item.Value)).ToArray()); + this.Text = "Edit user-defined parameter..."; + } } private void buttonSave_Click(object sender, EventArgs e) @@ -104,6 +117,10 @@ private void buttonRemoveCustomList_Click(object sender, EventArgs e) var selectedItems = this.listViewCustomList.Items.Cast().Where(item => item.Selected); this.listViewCustomList.Items.RemoveRange(selectedItems); } + private void listViewCustomList_SelectedIndexChanged(object sender, EventArgs e) + { + this.BeginInvoke((Action)(() => this.buttonRemoveCustomList.Enabled = this.listViewCustomList.GetSelectedItems().Any())); + } class ParameterItem { diff --git a/extensions/UIExtensions.cs b/extensions/UIExtensions.cs index de113ea..0d58367 100644 --- a/extensions/UIExtensions.cs +++ b/extensions/UIExtensions.cs @@ -1,5 +1,6 @@ using SSMSObjectExplorerMenu.objects; using System.Collections.Generic; +using System.Linq; using System.Windows.Forms; namespace SSMSObjectExplorerMenu.extensions @@ -24,5 +25,7 @@ public static void RemoveRange(this ListView.ListViewItemCollection litViewItems litViewItems.Remove(item); } } + + public static IEnumerable GetSelectedItems(this ListView listView) => listView.Items.Cast().Where(item => item.Selected); } } From 63878255a29dc172d6bc81464e3d7c621d5f2386 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 9 Oct 2025 16:35:36 +0200 Subject: [PATCH 20/29] Fixing XML export / import: - displaying the full path in the Context field of the exported XML - accepting string containing the full path to parse the appropriate MenuItemContext value. --- extensions/Extensions.cs | 20 +++++++++++++++++++- objects/MenuItem.cs | 11 +++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/extensions/Extensions.cs b/extensions/Extensions.cs index 5b1d677..2a5e09a 100644 --- a/extensions/Extensions.cs +++ b/extensions/Extensions.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.IO; +using System.Linq; using System.Text.RegularExpressions; using System.Xml.Serialization; @@ -150,5 +151,22 @@ public static string ToStringDescription(this T context) where T : Enum } throw new ArgumentException($"Unknown {nameof(T)} value.", nameof(context)); } - } + + public static T FromDescription(this string enumDescription) where T : Enum + { + if (enumDescription == null) + { + throw new ArgumentNullException(nameof(enumDescription)); + } + + var enumField = typeof(T).GetFields() + .SingleOrDefault(f => enumDescription.Equals( + (Attribute.GetCustomAttribute(f, typeof(DescriptionAttribute)) as DescriptionAttribute)?.Description, + StringComparison.OrdinalIgnoreCase)); + + return enumField != null + ? (T)enumField.GetValue(null) + : throw new ArgumentException($"Unknown {nameof(T)} description.", nameof(enumDescription)); + } + } } diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index 57f06b9..20c78de 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -1,10 +1,12 @@ using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.extensions; using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing.Design; using System.Linq; +using System.Xml.Serialization; namespace SSMSObjectExplorerMenu.objects { @@ -53,8 +55,17 @@ public string Script [Description("Tree node level where to display menu item.")] [DefaultValue(MenuItemContext.All)] [TypeConverter(typeof(MenuItemContextConverter))] + [XmlIgnore] public MenuItemContext Context { get; set; } = MenuItemContext.All; + [Browsable(false)] + [XmlElement("Context")] + public string ContextDescription + { + get => Context.ToStringDescription(); + set => Context = value.FromDescription(); + } + [Category("Menu item")] [DisplayName("User-defined parameters")] [Description("List of user-deifned parameters can be used in the T-SQL script.")] From 60f643afda9eab83df8a91e0a8868c3aeba2f51e Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Wed, 15 Oct 2025 16:01:13 +0200 Subject: [PATCH 21/29] Refactoring, adding explanation comments. Minor UI changes. Fix the issue when validation threw an exception in case the user did not enter anything for parameter name (UserDefinedParameter.cs) --- AddMenuItem.cs | 1 + AddUserDefinedParameter.Designer.cs | 2 +- AddUserDefinedParameter.cs | 47 ++++++++++++++--------------- ArgumentControl.cs | 41 +++++++++++++------------ EnterUserDefinedArguments.cs | 21 ++++--------- OptionsDialogPage.cs | 24 +++++---------- SSMSObjectExplorerMenu.cs | 4 +-- objects/MenuItem.cs | 20 +++++------- objects/StringListItem.cs | 3 +- objects/UserDefinedParameter.cs | 8 ++--- 10 files changed, 74 insertions(+), 97 deletions(-) diff --git a/AddMenuItem.cs b/AddMenuItem.cs index b5a697b..9ea3d20 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -141,6 +141,7 @@ private void buttonRemoveUserDefinedParam_Click(object sender, EventArgs e) private void listViewUserDefinedParam_SelectedIndexChanged(object sender, EventArgs e) { + // In case of removing items, a minimal delay is needed to work with the state of the listview after the item has been removed. this.BeginInvoke((Action)(() => { var selectedItemsCount = this.listViewUserDefinedParam.GetSelectedItems().Count(); diff --git a/AddUserDefinedParameter.Designer.cs b/AddUserDefinedParameter.Designer.cs index 4d64815..eae42a6 100644 --- a/AddUserDefinedParameter.Designer.cs +++ b/AddUserDefinedParameter.Designer.cs @@ -172,7 +172,7 @@ private void InitializeComponent() this.MinimizeBox = false; this.Name = "AddUserDefinedParameter"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Adding user-defined parameter..."; + this.Text = "Add user-defined parameter..."; this.panelCustomList.ResumeLayout(false); this.panelCustomList.PerformLayout(); this.ResumeLayout(false); diff --git a/AddUserDefinedParameter.cs b/AddUserDefinedParameter.cs index 872b1b0..da4f417 100644 --- a/AddUserDefinedParameter.cs +++ b/AddUserDefinedParameter.cs @@ -19,20 +19,11 @@ public UserDefinedParameter Parameter { get { - if (!TryValidate(out List _) || this.DialogResult != DialogResult.OK) + if (!TryValidate(out UserDefinedParameter parameter, out List _) || this.DialogResult != DialogResult.OK) { throw new InvalidOperationException("Dialog is in invalid state."); } - return new UserDefinedParameter - { - Name = _parameter.Name, - Type = _parameter.Type, - ValueSetOfCustomList = new BindingList( - _parameter.Type == UserDefinedParameterType.CustomList ? - this.listViewCustomList.Items.Cast().Select(item => new StringListItem(item.Text)).ToList() : - new List() - ) - }; + return parameter; } } @@ -40,7 +31,7 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse, bool edit = { if(edit && parameterToEdit is null) { - throw new ArgumentNullException(nameof(parameterToEdit), "Parameter to edit must be provided when edit is true."); + throw new ArgumentNullException(nameof(parameterToEdit), $"Parameter '{nameof(parameterToEdit)}' must not be null if patameter '{nameof(edit)}' is set to true."); } InitializeComponent(); @@ -70,7 +61,7 @@ public AddUserDefinedParameter(IEnumerable paramNamesInUse, bool edit = private void buttonSave_Click(object sender, EventArgs e) { - if (!TryValidate(out List validationErrors)) + if (!TryValidate(out UserDefinedParameter _, out List validationErrors)) { var errorMessageBuilder = new StringBuilder(); validationErrors.ForEach(error => errorMessageBuilder.AppendLine(error)); @@ -81,22 +72,26 @@ private void buttonSave_Click(object sender, EventArgs e) this.DialogResult = DialogResult.OK; } - private bool TryValidate(out List validationErros) + private bool TryValidate(out UserDefinedParameter validatedParameter, out List validationErrors) { - var paramBuiltFromDialog = new UserDefinedParameter - { - Name = _parameter.Name, - Type = _parameter.Type, - ValueSetOfCustomList = new BindingList( + var parameter = BuildParameter(); + validationErrors = !parameter.TryValidate(out IEnumerable errors, _paramNamesInUse) ? errors.ToList() : new List(); + + bool success = !validationErrors.Any(); + validatedParameter = success ? parameter : null; + return success; + } + + private UserDefinedParameter BuildParameter() => new UserDefinedParameter + { + Name = _parameter.Name, + Type = _parameter.Type, + ValueSetOfCustomList = new BindingList( _parameter.Type == UserDefinedParameterType.CustomList ? this.listViewCustomList.Items.Cast().Select(item => new StringListItem(item.Text)).ToList() : new List() ) - }; - - validationErros = !paramBuiltFromDialog.TryValidate(out IEnumerable errors, _paramNamesInUse) ? errors.ToList() : new List(); - return !validationErros.Any(); - } + }; private void comboBoxParameterType_SelectedValueChanged(object sender, EventArgs e) { @@ -119,6 +114,10 @@ private void buttonRemoveCustomList_Click(object sender, EventArgs e) } private void listViewCustomList_SelectedIndexChanged(object sender, EventArgs e) { + // In case of removing list items: + // This method is called shortly before the listview item is actually removed. + // So the collection returned by GetSelectedItems() contains also the item to remove. + // A very minor delay is needed to have the correct state of the listview. this.BeginInvoke((Action)(() => this.buttonRemoveCustomList.Enabled = this.listViewCustomList.GetSelectedItems().Any())); } diff --git a/ArgumentControl.cs b/ArgumentControl.cs index c701577..042905c 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -32,8 +32,6 @@ public string ParameterValueString } } - public Func Validator { get; private set; } - public ArgumentControl(UserDefinedParameter parameter, int width) { if(!parameter.TryValidate(out IEnumerable _)) @@ -67,7 +65,7 @@ public ArgumentControl(UserDefinedParameter parameter, int width) Init_CustomList(); break; default: - throw new ArgumentException("Parameter type is not known.", nameof(Parameter.Type)); + throw new ArgumentException("Parameter type is not known.", nameof(Parameter)); } this._labelParameterName = new Label(); @@ -83,6 +81,23 @@ public ArgumentControl(UserDefinedParameter parameter, int width) this.Controls.Add(this._valueControl); } + public bool IsValid() + { + switch (Parameter.Type) + { + case UserDefinedParameterType.UniqueIdentifier: + return Guid.TryParse(_valueControl.Text, out _); + case UserDefinedParameterType.Nvarchar: + return !string.IsNullOrWhiteSpace(_valueControl.Text); + case UserDefinedParameterType.Int: + case UserDefinedParameterType.Bit: + case UserDefinedParameterType.CustomList: + return true; + default: + throw new NotImplementedException($"Validation for parameter type {Parameter.Type} has not been implemented."); + } + } + private void Init_Uniqueidentifier() { var guidTextBox = new TextBox(); @@ -90,7 +105,6 @@ private void Init_Uniqueidentifier() guidTextBox.Text = string.Empty; _valueControl = guidTextBox; - Validator = Validate_Uniqueidentifier; } private void Init_Nvarchar() @@ -99,31 +113,18 @@ private void Init_Nvarchar() textBox.Text = string.Empty; _valueControl = textBox; - Validator = Validate_Nvarchar; } - private void Init_Int() - { - _valueControl = new NumericUpDown(); - Validator = () => true; - } + private void Init_Int() => _valueControl = new NumericUpDown(); + + private void Init_Bit() => _valueControl = new CheckBox(); - private void Init_Bit() - { - _valueControl = new CheckBox(); - Validator = () => true; - } private void Init_CustomList() { var comboBox = new ComboBox(); comboBox.DataSource = Parameter.ValueSetOfCustomList; _valueControl = comboBox; - Validator = () => true; } - - private bool Validate_Uniqueidentifier() => Guid.TryParse(_valueControl.Text, out _); - - private bool Validate_Nvarchar() => !string.IsNullOrWhiteSpace(_valueControl.Text); } } diff --git a/EnterUserDefinedArguments.cs b/EnterUserDefinedArguments.cs index fb5153d..c668cc2 100644 --- a/EnterUserDefinedArguments.cs +++ b/EnterUserDefinedArguments.cs @@ -19,7 +19,7 @@ public partial class EnterUserDefinedArguments : Form public IEnumerable UserDefinedArguments { get { - if(!TryValidate(out string _) || this.DialogResult != DialogResult.OK) + if(!TryValidate(out IEnumerable _) || this.DialogResult != DialogResult.OK) { throw new InvalidOperationException("Dialog is in invalid state."); } @@ -38,28 +38,19 @@ public EnterUserDefinedArguments(IEnumerable parameters) private void buttonOK_Click(object sender, EventArgs e) { - if(!TryValidate(out string validationErrorMessage)) + if(!TryValidate(out IEnumerable invalidArguments)) { - MessageBox.Show(this, validationErrorMessage, "Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(this, $"The following parameters have invalid values: {string.Join(", ", invalidArguments)}.", "Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } this.DialogResult = DialogResult.OK; } - private bool TryValidate(out string validationErrorMessage) + private bool TryValidate(out IEnumerable invalidArguments) { - foreach (var ac in _argumentControls) - { - if (!ac.Validator()) - { - validationErrorMessage = $"The value for parameter '{ac.Parameter.Name}' ({ac.Parameter.Type}) is not valid!"; - return false; - } - } - - validationErrorMessage = null; - return true; + invalidArguments = _argumentControls.Where(ac => !ac.IsValid()).Select(ac => ac.Parameter.Name); + return !invalidArguments.Any(); } } } diff --git a/OptionsDialogPage.cs b/OptionsDialogPage.cs index 7ec5619..8eaae5d 100644 --- a/OptionsDialogPage.cs +++ b/OptionsDialogPage.cs @@ -67,7 +67,7 @@ public override void LoadSettingsFromStorage() { base.LoadSettingsFromStorage(); - if (MenuItemsXml.Length > 0) + if (MenuItems.Count == 0 && MenuItemsXml.Length > 0) { try { @@ -103,24 +103,17 @@ protected override void OnApply(PageApplyEventArgs e) { ShowValidationErrorDialog(validationErrors); e.ApplyBehavior = ApplyKind.CancelNoNavigate; - return; } - - // Calls SaveSettingsToStorage - base.OnApply(e); - } + else base.OnApply(e); // Calls SaveSettingsToStorage + } private bool TryValidate(out List validationErrors) { - validationErrors = new List(); - foreach (var menuItem in MenuItems) - { - if (!menuItem.TryValidate(out IEnumerable errors)) - { - validationErrors.AddRange(errors); - } - } - return !validationErrors.Any(); + validationErrors = MenuItems.Select(mi => mi.TryValidate(out IEnumerable errors) ? null : errors) + .Where(e => e != null) + .SelectMany(e => e) + .ToList(); + return !validationErrors.Any(); } private void ShowValidationErrorDialog(List validationErrors) @@ -134,7 +127,6 @@ private void ShowValidationErrorDialog(List validationErrors { builder.AppendLine($"Menu item '{error.MenuItemName}': {error.ErrorMessage}"); } - // TODO: more advanced error dialog? MessageBox.Show(builder.ToString(), "SSMS Object Explorer Menu | Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } diff --git a/SSMSObjectExplorerMenu.cs b/SSMSObjectExplorerMenu.cs index ad9e000..167a808 100644 --- a/SSMSObjectExplorerMenu.cs +++ b/SSMSObjectExplorerMenu.cs @@ -343,14 +343,14 @@ private async Task Menu_ClickAsync(object sender, EventArgs e) IEnumerable<(string Parameter, string Value)> userDefinedArgs = Enumerable.Empty<(string, string)>(); var userDefinedParams = itemInstance.MenuItem.UserDefinedParameters; - if (userDefinedParams?.Any() ?? false) + if (userDefinedParams.Any()) { var enterArgumentsDialog = new EnterUserDefinedArguments(userDefinedParams); if (DialogResult.OK == enterArgumentsDialog.ShowDialog()) { userDefinedArgs = enterArgumentsDialog.UserDefinedArguments.Select(arg => ($"{{{arg.Name}}}", arg.ValueAsString)); } - // Abort in case the user pressed on Cancel + // Abort if the user pressed Cancel else return; } diff --git a/objects/MenuItem.cs b/objects/MenuItem.cs index 20c78de..ed6a074 100644 --- a/objects/MenuItem.cs +++ b/objects/MenuItem.cs @@ -98,19 +98,13 @@ public MenuItem(bool enabled, MenuItemContext context, string name, string scrip public bool TryValidate(out IEnumerable validationErrors) { - var errorList = new List(); - - foreach(var param in UserDefinedParameters) - { - var otherParamNames = UserDefinedParameters.Where(p => p != param).Select(p => p.Name); - if(!param.TryValidate(out IEnumerable paramErrors, Utils.ParametersFromContext.Concat(otherParamNames))) - { - errorList.Add(new MenuItemErrorModel { MenuItemName = Name, ErrorMessages = paramErrors }); - } - } - - validationErrors = errorList; - return !errorList.Any(); + validationErrors = + UserDefinedParameters.Select( + // reserved names: names coming from context + names of other user-defined parameters of the MenuItem + p => p.TryValidate(out IEnumerable paramErrors, Utils.ParametersFromContext.Concat(UserDefinedParameters.Where(pa => pa != p).Select(pa => pa.Name))) + ? null : new MenuItemErrorModel { MenuItemName = Name, ErrorMessages = paramErrors }) + .Where(e => e != null); + return !validationErrors.Any(); } } } diff --git a/objects/StringListItem.cs b/objects/StringListItem.cs index 70d64e0..b4e99db 100644 --- a/objects/StringListItem.cs +++ b/objects/StringListItem.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json.Linq; -using System; +using System; using System.Collections.Generic; namespace SSMSObjectExplorerMenu.objects diff --git a/objects/UserDefinedParameter.cs b/objects/UserDefinedParameter.cs index 16daebf..12155d6 100644 --- a/objects/UserDefinedParameter.cs +++ b/objects/UserDefinedParameter.cs @@ -42,15 +42,15 @@ public bool TryValidate(out IEnumerable validationErrors, IEnumerable string.IsNullOrWhiteSpace(value))) { - errors.Add("List of options cannot contain empty or whitespace-only elements."); + errors.Add($"Parameter '{Name}': list of options cannot contain empty or whitespace-only elements."); } if(ValueSetOfCustomList.Distinct(new StringListItemComparer(StringComparison.OrdinalIgnoreCase)).Count() != ValueSetOfCustomList.Count) { - errors.Add("List of options cannot have duplicate elements."); + errors.Add($"Parameter '{Name}': list of options cannot have duplicate elements."); } } @@ -66,7 +66,7 @@ public static bool TryValidateName(string parameterName, out IEnumerable { errors.Add("User-defined parameter name cannot be null or whitespace."); } - if (parameterName.Length > NAME_MAX_LENGTH) + if (parameterName?.Length > NAME_MAX_LENGTH) { errors.Add($"User-defined parameter name cannot be longer than {NAME_MAX_LENGTH} characters."); } From e35bbcfb36692fc9b6a143e6050c4b7aabd198b5 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 16 Oct 2025 10:08:48 +0200 Subject: [PATCH 22/29] Small fix for displaying user-defined parameter's type in the add menu item dialog. --- AddMenuItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AddMenuItem.cs b/AddMenuItem.cs index 9ea3d20..c1a9399 100644 --- a/AddMenuItem.cs +++ b/AddMenuItem.cs @@ -105,7 +105,7 @@ private void buttonAddUserDefinedParam_Click(object sender, EventArgs e) { var newParam = addDialog.Parameter; var newListViewItem = new ListViewItem { Text = newParam.Name, Tag = newParam }; - newListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem { Text = Enum.GetName(typeof(UserDefinedParameterType), newParam.Type) }); + newListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem { Text = newParam.Type.ToStringDescription() }); listViewUserDefinedParam.Items.Add(newListViewItem); } } From 7b2b9597e8b5ee9d5828fc76f1a7a634d4f90816 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 16 Oct 2025 10:11:19 +0200 Subject: [PATCH 23/29] Updating README. --- README.md | 43 ++++++++++++++++++++++++++++++++--- images/AddMenuItem.png | Bin 23502 -> 44622 bytes images/Options.png | Bin 76895 -> 63404 bytes images/Options_parameter.png | Bin 0 -> 39591 bytes 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 images/Options_parameter.png diff --git a/README.md b/README.md index cbc27a4..e5ba6a4 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Object Explorer Menu is a free, open-source extension for SQL Server Management These menu items can be configured to run either external T-SQL script files or inline T-SQL statements. Upon selection, the extension opens a new query window displaying the script. It also supports tag substitution within scripts and optional automatic execution, streamlining routine database tasks and enhancing productivity. +Adding own parameters to the menu items are also supported. Every menu item can have its own list of them. Their values can be enetered in a dialog before the T-SQL script's execution. + The project homepage is [https://sqlmedic.com](https://sqlmedic.com). [![GitHub release (latest by date)](https://img.shields.io/github/v/release/brink-daniel/ssms-object-explorer-menu)](https://github.com/brink-daniel/ssms-object-explorer-menu/releases) @@ -31,9 +33,10 @@ Once the Object Explorer Menu extension is installed, new menu items can be adde 1. Right-click on the node in the Object Explorer where you would like to add a context menu item and select `New` from the `My Scripts` menu. ![Object Explorer](images/ObjectExplorer.png) ![Add Menu Item](images/AddMenuItem.png) + 2. Open the Options dialog window in SSMS `Tools > Options > SQL Server Object Explorer > SSMS Object Explorer Menu` and add new menu items to the collection. Menu items can also be rearranged or removed using the Options dialog. ![Options Dialog](images/Options.png) - + ![Options Dialog](images/Options_parameter.png) ## Settings @@ -57,11 +60,14 @@ The following settings are available for each menu item: * Execute - Automatically run the selected script or tsql statements when the menu item is selected. * Name - Text displayed on the menu item. * Script - Inline tsql statements OR path to script file. +* User-defined parameters - list of custom parameters. They can be interpreted as a custom tag. The main difference is that their substitution values are not taken from the execution context - the user can enter them, before the T-SQL script will be run. ### Text substitution -The following tags are replaced in tsql scripts and statements before execution: +#### Tags of the execution context + +The following tags are replaced in T-SQL scripts and statements before execution: * `{SERVER}` * `{DATABASE}` @@ -76,6 +82,31 @@ The following tags are replaced in tsql scripts and statements before execution: * `{YYYY-MM-DD HH:mm:ss}` * `{OBJECT}` +#### User-defined parameters (tags) + +Every menu item can have a set of additional parameters if needed. They can be defined at the time when the menu item is added and can be edited later in the Options grid. Each of them must have a unique name and a (data) type. + +When adding a parameter, do not wrap its name in curly braces. It will be wrapped automatically when looking for the parameter during text substitution in the T-SQL script. + +* Use form without braces when giving a name for a parameter: `MY_CUSTOM_PARAM`. +* However, wrap the parameter name in braces in the T-SQL script: `{MY_CUSTOM_PARAM}`. + +The following rules are applied on parameter names: + +* A menu item cannot have two parameters having the same name (two names differ only in casing are considered as equal). +* Tag names of the execution context (like `{SERVER}`, `{DATABASE}`, etc.) cannot be used as a custom parameter name. + +A custom parameter can have one of the below types: + +* uniqueidentifier +* int +* nvarchar +* bit +* List of options + +The list of options can't have duplicate elements. + +These user-defined parameters are substituted the same way like the tags of the execution context. #### Example 1 @@ -85,7 +116,7 @@ select , '{DATABASE}' as [database] , '{SCHEMA}' as [schema] , '{TABLE}' as [table] - , '{VIEW}' as [view] + , '{VIEW}' as [view] , '{STORED_PROCEDURE}' as [stored_procedure] , '{FUNCTION}' as [function] , '{JOB}' as [job] @@ -103,7 +134,13 @@ select top 10 from {DATABASE}.{SCHEMA}.{TABLE} ``` +#### Example 3 +```sql +-- {OBJECT_TYPE} and {NAME_FILTER_EXP} are user-defined (custom) parameters +select * from sys.objects +where type_desc = '{OBJECT_TYPE}' and name like '{NAME_FILTER_EXP}'; +``` ## Compatibility diff --git a/images/AddMenuItem.png b/images/AddMenuItem.png index 0279bf43d9f141995c8960d6dd0669c215a01fe7..8c5e92270e59322fc136462d547cf91f41cc786b 100644 GIT binary patch literal 44622 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 literal 23502 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 KJDY68h4Ehslm?do diff --git a/images/Options.png b/images/Options.png index 526ecff4a339c075917e22a6db83416d7ce5bdb6..32eab700421e6f25598e3daa1b3a1240deff47fd 100644 GIT binary patch literal 63404 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ν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 G&;Jkd8y)HZ diff --git a/images/Options_parameter.png b/images/Options_parameter.png new file mode 100644 index 0000000000000000000000000000000000000000..3e10ccb1141ccc726b407837a2f76035d77b101f GIT binary patch literal 39591 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 C0^|w+ literal 0 HcmV?d00001 From bb0c9a610b6ddbaa05c7a63e6d377237c7fcf4be Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 16 Oct 2025 11:02:39 +0200 Subject: [PATCH 24/29] Fix AddMenuItem.png --- images/AddMenuItem.png | Bin 44622 -> 43436 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/AddMenuItem.png b/images/AddMenuItem.png index 8c5e92270e59322fc136462d547cf91f41cc786b..80f35ae5934f8f9a5faf8e252192bb451b091e0e 100644 GIT binary patch literal 43436 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 From 8c39cd72f3f23fc9875a8a4003f9feaa8dc2ddf5 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 23 Oct 2025 21:10:56 +0200 Subject: [PATCH 25/29] Fixing bug: user is not able to set negative value as an integer argument. --- ArgumentControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArgumentControl.cs b/ArgumentControl.cs index 042905c..c325db4 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -115,7 +115,7 @@ private void Init_Nvarchar() _valueControl = textBox; } - private void Init_Int() => _valueControl = new NumericUpDown(); + private void Init_Int() => _valueControl = new NumericUpDown() { Minimum = int.MinValue, Maximum = int.MaxValue }; private void Init_Bit() => _valueControl = new CheckBox(); From 03f3faaeb41109756783c3b03e9c5a556b566507 Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 23 Oct 2025 21:36:00 +0200 Subject: [PATCH 26/29] Removed the maximum size limit of the "Enter script arguments..." window. The flow panel and window now resize in sync. --- EnterUserDefinedArguments.Designer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/EnterUserDefinedArguments.Designer.cs b/EnterUserDefinedArguments.Designer.cs index 9880dcf..12d3268 100644 --- a/EnterUserDefinedArguments.Designer.cs +++ b/EnterUserDefinedArguments.Designer.cs @@ -54,7 +54,6 @@ private void InitializeComponent() this.flowLayoutPanelArguments.AutoSize = true; this.flowLayoutPanelArguments.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; this.flowLayoutPanelArguments.Location = new System.Drawing.Point(15, 26); - this.flowLayoutPanelArguments.MaximumSize = new System.Drawing.Size(300, 200); this.flowLayoutPanelArguments.Name = "flowLayoutPanelArguments"; this.flowLayoutPanelArguments.Size = new System.Drawing.Size(300, 50); this.flowLayoutPanelArguments.TabIndex = 1; From 8ea1aed295332f78e971e1af70c26a7910aa68fe Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Thu, 23 Oct 2025 22:41:35 +0200 Subject: [PATCH 27/29] Made argument controls as wide as their container (FlowLayout). Removed unused padding. --- EnterUserDefinedArguments.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/EnterUserDefinedArguments.cs b/EnterUserDefinedArguments.cs index c668cc2..49b68e4 100644 --- a/EnterUserDefinedArguments.cs +++ b/EnterUserDefinedArguments.cs @@ -9,11 +9,6 @@ namespace SSMSObjectExplorerMenu { public partial class EnterUserDefinedArguments : Form { - ///

- /// Space for the vertical scrollbar and some padding. - /// - private const int FLOWLAYOUTPANEL_PADDING = 25; - private readonly ArgumentControl[] _argumentControls; public IEnumerable UserDefinedArguments { @@ -31,7 +26,7 @@ public EnterUserDefinedArguments(IEnumerable parameters) { InitializeComponent(); - int argumentControlWidth = this.flowLayoutPanelArguments.ClientSize.Width - FLOWLAYOUTPANEL_PADDING; + int argumentControlWidth = this.flowLayoutPanelArguments.ClientSize.Width; _argumentControls = parameters.Select(p => new ArgumentControl(p, argumentControlWidth)).ToArray(); this.flowLayoutPanelArguments.Controls.AddRange(_argumentControls); } From ef4b1153b625673cd908efce6459a407241078ab Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 27 Oct 2025 20:58:28 +0100 Subject: [PATCH 28/29] Datetime2, datetimeoffset user-defined arguments. --- ArgumentControl.cs | 36 ++++++++++++++++++++++++++++++++ EnterUserDefinedArguments.cs | 7 +++++++ enums/UserDefinedArgumentType.cs | 4 ++++ 3 files changed, 47 insertions(+) diff --git a/ArgumentControl.cs b/ArgumentControl.cs index c325db4..8249604 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -61,6 +61,12 @@ public ArgumentControl(UserDefinedParameter parameter, int width) case UserDefinedParameterType.Bit: Init_Bit(); break; + case UserDefinedParameterType.DateTime2: + Init_DateTime2(); + break; + case UserDefinedParameterType.DateTimeOffset: + Init_DateTimeOffset(); + break; case UserDefinedParameterType.CustomList: Init_CustomList(); break; @@ -89,6 +95,10 @@ public bool IsValid() return Guid.TryParse(_valueControl.Text, out _); case UserDefinedParameterType.Nvarchar: return !string.IsNullOrWhiteSpace(_valueControl.Text); + case UserDefinedParameterType.DateTime2: + return DateTime.TryParse(_valueControl.Text, out _); + case UserDefinedParameterType.DateTimeOffset: + return DateTimeOffset.TryParse(_valueControl.Text, out _); case UserDefinedParameterType.Int: case UserDefinedParameterType.Bit: case UserDefinedParameterType.CustomList: @@ -119,6 +129,10 @@ private void Init_Nvarchar() private void Init_Bit() => _valueControl = new CheckBox(); + private void Init_DateTime2() => _valueControl = TextBoxWithPlaceholder("e.g. yyyy-MM-dd HH:mm:ss[.nnnnnnn]"); + + private void Init_DateTimeOffset() => _valueControl = TextBoxWithPlaceholder("e.g. yyyy-MM-dd HH:mm:ss[.nnnnnnn] [{+|-}hh:mm]"); + private void Init_CustomList() { var comboBox = new ComboBox(); @@ -126,5 +140,27 @@ private void Init_CustomList() _valueControl = comboBox; } + + private TextBox TextBoxWithPlaceholder(string placeholder) + { + var textBox = new TextBox() { Text = placeholder, ForeColor = Color.Gray }; + textBox.Enter += (s, e) => + { + if (textBox.Text == placeholder) + { + textBox.Text = string.Empty; + textBox.ForeColor = Color.Black; + } + }; + textBox.Leave += (s, e) => + { + if (string.IsNullOrWhiteSpace(textBox.Text)) + { + textBox.Text = placeholder; + textBox.ForeColor = Color.Gray; + } + }; + return textBox; + } } } diff --git a/EnterUserDefinedArguments.cs b/EnterUserDefinedArguments.cs index 49b68e4..fc87493 100644 --- a/EnterUserDefinedArguments.cs +++ b/EnterUserDefinedArguments.cs @@ -47,5 +47,12 @@ private bool TryValidate(out IEnumerable invalidArguments) invalidArguments = _argumentControls.Where(ac => !ac.IsValid()).Select(ac => ac.Parameter.Name); return !invalidArguments.Any(); } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + // To show placeholder text (e.g. for datetime and datetime2) for all controls when the form is shown + this.ActiveControl = null; + } } } diff --git a/enums/UserDefinedArgumentType.cs b/enums/UserDefinedArgumentType.cs index 9d97bc9..a560f0c 100644 --- a/enums/UserDefinedArgumentType.cs +++ b/enums/UserDefinedArgumentType.cs @@ -12,6 +12,10 @@ public enum UserDefinedParameterType : byte Nvarchar, [Description("bit")] Bit, + [Description("datetime2")] + DateTime2, + [Description("datetimeoffset")] + DateTimeOffset, /// /// This is not a SQL Server data type. Represents a list of options defined by the user. /// From 004db3be871becd94aa070a1b2543ce97c17724f Mon Sep 17 00:00:00 2001 From: Viktor Meszaros Date: Mon, 27 Oct 2025 22:21:54 +0100 Subject: [PATCH 29/29] Default value for user-defined parameters: extending UserDefinedParameter class, added validation. Filling ArgumentControls with the default values if any. --- ArgumentControl.cs | 38 +++++++++++++++++++++++++-------- extensions/Extensions.cs | 29 +++++++++++++++++++++++++ objects/UserDefinedParameter.cs | 28 ++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/ArgumentControl.cs b/ArgumentControl.cs index 8249604..22ae048 100644 --- a/ArgumentControl.cs +++ b/ArgumentControl.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Linq; using System.Windows.Forms; namespace SSMSObjectExplorerMenu @@ -112,7 +113,7 @@ private void Init_Uniqueidentifier() { var guidTextBox = new TextBox(); guidTextBox.MaxLength = UNIQUEIDENTIFIER_LENGTH; - guidTextBox.Text = string.Empty; + guidTextBox.Text = Parameter.UseDefaultValue ? Parameter.DefaultValueAsString : string.Empty; _valueControl = guidTextBox; } @@ -120,30 +121,49 @@ private void Init_Uniqueidentifier() private void Init_Nvarchar() { var textBox = new TextBox(); - textBox.Text = string.Empty; + textBox.Text = Parameter.UseDefaultValue ? Parameter.DefaultValueAsString : string.Empty; _valueControl = textBox; } - private void Init_Int() => _valueControl = new NumericUpDown() { Minimum = int.MinValue, Maximum = int.MaxValue }; - - private void Init_Bit() => _valueControl = new CheckBox(); + private void Init_Int() => _valueControl = new NumericUpDown() { + Minimum = int.MinValue, + Maximum = int.MaxValue, + Value = Parameter.UseDefaultValue && int.TryParse(Parameter.DefaultValueAsString, out int defaultValue) ? defaultValue : 0 + }; - private void Init_DateTime2() => _valueControl = TextBoxWithPlaceholder("e.g. yyyy-MM-dd HH:mm:ss[.nnnnnnn]"); + private void Init_Bit() => _valueControl = new CheckBox() { + Checked = Parameter.UseDefaultValue && bool.TryParse(Parameter.DefaultValueAsString, out bool bitValue) ? bitValue : false + }; - private void Init_DateTimeOffset() => _valueControl = TextBoxWithPlaceholder("e.g. yyyy-MM-dd HH:mm:ss[.nnnnnnn] [{+|-}hh:mm]"); + private void Init_DateTime2() => _valueControl = TextBoxWithPlaceholder( + "e.g. yyyy-MM-dd HH:mm:ss[.nnnnnnn]", + Parameter.UseDefaultValue && DateTime.TryParse(Parameter.DefaultValueAsString, out DateTime _) ? Parameter.DefaultValueAsString : null); + + private void Init_DateTimeOffset() => _valueControl = TextBoxWithPlaceholder( + "e.g. yyyy-MM-dd HH:mm:ss[.nnnnnnn] [{+|-}hh:mm]", + Parameter.UseDefaultValue && DateTimeOffset.TryParse(Parameter.DefaultValueAsString, out DateTimeOffset _) ? Parameter.DefaultValueAsString : null); private void Init_CustomList() { var comboBox = new ComboBox(); comboBox.DataSource = Parameter.ValueSetOfCustomList; + if(Parameter.UseDefaultValue) + { + var itemToSelect = Parameter.ValueSetOfCustomList.SingleOrDefault(s => s.Value == Parameter.DefaultValueAsString); + if(itemToSelect != null) + { + comboBox.SelectedItem = itemToSelect; + } + } + _valueControl = comboBox; } - private TextBox TextBoxWithPlaceholder(string placeholder) + private TextBox TextBoxWithPlaceholder(string placeholder, string value = null) { - var textBox = new TextBox() { Text = placeholder, ForeColor = Color.Gray }; + var textBox = new TextBox() { Text = value ?? placeholder, ForeColor = Color.Gray }; textBox.Enter += (s, e) => { if (textBox.Text == placeholder) diff --git a/extensions/Extensions.cs b/extensions/Extensions.cs index 2a5e09a..68767bc 100644 --- a/extensions/Extensions.cs +++ b/extensions/Extensions.cs @@ -8,6 +8,7 @@ using System.ComponentModel; using System.IO; using System.Linq; +using System.Reflection.Metadata; using System.Text.RegularExpressions; using System.Xml.Serialization; @@ -167,6 +168,34 @@ public static T FromDescription(this string enumDescription) where T : Enum return enumField != null ? (T)enumField.GetValue(null) : throw new ArgumentException($"Unknown {nameof(T)} description.", nameof(enumDescription)); + } + + public static bool ValidForUserDefinedParameterType(this string value, UserDefinedParameterType type) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + switch (type) + { + case UserDefinedParameterType.UniqueIdentifier: + return Guid.TryParse(value, out _); + case UserDefinedParameterType.Nvarchar: + return true; // Any string is valid for nvarchar + case UserDefinedParameterType.DateTime2: + return DateTime.TryParse(value, out _); + case UserDefinedParameterType.DateTimeOffset: + return DateTimeOffset.TryParse(value, out _); + case UserDefinedParameterType.Int: + return int.TryParse(value, out _); + case UserDefinedParameterType.Bit: + return bool.TryParse(value, out _); + case UserDefinedParameterType.CustomList: + throw new ArgumentException($"Operation is not applicable for type '{type}'."); + default: + throw new NotImplementedException($"Validation for parameter type {type} has not been implemented."); + } } } } diff --git a/objects/UserDefinedParameter.cs b/objects/UserDefinedParameter.cs index 12155d6..bab5a98 100644 --- a/objects/UserDefinedParameter.cs +++ b/objects/UserDefinedParameter.cs @@ -1,4 +1,5 @@ using SSMSObjectExplorerMenu.enums; +using SSMSObjectExplorerMenu.extensions; using System; using System.Collections.Generic; using System.ComponentModel; @@ -11,6 +12,8 @@ namespace SSMSObjectExplorerMenu.objects [TypeConverter(typeof(ExpandableObjectConverter))] public class UserDefinedParameter { + private bool _useDefaultValue; + public const short NAME_MAX_LENGTH = 64; [DisplayName("Name")] @@ -22,6 +25,22 @@ public class UserDefinedParameter [TypeConverter(typeof(UserDefinedArgumentTypeConverter))] public UserDefinedParameterType Type { get; set; } + [DisplayName("Use default value")] + [Description("Indicates whether to use the default value of the user-defined parameter.")] + public bool UseDefaultValue + { + get { return _useDefaultValue; } + set + { + _useDefaultValue = value; + if (!_useDefaultValue) DefaultValueAsString = string.Empty; + } + } + + [DisplayName("Default value")] + [Description("Default value of the user-defined parameter.")] + public string DefaultValueAsString { get; set; } + /// /// Populate if is . Otherwise it's ignored. /// @@ -52,6 +71,15 @@ public bool TryValidate(out IEnumerable validationErrors, IEnumerable