Fixing EAR event edition.
EAR HID event now displays 'Press a key' if not valid.
2 using System.Collections.Generic;
3 using System.ComponentModel;
5 using System.Diagnostics;
9 using System.Threading.Tasks;
10 using System.Windows.Forms;
11 using SharpLib.Display;
13 using System.Reflection;
14 using Microsoft.VisualBasic.CompilerServices;
16 using CodeProject.Dialog;
19 namespace SharpDisplayManager
22 /// Object edit dialog form.
24 public partial class FormEditObject<T> : Form where T: SharpLib.Ear.Object
26 public T Object = null;
28 public FormEditObject()
30 InitializeComponent();
36 /// <param name="sender"></param>
37 /// <param name="e"></param>
38 private void FormEditAction_Load(object sender, EventArgs e)
40 // Populate registered object types
41 IEnumerable < Type > types = Reflection.GetConcreteClassesDerivedFrom<T>();
42 foreach (Type type in types)
44 ItemObjectType item = new ItemObjectType(type);
45 iComboBoxObjectType.Items.Add(item);
50 // Creating new issue, select our first item
51 iComboBoxObjectType.SelectedIndex = 0;
55 // Editing existing object
56 // Look up our item in our object type combobox
57 foreach (ItemObjectType item in iComboBoxObjectType.Items)
59 if (item.Type == Object.GetType())
61 iComboBoxObjectType.SelectedItem = item;
71 /// <param name="sender"></param>
72 /// <param name="e"></param>
73 private void buttonOk_Click(object sender, EventArgs e)
75 FetchPropertiesValue(Object);
76 if (!Object.IsValid())
78 // Tell closing event to cancel
79 DialogResult = DialogResult.None;
87 /// <param name="sender"></param>
88 /// <param name="e"></param>
89 private void FormEditObject_FormClosing(object sender, FormClosingEventArgs e)
91 //Check if we need to cancel the closing of our form.
92 e.Cancel = DialogResult == DialogResult.None;
97 Object.CurrentState = SharpLib.Ear.Object.State.Rest;
98 Object.PropertyChanged -= PropertyChangedEventHandlerThreadSafe;
105 /// <param name="sender"></param>
106 /// <param name="e"></param>
107 private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e)
109 //Instantiate an action corresponding to our type
110 Type actionType = ((ItemObjectType) iComboBoxObjectType.SelectedItem).Type;
111 //Create another type of action only if needed
112 if (Object == null || Object.GetType() != actionType)
114 Object = (T)Activator.CreateInstance(actionType);
117 //Create input fields
123 /// Get properties values from our generated input fields
125 private void FetchPropertiesValue(T aObject)
128 //For each of our properties
129 foreach (PropertyInfo pi in aObject.GetType().GetProperties())
131 //Get our property attribute
132 AttributeObjectProperty[] attributes = ((AttributeObjectProperty[]) pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
133 if (attributes.Length != 1)
135 //No attribute, skip this property then.
138 AttributeObjectProperty attribute = attributes[0];
140 //Check that we support this type of property
141 if (!IsPropertyTypeSupported(pi))
146 //Now fetch our property value
147 GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aObject); //+1 otherwise we get the label
149 ctrlIndex+=2; //Jump over the label too
154 /// Extend this function to support reading new types of properties.
156 /// <param name="aObject"></param>
157 private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, T aObject)
159 if (aInfo.PropertyType == typeof(int))
161 NumericUpDown ctrl=(NumericUpDown)aControl;
162 aInfo.SetValue(aObject,(int)ctrl.Value);
164 else if (aInfo.PropertyType.IsEnum)
166 // Instantiate our enum
167 object enumValue= Activator.CreateInstance(aInfo.PropertyType);
168 // Parse our enum from combo box
169 enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString());
170 //enumValue = ((ComboBox)aControl).SelectedValue;
172 aInfo.SetValue(aObject, enumValue);
174 else if (aInfo.PropertyType == typeof(bool))
176 CheckBox ctrl = (CheckBox)aControl;
177 aInfo.SetValue(aObject, ctrl.Checked);
179 else if (aInfo.PropertyType == typeof(string))
181 TextBox ctrl = (TextBox)aControl;
182 aInfo.SetValue(aObject, ctrl.Text);
184 else if (aInfo.PropertyType == typeof(PropertyFile))
186 Button ctrl = (Button)aControl;
187 PropertyFile value = new PropertyFile {FullPath=ctrl.Text};
188 aInfo.SetValue(aObject, value);
190 else if (aInfo.PropertyType == typeof(PropertyComboBox))
192 ComboBox ctrl = (ComboBox)aControl;
193 string currentItem = ctrl.SelectedItem.ToString();
194 PropertyComboBox value = (PropertyComboBox)aInfo.GetValue(aObject);
195 value.CurrentItem = currentItem;
196 //Not strictly needed but makes sure the set method is called
197 aInfo.SetValue(aObject, value);
200 //TODO: add support for other types here
205 /// Create a control for the given property.
207 /// <param name="aInfo"></param>
208 /// <param name="aAttribute"></param>
209 /// <param name="aObject"></param>
210 /// <returns></returns>
211 private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aObject)
213 if (aInfo.PropertyType == typeof(int))
215 //Integer properties are using numeric editor
216 NumericUpDown ctrl = new NumericUpDown();
217 ctrl.AutoSize = true;
218 ctrl.Minimum = Int32.Parse(aAttribute.Minimum);
219 ctrl.Maximum = Int32.Parse(aAttribute.Maximum);
220 ctrl.Increment = Int32.Parse(aAttribute.Increment);
221 ctrl.Value = (int)aInfo.GetValue(aObject);
222 // Hook-in change notification after setting the value
223 ctrl.ValueChanged += ControlValueChanged;
226 else if (aInfo.PropertyType.IsEnum)
228 //Enum properties are using combo box
229 ComboBox ctrl = new ComboBox();
230 ctrl.AutoSize = true;
232 ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
233 //Data source is fine but it gives us duplicate entries for duplicated enum values
234 //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType);
236 //Therefore we need to explicitly create our items
237 Size cbSize = new Size(0, 0);
238 foreach (string name in aInfo.PropertyType.GetEnumNames())
240 ctrl.Items.Add(name.ToString());
241 Graphics g = this.CreateGraphics();
242 //Since combobox autosize would not work we need to get measure text ourselves
243 SizeF size = g.MeasureString(name.ToString(), ctrl.Font);
244 cbSize.Width = Math.Max(cbSize.Width, (int)size.Width);
245 cbSize.Height = Math.Max(cbSize.Height, (int)size.Height);
248 //Make sure our combobox is large enough
249 ctrl.MinimumSize = cbSize;
251 // Instantiate our enum
252 object enumValue = Activator.CreateInstance(aInfo.PropertyType);
253 enumValue = aInfo.GetValue(aObject);
254 //Set the current item
255 ctrl.SelectedItem = enumValue.ToString();
256 // Hook-in change notification after setting the value
257 ctrl.SelectedIndexChanged += ControlValueChanged;
261 else if (aInfo.PropertyType == typeof(bool))
263 CheckBox ctrl = new CheckBox();
264 ctrl.AutoSize = true;
265 ctrl.Text = aAttribute.Description;
266 ctrl.Checked = (bool)aInfo.GetValue(aObject);
267 // Hook-in change notification after setting the value
268 ctrl.CheckedChanged += ControlValueChanged;
271 else if (aInfo.PropertyType == typeof(string))
273 TextBox ctrl = new TextBox();
274 ctrl.AutoSize = true;
275 ctrl.Text = (string)aInfo.GetValue(aObject);
276 // Hook-in change notification after setting the value
277 ctrl.TextChanged += ControlValueChanged;
280 else if (aInfo.PropertyType == typeof(PropertyFile))
282 // We have a file property
283 // Create a button that will trigger the open file dialog to select our file.
284 Button ctrl = new Button();
285 ctrl.AutoSize = true;
286 ctrl.Text = ((PropertyFile)aInfo.GetValue(aObject)).FullPath;
287 // Add lambda expression to Click event
288 ctrl.Click += (sender, e) =>
290 // Create open file dialog
291 OpenFileDialog ofd = new OpenFileDialog();
292 ofd.RestoreDirectory = true;
293 // Use file filter specified by our property
294 ofd.Filter = aAttribute.Filter;
296 if (DlgBox.ShowDialog(ofd) == DialogResult.OK)
298 // Fetch selected file name
299 ctrl.Text = ofd.FileName;
303 // Hook-in change notification after setting the value
304 ctrl.TextChanged += ControlValueChanged;
307 else if (aInfo.PropertyType == typeof(PropertyComboBox))
310 ComboBox ctrl = new ComboBox();
311 ctrl.AutoSize = true;
313 ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
314 //Data source is such a pain to set the current item
315 //ctrl.DataSource = ((PropertyComboBox)aInfo.GetValue(aObject)).Items;
317 PropertyComboBox pcb = ((PropertyComboBox)aInfo.GetValue(aObject));
318 foreach (string item in pcb.Items)
320 ctrl.Items.Add(item);
323 ctrl.SelectedItem = ((PropertyComboBox)aInfo.GetValue(aObject)).CurrentItem;
327 //TODO: add support for other control type here
332 /// Don't forget to extend that one and adding types
334 /// <returns></returns>
335 private bool IsPropertyTypeSupported(PropertyInfo aInfo)
337 if (aInfo.PropertyType == typeof(int))
341 else if (aInfo.PropertyType.IsEnum)
345 else if (aInfo.PropertyType == typeof(bool))
349 else if (aInfo.PropertyType == typeof(string))
353 else if (aInfo.PropertyType == typeof(PropertyFile))
357 else if (aInfo.PropertyType == typeof(PropertyComboBox))
362 //TODO: add support for other type here
368 /// Update our table layout.
369 /// Will instantiated every field control as defined by our object.
371 /// <param name="aLayout"></param>
372 private void UpdateControls()
376 //Debug.Print("UpdateTableLayoutPanel")
377 //First clean our current panel
378 iTableLayoutPanel.Controls.Clear();
379 iTableLayoutPanel.RowStyles.Clear();
380 iTableLayoutPanel.ColumnStyles.Clear();
381 iTableLayoutPanel.RowCount = 0;
383 //We always want two columns: one for label and one for the field
384 iTableLayoutPanel.ColumnCount = 2;
385 iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
386 iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
395 UpdateStaticControls();
397 //IEnumerable<PropertyInfo> properties = aObject.GetType().GetProperties().Where(
398 // prop => Attribute.IsDefined(prop, typeof(AttributeObjectProperty)));
400 //TODO: Do this whenever a field changes
401 iLabelBrief.Text = Object.Brief();
404 foreach (PropertyInfo pi in Object.GetType().GetProperties())
406 AttributeObjectProperty[] attributes = ((AttributeObjectProperty[])pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
407 if (attributes.Length != 1)
412 AttributeObjectProperty attribute = attributes[0];
414 //Before anything we need to check if that kind of property is supported by our UI
416 Control ctrl = CreateControlForProperty(pi, attribute, Object);
419 //Property type not supported
424 iTableLayoutPanel.RowCount++;
425 iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
427 Label label = new Label();
428 label.AutoSize = true;
429 label.Dock = DockStyle.Fill;
430 label.TextAlign = ContentAlignment.MiddleCenter;
431 label.Text = attribute.Name;
432 toolTip.SetToolTip(label, attribute.Description);
433 iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1);
435 //Add our editor to our form
436 iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1);
437 //Add tooltip to editor too
438 toolTip.SetToolTip(ctrl, attribute.Description);
442 //Entrer object edit mode
443 Object.CurrentState = SharpLib.Ear.Object.State.Edit;
444 Object.PropertyChanged += PropertyChangedEventHandlerThreadSafe;
450 /// <param name="sender"></param>
451 /// <param name="e"></param>
452 void PropertyChangedEventHandlerThreadSafe(object sender, PropertyChangedEventArgs e)
454 if (this.InvokeRequired)
456 //Not in the proper thread, invoke ourselves
457 PropertyChangedEventHandler d = new PropertyChangedEventHandler(PropertyChangedEventHandlerThreadSafe);
458 this.Invoke(d, new object[] { sender, e });
462 // We could test the name of the property that has changed as follow
463 // It's currently not needed though
464 //if (e.PropertyName == "Brief")
466 // Our object has changed behind our back.
467 // That's currently only the case for HID events that are listening for inputs.
468 UpdateStaticControls();
472 private void buttonTest_Click(object sender, EventArgs e)
474 FetchPropertiesValue(Object);
476 //If our object has a test method with no parameters just run it then
477 MethodInfo info = Object.GetType().GetMethod("Test");
478 if ( info != null && info.GetParameters().Length==0)
480 info.Invoke(Object,null);
489 /// <param name="sender"></param>
490 /// <param name="e"></param>
491 private void ControlValueChanged(object sender, EventArgs e)
499 private void UpdateObject()
501 // Update our object with the content of our controls
502 FetchPropertiesValue(Object);
504 UpdateStaticControls();
512 private void UpdateStaticControls()
514 // Update OK and test button status
515 iButtonOk.Enabled = Object.IsValid();
516 iButtonTest.Enabled = iButtonOk.Enabled;
518 // Update brief title
519 iLabelBrief.Text = Object.Brief();
521 // Update object description
522 iLabelDescription.Text = Object.Description;
528 /// <param name="sender"></param>
529 /// <param name="e"></param>
530 private void iComboBoxObjectType_KeyPress(object sender, KeyPressEventArgs e)
532 //Special case for HID events
533 if (Object is EventHid)
535 //Disable handling of key input as we are using key input for changing our event