Server/FormEditObject.cs
changeset 231 4c706feaf706
child 236 6ba20e02d04f
     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 +}