StephaneLenclud@231: using System;
StephaneLenclud@231: using System.Collections.Generic;
StephaneLenclud@231: using System.ComponentModel;
StephaneLenclud@231: using System.Data;
StephaneLenclud@231: using System.Diagnostics;
StephaneLenclud@231: using System.Drawing;
StephaneLenclud@231: using System.Linq;
StephaneLenclud@231: using System.Text;
StephaneLenclud@231: using System.Threading.Tasks;
StephaneLenclud@231: using System.Windows.Forms;
StephaneLenclud@231: using SharpLib.Display;
StephaneLenclud@231: using SharpLib.Ear;
StephaneLenclud@231: using System.Reflection;
StephaneLenclud@231: using Microsoft.VisualBasic.CompilerServices;
StephaneLenclud@231: using SharpLib.Utils;
StephaneLenclud@238: using CodeProject.Dialog;
StephaneLenclud@239: using System.IO;
StephaneLenclud@231:
StephaneLenclud@231: namespace SharpDisplayManager
StephaneLenclud@231: {
StephaneLenclud@231: ///
StephaneLenclud@231: /// Object edit dialog form.
StephaneLenclud@231: ///
StephaneLenclud@239: public partial class FormEditObject : Form where T: SharpLib.Ear.Object
StephaneLenclud@231: {
StephaneLenclud@231: public T Object = null;
StephaneLenclud@231:
StephaneLenclud@231: public FormEditObject()
StephaneLenclud@231: {
StephaneLenclud@231: InitializeComponent();
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: ///
StephaneLenclud@231: ///
StephaneLenclud@231: ///
StephaneLenclud@231: ///
StephaneLenclud@231: ///
StephaneLenclud@231: private void FormEditAction_Load(object sender, EventArgs e)
StephaneLenclud@231: {
StephaneLenclud@236: // Populate registered object types
StephaneLenclud@231: IEnumerable < Type > types = Reflection.GetConcreteClassesDerivedFrom();
StephaneLenclud@231: foreach (Type type in types)
StephaneLenclud@231: {
StephaneLenclud@231: ItemObjectType item = new ItemObjectType(type);
StephaneLenclud@231: comboBoxActionType.Items.Add(item);
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: if (Object == null)
StephaneLenclud@231: {
StephaneLenclud@231: // Creating new issue, select our first item
StephaneLenclud@231: comboBoxActionType.SelectedIndex = 0;
StephaneLenclud@231: }
StephaneLenclud@231: else
StephaneLenclud@231: {
StephaneLenclud@231: // Editing existing object
StephaneLenclud@239: // Look up our item in our combobox
StephaneLenclud@231: foreach (ItemObjectType item in comboBoxActionType.Items)
StephaneLenclud@231: {
StephaneLenclud@231: if (item.Type == Object.GetType())
StephaneLenclud@231: {
StephaneLenclud@231: comboBoxActionType.SelectedItem = item;
StephaneLenclud@231: }
StephaneLenclud@231: }
StephaneLenclud@239: }
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: private void buttonOk_Click(object sender, EventArgs e)
StephaneLenclud@231: {
StephaneLenclud@231: FetchPropertiesValue(Object);
StephaneLenclud@239: if (!Object.IsValid())
StephaneLenclud@239: {
StephaneLenclud@239: // Tell for closing event to abort
StephaneLenclud@239: DialogResult = DialogResult.None;
StephaneLenclud@239: }
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@239:
StephaneLenclud@239: private void FormEditObject_FormClosing(object sender, FormClosingEventArgs e)
StephaneLenclud@231: {
StephaneLenclud@239: e.Cancel = DialogResult == DialogResult.None;
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e)
StephaneLenclud@231: {
StephaneLenclud@231: //Instantiate an action corresponding to our type
StephaneLenclud@231: Type actionType = ((ItemObjectType) comboBoxActionType.SelectedItem).Type;
StephaneLenclud@231: //Create another type of action only if needed
StephaneLenclud@231: if (Object == null || Object.GetType() != actionType)
StephaneLenclud@231: {
StephaneLenclud@231: Object = (T)Activator.CreateInstance(actionType);
StephaneLenclud@231: }
StephaneLenclud@239:
StephaneLenclud@239: //Disable ok button if our object is not valid
StephaneLenclud@239: buttonOk.Enabled = Object.IsValid();
StephaneLenclud@239:
StephaneLenclud@231: //Create input fields
StephaneLenclud@231: UpdateTableLayoutPanel(Object);
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231:
StephaneLenclud@231: ///
StephaneLenclud@231: /// Get properties values from our generated input fields
StephaneLenclud@231: ///
StephaneLenclud@236: private void FetchPropertiesValue(T aObject)
StephaneLenclud@231: {
StephaneLenclud@231: int ctrlIndex = 0;
Stephane@243: //For each of our properties
StephaneLenclud@236: foreach (PropertyInfo pi in aObject.GetType().GetProperties())
StephaneLenclud@231: {
Stephane@243: //Get our property attribute
Stephane@243: AttributeObjectProperty[] attributes = ((AttributeObjectProperty[]) pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
StephaneLenclud@231: if (attributes.Length != 1)
StephaneLenclud@231: {
Stephane@243: //No attribute, skip this property then.
StephaneLenclud@231: continue;
StephaneLenclud@231: }
StephaneLenclud@231: AttributeObjectProperty attribute = attributes[0];
StephaneLenclud@231:
Stephane@243: //Check that we support this type of property
StephaneLenclud@231: if (!IsPropertyTypeSupported(pi))
StephaneLenclud@231: {
StephaneLenclud@231: continue;
StephaneLenclud@231: }
StephaneLenclud@231:
Stephane@243: //Now fetch our property value
StephaneLenclud@236: GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aObject); //+1 otherwise we get the label
StephaneLenclud@231:
StephaneLenclud@231: ctrlIndex+=2; //Jump over the label too
StephaneLenclud@231: }
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: ///
StephaneLenclud@231: /// Extend this function to support reading new types of properties.
StephaneLenclud@231: ///
StephaneLenclud@236: ///
StephaneLenclud@236: private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, T aObject)
StephaneLenclud@231: {
StephaneLenclud@231: if (aInfo.PropertyType == typeof(int))
StephaneLenclud@231: {
StephaneLenclud@231: NumericUpDown ctrl=(NumericUpDown)aControl;
StephaneLenclud@236: aInfo.SetValue(aObject,(int)ctrl.Value);
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType.IsEnum)
StephaneLenclud@231: {
StephaneLenclud@231: // Instantiate our enum
StephaneLenclud@231: object enumValue= Activator.CreateInstance(aInfo.PropertyType);
StephaneLenclud@231: // Parse our enum from combo box
StephaneLenclud@231: enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString());
StephaneLenclud@231: //enumValue = ((ComboBox)aControl).SelectedValue;
StephaneLenclud@231: // Set enum value
StephaneLenclud@236: aInfo.SetValue(aObject, enumValue);
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType == typeof(bool))
StephaneLenclud@231: {
StephaneLenclud@231: CheckBox ctrl = (CheckBox)aControl;
StephaneLenclud@236: aInfo.SetValue(aObject, ctrl.Checked);
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType == typeof(string))
StephaneLenclud@231: {
StephaneLenclud@231: TextBox ctrl = (TextBox)aControl;
StephaneLenclud@236: aInfo.SetValue(aObject, ctrl.Text);
StephaneLenclud@231: }
StephaneLenclud@238: else if (aInfo.PropertyType == typeof(PropertyFile))
StephaneLenclud@238: {
StephaneLenclud@238: Button ctrl = (Button)aControl;
StephaneLenclud@238: PropertyFile value = new PropertyFile {FullPath=ctrl.Text};
StephaneLenclud@238: aInfo.SetValue(aObject, value);
StephaneLenclud@238: }
Stephane@243: else if (aInfo.PropertyType == typeof(PropertyComboBox))
Stephane@243: {
Stephane@243: ComboBox ctrl = (ComboBox)aControl;
Stephane@243: string currentItem = ctrl.SelectedItem.ToString();
StephaneLenclud@244: PropertyComboBox value = (PropertyComboBox)aInfo.GetValue(aObject);
StephaneLenclud@244: value.CurrentItem = currentItem;
StephaneLenclud@244: //Not strictly needed but makes sure the set method is called
StephaneLenclud@244: aInfo.SetValue(aObject, value);
Stephane@243: }
Stephane@243:
StephaneLenclud@231: //TODO: add support for other types here
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@236:
StephaneLenclud@231: ///
StephaneLenclud@236: /// Create a control for the given property.
StephaneLenclud@231: ///
StephaneLenclud@231: ///
StephaneLenclud@236: ///
StephaneLenclud@236: ///
StephaneLenclud@236: ///
StephaneLenclud@236: private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aObject)
StephaneLenclud@231: {
StephaneLenclud@231: if (aInfo.PropertyType == typeof(int))
StephaneLenclud@231: {
StephaneLenclud@231: //Integer properties are using numeric editor
StephaneLenclud@231: NumericUpDown ctrl = new NumericUpDown();
StephaneLenclud@231: ctrl.AutoSize = true;
StephaneLenclud@231: ctrl.Minimum = Int32.Parse(aAttribute.Minimum);
StephaneLenclud@231: ctrl.Maximum = Int32.Parse(aAttribute.Maximum);
StephaneLenclud@231: ctrl.Increment = Int32.Parse(aAttribute.Increment);
StephaneLenclud@236: ctrl.Value = (int)aInfo.GetValue(aObject);
StephaneLenclud@231: return ctrl;
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType.IsEnum)
StephaneLenclud@231: {
StephaneLenclud@231: //Enum properties are using combo box
StephaneLenclud@231: ComboBox ctrl = new ComboBox();
Stephane@243: ctrl.AutoSize = true;
Stephane@243: ctrl.Sorted = true;
StephaneLenclud@231: ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
StephaneLenclud@231: //Data source is fine but it gives us duplicate entries for duplicated enum values
StephaneLenclud@231: //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType);
StephaneLenclud@231:
StephaneLenclud@231: //Therefore we need to explicitly create our items
Stephane@243: Size cbSize = new Size(0, 0);
StephaneLenclud@231: foreach (string name in aInfo.PropertyType.GetEnumNames())
StephaneLenclud@231: {
StephaneLenclud@231: ctrl.Items.Add(name.ToString());
StephaneLenclud@231: Graphics g = this.CreateGraphics();
StephaneLenclud@231: //Since combobox autosize would not work we need to get measure text ourselves
Stephane@243: SizeF size = g.MeasureString(name.ToString(), ctrl.Font);
Stephane@243: cbSize.Width = Math.Max(cbSize.Width, (int)size.Width);
StephaneLenclud@231: cbSize.Height = Math.Max(cbSize.Height, (int)size.Height);
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: //Make sure our combobox is large enough
StephaneLenclud@231: ctrl.MinimumSize = cbSize;
StephaneLenclud@231:
StephaneLenclud@231: // Instantiate our enum
StephaneLenclud@231: object enumValue = Activator.CreateInstance(aInfo.PropertyType);
StephaneLenclud@236: enumValue = aInfo.GetValue(aObject);
StephaneLenclud@231: //Set the current item
StephaneLenclud@231: ctrl.SelectedItem = enumValue.ToString();
StephaneLenclud@231:
StephaneLenclud@231: return ctrl;
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType == typeof(bool))
StephaneLenclud@231: {
StephaneLenclud@231: CheckBox ctrl = new CheckBox();
StephaneLenclud@231: ctrl.AutoSize = true;
StephaneLenclud@231: ctrl.Text = aAttribute.Description;
Stephane@243: ctrl.Checked = (bool)aInfo.GetValue(aObject);
StephaneLenclud@231: return ctrl;
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType == typeof(string))
StephaneLenclud@231: {
StephaneLenclud@231: TextBox ctrl = new TextBox();
StephaneLenclud@231: ctrl.AutoSize = true;
StephaneLenclud@236: ctrl.Text = (string)aInfo.GetValue(aObject);
StephaneLenclud@231: return ctrl;
StephaneLenclud@231: }
StephaneLenclud@238: else if (aInfo.PropertyType == typeof(PropertyFile))
StephaneLenclud@238: {
StephaneLenclud@238: // We have a file property
StephaneLenclud@238: // Create a button that will trigger the open file dialog to select our file.
StephaneLenclud@238: Button ctrl = new Button();
StephaneLenclud@238: ctrl.AutoSize = true;
StephaneLenclud@238: ctrl.Text = ((PropertyFile)aInfo.GetValue(aObject)).FullPath;
StephaneLenclud@239:
StephaneLenclud@238: // Add lambda expression to Click event
StephaneLenclud@238: ctrl.Click += (sender, e) =>
StephaneLenclud@238: {
StephaneLenclud@238: // Create open file dialog
StephaneLenclud@238: OpenFileDialog ofd = new OpenFileDialog();
StephaneLenclud@238: ofd.RestoreDirectory = true;
StephaneLenclud@238: // Use file filter specified by our property
StephaneLenclud@238: ofd.Filter = aAttribute.Filter;
StephaneLenclud@238: // Show our dialog
StephaneLenclud@238: if (DlgBox.ShowDialog(ofd) == DialogResult.OK)
StephaneLenclud@238: {
StephaneLenclud@238: // Fetch selected file name
StephaneLenclud@238: ctrl.Text = ofd.FileName;
StephaneLenclud@239: //Enable Ok button then
StephaneLenclud@239: buttonOk.Enabled = Object.IsValid();
StephaneLenclud@238: }
StephaneLenclud@238: };
StephaneLenclud@238:
StephaneLenclud@238: return ctrl;
StephaneLenclud@238: }
Stephane@243: else if (aInfo.PropertyType == typeof(PropertyComboBox))
Stephane@243: {
Stephane@243: //ComboBox property
Stephane@243: ComboBox ctrl = new ComboBox();
Stephane@243: ctrl.AutoSize = true;
Stephane@243: ctrl.Sorted = true;
Stephane@243: ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
Stephane@243: //Data source is such a pain to set the current item
Stephane@243: //ctrl.DataSource = ((PropertyComboBox)aInfo.GetValue(aObject)).Items;
Stephane@243:
Stephane@243: PropertyComboBox pcb = ((PropertyComboBox)aInfo.GetValue(aObject));
Stephane@243: foreach (string item in pcb.Items)
Stephane@243: {
Stephane@243: ctrl.Items.Add(item);
Stephane@243: }
Stephane@243:
Stephane@243: ctrl.SelectedItem = ((PropertyComboBox)aInfo.GetValue(aObject)).CurrentItem;
Stephane@243: //
Stephane@243: return ctrl;
Stephane@243: }
StephaneLenclud@231: //TODO: add support for other control type here
StephaneLenclud@231: return null;
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: ///
StephaneLenclud@231: /// Don't forget to extend that one and adding types
StephaneLenclud@231: ///
StephaneLenclud@231: ///
StephaneLenclud@231: private bool IsPropertyTypeSupported(PropertyInfo aInfo)
StephaneLenclud@231: {
StephaneLenclud@231: if (aInfo.PropertyType == typeof(int))
StephaneLenclud@231: {
StephaneLenclud@231: return true;
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType.IsEnum)
StephaneLenclud@231: {
StephaneLenclud@231: return true;
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType == typeof(bool))
StephaneLenclud@231: {
StephaneLenclud@231: return true;
StephaneLenclud@231: }
StephaneLenclud@231: else if (aInfo.PropertyType == typeof(string))
StephaneLenclud@231: {
StephaneLenclud@231: return true;
StephaneLenclud@231: }
StephaneLenclud@238: else if (aInfo.PropertyType == typeof(PropertyFile))
StephaneLenclud@238: {
StephaneLenclud@238: return true;
StephaneLenclud@238: }
Stephane@243: else if (aInfo.PropertyType == typeof(PropertyComboBox))
Stephane@243: {
Stephane@243: return true;
Stephane@243: }
Stephane@243:
StephaneLenclud@231: //TODO: add support for other type here
StephaneLenclud@231:
StephaneLenclud@231: return false;
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: ///
StephaneLenclud@231: /// Update our table layout.
StephaneLenclud@231: /// Will instantiated every field control as defined by our action.
StephaneLenclud@231: /// Fields must be specified by rows from the left.
StephaneLenclud@231: ///
StephaneLenclud@231: ///
StephaneLenclud@236: private void UpdateTableLayoutPanel(T aObject)
StephaneLenclud@231: {
StephaneLenclud@231: toolTip.RemoveAll();
StephaneLenclud@231: //Debug.Print("UpdateTableLayoutPanel")
StephaneLenclud@231: //First clean our current panel
StephaneLenclud@231: iTableLayoutPanel.Controls.Clear();
StephaneLenclud@231: iTableLayoutPanel.RowStyles.Clear();
StephaneLenclud@231: iTableLayoutPanel.ColumnStyles.Clear();
StephaneLenclud@231: iTableLayoutPanel.RowCount = 0;
StephaneLenclud@231:
StephaneLenclud@231: //We always want two columns: one for label and one for the field
StephaneLenclud@231: iTableLayoutPanel.ColumnCount = 2;
StephaneLenclud@231: iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
StephaneLenclud@231: iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
StephaneLenclud@231:
StephaneLenclud@231:
StephaneLenclud@236: if (aObject == null)
StephaneLenclud@231: {
StephaneLenclud@231: //Just drop it
StephaneLenclud@231: return;
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@236: //IEnumerable properties = aObject.GetType().GetProperties().Where(
StephaneLenclud@231: // prop => Attribute.IsDefined(prop, typeof(AttributeObjectProperty)));
StephaneLenclud@231:
StephaneLenclud@231:
StephaneLenclud@236: foreach (PropertyInfo pi in aObject.GetType().GetProperties())
StephaneLenclud@231: {
StephaneLenclud@231: AttributeObjectProperty[] attributes = ((AttributeObjectProperty[])pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
StephaneLenclud@231: if (attributes.Length != 1)
StephaneLenclud@231: {
StephaneLenclud@231: continue;
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: AttributeObjectProperty attribute = attributes[0];
StephaneLenclud@231:
StephaneLenclud@231: //Before anything we need to check if that kind of property is supported by our UI
StephaneLenclud@231: //Create the editor
StephaneLenclud@236: Control ctrl = CreateControlForProperty(pi, attribute, aObject);
StephaneLenclud@231: if (ctrl == null)
StephaneLenclud@231: {
StephaneLenclud@231: //Property type not supported
StephaneLenclud@231: continue;
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: //Add a new row
StephaneLenclud@231: iTableLayoutPanel.RowCount++;
StephaneLenclud@231: iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
StephaneLenclud@231: //Create the label
StephaneLenclud@231: Label label = new Label();
StephaneLenclud@231: label.AutoSize = true;
StephaneLenclud@231: label.Dock = DockStyle.Fill;
StephaneLenclud@231: label.TextAlign = ContentAlignment.MiddleCenter;
StephaneLenclud@231: label.Text = attribute.Name;
StephaneLenclud@231: toolTip.SetToolTip(label, attribute.Description);
StephaneLenclud@231: iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1);
StephaneLenclud@231:
StephaneLenclud@231: //Add our editor to our form
StephaneLenclud@231: iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1);
StephaneLenclud@231: //Add tooltip to editor too
StephaneLenclud@231: toolTip.SetToolTip(ctrl, attribute.Description);
StephaneLenclud@231:
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: private void buttonTest_Click(object sender, EventArgs e)
StephaneLenclud@231: {
StephaneLenclud@231: FetchPropertiesValue(Object);
StephaneLenclud@231:
StephaneLenclud@231: //If our object has a test method with no parameters just run it then
StephaneLenclud@231: MethodInfo info = Object.GetType().GetMethod("Test");
StephaneLenclud@231: if ( info != null && info.GetParameters().Length==0)
StephaneLenclud@231: {
StephaneLenclud@231: info.Invoke(Object,null);
StephaneLenclud@231: }
StephaneLenclud@231:
StephaneLenclud@231: }
StephaneLenclud@231: }
StephaneLenclud@231: }