diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormEditObject.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Server/FormEditObject.cs Fri Aug 12 20:25:05 2016 +0200 @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using SharpLib.Display; +using SharpLib.Ear; +using System.Reflection; +using Microsoft.VisualBasic.CompilerServices; +using SharpLib.Utils; + +namespace SharpDisplayManager +{ + /// + /// Object edit dialog form. + /// + public partial class FormEditObject : Form where T : class + { + public T Object = null; + + public FormEditObject() + { + InitializeComponent(); + } + + /// + /// + /// + /// + /// + private void FormEditAction_Load(object sender, EventArgs e) + { + // Populate registered actions + IEnumerable < Type > types = Reflection.GetConcreteClassesDerivedFrom(); + foreach (Type type in types) + { + ItemObjectType item = new ItemObjectType(type); + comboBoxActionType.Items.Add(item); + } + + if (Object == null) + { + // Creating new issue, select our first item + comboBoxActionType.SelectedIndex = 0; + } + else + { + // Editing existing object + // Look up our item in our combobox + foreach (ItemObjectType item in comboBoxActionType.Items) + { + if (item.Type == Object.GetType()) + { + comboBoxActionType.SelectedItem = item; + } + } + } + } + + private void buttonOk_Click(object sender, EventArgs e) + { + FetchPropertiesValue(Object); + } + + private void FormEditAction_Validating(object sender, CancelEventArgs e) + { + + } + + private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e) + { + //Instantiate an action corresponding to our type + Type actionType = ((ItemObjectType) comboBoxActionType.SelectedItem).Type; + //Create another type of action only if needed + if (Object == null || Object.GetType() != actionType) + { + Object = (T)Activator.CreateInstance(actionType); + } + + //Create input fields + UpdateTableLayoutPanel(Object); + } + + + /// + /// Get properties values from our generated input fields + /// + private void FetchPropertiesValue(T aAction) + { + int ctrlIndex = 0; + foreach (PropertyInfo pi in aAction.GetType().GetProperties()) + { + AttributeObjectProperty[] attributes = + ((AttributeObjectProperty[]) pi.GetCustomAttributes(typeof(AttributeObjectProperty), true)); + if (attributes.Length != 1) + { + continue; + } + + AttributeObjectProperty attribute = attributes[0]; + + if (!IsPropertyTypeSupported(pi)) + { + continue; + } + + GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aAction); //+1 otherwise we get the label + + ctrlIndex+=2; //Jump over the label too + } + } + + /// + /// Extend this function to support reading new types of properties. + /// + /// + private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, T aAction) + { + if (aInfo.PropertyType == typeof(int)) + { + NumericUpDown ctrl=(NumericUpDown)aControl; + aInfo.SetValue(aAction,(int)ctrl.Value); + } + else if (aInfo.PropertyType.IsEnum) + { + // Instantiate our enum + object enumValue= Activator.CreateInstance(aInfo.PropertyType); + // Parse our enum from combo box + enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString()); + //enumValue = ((ComboBox)aControl).SelectedValue; + // Set enum value + aInfo.SetValue(aAction, enumValue); + } + else if (aInfo.PropertyType == typeof(bool)) + { + CheckBox ctrl = (CheckBox)aControl; + aInfo.SetValue(aAction, ctrl.Checked); + } + else if (aInfo.PropertyType == typeof(string)) + { + TextBox ctrl = (TextBox)aControl; + aInfo.SetValue(aAction, ctrl.Text); + } + //TODO: add support for other types here + } + + /// + /// + /// + /// + /// + private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aAction) + { + if (aInfo.PropertyType == typeof(int)) + { + //Integer properties are using numeric editor + NumericUpDown ctrl = new NumericUpDown(); + ctrl.AutoSize = true; + ctrl.Minimum = Int32.Parse(aAttribute.Minimum); + ctrl.Maximum = Int32.Parse(aAttribute.Maximum); + ctrl.Increment = Int32.Parse(aAttribute.Increment); + ctrl.Value = (int)aInfo.GetValue(aAction); + return ctrl; + } + else if (aInfo.PropertyType.IsEnum) + { + //Enum properties are using combo box + ComboBox ctrl = new ComboBox(); + ctrl.AutoSize = true; + ctrl.Sorted = true; + ctrl.DropDownStyle = ComboBoxStyle.DropDownList; + //Data source is fine but it gives us duplicate entries for duplicated enum values + //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType); + + //Therefore we need to explicitly create our items + Size cbSize = new Size(0,0); + foreach (string name in aInfo.PropertyType.GetEnumNames()) + { + ctrl.Items.Add(name.ToString()); + Graphics g = this.CreateGraphics(); + //Since combobox autosize would not work we need to get measure text ourselves + SizeF size=g.MeasureString(name.ToString(), ctrl.Font); + cbSize.Width = Math.Max(cbSize.Width,(int)size.Width); + cbSize.Height = Math.Max(cbSize.Height, (int)size.Height); + } + + //Make sure our combobox is large enough + ctrl.MinimumSize = cbSize; + + // Instantiate our enum + object enumValue = Activator.CreateInstance(aInfo.PropertyType); + enumValue = aInfo.GetValue(aAction); + //Set the current item + ctrl.SelectedItem = enumValue.ToString(); + + return ctrl; + } + else if (aInfo.PropertyType == typeof(bool)) + { + CheckBox ctrl = new CheckBox(); + ctrl.AutoSize = true; + ctrl.Text = aAttribute.Description; + ctrl.Checked = (bool)aInfo.GetValue(aAction); + return ctrl; + } + else if (aInfo.PropertyType == typeof(string)) + { + TextBox ctrl = new TextBox(); + ctrl.AutoSize = true; + ctrl.Text = (string)aInfo.GetValue(aAction); + return ctrl; + } + //TODO: add support for other control type here + + return null; + } + + /// + /// Don't forget to extend that one and adding types + /// + /// + private bool IsPropertyTypeSupported(PropertyInfo aInfo) + { + if (aInfo.PropertyType == typeof(int)) + { + return true; + } + else if (aInfo.PropertyType.IsEnum) + { + return true; + } + else if (aInfo.PropertyType == typeof(bool)) + { + return true; + } + else if (aInfo.PropertyType == typeof(string)) + { + return true; + } + //TODO: add support for other type here + + return false; + } + + /// + /// Update our table layout. + /// Will instantiated every field control as defined by our action. + /// Fields must be specified by rows from the left. + /// + /// + private void UpdateTableLayoutPanel(T aAction) + { + toolTip.RemoveAll(); + //Debug.Print("UpdateTableLayoutPanel") + //First clean our current panel + iTableLayoutPanel.Controls.Clear(); + iTableLayoutPanel.RowStyles.Clear(); + iTableLayoutPanel.ColumnStyles.Clear(); + iTableLayoutPanel.RowCount = 0; + + //We always want two columns: one for label and one for the field + iTableLayoutPanel.ColumnCount = 2; + iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + + + if (aAction == null) + { + //Just drop it + return; + } + + //IEnumerable properties = aAction.GetType().GetProperties().Where( + // prop => Attribute.IsDefined(prop, typeof(AttributeObjectProperty))); + + + foreach (PropertyInfo pi in aAction.GetType().GetProperties()) + { + AttributeObjectProperty[] attributes = ((AttributeObjectProperty[])pi.GetCustomAttributes(typeof(AttributeObjectProperty), true)); + if (attributes.Length != 1) + { + continue; + } + + AttributeObjectProperty attribute = attributes[0]; + + //Before anything we need to check if that kind of property is supported by our UI + //Create the editor + Control ctrl = CreateControlForProperty(pi, attribute, aAction); + if (ctrl == null) + { + //Property type not supported + continue; + } + + //Add a new row + iTableLayoutPanel.RowCount++; + iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + //Create the label + Label label = new Label(); + label.AutoSize = true; + label.Dock = DockStyle.Fill; + label.TextAlign = ContentAlignment.MiddleCenter; + label.Text = attribute.Name; + toolTip.SetToolTip(label, attribute.Description); + iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1); + + //Add our editor to our form + iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1); + //Add tooltip to editor too + toolTip.SetToolTip(ctrl, attribute.Description); + + } + + } + + private void buttonTest_Click(object sender, EventArgs e) + { + FetchPropertiesValue(Object); + + //If our object has a test method with no parameters just run it then + MethodInfo info = Object.GetType().GetMethod("Test"); + if ( info != null && info.GetParameters().Length==0) + { + info.Invoke(Object,null); + } + + } + } +}