1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/Server/FormEditObject.cs Fri Aug 12 20:25:05 2016 +0200
1.3 @@ -0,0 +1,335 @@
1.4 +using System;
1.5 +using System.Collections.Generic;
1.6 +using System.ComponentModel;
1.7 +using System.Data;
1.8 +using System.Diagnostics;
1.9 +using System.Drawing;
1.10 +using System.Linq;
1.11 +using System.Text;
1.12 +using System.Threading.Tasks;
1.13 +using System.Windows.Forms;
1.14 +using SharpLib.Display;
1.15 +using SharpLib.Ear;
1.16 +using System.Reflection;
1.17 +using Microsoft.VisualBasic.CompilerServices;
1.18 +using SharpLib.Utils;
1.19 +
1.20 +namespace SharpDisplayManager
1.21 +{
1.22 + /// <summary>
1.23 + /// Object edit dialog form.
1.24 + /// </summary>
1.25 + public partial class FormEditObject<T> : Form where T : class
1.26 + {
1.27 + public T Object = null;
1.28 +
1.29 + public FormEditObject()
1.30 + {
1.31 + InitializeComponent();
1.32 + }
1.33 +
1.34 + /// <summary>
1.35 + ///
1.36 + /// </summary>
1.37 + /// <param name="sender"></param>
1.38 + /// <param name="e"></param>
1.39 + private void FormEditAction_Load(object sender, EventArgs e)
1.40 + {
1.41 + // Populate registered actions
1.42 + IEnumerable < Type > types = Reflection.GetConcreteClassesDerivedFrom<T>();
1.43 + foreach (Type type in types)
1.44 + {
1.45 + ItemObjectType item = new ItemObjectType(type);
1.46 + comboBoxActionType.Items.Add(item);
1.47 + }
1.48 +
1.49 + if (Object == null)
1.50 + {
1.51 + // Creating new issue, select our first item
1.52 + comboBoxActionType.SelectedIndex = 0;
1.53 + }
1.54 + else
1.55 + {
1.56 + // Editing existing object
1.57 + // Look up our item in our combobox
1.58 + foreach (ItemObjectType item in comboBoxActionType.Items)
1.59 + {
1.60 + if (item.Type == Object.GetType())
1.61 + {
1.62 + comboBoxActionType.SelectedItem = item;
1.63 + }
1.64 + }
1.65 + }
1.66 + }
1.67 +
1.68 + private void buttonOk_Click(object sender, EventArgs e)
1.69 + {
1.70 + FetchPropertiesValue(Object);
1.71 + }
1.72 +
1.73 + private void FormEditAction_Validating(object sender, CancelEventArgs e)
1.74 + {
1.75 +
1.76 + }
1.77 +
1.78 + private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e)
1.79 + {
1.80 + //Instantiate an action corresponding to our type
1.81 + Type actionType = ((ItemObjectType) comboBoxActionType.SelectedItem).Type;
1.82 + //Create another type of action only if needed
1.83 + if (Object == null || Object.GetType() != actionType)
1.84 + {
1.85 + Object = (T)Activator.CreateInstance(actionType);
1.86 + }
1.87 +
1.88 + //Create input fields
1.89 + UpdateTableLayoutPanel(Object);
1.90 + }
1.91 +
1.92 +
1.93 + /// <summary>
1.94 + /// Get properties values from our generated input fields
1.95 + /// </summary>
1.96 + private void FetchPropertiesValue(T aAction)
1.97 + {
1.98 + int ctrlIndex = 0;
1.99 + foreach (PropertyInfo pi in aAction.GetType().GetProperties())
1.100 + {
1.101 + AttributeObjectProperty[] attributes =
1.102 + ((AttributeObjectProperty[]) pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
1.103 + if (attributes.Length != 1)
1.104 + {
1.105 + continue;
1.106 + }
1.107 +
1.108 + AttributeObjectProperty attribute = attributes[0];
1.109 +
1.110 + if (!IsPropertyTypeSupported(pi))
1.111 + {
1.112 + continue;
1.113 + }
1.114 +
1.115 + GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aAction); //+1 otherwise we get the label
1.116 +
1.117 + ctrlIndex+=2; //Jump over the label too
1.118 + }
1.119 + }
1.120 +
1.121 + /// <summary>
1.122 + /// Extend this function to support reading new types of properties.
1.123 + /// </summary>
1.124 + /// <param name="aAction"></param>
1.125 + private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, T aAction)
1.126 + {
1.127 + if (aInfo.PropertyType == typeof(int))
1.128 + {
1.129 + NumericUpDown ctrl=(NumericUpDown)aControl;
1.130 + aInfo.SetValue(aAction,(int)ctrl.Value);
1.131 + }
1.132 + else if (aInfo.PropertyType.IsEnum)
1.133 + {
1.134 + // Instantiate our enum
1.135 + object enumValue= Activator.CreateInstance(aInfo.PropertyType);
1.136 + // Parse our enum from combo box
1.137 + enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString());
1.138 + //enumValue = ((ComboBox)aControl).SelectedValue;
1.139 + // Set enum value
1.140 + aInfo.SetValue(aAction, enumValue);
1.141 + }
1.142 + else if (aInfo.PropertyType == typeof(bool))
1.143 + {
1.144 + CheckBox ctrl = (CheckBox)aControl;
1.145 + aInfo.SetValue(aAction, ctrl.Checked);
1.146 + }
1.147 + else if (aInfo.PropertyType == typeof(string))
1.148 + {
1.149 + TextBox ctrl = (TextBox)aControl;
1.150 + aInfo.SetValue(aAction, ctrl.Text);
1.151 + }
1.152 + //TODO: add support for other types here
1.153 + }
1.154 +
1.155 + /// <summary>
1.156 + ///
1.157 + /// </summary>
1.158 + /// <param name="aInfo"></param>
1.159 + /// <param name="action"></param>
1.160 + private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aAction)
1.161 + {
1.162 + if (aInfo.PropertyType == typeof(int))
1.163 + {
1.164 + //Integer properties are using numeric editor
1.165 + NumericUpDown ctrl = new NumericUpDown();
1.166 + ctrl.AutoSize = true;
1.167 + ctrl.Minimum = Int32.Parse(aAttribute.Minimum);
1.168 + ctrl.Maximum = Int32.Parse(aAttribute.Maximum);
1.169 + ctrl.Increment = Int32.Parse(aAttribute.Increment);
1.170 + ctrl.Value = (int)aInfo.GetValue(aAction);
1.171 + return ctrl;
1.172 + }
1.173 + else if (aInfo.PropertyType.IsEnum)
1.174 + {
1.175 + //Enum properties are using combo box
1.176 + ComboBox ctrl = new ComboBox();
1.177 + ctrl.AutoSize = true;
1.178 + ctrl.Sorted = true;
1.179 + ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
1.180 + //Data source is fine but it gives us duplicate entries for duplicated enum values
1.181 + //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType);
1.182 +
1.183 + //Therefore we need to explicitly create our items
1.184 + Size cbSize = new Size(0,0);
1.185 + foreach (string name in aInfo.PropertyType.GetEnumNames())
1.186 + {
1.187 + ctrl.Items.Add(name.ToString());
1.188 + Graphics g = this.CreateGraphics();
1.189 + //Since combobox autosize would not work we need to get measure text ourselves
1.190 + SizeF size=g.MeasureString(name.ToString(), ctrl.Font);
1.191 + cbSize.Width = Math.Max(cbSize.Width,(int)size.Width);
1.192 + cbSize.Height = Math.Max(cbSize.Height, (int)size.Height);
1.193 + }
1.194 +
1.195 + //Make sure our combobox is large enough
1.196 + ctrl.MinimumSize = cbSize;
1.197 +
1.198 + // Instantiate our enum
1.199 + object enumValue = Activator.CreateInstance(aInfo.PropertyType);
1.200 + enumValue = aInfo.GetValue(aAction);
1.201 + //Set the current item
1.202 + ctrl.SelectedItem = enumValue.ToString();
1.203 +
1.204 + return ctrl;
1.205 + }
1.206 + else if (aInfo.PropertyType == typeof(bool))
1.207 + {
1.208 + CheckBox ctrl = new CheckBox();
1.209 + ctrl.AutoSize = true;
1.210 + ctrl.Text = aAttribute.Description;
1.211 + ctrl.Checked = (bool)aInfo.GetValue(aAction);
1.212 + return ctrl;
1.213 + }
1.214 + else if (aInfo.PropertyType == typeof(string))
1.215 + {
1.216 + TextBox ctrl = new TextBox();
1.217 + ctrl.AutoSize = true;
1.218 + ctrl.Text = (string)aInfo.GetValue(aAction);
1.219 + return ctrl;
1.220 + }
1.221 + //TODO: add support for other control type here
1.222 +
1.223 + return null;
1.224 + }
1.225 +
1.226 + /// <summary>
1.227 + /// Don't forget to extend that one and adding types
1.228 + /// </summary>
1.229 + /// <returns></returns>
1.230 + private bool IsPropertyTypeSupported(PropertyInfo aInfo)
1.231 + {
1.232 + if (aInfo.PropertyType == typeof(int))
1.233 + {
1.234 + return true;
1.235 + }
1.236 + else if (aInfo.PropertyType.IsEnum)
1.237 + {
1.238 + return true;
1.239 + }
1.240 + else if (aInfo.PropertyType == typeof(bool))
1.241 + {
1.242 + return true;
1.243 + }
1.244 + else if (aInfo.PropertyType == typeof(string))
1.245 + {
1.246 + return true;
1.247 + }
1.248 + //TODO: add support for other type here
1.249 +
1.250 + return false;
1.251 + }
1.252 +
1.253 + /// <summary>
1.254 + /// Update our table layout.
1.255 + /// Will instantiated every field control as defined by our action.
1.256 + /// Fields must be specified by rows from the left.
1.257 + /// </summary>
1.258 + /// <param name="aLayout"></param>
1.259 + private void UpdateTableLayoutPanel(T aAction)
1.260 + {
1.261 + toolTip.RemoveAll();
1.262 + //Debug.Print("UpdateTableLayoutPanel")
1.263 + //First clean our current panel
1.264 + iTableLayoutPanel.Controls.Clear();
1.265 + iTableLayoutPanel.RowStyles.Clear();
1.266 + iTableLayoutPanel.ColumnStyles.Clear();
1.267 + iTableLayoutPanel.RowCount = 0;
1.268 +
1.269 + //We always want two columns: one for label and one for the field
1.270 + iTableLayoutPanel.ColumnCount = 2;
1.271 + iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
1.272 + iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
1.273 +
1.274 +
1.275 + if (aAction == null)
1.276 + {
1.277 + //Just drop it
1.278 + return;
1.279 + }
1.280 +
1.281 + //IEnumerable<PropertyInfo> properties = aAction.GetType().GetProperties().Where(
1.282 + // prop => Attribute.IsDefined(prop, typeof(AttributeObjectProperty)));
1.283 +
1.284 +
1.285 + foreach (PropertyInfo pi in aAction.GetType().GetProperties())
1.286 + {
1.287 + AttributeObjectProperty[] attributes = ((AttributeObjectProperty[])pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
1.288 + if (attributes.Length != 1)
1.289 + {
1.290 + continue;
1.291 + }
1.292 +
1.293 + AttributeObjectProperty attribute = attributes[0];
1.294 +
1.295 + //Before anything we need to check if that kind of property is supported by our UI
1.296 + //Create the editor
1.297 + Control ctrl = CreateControlForProperty(pi, attribute, aAction);
1.298 + if (ctrl == null)
1.299 + {
1.300 + //Property type not supported
1.301 + continue;
1.302 + }
1.303 +
1.304 + //Add a new row
1.305 + iTableLayoutPanel.RowCount++;
1.306 + iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
1.307 + //Create the label
1.308 + Label label = new Label();
1.309 + label.AutoSize = true;
1.310 + label.Dock = DockStyle.Fill;
1.311 + label.TextAlign = ContentAlignment.MiddleCenter;
1.312 + label.Text = attribute.Name;
1.313 + toolTip.SetToolTip(label, attribute.Description);
1.314 + iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1);
1.315 +
1.316 + //Add our editor to our form
1.317 + iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1);
1.318 + //Add tooltip to editor too
1.319 + toolTip.SetToolTip(ctrl, attribute.Description);
1.320 +
1.321 + }
1.322 +
1.323 + }
1.324 +
1.325 + private void buttonTest_Click(object sender, EventArgs e)
1.326 + {
1.327 + FetchPropertiesValue(Object);
1.328 +
1.329 + //If our object has a test method with no parameters just run it then
1.330 + MethodInfo info = Object.GetType().GetMethod("Test");
1.331 + if ( info != null && info.GetParameters().Length==0)
1.332 + {
1.333 + info.Invoke(Object,null);
1.334 + }
1.335 +
1.336 + }
1.337 + }
1.338 +}