# HG changeset patch # User StephaneLenclud # Date 1471026305 -7200 # Node ID 4c706feaf7060eba847ea0538dacb95b06de9017 # Parent 8c5cf2228e9af21655ca93ae088ece29dcef8f1e Events can now be instantiated. Action editor is now a generic object editor. diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecActiveSource.cs --- a/Server/Actions/ActionCecActiveSource.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecActiveSource.cs Fri Aug 12 20:25:05 2016 +0200 @@ -10,7 +10,7 @@ namespace SharpDisplayManager { [DataContract] - [AttributeAction(Id = "Cec.ActiveSource", Name = "CEC Active Source", Description = "Set this CEC device as active source.")] + [AttributeObject(Id = "Cec.ActiveSource", Name = "CEC Active Source", Description = "Set this CEC device as active source.")] class ActionCecActiveSource : ActionCecDeviceType { /// diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecClose.cs --- a/Server/Actions/ActionCecClose.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecClose.cs Fri Aug 12 20:25:05 2016 +0200 @@ -10,7 +10,7 @@ namespace SharpDisplayManager { [DataContract] - [AttributeAction(Id = "Cec.Close", Name = "CEC Close", Description = "Close CEC connection.")] + [AttributeObject(Id = "Cec.Close", Name = "CEC Close", Description = "Close CEC connection.")] class ActionCecClose : SharpLib.Ear.Action { protected override void DoExecute() diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecDevice.cs --- a/Server/Actions/ActionCecDevice.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecDevice.cs Fri Aug 12 20:25:05 2016 +0200 @@ -17,7 +17,7 @@ public abstract class ActionCecDevice: SharpLib.Ear.Action { [DataMember] - [AttributeActionProperty + [AttributeObjectProperty ( Id = "CEC.Device", Name = "Device", diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecDevicePowerOn.cs --- a/Server/Actions/ActionCecDevicePowerOn.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecDevicePowerOn.cs Fri Aug 12 20:25:05 2016 +0200 @@ -11,7 +11,7 @@ namespace SharpDisplayManager { [DataContract] - [AttributeAction(Id = "Cec.Device.PowerOn", Name = "CEC Device Power On", Description = "Turns on the specified CEC device on your HDMI bus.")] + [AttributeObject(Id = "Cec.Device.PowerOn", Name = "CEC Device Power On", Description = "Turns on the specified CEC device on your HDMI bus.")] public class ActionCecDevicePowerOn : ActionCecDevice { /// diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecDeviceStandby.cs --- a/Server/Actions/ActionCecDeviceStandby.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecDeviceStandby.cs Fri Aug 12 20:25:05 2016 +0200 @@ -11,7 +11,7 @@ namespace SharpDisplayManager { [DataContract] - [AttributeAction(Id = "Cec.Device.Standby", Name = "CEC Device Standby", Description = "Puts on standby the specified CEC device on your HDMI bus.")] + [AttributeObject(Id = "Cec.Device.Standby", Name = "CEC Device Standby", Description = "Puts on standby the specified CEC device on your HDMI bus.")] public class ActionCecDeviceStandby : ActionCecDevice { /// diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecDeviceType.cs --- a/Server/Actions/ActionCecDeviceType.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecDeviceType.cs Fri Aug 12 20:25:05 2016 +0200 @@ -17,7 +17,7 @@ public abstract class ActionCecDeviceType : SharpLib.Ear.Action { [DataMember] - [AttributeActionProperty + [AttributeObjectProperty ( Id = "CEC.DeviceType", Name = "Device Type", diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecInactiveSource.cs --- a/Server/Actions/ActionCecInactiveSource.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecInactiveSource.cs Fri Aug 12 20:25:05 2016 +0200 @@ -10,7 +10,7 @@ namespace SharpDisplayManager { [DataContract] - [AttributeAction(Id = "Cec.InactiveSource", Name = "CEC Inactive Source", Description = "Set this CEC device as inactive source.")] + [AttributeObject(Id = "Cec.InactiveSource", Name = "CEC Inactive Source", Description = "Set this CEC device as inactive source.")] class ActionCecInactiveSource : SharpLib.Ear.Action { protected override void DoExecute() diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecOpen.cs --- a/Server/Actions/ActionCecOpen.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecOpen.cs Fri Aug 12 20:25:05 2016 +0200 @@ -10,7 +10,7 @@ namespace SharpDisplayManager { [DataContract] - [AttributeAction(Id = "Cec.Open", Name = "CEC Open", Description = "Open CEC connection.")] + [AttributeObject(Id = "Cec.Open", Name = "CEC Open", Description = "Open CEC connection.")] class ActionCecOpen : SharpLib.Ear.Action { protected override void DoExecute() diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecScan.cs --- a/Server/Actions/ActionCecScan.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecScan.cs Fri Aug 12 20:25:05 2016 +0200 @@ -11,7 +11,7 @@ { [DataContract] - [AttributeAction(Id = "Cec.Scan", Name = "CEC Scan", Description = "Scan devices on your CEC HDMI network.")] + [AttributeObject(Id = "Cec.Scan", Name = "CEC Scan", Description = "Scan devices on your CEC HDMI network.")] class ActionCecScan : SharpLib.Ear.Action { protected override void DoExecute() diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecUserControlPressed.cs --- a/Server/Actions/ActionCecUserControlPressed.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecUserControlPressed.cs Fri Aug 12 20:25:05 2016 +0200 @@ -14,7 +14,7 @@ /// Send a user key press event to the given CEC device. /// [DataContract] - [AttributeAction(Id = "Cec.UserControlPressed", Name = "CEC User Control Pressed", Description = "Send user control code to defined CEC device.")] + [AttributeObject(Id = "Cec.UserControlPressed", Name = "CEC User Control Pressed", Description = "Send user control code to defined CEC device.")] public class ActionCecUserControlPressed : ActionCecDevice { @@ -24,7 +24,7 @@ } [DataMember] - [AttributeActionProperty( + [AttributeObjectProperty( Id = "Cec.UserControlPressed.Code", Name = "Code", Description = "The key code used by this action." @@ -32,7 +32,7 @@ public CecUserControlCode Code { get; set; } [DataMember] - [AttributeActionProperty( + [AttributeObjectProperty( Id = "Cec.UserControlPressed.Wait", Name = "Wait", Description = "Wait for that command." diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionCecUserControlReleased.cs --- a/Server/Actions/ActionCecUserControlReleased.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionCecUserControlReleased.cs Fri Aug 12 20:25:05 2016 +0200 @@ -14,7 +14,7 @@ /// Send a user key press event to the given CEC device. /// [DataContract] - [AttributeAction(Id = "Cec.UserControlReleased", Name = "CEC User Control Released", Description = "Send user control release opcode to a given CEC device.")] + [AttributeObject(Id = "Cec.UserControlReleased", Name = "CEC User Control Released", Description = "Send user control release opcode to a given CEC device.")] public class ActionCecUserControlReleased : ActionCecDevice { @@ -24,7 +24,7 @@ } [DataMember] - [AttributeActionProperty( + [AttributeObjectProperty( Id = "Cec.UserControlPressed.Wait", Name = "Wait", Description = "Wait for that command." diff -r 8c5cf2228e9a -r 4c706feaf706 Server/Actions/ActionDisplayMessage.cs --- a/Server/Actions/ActionDisplayMessage.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/Actions/ActionDisplayMessage.cs Fri Aug 12 20:25:05 2016 +0200 @@ -13,11 +13,11 @@ [DataContract] - [AttributeAction(Id = "Display.Message", Name = "Display Message", Description = "Shows a message on your internal display.")] + [AttributeObject(Id = "Display.Message", Name = "Display Message", Description = "Shows a message on your internal display.")] class ActionDisplayMessage : SharpLib.Ear.Action { [DataMember] - [AttributeActionProperty( + [AttributeObjectProperty( Id = "Display.Message.Duration", Name = "Duration (ms)", Description = "Specifies the number of milliseconds this message should be displayed.", @@ -29,7 +29,7 @@ [DataMember] - [AttributeActionProperty( + [AttributeObjectProperty( Id = "Display.Message.PrimaryText", Name = "Primary Text", Description = "The primary text of this message." @@ -37,7 +37,7 @@ public string PrimaryText { get; set; } = "Your message"; [DataMember] - [AttributeActionProperty( + [AttributeObjectProperty( Id = "Display.Message.SecondaryText", Name = "Secondary Text", Description = "The secondary text of this message." diff -r 8c5cf2228e9a -r 4c706feaf706 Server/ConsumerElectronicControl.cs --- a/Server/ConsumerElectronicControl.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/ConsumerElectronicControl.cs Fri Aug 12 20:25:05 2016 +0200 @@ -82,14 +82,14 @@ { MonitorPowerOn = true; //Trigger corresponding event thus executing associated actions - ManagerEventAction.Current.GetEvent().Trigger(); + ManagerEventAction.Current.TriggerEvent(); } private void OnMonitorPowerOff() { MonitorPowerOn = false; //Trigger corresponding event thus executing associated actions - ManagerEventAction.Current.GetEvent().Trigger(); + ManagerEventAction.Current.TriggerEvent(); } /// diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormEditAction.Designer.cs --- a/Server/FormEditAction.Designer.cs Sun Jul 31 12:03:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -namespace SharpDisplayManager -{ - partial class FormEditAction - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.comboBoxActionType = new System.Windows.Forms.ComboBox(); - this.labelActionType = new System.Windows.Forms.Label(); - this.buttonOk = new System.Windows.Forms.Button(); - this.buttonCancel = new System.Windows.Forms.Button(); - this.iTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); - this.toolTip = new System.Windows.Forms.ToolTip(this.components); - this.buttonTest = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // comboBoxActionType - // - this.comboBoxActionType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.comboBoxActionType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBoxActionType.FormattingEnabled = true; - this.comboBoxActionType.Location = new System.Drawing.Point(55, 12); - this.comboBoxActionType.Name = "comboBoxActionType"; - this.comboBoxActionType.Size = new System.Drawing.Size(272, 21); - this.comboBoxActionType.Sorted = true; - this.comboBoxActionType.TabIndex = 18; - this.comboBoxActionType.SelectedIndexChanged += new System.EventHandler(this.comboBoxActionType_SelectedIndexChanged); - // - // labelActionType - // - this.labelActionType.AutoSize = true; - this.labelActionType.Location = new System.Drawing.Point(12, 15); - this.labelActionType.Name = "labelActionType"; - this.labelActionType.Size = new System.Drawing.Size(37, 13); - this.labelActionType.TabIndex = 20; - this.labelActionType.Text = "Type :"; - // - // buttonOk - // - this.buttonOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.OK; - this.buttonOk.Location = new System.Drawing.Point(12, 72); - this.buttonOk.Name = "buttonOk"; - this.buttonOk.Size = new System.Drawing.Size(75, 23); - this.buttonOk.TabIndex = 21; - this.buttonOk.Text = "Ok"; - this.buttonOk.UseVisualStyleBackColor = true; - this.buttonOk.Click += new System.EventHandler(this.buttonOk_Click); - // - // buttonCancel - // - this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.Location = new System.Drawing.Point(93, 72); - this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(75, 23); - this.buttonCancel.TabIndex = 22; - this.buttonCancel.Text = "Cancel"; - this.buttonCancel.UseVisualStyleBackColor = true; - // - // iTableLayoutPanel - // - this.iTableLayoutPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.iTableLayoutPanel.AutoSize = true; - this.iTableLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.iTableLayoutPanel.ColumnCount = 2; - this.iTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.iTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.iTableLayoutPanel.Location = new System.Drawing.Point(15, 50); - this.iTableLayoutPanel.Name = "iTableLayoutPanel"; - this.iTableLayoutPanel.RowCount = 2; - this.iTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.iTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.iTableLayoutPanel.Size = new System.Drawing.Size(312, 16); - this.iTableLayoutPanel.TabIndex = 23; - // - // buttonTest - // - this.buttonTest.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonTest.Location = new System.Drawing.Point(252, 72); - this.buttonTest.Name = "buttonTest"; - this.buttonTest.Size = new System.Drawing.Size(75, 23); - this.buttonTest.TabIndex = 24; - this.buttonTest.Text = "Test"; - this.buttonTest.UseVisualStyleBackColor = true; - this.buttonTest.Click += new System.EventHandler(this.buttonTest_Click); - // - // FormEditAction - // - this.AcceptButton = this.buttonOk; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.CancelButton = this.buttonCancel; - this.ClientSize = new System.Drawing.Size(339, 107); - this.Controls.Add(this.buttonTest); - this.Controls.Add(this.iTableLayoutPanel); - this.Controls.Add(this.buttonCancel); - this.Controls.Add(this.buttonOk); - this.Controls.Add(this.labelActionType); - this.Controls.Add(this.comboBoxActionType); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "FormEditAction"; - this.Text = "Edit action"; - this.Load += new System.EventHandler(this.FormEditAction_Load); - this.Validating += new System.ComponentModel.CancelEventHandler(this.FormEditAction_Validating); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.ComboBox comboBoxActionType; - private System.Windows.Forms.Label labelActionType; - private System.Windows.Forms.Button buttonOk; - private System.Windows.Forms.Button buttonCancel; - private System.Windows.Forms.TableLayoutPanel iTableLayoutPanel; - private System.Windows.Forms.ToolTip toolTip; - private System.Windows.Forms.Button buttonTest; - } -} \ No newline at end of file diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormEditAction.cs --- a/Server/FormEditAction.cs Sun Jul 31 12:03:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,325 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Diagnostics; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using SharpLib.Display; -using SharpLib.Ear; -using System.Reflection; - -namespace SharpDisplayManager -{ - /// - /// Action edit dialog form. - /// - public partial class FormEditAction : Form - { - public SharpLib.Ear.Action Action = null; - - public FormEditAction() - { - InitializeComponent(); - } - - /// - /// - /// - /// - /// - private void FormEditAction_Load(object sender, EventArgs e) - { - // Populate registered actions - foreach (string key in ManagerEventAction.Current.ActionTypes.Keys) - { - ItemActionType item = new ItemActionType(ManagerEventAction.Current.ActionTypes[key]); - comboBoxActionType.Items.Add(item); - } - - if (Action == null) - { - // Creating new issue, select our first item - comboBoxActionType.SelectedIndex = 0; - } - else - { - // Editing existing issue - // Look up our item in our combobox - foreach (ItemActionType item in comboBoxActionType.Items) - { - if (item.Type == Action.GetType()) - { - comboBoxActionType.SelectedItem = item; - } - } - } - } - - private void buttonOk_Click(object sender, EventArgs e) - { - FetchPropertiesValue(Action); - } - - private void FormEditAction_Validating(object sender, CancelEventArgs e) - { - - } - - private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e) - { - //Instantiate an action corresponding to our type - Type actionType = ((ItemActionType) comboBoxActionType.SelectedItem).Type; - //Create another type of action only if needed - if (Action == null || Action.GetType() != actionType) - { - Action = (SharpLib.Ear.Action)Activator.CreateInstance(actionType); - } - - //Create input fields - UpdateTableLayoutPanel(Action); - } - - - /// - /// Get properties values from our generated input fields - /// - private void FetchPropertiesValue(SharpLib.Ear.Action aAction) - { - int ctrlIndex = 0; - foreach (PropertyInfo pi in aAction.GetType().GetProperties()) - { - AttributeActionProperty[] attributes = - ((AttributeActionProperty[]) pi.GetCustomAttributes(typeof(AttributeActionProperty), true)); - if (attributes.Length != 1) - { - continue; - } - - AttributeActionProperty attribute = attributes[0]; - - if (!IsPropertyTypeSupported(pi)) - { - continue; - } - - GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aAction); //+1 otherwise we get the label - - ctrlIndex+=2; //Jump over the label too - } - } - - /// - /// Extend this function to support reading new types of properties. - /// - /// - private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, SharpLib.Ear.Action aAction) - { - if (aInfo.PropertyType == typeof(int)) - { - NumericUpDown ctrl=(NumericUpDown)aControl; - aInfo.SetValue(aAction,(int)ctrl.Value); - } - else if (aInfo.PropertyType.IsEnum) - { - // Instantiate our enum - object enumValue= Activator.CreateInstance(aInfo.PropertyType); - // Parse our enum from combo box - enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString()); - //enumValue = ((ComboBox)aControl).SelectedValue; - // Set enum value - aInfo.SetValue(aAction, enumValue); - } - else if (aInfo.PropertyType == typeof(bool)) - { - CheckBox ctrl = (CheckBox)aControl; - aInfo.SetValue(aAction, ctrl.Checked); - } - else if (aInfo.PropertyType == typeof(string)) - { - TextBox ctrl = (TextBox)aControl; - aInfo.SetValue(aAction, ctrl.Text); - } - //TODO: add support for other types here - } - - /// - /// - /// - /// - /// - private Control CreateControlForProperty(PropertyInfo aInfo, AttributeActionProperty aAttribute, SharpLib.Ear.Action aAction) - { - if (aInfo.PropertyType == typeof(int)) - { - //Integer properties are using numeric editor - NumericUpDown ctrl = new NumericUpDown(); - ctrl.AutoSize = true; - ctrl.Minimum = Int32.Parse(aAttribute.Minimum); - ctrl.Maximum = Int32.Parse(aAttribute.Maximum); - ctrl.Increment = Int32.Parse(aAttribute.Increment); - ctrl.Value = (int)aInfo.GetValue(aAction); - return ctrl; - } - else if (aInfo.PropertyType.IsEnum) - { - //Enum properties are using combo box - ComboBox ctrl = new ComboBox(); - ctrl.AutoSize = true; - ctrl.Sorted = true; - ctrl.DropDownStyle = ComboBoxStyle.DropDownList; - //Data source is fine but it gives us duplicate entries for duplicated enum values - //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType); - - //Therefore we need to explicitly create our items - Size cbSize = new Size(0,0); - foreach (string name in aInfo.PropertyType.GetEnumNames()) - { - ctrl.Items.Add(name.ToString()); - Graphics g = this.CreateGraphics(); - //Since combobox autosize would not work we need to get measure text ourselves - SizeF size=g.MeasureString(name.ToString(), ctrl.Font); - cbSize.Width = Math.Max(cbSize.Width,(int)size.Width); - cbSize.Height = Math.Max(cbSize.Height, (int)size.Height); - } - - //Make sure our combobox is large enough - ctrl.MinimumSize = cbSize; - - // Instantiate our enum - object enumValue = Activator.CreateInstance(aInfo.PropertyType); - enumValue = aInfo.GetValue(aAction); - //Set the current item - ctrl.SelectedItem = enumValue.ToString(); - - return ctrl; - } - else if (aInfo.PropertyType == typeof(bool)) - { - CheckBox ctrl = new CheckBox(); - ctrl.AutoSize = true; - ctrl.Text = aAttribute.Description; - ctrl.Checked = (bool)aInfo.GetValue(aAction); - return ctrl; - } - else if (aInfo.PropertyType == typeof(string)) - { - TextBox ctrl = new TextBox(); - ctrl.AutoSize = true; - ctrl.Text = (string)aInfo.GetValue(aAction); - return ctrl; - } - //TODO: add support for other control type here - - return null; - } - - /// - /// Don't forget to extend that one and adding types - /// - /// - private bool IsPropertyTypeSupported(PropertyInfo aInfo) - { - if (aInfo.PropertyType == typeof(int)) - { - return true; - } - else if (aInfo.PropertyType.IsEnum) - { - return true; - } - else if (aInfo.PropertyType == typeof(bool)) - { - return true; - } - else if (aInfo.PropertyType == typeof(string)) - { - return true; - } - //TODO: add support for other type here - - return false; - } - - /// - /// Update our table layout. - /// Will instantiated every field control as defined by our action. - /// Fields must be specified by rows from the left. - /// - /// - private void UpdateTableLayoutPanel(SharpLib.Ear.Action aAction) - { - toolTip.RemoveAll(); - //Debug.Print("UpdateTableLayoutPanel") - //First clean our current panel - iTableLayoutPanel.Controls.Clear(); - iTableLayoutPanel.RowStyles.Clear(); - iTableLayoutPanel.ColumnStyles.Clear(); - iTableLayoutPanel.RowCount = 0; - - //We always want two columns: one for label and one for the field - iTableLayoutPanel.ColumnCount = 2; - iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - - - if (aAction == null) - { - //Just drop it - return; - } - - //IEnumerable properties = aAction.GetType().GetProperties().Where( - // prop => Attribute.IsDefined(prop, typeof(AttributeActionProperty))); - - - foreach (PropertyInfo pi in aAction.GetType().GetProperties()) - { - AttributeActionProperty[] attributes = ((AttributeActionProperty[])pi.GetCustomAttributes(typeof(AttributeActionProperty), true)); - if (attributes.Length != 1) - { - continue; - } - - AttributeActionProperty attribute = attributes[0]; - - //Before anything we need to check if that kind of property is supported by our UI - //Create the editor - Control ctrl = CreateControlForProperty(pi, attribute, aAction); - if (ctrl == null) - { - //Property type not supported - continue; - } - - //Add a new row - iTableLayoutPanel.RowCount++; - iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - //Create the label - Label label = new Label(); - label.AutoSize = true; - label.Dock = DockStyle.Fill; - label.TextAlign = ContentAlignment.MiddleCenter; - label.Text = attribute.Name; - toolTip.SetToolTip(label, attribute.Description); - iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1); - - //Add our editor to our form - iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1); - //Add tooltip to editor too - toolTip.SetToolTip(ctrl, attribute.Description); - - } - - } - - private void buttonTest_Click(object sender, EventArgs e) - { - FetchPropertiesValue(Action); - Action.Execute(); - } - } -} diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormEditAction.resx --- a/Server/FormEditAction.resx Sun Jul 31 12:03:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - \ No newline at end of file diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormEditObject.Designer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Server/FormEditObject.Designer.cs Fri Aug 12 20:25:05 2016 +0200 @@ -0,0 +1,152 @@ +namespace SharpDisplayManager +{ + partial class FormEditObject + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.comboBoxActionType = new System.Windows.Forms.ComboBox(); + this.labelActionType = new System.Windows.Forms.Label(); + this.buttonOk = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.iTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.buttonTest = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // comboBoxActionType + // + this.comboBoxActionType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.comboBoxActionType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxActionType.FormattingEnabled = true; + this.comboBoxActionType.Location = new System.Drawing.Point(55, 12); + this.comboBoxActionType.Name = "comboBoxActionType"; + this.comboBoxActionType.Size = new System.Drawing.Size(272, 21); + this.comboBoxActionType.Sorted = true; + this.comboBoxActionType.TabIndex = 18; + this.comboBoxActionType.SelectedIndexChanged += new System.EventHandler(this.comboBoxActionType_SelectedIndexChanged); + // + // labelActionType + // + this.labelActionType.AutoSize = true; + this.labelActionType.Location = new System.Drawing.Point(12, 15); + this.labelActionType.Name = "labelActionType"; + this.labelActionType.Size = new System.Drawing.Size(37, 13); + this.labelActionType.TabIndex = 20; + this.labelActionType.Text = "Type :"; + // + // buttonOk + // + this.buttonOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOk.Location = new System.Drawing.Point(12, 72); + this.buttonOk.Name = "buttonOk"; + this.buttonOk.Size = new System.Drawing.Size(75, 23); + this.buttonOk.TabIndex = 21; + this.buttonOk.Text = "Ok"; + this.buttonOk.UseVisualStyleBackColor = true; + this.buttonOk.Click += new System.EventHandler(this.buttonOk_Click); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(93, 72); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 22; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // iTableLayoutPanel + // + this.iTableLayoutPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.iTableLayoutPanel.AutoSize = true; + this.iTableLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.iTableLayoutPanel.ColumnCount = 2; + this.iTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.iTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.iTableLayoutPanel.Location = new System.Drawing.Point(15, 50); + this.iTableLayoutPanel.Name = "iTableLayoutPanel"; + this.iTableLayoutPanel.RowCount = 2; + this.iTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.iTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.iTableLayoutPanel.Size = new System.Drawing.Size(312, 16); + this.iTableLayoutPanel.TabIndex = 23; + // + // buttonTest + // + this.buttonTest.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonTest.Location = new System.Drawing.Point(252, 72); + this.buttonTest.Name = "buttonTest"; + this.buttonTest.Size = new System.Drawing.Size(75, 23); + this.buttonTest.TabIndex = 24; + this.buttonTest.Text = "Test"; + this.buttonTest.UseVisualStyleBackColor = true; + this.buttonTest.Click += new System.EventHandler(this.buttonTest_Click); + // + // FormEditAction + // + this.AcceptButton = this.buttonOk; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.CancelButton = this.buttonCancel; + this.ClientSize = new System.Drawing.Size(339, 107); + this.Controls.Add(this.buttonTest); + this.Controls.Add(this.iTableLayoutPanel); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOk); + this.Controls.Add(this.labelActionType); + this.Controls.Add(this.comboBoxActionType); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormEditAction"; + this.Text = "Edit action"; + this.Load += new System.EventHandler(this.FormEditAction_Load); + this.Validating += new System.ComponentModel.CancelEventHandler(this.FormEditAction_Validating); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ComboBox comboBoxActionType; + private System.Windows.Forms.Label labelActionType; + private System.Windows.Forms.Button buttonOk; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.TableLayoutPanel iTableLayoutPanel; + private System.Windows.Forms.ToolTip toolTip; + private System.Windows.Forms.Button buttonTest; + } +} \ No newline at end of file diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormEditObject.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Server/FormEditObject.cs Fri Aug 12 20:25:05 2016 +0200 @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using SharpLib.Display; +using SharpLib.Ear; +using System.Reflection; +using Microsoft.VisualBasic.CompilerServices; +using SharpLib.Utils; + +namespace SharpDisplayManager +{ + /// + /// Object edit dialog form. + /// + public partial class FormEditObject : Form where T : class + { + public T Object = null; + + public FormEditObject() + { + InitializeComponent(); + } + + /// + /// + /// + /// + /// + private void FormEditAction_Load(object sender, EventArgs e) + { + // Populate registered actions + IEnumerable < Type > types = Reflection.GetConcreteClassesDerivedFrom(); + foreach (Type type in types) + { + ItemObjectType item = new ItemObjectType(type); + comboBoxActionType.Items.Add(item); + } + + if (Object == null) + { + // Creating new issue, select our first item + comboBoxActionType.SelectedIndex = 0; + } + else + { + // Editing existing object + // Look up our item in our combobox + foreach (ItemObjectType item in comboBoxActionType.Items) + { + if (item.Type == Object.GetType()) + { + comboBoxActionType.SelectedItem = item; + } + } + } + } + + private void buttonOk_Click(object sender, EventArgs e) + { + FetchPropertiesValue(Object); + } + + private void FormEditAction_Validating(object sender, CancelEventArgs e) + { + + } + + private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e) + { + //Instantiate an action corresponding to our type + Type actionType = ((ItemObjectType) comboBoxActionType.SelectedItem).Type; + //Create another type of action only if needed + if (Object == null || Object.GetType() != actionType) + { + Object = (T)Activator.CreateInstance(actionType); + } + + //Create input fields + UpdateTableLayoutPanel(Object); + } + + + /// + /// Get properties values from our generated input fields + /// + private void FetchPropertiesValue(T aAction) + { + int ctrlIndex = 0; + foreach (PropertyInfo pi in aAction.GetType().GetProperties()) + { + AttributeObjectProperty[] attributes = + ((AttributeObjectProperty[]) pi.GetCustomAttributes(typeof(AttributeObjectProperty), true)); + if (attributes.Length != 1) + { + continue; + } + + AttributeObjectProperty attribute = attributes[0]; + + if (!IsPropertyTypeSupported(pi)) + { + continue; + } + + GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aAction); //+1 otherwise we get the label + + ctrlIndex+=2; //Jump over the label too + } + } + + /// + /// Extend this function to support reading new types of properties. + /// + /// + private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, T aAction) + { + if (aInfo.PropertyType == typeof(int)) + { + NumericUpDown ctrl=(NumericUpDown)aControl; + aInfo.SetValue(aAction,(int)ctrl.Value); + } + else if (aInfo.PropertyType.IsEnum) + { + // Instantiate our enum + object enumValue= Activator.CreateInstance(aInfo.PropertyType); + // Parse our enum from combo box + enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString()); + //enumValue = ((ComboBox)aControl).SelectedValue; + // Set enum value + aInfo.SetValue(aAction, enumValue); + } + else if (aInfo.PropertyType == typeof(bool)) + { + CheckBox ctrl = (CheckBox)aControl; + aInfo.SetValue(aAction, ctrl.Checked); + } + else if (aInfo.PropertyType == typeof(string)) + { + TextBox ctrl = (TextBox)aControl; + aInfo.SetValue(aAction, ctrl.Text); + } + //TODO: add support for other types here + } + + /// + /// + /// + /// + /// + private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aAction) + { + if (aInfo.PropertyType == typeof(int)) + { + //Integer properties are using numeric editor + NumericUpDown ctrl = new NumericUpDown(); + ctrl.AutoSize = true; + ctrl.Minimum = Int32.Parse(aAttribute.Minimum); + ctrl.Maximum = Int32.Parse(aAttribute.Maximum); + ctrl.Increment = Int32.Parse(aAttribute.Increment); + ctrl.Value = (int)aInfo.GetValue(aAction); + return ctrl; + } + else if (aInfo.PropertyType.IsEnum) + { + //Enum properties are using combo box + ComboBox ctrl = new ComboBox(); + ctrl.AutoSize = true; + ctrl.Sorted = true; + ctrl.DropDownStyle = ComboBoxStyle.DropDownList; + //Data source is fine but it gives us duplicate entries for duplicated enum values + //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType); + + //Therefore we need to explicitly create our items + Size cbSize = new Size(0,0); + foreach (string name in aInfo.PropertyType.GetEnumNames()) + { + ctrl.Items.Add(name.ToString()); + Graphics g = this.CreateGraphics(); + //Since combobox autosize would not work we need to get measure text ourselves + SizeF size=g.MeasureString(name.ToString(), ctrl.Font); + cbSize.Width = Math.Max(cbSize.Width,(int)size.Width); + cbSize.Height = Math.Max(cbSize.Height, (int)size.Height); + } + + //Make sure our combobox is large enough + ctrl.MinimumSize = cbSize; + + // Instantiate our enum + object enumValue = Activator.CreateInstance(aInfo.PropertyType); + enumValue = aInfo.GetValue(aAction); + //Set the current item + ctrl.SelectedItem = enumValue.ToString(); + + return ctrl; + } + else if (aInfo.PropertyType == typeof(bool)) + { + CheckBox ctrl = new CheckBox(); + ctrl.AutoSize = true; + ctrl.Text = aAttribute.Description; + ctrl.Checked = (bool)aInfo.GetValue(aAction); + return ctrl; + } + else if (aInfo.PropertyType == typeof(string)) + { + TextBox ctrl = new TextBox(); + ctrl.AutoSize = true; + ctrl.Text = (string)aInfo.GetValue(aAction); + return ctrl; + } + //TODO: add support for other control type here + + return null; + } + + /// + /// Don't forget to extend that one and adding types + /// + /// + private bool IsPropertyTypeSupported(PropertyInfo aInfo) + { + if (aInfo.PropertyType == typeof(int)) + { + return true; + } + else if (aInfo.PropertyType.IsEnum) + { + return true; + } + else if (aInfo.PropertyType == typeof(bool)) + { + return true; + } + else if (aInfo.PropertyType == typeof(string)) + { + return true; + } + //TODO: add support for other type here + + return false; + } + + /// + /// Update our table layout. + /// Will instantiated every field control as defined by our action. + /// Fields must be specified by rows from the left. + /// + /// + private void UpdateTableLayoutPanel(T aAction) + { + toolTip.RemoveAll(); + //Debug.Print("UpdateTableLayoutPanel") + //First clean our current panel + iTableLayoutPanel.Controls.Clear(); + iTableLayoutPanel.RowStyles.Clear(); + iTableLayoutPanel.ColumnStyles.Clear(); + iTableLayoutPanel.RowCount = 0; + + //We always want two columns: one for label and one for the field + iTableLayoutPanel.ColumnCount = 2; + iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + + + if (aAction == null) + { + //Just drop it + return; + } + + //IEnumerable properties = aAction.GetType().GetProperties().Where( + // prop => Attribute.IsDefined(prop, typeof(AttributeObjectProperty))); + + + foreach (PropertyInfo pi in aAction.GetType().GetProperties()) + { + AttributeObjectProperty[] attributes = ((AttributeObjectProperty[])pi.GetCustomAttributes(typeof(AttributeObjectProperty), true)); + if (attributes.Length != 1) + { + continue; + } + + AttributeObjectProperty attribute = attributes[0]; + + //Before anything we need to check if that kind of property is supported by our UI + //Create the editor + Control ctrl = CreateControlForProperty(pi, attribute, aAction); + if (ctrl == null) + { + //Property type not supported + continue; + } + + //Add a new row + iTableLayoutPanel.RowCount++; + iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + //Create the label + Label label = new Label(); + label.AutoSize = true; + label.Dock = DockStyle.Fill; + label.TextAlign = ContentAlignment.MiddleCenter; + label.Text = attribute.Name; + toolTip.SetToolTip(label, attribute.Description); + iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1); + + //Add our editor to our form + iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1); + //Add tooltip to editor too + toolTip.SetToolTip(ctrl, attribute.Description); + + } + + } + + private void buttonTest_Click(object sender, EventArgs e) + { + FetchPropertiesValue(Object); + + //If our object has a test method with no parameters just run it then + MethodInfo info = Object.GetType().GetMethod("Test"); + if ( info != null && info.GetParameters().Length==0) + { + info.Invoke(Object,null); + } + + } + } +} diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormEditObject.resx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Server/FormEditObject.resx Fri Aug 12 20:25:05 2016 +0200 @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormMain.Designer.cs --- a/Server/FormMain.Designer.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/FormMain.Designer.cs Fri Aug 12 20:25:05 2016 +0200 @@ -110,6 +110,10 @@ this.labelHdmiPort = new System.Windows.Forms.Label(); this.comboBoxHdmiPort = new System.Windows.Forms.ComboBox(); this.tabPageEvent = new System.Windows.Forms.TabPage(); + this.buttonEventEdit = new System.Windows.Forms.Button(); + this.buttonEventDelete = new System.Windows.Forms.Button(); + this.buttonEventAdd = new System.Windows.Forms.Button(); + this.buttonEventTest = new System.Windows.Forms.Button(); this.buttonActionEdit = new System.Windows.Forms.Button(); this.buttonActionMoveUp = new System.Windows.Forms.Button(); this.buttonActionMoveDown = new System.Windows.Forms.Button(); @@ -129,7 +133,6 @@ this.labelFontHeight = new System.Windows.Forms.Label(); this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); - this.buttonEventTest = new System.Windows.Forms.Button(); this.panelDisplay.SuspendLayout(); this.iTableLayoutPanel.SuspendLayout(); this.statusStrip.SuspendLayout(); @@ -974,6 +977,9 @@ // // tabPageEvent // + this.tabPageEvent.Controls.Add(this.buttonEventEdit); + this.tabPageEvent.Controls.Add(this.buttonEventDelete); + this.tabPageEvent.Controls.Add(this.buttonEventAdd); this.tabPageEvent.Controls.Add(this.buttonEventTest); this.tabPageEvent.Controls.Add(this.buttonActionEdit); this.tabPageEvent.Controls.Add(this.buttonActionMoveUp); @@ -990,10 +996,53 @@ this.tabPageEvent.Text = "Events"; this.tabPageEvent.UseVisualStyleBackColor = true; // + // buttonEventEdit + // + this.buttonEventEdit.Enabled = false; + this.buttonEventEdit.Location = new System.Drawing.Point(6, 35); + this.buttonEventEdit.Name = "buttonEventEdit"; + this.buttonEventEdit.Size = new System.Drawing.Size(96, 23); + this.buttonEventEdit.TabIndex = 29; + this.buttonEventEdit.Text = "Edit Event"; + this.buttonEventEdit.UseVisualStyleBackColor = true; + this.buttonEventEdit.Click += new System.EventHandler(this.buttonEventEdit_Click); + // + // buttonEventDelete + // + this.buttonEventDelete.Enabled = false; + this.buttonEventDelete.Location = new System.Drawing.Point(6, 64); + this.buttonEventDelete.Name = "buttonEventDelete"; + this.buttonEventDelete.Size = new System.Drawing.Size(96, 23); + this.buttonEventDelete.TabIndex = 28; + this.buttonEventDelete.Text = "Delete Event"; + this.buttonEventDelete.UseVisualStyleBackColor = true; + this.buttonEventDelete.Click += new System.EventHandler(this.buttonEventDelete_Click); + // + // buttonEventAdd + // + this.buttonEventAdd.Location = new System.Drawing.Point(6, 6); + this.buttonEventAdd.Name = "buttonEventAdd"; + this.buttonEventAdd.Size = new System.Drawing.Size(96, 23); + this.buttonEventAdd.TabIndex = 27; + this.buttonEventAdd.Text = "Add Event"; + this.buttonEventAdd.UseVisualStyleBackColor = true; + this.buttonEventAdd.Click += new System.EventHandler(this.buttonEventAdd_Click); + // + // buttonEventTest + // + this.buttonEventTest.Enabled = false; + this.buttonEventTest.Location = new System.Drawing.Point(6, 93); + this.buttonEventTest.Name = "buttonEventTest"; + this.buttonEventTest.Size = new System.Drawing.Size(96, 23); + this.buttonEventTest.TabIndex = 26; + this.buttonEventTest.Text = "Test Event"; + this.buttonEventTest.UseVisualStyleBackColor = true; + this.buttonEventTest.Click += new System.EventHandler(this.buttonEventTest_Click); + // // buttonActionEdit // this.buttonActionEdit.Enabled = false; - this.buttonActionEdit.Location = new System.Drawing.Point(6, 35); + this.buttonActionEdit.Location = new System.Drawing.Point(6, 190); this.buttonActionEdit.Name = "buttonActionEdit"; this.buttonActionEdit.Size = new System.Drawing.Size(96, 23); this.buttonActionEdit.TabIndex = 25; @@ -1026,7 +1075,7 @@ // buttonActionTest // this.buttonActionTest.Enabled = false; - this.buttonActionTest.Location = new System.Drawing.Point(6, 93); + this.buttonActionTest.Location = new System.Drawing.Point(6, 248); this.buttonActionTest.Name = "buttonActionTest"; this.buttonActionTest.Size = new System.Drawing.Size(96, 23); this.buttonActionTest.TabIndex = 22; @@ -1037,7 +1086,7 @@ // buttonActionDelete // this.buttonActionDelete.Enabled = false; - this.buttonActionDelete.Location = new System.Drawing.Point(6, 64); + this.buttonActionDelete.Location = new System.Drawing.Point(6, 219); this.buttonActionDelete.Name = "buttonActionDelete"; this.buttonActionDelete.Size = new System.Drawing.Size(96, 23); this.buttonActionDelete.TabIndex = 21; @@ -1048,9 +1097,9 @@ // buttonActionAdd // this.buttonActionAdd.Enabled = false; - this.buttonActionAdd.Location = new System.Drawing.Point(6, 6); + this.buttonActionAdd.Location = new System.Drawing.Point(6, 157); this.buttonActionAdd.Name = "buttonActionAdd"; - this.buttonActionAdd.Size = new System.Drawing.Size(96, 23); + this.buttonActionAdd.Size = new System.Drawing.Size(96, 27); this.buttonActionAdd.TabIndex = 20; this.buttonActionAdd.Text = "Add Action"; this.buttonActionAdd.UseVisualStyleBackColor = true; @@ -1067,6 +1116,7 @@ this.iTreeViewEvents.Size = new System.Drawing.Size(638, 376); this.iTreeViewEvents.TabIndex = 1; this.iTreeViewEvents.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.iTreeViewEvents_AfterSelect); + this.iTreeViewEvents.Leave += new System.EventHandler(this.iTreeViewEvents_Leave); // // tabPageApp // @@ -1189,17 +1239,6 @@ // this.openFileDialog.Filter = "EXE files (*.exe)|*.exe|All files (*.*)|*.*"; // - // buttonEventTest - // - this.buttonEventTest.Enabled = false; - this.buttonEventTest.Location = new System.Drawing.Point(6, 122); - this.buttonEventTest.Name = "buttonEventTest"; - this.buttonEventTest.Size = new System.Drawing.Size(96, 23); - this.buttonEventTest.TabIndex = 26; - this.buttonEventTest.Text = "Test Event"; - this.buttonEventTest.UseVisualStyleBackColor = true; - this.buttonEventTest.Click += new System.EventHandler(this.buttonEventTest_Click); - // // FormMain // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1344,6 +1383,9 @@ private System.Windows.Forms.Button buttonActionTest; private System.Windows.Forms.Button buttonActionEdit; private System.Windows.Forms.Button buttonEventTest; + private System.Windows.Forms.Button buttonEventDelete; + private System.Windows.Forms.Button buttonEventAdd; + private System.Windows.Forms.Button buttonEventEdit; } } diff -r 8c5cf2228e9a -r 4c706feaf706 Server/FormMain.cs --- a/Server/FormMain.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/FormMain.cs Fri Aug 12 20:25:05 2016 +0200 @@ -322,23 +322,33 @@ Event currentEvent = CurrentEvent(); SharpLib.Ear.Action currentAction = CurrentAction(); TreeNode treeNodeToSelect = null; - + //Reset our tree iTreeViewEvents.Nodes.Clear(); //Populate registered events - foreach (string key in ManagerEventAction.Current.Events.Keys) + foreach (SharpLib.Ear.Event e in ManagerEventAction.Current.Events) { - Event e = ManagerEventAction.Current.Events[key]; - TreeNode eventNode = iTreeViewEvents.Nodes.Add(key, e.Name); - eventNode.Tag = e; - eventNode.Nodes.Add(key + ".Description", e.Description); - TreeNode actionsNodes = eventNode.Nodes.Add(key + ".Actions", "Actions"); + //Create our event node + TreeNode eventNode = iTreeViewEvents.Nodes.Add(e.Name); + eventNode.Tag = e; //For easy access to our event + if (!e.Enabled) + { + //Dim our nodes if disabled + eventNode.ForeColor = Color.DimGray; + } + + //Add event description as child node + eventNode.Nodes.Add(e.Description).ForeColor = eventNode.ForeColor; + //Create child node for actions root + TreeNode actionsNodes = eventNode.Nodes.Add("Actions"); + actionsNodes.ForeColor = eventNode.ForeColor; // Add our actions for that event foreach (SharpLib.Ear.Action a in e.Actions) { TreeNode actionNode = actionsNodes.Nodes.Add(a.Brief()); actionNode.Tag = a; + actionNode.ForeColor = eventNode.ForeColor; if (a == currentAction) { treeNodeToSelect = actionNode; @@ -360,7 +370,14 @@ iTreeViewEvents.SelectedNode.Nodes[1].Nodes[ iTreeViewEvents.SelectedNode.Nodes[1].GetNodeCount(false) - 1]; } - + else if (iTreeViewEvents.SelectedNode == null && iTreeViewEvents.Nodes.Count > 0) + { + //Still no selected node select the first one then + iTreeViewEvents.SelectedNode = iTreeViewEvents.Nodes[0]; + } + + + UpdateEventView(); } /// @@ -2727,12 +2744,13 @@ return; } - string key = aEvent.GetType().Name; - TreeNode[] res = iTreeViewEvents.Nodes.Find(key, false); - if (res.Length > 0) + foreach (TreeNode node in iTreeViewEvents.Nodes) { - iTreeViewEvents.SelectedNode = res[0]; - iTreeViewEvents.Focus(); + if (node.Tag == aEvent) + { + iTreeViewEvents.SelectedNode = node; + iTreeViewEvents.Focus(); + } } } @@ -2789,12 +2807,12 @@ return; } - FormEditAction ea = new FormEditAction(); + FormEditObject ea = new FormEditObject(); ea.Text = "Add action"; DialogResult res = CodeProject.Dialog.DlgBox.ShowDialog(ea); if (res == DialogResult.OK) { - selectedEvent.Actions.Add(ea.Action); + selectedEvent.Actions.Add(ea.Object); Properties.Settings.Default.Actions = ManagerEventAction.Current; Properties.Settings.Default.Save(); PopulateEventsTreeView(); @@ -2816,15 +2834,15 @@ return; } - FormEditAction ea = new FormEditAction(); + FormEditObject ea = new FormEditObject(); ea.Text = "Edit action"; - ea.Action = selectedAction; + ea.Object = selectedAction; int actionIndex = iTreeViewEvents.SelectedNode.Index; DialogResult res = CodeProject.Dialog.DlgBox.ShowDialog(ea); if (res == DialogResult.OK) { //Update our action - selectedEvent.Actions[actionIndex]=ea.Action; + selectedEvent.Actions[actionIndex]=ea.Object; //Save and rebuild our event tree view Properties.Settings.Default.Actions = ManagerEventAction.Current; Properties.Settings.Default.Save(); @@ -2863,8 +2881,7 @@ SharpLib.Ear.Action a = CurrentAction(); if (a != null) { - Console.WriteLine("Action testing:"); - a.Execute(); + a.Test(); } iTreeViewEvents.Focus(); } @@ -2939,8 +2956,7 @@ Event earEvent = CurrentEvent(); if (earEvent != null) { - Console.WriteLine("Event testing:"); - earEvent.Trigger(); + earEvent.Test(); } } @@ -2951,9 +2967,22 @@ /// private void iTreeViewEvents_AfterSelect(object sender, TreeViewEventArgs e) { + UpdateEventView(); + } + + /// + /// + /// + private void UpdateEventView() + { + //One can always add an event + buttonEventAdd.Enabled = true; + //Enable buttons according to selected item buttonActionAdd.Enabled = buttonEventTest.Enabled = + buttonEventDelete.Enabled = + buttonEventEdit.Enabled = CurrentEvent() != null; SharpLib.Ear.Action currentAction = CurrentAction(); @@ -2962,7 +2991,7 @@ buttonActionDelete.Enabled = buttonActionMoveUp.Enabled = buttonActionMoveDown.Enabled = - buttonActionEdit.Enabled = + buttonActionEdit.Enabled = currentAction != null; if (currentAction != null) @@ -2972,8 +3001,65 @@ buttonActionMoveDown.Enabled = iTreeViewEvents.SelectedNode.Index < iTreeViewEvents.SelectedNode.Parent.Nodes.Count - 1; } - } + private void buttonEventAdd_Click(object sender, EventArgs e) + { + FormEditObject ea = new FormEditObject(); + ea.Text = "Add event"; + DialogResult res = CodeProject.Dialog.DlgBox.ShowDialog(ea); + if (res == DialogResult.OK) + { + ManagerEventAction.Current.Events.Add(ea.Object); + Properties.Settings.Default.Actions = ManagerEventAction.Current; + Properties.Settings.Default.Save(); + PopulateEventsTreeView(); + SelectEvent(ea.Object); + } + } + + private void buttonEventDelete_Click(object sender, EventArgs e) + { + SharpLib.Ear.Event currentEvent = CurrentEvent(); + if (currentEvent == null) + { + //Must select action node + return; + } + + ManagerEventAction.Current.Events.Remove(currentEvent); + Properties.Settings.Default.Actions = ManagerEventAction.Current; + Properties.Settings.Default.Save(); + PopulateEventsTreeView(); + } + + private void buttonEventEdit_Click(object sender, EventArgs e) + { + Event selectedEvent = CurrentEvent(); + if (selectedEvent == null) + { + //We did not find a corresponding event + return; + } + + FormEditObject ea = new FormEditObject(); + ea.Text = "Edit event"; + ea.Object = selectedEvent; + int actionIndex = iTreeViewEvents.SelectedNode.Index; + DialogResult res = CodeProject.Dialog.DlgBox.ShowDialog(ea); + if (res == DialogResult.OK) + { + //Save and rebuild our event tree view + Properties.Settings.Default.Actions = ManagerEventAction.Current; + Properties.Settings.Default.Save(); + PopulateEventsTreeView(); + } + } + + private void iTreeViewEvents_Leave(object sender, EventArgs e) + { + //Make sure our event tree never looses focus + ((TreeView) sender).Focus(); + } } } diff -r 8c5cf2228e9a -r 4c706feaf706 Server/ItemActionType.cs --- a/Server/ItemActionType.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/ItemActionType.cs Fri Aug 12 20:25:05 2016 +0200 @@ -10,11 +10,11 @@ /// /// Used to populate our action type combobox with friendly names /// - class ItemActionType + class ItemObjectType { public Type Type; - public ItemActionType(Type type) + public ItemObjectType(Type type) { this.Type = type; } @@ -23,7 +23,7 @@ { //Get friendly action name from action attribute. //That we then show up in our combobox - return SharpLib.Utils.Reflection.GetAttribute(Type).Name; + return SharpLib.Utils.Reflection.GetAttribute(Type).Name; } } } diff -r 8c5cf2228e9a -r 4c706feaf706 Server/SharpDisplayManager.csproj --- a/Server/SharpDisplayManager.csproj Sun Jul 31 12:03:52 2016 +0200 +++ b/Server/SharpDisplayManager.csproj Fri Aug 12 20:25:05 2016 +0200 @@ -169,11 +169,11 @@ - + Form - - FormEditAction.cs + + FormEditObject.cs Form @@ -210,8 +210,8 @@ - - FormEditAction.cs + + FormEditObject.cs FormMain.cs diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/Action.cs --- a/SharpLibEar/Action.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/SharpLibEar/Action.cs Fri Aug 12 20:25:05 2016 +0200 @@ -14,6 +14,15 @@ { protected abstract void DoExecute(); + /// + /// Allows testing from generic edit dialog. + /// + public void Test() + { + Console.WriteLine("Action test"); + Execute(); + } + public void Execute() { Console.WriteLine("Action executing: " + Brief()); @@ -22,7 +31,7 @@ public string Name { //Get the name of this object action attribute - get { return Utils.Reflection.GetAttribute(GetType()).Name; } + get { return Utils.Reflection.GetAttribute(GetType()).Name; } private set { } } @@ -34,7 +43,7 @@ public int CompareTo(object obj) { //Sort by action name - return Utils.Reflection.GetAttribute(GetType()).Name.CompareTo(obj.GetType()); + return Utils.Reflection.GetAttribute(GetType()).Name.CompareTo(obj.GetType()); } private static IEnumerable DerivedTypes() diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/ActionSleep.cs --- a/SharpLibEar/ActionSleep.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/SharpLibEar/ActionSleep.cs Fri Aug 12 20:25:05 2016 +0200 @@ -10,11 +10,11 @@ [DataContract] - [AttributeAction(Id = "Thread.Sleep", Name = "Sleep", Description = "Have the current thread sleep for the specified amount of milliseconds.")] + [AttributeObject(Id = "Thread.Sleep", Name = "Sleep", Description = "Have the current thread sleep for the specified amount of milliseconds.")] public class ActionSleep : Action { [DataMember] - [AttributeActionProperty + [AttributeObjectProperty ( Id = "Thread.Sleep.Timeout", Name = "Timeout (ms)", diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/AttributeAction.cs --- a/SharpLibEar/AttributeAction.cs Sun Jul 31 12:03:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SharpLib.Ear -{ - - /// - /// For action class to define name and description. - /// - [System.AttributeUsage(System.AttributeTargets.Class)] - public class AttributeAction : System.Attribute - { - public string Id; - public string Name; - public string Description; - } - - -} diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/AttributeActionProperty.cs --- a/SharpLibEar/AttributeActionProperty.cs Sun Jul 31 12:03:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SharpLib.Ear -{ - /// - /// To expose an action property thus enabling user to edit it. - /// - [System.AttributeUsage(System.AttributeTargets.Property)] - public class AttributeActionProperty : System.Attribute - { - public string Id; - public string Name; - public string Description; - // For numerics - public string Minimum; - public string Maximum; - public string Increment; - } - - - - -} diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/AttributeObject.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SharpLibEar/AttributeObject.cs Fri Aug 12 20:25:05 2016 +0200 @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpLib.Ear +{ + + /// + /// For action class to define name and description. + /// + [System.AttributeUsage(System.AttributeTargets.Class)] + public class AttributeObject : System.Attribute + { + public string Id; + public string Name; + public string Description; + } + + +} diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/AttributeObjectProperty.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SharpLibEar/AttributeObjectProperty.cs Fri Aug 12 20:25:05 2016 +0200 @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpLib.Ear +{ + /// + /// To expose an action property thus enabling user to edit it. + /// + [System.AttributeUsage(System.AttributeTargets.Property)] + public class AttributeObjectProperty : System.Attribute + { + public string Id; + public string Name; + public string Description; + // For numerics + public string Minimum; + public string Maximum; + public string Increment; + } + + + + +} diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/Event.cs --- a/SharpLibEar/Event.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/SharpLibEar/Event.cs Fri Aug 12 20:25:05 2016 +0200 @@ -8,26 +8,54 @@ namespace SharpLib.Ear { [DataContract] - public abstract class MEvent + [KnownType("DerivedTypes")] + public abstract class Event { - public string Name { get; protected set; } - public string Description { get; protected set; } + [DataMember] + [AttributeObjectProperty + ( + Id = "Event.Enabled", + Name = "Enabled", + Description = "When enabled an event instance can be triggered." + ) + ] + public bool Enabled { get; set; } - public abstract void Trigger(); - }; - - [DataContract] - public abstract class Event : MEvent - { [DataMember] public List Actions = new List(); + public string Name + { + //Get the name of this object attribute + get { return Utils.Reflection.GetAttribute(GetType()).Name; } + private set { } + } + + public string Description + { + //Get the description of this object attribute + get { return Utils.Reflection.GetAttribute(GetType()).Description; } + private set { } + } + + protected Event() { - + Enabled = true; } - public override void Trigger() + + /// + /// Allows testing from generic edit dialog. + /// + public void Test() + { + Console.WriteLine("Event test"); + Trigger(); + } + + + public void Trigger() { Console.WriteLine("Event triggered: " + Name); foreach (Action action in Actions) @@ -35,6 +63,15 @@ action.Execute(); } } - } + + /// + /// So that data contract knows all our types. + /// + /// + private static IEnumerable DerivedTypes() + { + return SharpLib.Utils.Reflection.GetDerivedTypes(); + } + }; } \ No newline at end of file diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/EventMonitorPowerOff.cs --- a/SharpLibEar/EventMonitorPowerOff.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/SharpLibEar/EventMonitorPowerOff.cs Fri Aug 12 20:25:05 2016 +0200 @@ -6,12 +6,11 @@ namespace SharpLib.Ear { [DataContract] + [AttributeObject(Id = "Event.Monitor.PowerOff", Name = "Monitor Power Off", Description = "Windows is powering off your monitor.")] public class EventMonitorPowerOff : Event { public EventMonitorPowerOff() { - Name = "Monitor Power Off"; - Description = "Windows is powering off your monitor."; } } diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/EventMonitorPowerOn.cs --- a/SharpLibEar/EventMonitorPowerOn.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/SharpLibEar/EventMonitorPowerOn.cs Fri Aug 12 20:25:05 2016 +0200 @@ -6,12 +6,11 @@ namespace SharpLib.Ear { [DataContract] + [AttributeObject(Id = "Event.Monitor.PowerOn", Name = "Monitor Power On", Description = "Windows is powering on your monitor.")] public class EventMonitorPowerOn : Event { public EventMonitorPowerOn() { - Name = "Monitor Power On"; - Description = "Windows is powering on your monitor."; } } diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/ManagerEventAction.cs --- a/SharpLibEar/ManagerEventAction.cs Sun Jul 31 12:03:52 2016 +0200 +++ b/SharpLibEar/ManagerEventAction.cs Fri Aug 12 20:25:05 2016 +0200 @@ -16,10 +16,16 @@ public class ManagerEventAction { public static ManagerEventAction Current = null; - public IDictionary ActionTypes; - public IDictionary Events; + //public IDictionary ActionTypes; + //public IDictionary EventTypes; + + /// + /// Our events instances. + /// [DataMember] - public Dictionary> ActionsByEvents = new Dictionary>(); + public List Events; + + public ManagerEventAction() @@ -28,47 +34,30 @@ } /// - /// + /// Executes after internalization took place. /// public void Init() { - //Create our list of supported actions - ActionTypes = Utils.Reflection.GetConcreteClassesDerivedFromByName(); - //Create our list or support events - Events = Utils.Reflection.GetConcreteClassesInstanceDerivedFromByName(); + if (Events == null) + { + Events = new List(); + } + + } - if (ActionsByEvents == null) - { - ActionsByEvents = new Dictionary>(); - } - - //Hook in loaded actions with corresponding events - foreach (string key in Events.Keys) + /// + /// + /// + /// + public void TriggerEvent() where T: class + { + //Only trigger enabled events matching the desired type + foreach (Event e in Events.Where(e => e.GetType() == typeof(T) && e.Enabled)) { - Event e = Events[key]; - if (ActionsByEvents.ContainsKey(key)) - { - //We have actions for that event, hook them in then - e.Actions = ActionsByEvents[key]; - } - else - { - //We do not have actions for that event yet, create empty action list - e.Actions = new List(); - ActionsByEvents[key] = e.Actions; - } + e.Trigger(); } } - /// - /// Get and event instance from its type. - /// - /// - /// - public Event GetEvent() where T : class - { - return Events[typeof(T).Name]; - } /// /// @@ -76,17 +65,14 @@ /// public void RemoveAction(Action aAction) { - foreach (string key in Events.Keys) + foreach (Event e in Events) { - Event e = Events[key]; if (e.Actions.Remove(aAction)) { //We removed our action, we are done here. return; } - } } - } } \ No newline at end of file diff -r 8c5cf2228e9a -r 4c706feaf706 SharpLibEar/SharpLibEar.csproj --- a/SharpLibEar/SharpLibEar.csproj Sun Jul 31 12:03:52 2016 +0200 +++ b/SharpLibEar/SharpLibEar.csproj Fri Aug 12 20:25:05 2016 +0200 @@ -45,8 +45,8 @@ - - + +