# HG changeset patch # User StephaneLenclud # Date 1472667632 -7200 # Node ID 82e87f4956eadd5d3e1cc1a7e63b8d55fae08541 # Parent 4a08e1b7ba64a64cd45e0a51ce09a45e1716ce26 Actions can now have children. diff -r 4a08e1b7ba64 -r 82e87f4956ea Server/FormMain.cs --- a/Server/FormMain.cs Wed Aug 31 17:28:30 2016 +0200 +++ b/Server/FormMain.cs Wed Aug 31 20:20:32 2016 +0200 @@ -309,6 +309,65 @@ } + + private static void AddActionsToTreeNode(TreeNode aParentNode, Ear.Object aObject) + { + foreach (Ear.Action a in aObject.Objects.OfType()) + { + //Create action node + TreeNode actionNode = aParentNode.Nodes.Add(a.Brief()); + actionNode.Tag = a; + //Use color from parent unless our action itself is disabled + actionNode.ForeColor = a.Enabled ? aParentNode.ForeColor : Color.DimGray; + //Go recursive + AddActionsToTreeNode(actionNode,a); + } + } + + + /// + /// + /// + /// + /// + private static TreeNode FindTreeNodeForEarObject(Ear.Object aObject, TreeNode aNode) + { + if (aNode.Tag == aObject) + { + return aNode; + } + + foreach (TreeNode n in aNode.Nodes) + { + TreeNode found = FindTreeNodeForEarObject(aObject,n); + if (found != null) + { + return found; + } + } + + return null; + } + + + /// + /// + /// + /// + private void SelectEarObject(Ear.Object aObject) + { + foreach (TreeNode n in iTreeViewEvents.Nodes) + { + TreeNode found = FindTreeNodeForEarObject(aObject, n); + if (found != null) + { + iTreeViewEvents.SelectedNode=found; + iTreeViewEvents.Focus(); + return; + } + } + } + /// /// Populate tree view with events and actions /// @@ -318,9 +377,6 @@ buttonActionAdd.Enabled = false; buttonActionDelete.Enabled = false; - Ear.Event currentEvent = CurrentEvent(); - Ear.Action currentAction = CurrentAction(); - TreeNode treeNodeToSelect = null; //Reset our tree iTreeViewEvents.Nodes.Clear(); @@ -352,43 +408,14 @@ //Add event description as child node eventNode.Nodes.Add(e.AttributeDescription).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 (Ear.Action a in e.Actions) - { - TreeNode actionNode = actionsNodes.Nodes.Add(a.Brief()); - actionNode.Tag = a; - //Use color from event unless our action itself is disabled - actionNode.ForeColor = a.Enabled? eventNode.ForeColor: Color.DimGray; - if (a == currentAction) - { - treeNodeToSelect = actionNode; - } - } + TreeNode actionsNode = eventNode.Nodes.Add("Actions"); + actionsNode.ForeColor = eventNode.ForeColor; + + // Recursively add our actions for that event + AddActionsToTreeNode(actionsNode,e); } iTreeViewEvents.ExpandAll(); - SelectEvent(currentEvent); - - if (treeNodeToSelect != null) - { - iTreeViewEvents.SelectedNode = treeNodeToSelect; - } - else if (iTreeViewEvents.SelectedNode != null && iTreeViewEvents.SelectedNode.Nodes[1].GetNodeCount(false) > 0) - { - //Select the last action if any - iTreeViewEvents.SelectedNode = - 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(); } @@ -2650,26 +2677,6 @@ } - /// - /// - /// - /// - private void SelectEvent(Ear.Event aEvent) - { - if (aEvent == null) - { - return; - } - - foreach (TreeNode node in iTreeViewEvents.Nodes) - { - if (node.Tag == aEvent) - { - iTreeViewEvents.SelectedNode = node; - iTreeViewEvents.Focus(); - } - } - } @@ -2713,14 +2720,58 @@ /// /// /// + /// + private Ear.Object CurrentEarObject() + { + Ear.Action a = CurrentAction(); + Ear.Event e = CurrentEvent(); + + if (a != null) + { + return a; + } + + return e; + } + + /// + /// Get the current action based on event tree view selection + /// + /// + private Ear.Object CurrentEarParent() + { + TreeNode node = iTreeViewEvents.SelectedNode; + if (node == null || node.Parent == null) + { + return null; + } + + if (node.Parent.Tag is Ear.Object) + { + return (Ear.Object)node.Parent.Tag; + } + + if (node.Parent.Parent != null && node.Parent.Parent.Tag is Ear.Object) + { + //Can be the case for events + return (Ear.Object)node.Parent.Parent.Tag; + } + + return null; + } + + + /// + /// + /// /// /// private void buttonActionAdd_Click(object sender, EventArgs e) { - Ear.Event selectedEvent = CurrentEvent(); - if (selectedEvent == null) + Ear.Object parent = CurrentEarObject(); + if (parent == null ) { - //We did not find a corresponding event + //We did not find a corresponding event or action return; } @@ -2729,9 +2780,10 @@ DialogResult res = CodeProject.Dialog.DlgBox.ShowDialog(ea); if (res == DialogResult.OK) { - selectedEvent.Actions.Add(ea.Object); + parent.Objects.Add(ea.Object); Properties.Settings.Default.Save(); PopulateTreeViewEvents(); + SelectEarObject(ea.Object); } } @@ -2742,11 +2794,12 @@ /// private void buttonActionEdit_Click(object sender, EventArgs e) { - Ear.Event selectedEvent = CurrentEvent(); Ear.Action selectedAction = CurrentAction(); - if (selectedEvent == null || selectedAction == null) + Ear.Object parent = CurrentEarParent() + ; + if (parent == null || selectedAction == null) { - //We did not find a corresponding event + //We did not find a corresponding parent return; } @@ -2757,11 +2810,14 @@ DialogResult res = CodeProject.Dialog.DlgBox.ShowDialog(ea); if (res == DialogResult.OK) { + //Make sure we keep the same children as before + ea.Object.Objects = parent.Objects[actionIndex].Objects; //Update our action - selectedEvent.Actions[actionIndex]=ea.Object; + parent.Objects[actionIndex]=ea.Object; //Save and rebuild our event tree view Properties.Settings.Default.Save(); PopulateTreeViewEvents(); + SelectEarObject(ea.Object); } } @@ -2772,7 +2828,6 @@ /// private void buttonActionDelete_Click(object sender, EventArgs e) { - Ear.Action action = CurrentAction(); if (action == null) { @@ -2816,16 +2871,17 @@ } //Swap actions in event's action list - Ear.Event currentEvent = CurrentEvent(); + Ear.Object parent = CurrentEarParent(); int currentIndex = iTreeViewEvents.SelectedNode.Index; - Ear.Action movingUp = currentEvent.Actions[currentIndex]; - Ear.Action movingDown = currentEvent.Actions[currentIndex-1]; - currentEvent.Actions[currentIndex] = movingDown; - currentEvent.Actions[currentIndex-1] = movingUp; + Ear.Action movingUp = parent.Objects[currentIndex] as Ear.Action; + Ear.Action movingDown = parent.Objects[currentIndex-1] as Ear.Action; + parent.Objects[currentIndex] = movingDown; + parent.Objects[currentIndex-1] = movingUp; //Save and populate our tree again Properties.Settings.Default.Save(); PopulateTreeViewEvents(); + SelectEarObject(a); } @@ -2845,16 +2901,17 @@ } //Swap actions in event's action list - Ear.Event currentEvent = CurrentEvent(); + Ear.Object parent = CurrentEarParent(); int currentIndex = iTreeViewEvents.SelectedNode.Index; - Ear.Action movingDown = currentEvent.Actions[currentIndex]; - Ear.Action movingUp = currentEvent.Actions[currentIndex + 1]; - currentEvent.Actions[currentIndex] = movingUp; - currentEvent.Actions[currentIndex + 1] = movingDown; + Ear.Action movingDown = parent.Objects[currentIndex] as Ear.Action; + Ear.Action movingUp = parent.Objects[currentIndex + 1] as Ear.Action; + parent.Objects[currentIndex] = movingUp; + parent.Objects[currentIndex + 1] = movingDown; //Save and populate our tree again Properties.Settings.Default.Save(); PopulateTreeViewEvents(); + SelectEarObject(a); } @@ -2930,7 +2987,7 @@ Properties.Settings.Default.EarManager.Events.Add(ea.Object); Properties.Settings.Default.Save(); PopulateTreeViewEvents(); - SelectEvent(ea.Object); + SelectEarObject(ea.Object); } } @@ -2975,12 +3032,13 @@ if (res == DialogResult.OK) { //Make sure we keep the same actions as before - ea.Object.Actions = Properties.Settings.Default.EarManager.Events[index].Actions; + ea.Object.Objects = Properties.Settings.Default.EarManager.Events[index].Objects; //Update our event Properties.Settings.Default.EarManager.Events[index] = ea.Object; //Save and rebuild our event tree view Properties.Settings.Default.Save(); PopulateTreeViewEvents(); + SelectEarObject(ea.Object); } } diff -r 4a08e1b7ba64 -r 82e87f4956ea SharpLibEar/Action.cs --- a/SharpLibEar/Action.cs Wed Aug 31 17:28:30 2016 +0200 +++ b/SharpLibEar/Action.cs Wed Aug 31 20:20:32 2016 +0200 @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; @@ -11,7 +12,8 @@ namespace SharpLib.Ear { [DataContract] - public abstract class Action: Object + [AttributeObject(Id = "Action", Name = "Action", Description = "An empty action.")] + public class Action: Object { [DataMember] [AttributeObjectProperty @@ -34,7 +36,14 @@ get { return Iterations > 0; } } - protected abstract Task DoExecute(); + /// + /// Basic action just does nothing + /// + /// + protected virtual async Task DoExecute() + { + + } /// /// Allows testing from generic edit dialog. @@ -66,14 +75,25 @@ for (int i = Iterations; i > 0; i--) { Trace.WriteLine($"EAR: Action.Execute: [{Iterations - i + 1}/{Iterations}] - {BriefBase()}"); + //For each iteration + //We first execute ourselves await DoExecute(); + + //Then our children + foreach (Action a in Objects.OfType()) + { + await a.Execute(); + } } } - + /// + /// For inherited classes to override. + /// + /// public virtual string BriefBase() { - return base.Brief(); + return Name; } /// diff -r 4a08e1b7ba64 -r 82e87f4956ea SharpLibEar/ActionDelay.cs --- a/SharpLibEar/ActionDelay.cs Wed Aug 31 17:28:30 2016 +0200 +++ b/SharpLibEar/ActionDelay.cs Wed Aug 31 20:20:32 2016 +0200 @@ -8,7 +8,7 @@ namespace SharpLib.Ear { [DataContract] - [AttributeObject(Id = "Task.Delay", Name = "Delay", Description = "Delay the execution of the next task by the specified amount of milliseconds.")] + [AttributeObject(Id = "Action.Task.Delay", Name = "Delay", Description = "Delay the execution of the next task.")] public class ActionDelay : Action { [DataMember] @@ -16,7 +16,7 @@ ( Id = "Task.Delay.Milliseconds", Name = "Delay (ms)", - Description = "Specifies our delay in milliseconds.", + Description = "Specifies the delay in milliseconds.", Minimum = "0", Maximum = "60000", Increment = "1000" diff -r 4a08e1b7ba64 -r 82e87f4956ea SharpLibEar/Event.cs --- a/SharpLibEar/Event.cs Wed Aug 31 17:28:30 2016 +0200 +++ b/SharpLibEar/Event.cs Wed Aug 31 20:20:32 2016 +0200 @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.Serialization; using System.Threading.Tasks; @@ -24,41 +25,6 @@ public bool Enabled { get; set; } = true; - /// - /// TODO: Should the name property be moved to our EAR Object? - /// - [DataMember] - [AttributeObjectProperty - ( - Id = "Event.Name", - Name = "Name", - Description = "Given event name. Can be used to trigger it." - ) - ] - public string Name { get; set; } = ""; - - - [DataMember] - public List Actions = new List(); - - - protected override void DoConstruct() - { - base.DoConstruct(); - - //Make sure our name is not null - if (Name == null) - { - Name = ""; - } - - // TODO: Construct properties too - foreach (Action a in Actions) - { - a.Construct(); - } - - } /// @@ -74,7 +40,7 @@ public async Task Trigger() { Trace.WriteLine("Event triggered: " + AttributeName); - foreach (Action action in Actions) + foreach (Action action in Objects.OfType()) { await action.Execute(); } diff -r 4a08e1b7ba64 -r 82e87f4956ea SharpLibEar/Manager.cs --- a/SharpLibEar/Manager.cs Wed Aug 31 17:28:30 2016 +0200 +++ b/SharpLibEar/Manager.cs Wed Aug 31 20:20:32 2016 +0200 @@ -102,12 +102,38 @@ { foreach (Event e in Events) { - if (e.Actions.Remove(aAction)) + if (RemoveObject(e,aAction)) { //We removed our action, we are done here. return; } } } + + /// + /// Remove the specified action from the event it belongs too. + /// + /// + private static bool RemoveObject(Object aCurrent, Object aToRemove) + { + //Exit condition + if (aCurrent.Objects.Remove(aToRemove)) + { + //We removed our action, we are done here. + return true; + } + + foreach (Object o in aCurrent.Objects) + { + bool done = RemoveObject(o, aToRemove); + if (done) + { + return true; + } + } + + return false; + } + } } \ No newline at end of file diff -r 4a08e1b7ba64 -r 82e87f4956ea SharpLibEar/Object.cs --- a/SharpLibEar/Object.cs Wed Aug 31 17:28:30 2016 +0200 +++ b/SharpLibEar/Object.cs Wed Aug 31 20:20:32 2016 +0200 @@ -19,6 +19,22 @@ { private bool iConstructed = false; + [DataMember] + public List Objects = new List(); + + /// + /// + [DataMember] + [AttributeObjectProperty + ( + Id = "Object.Name", + Name = "Name", + Description = "Given object name." + ) + ] + public string Name { get; set; } = ""; + + protected Object() { Construct(); @@ -29,11 +45,18 @@ /// public void Construct() { + //Construct ourselves first if (!iConstructed) { DoConstruct(); iConstructed = true; } + + //Then construct our children + foreach (Object o in Objects) + { + o.Construct(); + } } /// @@ -41,10 +64,19 @@ /// protected virtual void DoConstruct() { + //Make sure our name is not null + if (Name == null) + { + Name = ""; + } + // Makes sure our objects are not null + if (Objects == null) + { + Objects = new List(); + } } - public enum State { Rest=0,