Server/FormEditObject.cs
author StephaneLenclud
Fri, 19 Aug 2016 19:18:54 +0200
changeset 244 2e4d2558bb21
parent 243 cc2251d065db
child 246 30a221eecc06
permissions -rw-r--r--
Adding non functional generic EAR HID event.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Diagnostics;
     6 using System.Drawing;
     7 using System.Linq;
     8 using System.Text;
     9 using System.Threading.Tasks;
    10 using System.Windows.Forms;
    11 using SharpLib.Display;
    12 using SharpLib.Ear;
    13 using System.Reflection;
    14 using Microsoft.VisualBasic.CompilerServices;
    15 using SharpLib.Utils;
    16 using CodeProject.Dialog;
    17 using System.IO;
    18 
    19 namespace SharpDisplayManager
    20 {
    21     /// <summary>
    22     /// Object edit dialog form.
    23     /// </summary>
    24     public partial class FormEditObject<T> : Form where T: SharpLib.Ear.Object
    25     {
    26         public T Object = null;
    27 
    28         public FormEditObject()
    29         {
    30             InitializeComponent();
    31         }
    32 
    33         /// <summary>
    34         /// 
    35         /// </summary>
    36         /// <param name="sender"></param>
    37         /// <param name="e"></param>
    38         private void FormEditAction_Load(object sender, EventArgs e)
    39         {
    40             // Populate registered object types
    41             IEnumerable < Type > types = Reflection.GetConcreteClassesDerivedFrom<T>();
    42             foreach (Type type in types)
    43             {
    44                 ItemObjectType item = new ItemObjectType(type);
    45                 comboBoxActionType.Items.Add(item);
    46             }
    47 
    48             if (Object == null)
    49             {
    50                 // Creating new issue, select our first item
    51                 comboBoxActionType.SelectedIndex = 0;
    52             }
    53             else
    54             {
    55                 // Editing existing object
    56                 // Look up our item in our combobox
    57                 foreach (ItemObjectType item in comboBoxActionType.Items)
    58                 {
    59                     if (item.Type == Object.GetType())
    60                     {
    61                         comboBoxActionType.SelectedItem = item;
    62                     }
    63                 }
    64             }
    65         }
    66 
    67         private void buttonOk_Click(object sender, EventArgs e)
    68         {
    69             FetchPropertiesValue(Object);
    70             if (!Object.IsValid())
    71             {
    72                 // Tell for closing event to abort
    73                 DialogResult = DialogResult.None;
    74             }
    75         }
    76 
    77 
    78         private void FormEditObject_FormClosing(object sender, FormClosingEventArgs e)
    79         {
    80             e.Cancel = DialogResult == DialogResult.None;
    81         }
    82 
    83         private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e)
    84         {
    85             //Instantiate an action corresponding to our type
    86             Type actionType = ((ItemObjectType) comboBoxActionType.SelectedItem).Type;
    87             //Create another type of action only if needed
    88             if (Object == null || Object.GetType() != actionType)
    89             {
    90                 Object = (T)Activator.CreateInstance(actionType);
    91             }
    92 
    93             //Disable ok button if our object is not valid
    94             buttonOk.Enabled = Object.IsValid();
    95 
    96             //Create input fields
    97             UpdateTableLayoutPanel(Object);
    98         }
    99 
   100 
   101         /// <summary>
   102         /// Get properties values from our generated input fields
   103         /// </summary>
   104         private void FetchPropertiesValue(T aObject)
   105         {
   106             int ctrlIndex = 0;
   107             //For each of our properties
   108             foreach (PropertyInfo pi in aObject.GetType().GetProperties())
   109             {
   110                 //Get our property attribute
   111                 AttributeObjectProperty[] attributes = ((AttributeObjectProperty[]) pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
   112                 if (attributes.Length != 1)
   113                 {
   114                     //No attribute, skip this property then.
   115                     continue;
   116                 }
   117                 AttributeObjectProperty attribute = attributes[0];
   118 
   119                 //Check that we support this type of property
   120                 if (!IsPropertyTypeSupported(pi))
   121                 {
   122                     continue;
   123                 }
   124 
   125                 //Now fetch our property value
   126                 GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aObject); //+1 otherwise we get the label
   127 
   128                 ctrlIndex+=2; //Jump over the label too
   129             }
   130         }
   131 
   132         /// <summary>
   133         /// Extend this function to support reading new types of properties.
   134         /// </summary>
   135         /// <param name="aObject"></param>
   136         private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, T aObject)
   137         {
   138             if (aInfo.PropertyType == typeof(int))
   139             {
   140                 NumericUpDown ctrl=(NumericUpDown)aControl;
   141                 aInfo.SetValue(aObject,(int)ctrl.Value);
   142             }
   143             else if (aInfo.PropertyType.IsEnum)
   144             {
   145                 // Instantiate our enum
   146                 object enumValue= Activator.CreateInstance(aInfo.PropertyType);
   147                 // Parse our enum from combo box
   148                 enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString());
   149                 //enumValue = ((ComboBox)aControl).SelectedValue;
   150                 // Set enum value
   151                 aInfo.SetValue(aObject, enumValue);
   152             }
   153             else if (aInfo.PropertyType == typeof(bool))
   154             {
   155                 CheckBox ctrl = (CheckBox)aControl;
   156                 aInfo.SetValue(aObject, ctrl.Checked);
   157             }
   158             else if (aInfo.PropertyType == typeof(string))
   159             {
   160                 TextBox ctrl = (TextBox)aControl;
   161                 aInfo.SetValue(aObject, ctrl.Text);
   162             }
   163             else if (aInfo.PropertyType == typeof(PropertyFile))
   164             {
   165                 Button ctrl = (Button)aControl;
   166                 PropertyFile value = new PropertyFile {FullPath=ctrl.Text};
   167                 aInfo.SetValue(aObject, value);
   168             }
   169             else if (aInfo.PropertyType == typeof(PropertyComboBox))
   170             {
   171                 ComboBox ctrl = (ComboBox)aControl;
   172                 string currentItem = ctrl.SelectedItem.ToString();
   173                 PropertyComboBox value = (PropertyComboBox)aInfo.GetValue(aObject);
   174                 value.CurrentItem = currentItem;
   175                 //Not strictly needed but makes sure the set method is called
   176                 aInfo.SetValue(aObject, value);                
   177             }
   178 
   179             //TODO: add support for other types here
   180         }
   181 
   182 
   183         /// <summary>
   184         /// Create a control for the given property.
   185         /// </summary>
   186         /// <param name="aInfo"></param>
   187         /// <param name="aAttribute"></param>
   188         /// <param name="aObject"></param>
   189         /// <returns></returns>
   190         private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aObject)
   191         {
   192             if (aInfo.PropertyType == typeof(int))
   193             {
   194                 //Integer properties are using numeric editor
   195                 NumericUpDown ctrl = new NumericUpDown();
   196                 ctrl.AutoSize = true;
   197                 ctrl.Minimum = Int32.Parse(aAttribute.Minimum);
   198                 ctrl.Maximum = Int32.Parse(aAttribute.Maximum);
   199                 ctrl.Increment = Int32.Parse(aAttribute.Increment);
   200                 ctrl.Value = (int)aInfo.GetValue(aObject);
   201                 return ctrl;
   202             }
   203             else if (aInfo.PropertyType.IsEnum)
   204             {
   205                 //Enum properties are using combo box
   206                 ComboBox ctrl = new ComboBox();
   207                 ctrl.AutoSize = true;
   208                 ctrl.Sorted = true;
   209                 ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
   210                 //Data source is fine but it gives us duplicate entries for duplicated enum values
   211                 //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType);
   212 
   213                 //Therefore we need to explicitly create our items
   214                 Size cbSize = new Size(0, 0);
   215                 foreach (string name in aInfo.PropertyType.GetEnumNames())
   216                 {
   217                     ctrl.Items.Add(name.ToString());
   218                     Graphics g = this.CreateGraphics();
   219                     //Since combobox autosize would not work we need to get measure text ourselves
   220                     SizeF size = g.MeasureString(name.ToString(), ctrl.Font);
   221                     cbSize.Width = Math.Max(cbSize.Width, (int)size.Width);
   222                     cbSize.Height = Math.Max(cbSize.Height, (int)size.Height);
   223                 }
   224 
   225                 //Make sure our combobox is large enough
   226                 ctrl.MinimumSize = cbSize;
   227 
   228                 // Instantiate our enum
   229                 object enumValue = Activator.CreateInstance(aInfo.PropertyType);
   230                 enumValue = aInfo.GetValue(aObject);
   231                 //Set the current item
   232                 ctrl.SelectedItem = enumValue.ToString();
   233 
   234                 return ctrl;
   235             }
   236             else if (aInfo.PropertyType == typeof(bool))
   237             {
   238                 CheckBox ctrl = new CheckBox();
   239                 ctrl.AutoSize = true;
   240                 ctrl.Text = aAttribute.Description;
   241                 ctrl.Checked = (bool)aInfo.GetValue(aObject);
   242                 return ctrl;
   243             }
   244             else if (aInfo.PropertyType == typeof(string))
   245             {
   246                 TextBox ctrl = new TextBox();
   247                 ctrl.AutoSize = true;
   248                 ctrl.Text = (string)aInfo.GetValue(aObject);
   249                 return ctrl;
   250             }
   251             else if (aInfo.PropertyType == typeof(PropertyFile))
   252             {
   253                 // We have a file property
   254                 // Create a button that will trigger the open file dialog to select our file.
   255                 Button ctrl = new Button();
   256                 ctrl.AutoSize = true;
   257                 ctrl.Text = ((PropertyFile)aInfo.GetValue(aObject)).FullPath;
   258 
   259                 // Add lambda expression to Click event
   260                 ctrl.Click += (sender, e) =>
   261                 {
   262                     // Create open file dialog
   263                     OpenFileDialog ofd = new OpenFileDialog();
   264                     ofd.RestoreDirectory = true;
   265                     // Use file filter specified by our property
   266                     ofd.Filter = aAttribute.Filter;
   267                     // Show our dialog
   268                     if (DlgBox.ShowDialog(ofd) == DialogResult.OK)
   269                     {
   270                         // Fetch selected file name
   271                         ctrl.Text = ofd.FileName;
   272                         //Enable Ok button then
   273                         buttonOk.Enabled = Object.IsValid();
   274                     }
   275                 };
   276 
   277                 return ctrl;
   278             }
   279             else if (aInfo.PropertyType == typeof(PropertyComboBox))
   280             {
   281                 //ComboBox property
   282                 ComboBox ctrl = new ComboBox();
   283                 ctrl.AutoSize = true;
   284                 ctrl.Sorted = true;
   285                 ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
   286                 //Data source is such a pain to set the current item
   287                 //ctrl.DataSource = ((PropertyComboBox)aInfo.GetValue(aObject)).Items;                
   288 
   289                 PropertyComboBox pcb = ((PropertyComboBox)aInfo.GetValue(aObject));
   290                 foreach (string item in pcb.Items)
   291                 {
   292                     ctrl.Items.Add(item);
   293                 }
   294 
   295                 ctrl.SelectedItem = ((PropertyComboBox)aInfo.GetValue(aObject)).CurrentItem;
   296                 //
   297                 return ctrl;
   298             }
   299             //TODO: add support for other control type here
   300             return null;
   301         }
   302 
   303         /// <summary>
   304         /// Don't forget to extend that one and adding types
   305         /// </summary>
   306         /// <returns></returns>
   307         private bool IsPropertyTypeSupported(PropertyInfo aInfo)
   308         {
   309             if (aInfo.PropertyType == typeof(int))
   310             {
   311                 return true;
   312             }
   313             else if (aInfo.PropertyType.IsEnum)
   314             {
   315                 return true;
   316             }
   317             else if (aInfo.PropertyType == typeof(bool))
   318             {
   319                 return true;
   320             }
   321             else if (aInfo.PropertyType == typeof(string))
   322             {
   323                 return true;
   324             }
   325             else if (aInfo.PropertyType == typeof(PropertyFile))
   326             {
   327                 return true;
   328             }
   329             else if (aInfo.PropertyType == typeof(PropertyComboBox))
   330             {
   331                 return true;
   332             }
   333 
   334             //TODO: add support for other type here
   335 
   336             return false;
   337         }
   338 
   339         /// <summary>
   340         /// Update our table layout.
   341         /// Will instantiated every field control as defined by our action.
   342         /// Fields must be specified by rows from the left.
   343         /// </summary>
   344         /// <param name="aLayout"></param>
   345         private void UpdateTableLayoutPanel(T aObject)
   346         {
   347             toolTip.RemoveAll();
   348             //Debug.Print("UpdateTableLayoutPanel")
   349             //First clean our current panel
   350             iTableLayoutPanel.Controls.Clear();
   351             iTableLayoutPanel.RowStyles.Clear();
   352             iTableLayoutPanel.ColumnStyles.Clear();
   353             iTableLayoutPanel.RowCount = 0;
   354 
   355             //We always want two columns: one for label and one for the field
   356             iTableLayoutPanel.ColumnCount = 2;
   357             iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
   358             iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
   359 
   360 
   361             if (aObject == null)
   362             {
   363                 //Just drop it
   364                 return;
   365             }
   366             
   367             //IEnumerable<PropertyInfo> properties = aObject.GetType().GetProperties().Where(
   368             //    prop => Attribute.IsDefined(prop, typeof(AttributeObjectProperty)));
   369 
   370 
   371             foreach (PropertyInfo pi in aObject.GetType().GetProperties())
   372             {
   373                 AttributeObjectProperty[] attributes = ((AttributeObjectProperty[])pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
   374                 if (attributes.Length != 1)
   375                 {
   376                     continue;
   377                 }
   378 
   379                 AttributeObjectProperty attribute = attributes[0];
   380 
   381                 //Before anything we need to check if that kind of property is supported by our UI
   382                 //Create the editor
   383                 Control ctrl = CreateControlForProperty(pi, attribute, aObject);
   384                 if (ctrl == null)
   385                 {
   386                     //Property type not supported
   387                     continue;
   388                 }
   389 
   390                 //Add a new row
   391                 iTableLayoutPanel.RowCount++;
   392                 iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
   393                 //Create the label
   394                 Label label = new Label();
   395                 label.AutoSize = true;
   396                 label.Dock = DockStyle.Fill;
   397                 label.TextAlign = ContentAlignment.MiddleCenter;
   398                 label.Text = attribute.Name;
   399                 toolTip.SetToolTip(label, attribute.Description);
   400                 iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1);
   401 
   402                 //Add our editor to our form
   403                 iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1);
   404                 //Add tooltip to editor too
   405                 toolTip.SetToolTip(ctrl, attribute.Description);
   406 
   407             }        
   408 
   409         }
   410 
   411         private void buttonTest_Click(object sender, EventArgs e)
   412         {
   413             FetchPropertiesValue(Object);
   414 
   415             //If our object has a test method with no parameters just run it then
   416             MethodInfo info = Object.GetType().GetMethod("Test");
   417             if ( info != null && info.GetParameters().Length==0)
   418             {
   419                 info.Invoke(Object,null);
   420             }
   421 
   422         }
   423     }
   424 }