├── .gitattributes ├── .gitignore ├── FlowTomator.Common ├── Error.cs ├── Evaluator │ ├── BasicNodesEvaluator.cs │ └── NodesEvaluator.cs ├── FlowTomator.Common.csproj ├── Log.cs ├── Model │ ├── Choice.cs │ ├── EditableFlow.cs │ ├── Event.cs │ ├── Flow.cs │ ├── Node.cs │ ├── Slot.cs │ ├── Task.cs │ └── Variable.cs ├── NodeAttribute.cs ├── Nodes │ ├── Applications │ │ └── RunApplication.cs │ ├── DateTime │ │ ├── CheckTime.cs │ │ └── TimedEvent.cs │ ├── Devices │ │ ├── Inputs │ │ │ └── MouseMove.cs │ │ └── Network │ │ │ └── NetworkSpeed.cs │ ├── End.cs │ ├── General │ │ ├── Debug.cs │ │ ├── Message.cs │ │ ├── Nope.cs │ │ ├── Sleep.cs │ │ └── Wait.cs │ ├── IO │ │ ├── AppendFile.cs │ │ ├── ChooseFile.cs │ │ ├── CreateDirectory.cs │ │ ├── CreateFile.cs │ │ ├── DeleteFile.cs │ │ ├── DirectoryExists.cs │ │ ├── FileChanged.cs │ │ ├── FileExists.cs │ │ ├── ReadFile.cs │ │ └── WriteFile.cs │ ├── Origin.cs │ ├── System │ │ ├── Clipboard.cs │ │ ├── Desktop.cs │ │ ├── Device │ │ │ ├── Lifetime.cs │ │ │ ├── Lock.cs │ │ │ └── Login.cs │ │ └── Screenshot.cs │ ├── Text │ │ └── Regex.cs │ └── Web │ │ └── WebRequest.cs ├── NumberPattern.cs ├── Properties │ └── AssemblyInfo.cs ├── Storage │ ├── FlowStorageAttribute.cs │ ├── XDependencyFlow.cs │ └── XFlow.cs ├── Utilities.cs └── Utils │ ├── DeviceEvents.cs │ └── Utils.cs ├── FlowTomator.Data ├── DataSet.cs ├── DumpData.cs ├── FlowTomator.Data.csproj ├── Properties │ └── AssemblyInfo.cs ├── SqlQuery.cs ├── app.config └── packages.config ├── FlowTomator.Desktop ├── Actions │ ├── Action.cs │ ├── ActionGroup.cs │ ├── AddLink.cs │ ├── AddNode.cs │ ├── DeleteLink.cs │ ├── DeleteNode.cs │ ├── EditVariable.cs │ ├── HistoryInfo.cs │ ├── LinkVariable.cs │ ├── MoveNode.cs │ └── RenameVariable.cs ├── App.xaml ├── App.xaml.cs ├── Controls │ ├── Anchor.cs │ ├── NodeControl.xaml │ └── NodeControl.xaml.cs ├── Editors │ ├── FlowEditorAttribute.cs │ ├── FlowEditorTemplateSelector.cs │ ├── Flows │ │ ├── FlowEditor.cs │ │ ├── XFlowEditor.xaml │ │ └── XFlowEditor.xaml.cs │ ├── VariableEditorAttribute.cs │ ├── VariableEditorTemplateSelector.cs │ └── Variables │ │ ├── BooleanVariableEditor.xaml │ │ ├── BooleanVariableEditor.xaml.cs │ │ ├── DateTimeVariableEditor.xaml │ │ ├── DateTimeVariableEditor.xaml.cs │ │ ├── DirectoryInfoVariableEditor.xaml │ │ ├── DirectoryInfoVariableEditor.xaml.cs │ │ ├── DynamicEnumerableVariableEditor.xaml │ │ ├── DynamicEnumerableVariableEditor.xaml.cs │ │ ├── EnumerableVariableEditor.xaml │ │ ├── EnumerableVariableEditor.xaml.cs │ │ ├── FileInfoVariableEditor.xaml │ │ ├── FileInfoVariableEditor.xaml.cs │ │ ├── TextVariableEditor.xaml │ │ ├── TextVariableEditor.xaml.cs │ │ ├── TimeSpanVariableEditor.xaml │ │ └── TimeSpanVariableEditor.xaml.cs ├── FlowTomator.Desktop.csproj ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MessageSourceFilterConverter.cs ├── Model │ ├── FlowDebugger.cs │ ├── FlowInfo.cs │ ├── LinkInfo.cs │ ├── NodeCategoryInfo.cs │ ├── NodeInfo.cs │ ├── NodeTypeInfo.cs │ ├── SlotInfo.cs │ └── VariableInfo.cs ├── OpenFolderDialog.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Resources │ ├── Add.png │ ├── Break.png │ ├── BuildSelection.png │ ├── BuildSolution.png │ ├── Cancel.png │ ├── CancelBuild.png │ ├── Clear.png │ ├── Connect.png │ ├── Copy.png │ ├── Cut.png │ ├── Database.png │ ├── Debug.png │ ├── Disconnect.png │ ├── Error.png │ ├── Filter.png │ ├── Grid.png │ ├── Info.png │ ├── List.png │ ├── ListView.png │ ├── NewFile.png │ ├── NewSolution.png │ ├── Open.png │ ├── Paste.png │ ├── Redo.png │ ├── Refresh.png │ ├── Restart.png │ ├── Save.png │ ├── SaveAll.png │ ├── Server 1.png │ ├── Server 2.png │ ├── Settings.png │ ├── Start.png │ ├── Step.png │ ├── StepOver.png │ ├── Stop.png │ ├── Trace.png │ ├── Undo.png │ └── Warning.png ├── Utilities.cs ├── VerbosityIconConverter.cs ├── Windows │ ├── ReferencesWindow.xaml │ └── ReferencesWindow.xaml.cs ├── _WPF_ │ ├── DataGridBehavior.cs │ ├── DelegateCommand.cs │ ├── DependencyManager.cs │ ├── DependencyModel.cs │ ├── DependsOnAttribute.cs │ ├── IPropertyUpdatable.cs │ ├── ObservableDictionary.cs │ └── VisualSnapshotConverter.cs └── app.config ├── FlowTomator.Engine ├── App.config ├── FlowTomator.Engine.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── FlowTomator.Service ├── Application.cs ├── FlowEnvironment.cs ├── FlowTomator.Service.csproj ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Service.cs ├── StopService.bat ├── app.config └── app.manifest ├── FlowTomator.SmartSync ├── External │ └── SmartSync.Common.dll ├── FlowTomator.SmartSync.csproj ├── ManualSync.cs ├── ProfileSync.cs └── Properties │ └── AssemblyInfo.cs ├── FlowTomator.Ssh ├── FlowTomator.Ssh.csproj ├── ModuleInitializer.cs ├── Properties │ └── AssemblyInfo.cs ├── SshCommand.cs └── packages.config ├── FlowTomator.VisualStudio ├── Build.cs ├── FlowTomator.VisualStudio.csproj ├── Properties │ └── AssemblyInfo.cs ├── Run.cs ├── Solution.cs ├── VisualStudio.cs └── app.config ├── FlowTomator.sln ├── FlowTomator.suo ├── Icon-16.png ├── Icon-256.png ├── Icon.ico ├── LICENSE ├── README.md ├── Samples ├── Sample.xflow └── VisualStudio.xflow └── Tomato.psd /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /FlowTomator.Common/Error.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Drawing; 5 | using System.IO; 6 | using System.IO.Pipes; 7 | using System.Linq; 8 | using System.Reflection; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using System.Windows.Forms; 13 | 14 | namespace FlowTomator.Common 15 | { 16 | public static class Error 17 | { 18 | public static void Throw(Exception exception) 19 | { 20 | Log.Error(exception.Message); 21 | 22 | if (Debugger.IsAttached) 23 | throw exception; 24 | } 25 | 26 | public static void Show(string message, string title) 27 | { 28 | Show(null, null, title); 29 | } 30 | public static void Show(Exception exception, string title) 31 | { 32 | Show(exception, null, title); 33 | } 34 | public static void Show(Exception exception, string message, string title) 35 | { 36 | if (message == null) 37 | message = ""; 38 | else if (!message.EndsWith(".")) 39 | message += "."; 40 | 41 | if (exception != null) 42 | message += " " + exception.Message; 43 | 44 | Log.Error(message); 45 | 46 | if (Debugger.IsAttached) 47 | throw exception; 48 | 49 | if (Log.Verbosity <= LogVerbosity.Debug) 50 | message += Environment.NewLine + Environment.NewLine + exception.StackTrace; 51 | 52 | MessageBox.Show(message.Trim(), title); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Evaluator/NodesEvaluator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | public abstract class NodesEvaluator 11 | { 12 | public abstract IList Nodes { get; } 13 | public abstract bool Evaluating { get; } 14 | 15 | public abstract NodeResult Evaluate(); 16 | public abstract void BeginEvaluate(); 17 | public abstract NodeResult EndEvaluate(); 18 | 19 | public abstract void Stop(); 20 | } 21 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Log.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.IO.Pipes; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using System.Windows.Forms; 12 | 13 | public enum LogVerbosity 14 | { 15 | Trace, 16 | Debug, 17 | Info, 18 | Warning, 19 | Error 20 | } 21 | 22 | public delegate void LogMessageHandler(LogVerbosity verbosity, Log.Category category, string message); 23 | 24 | public static class Log 25 | { 26 | public class Category 27 | { 28 | public static Category Common { get; } = new Category("Common"); 29 | 30 | public string Name { get; private set; } 31 | 32 | public Category(string name) 33 | { 34 | Name = name; 35 | } 36 | } 37 | 38 | public static LogVerbosity Verbosity { get; set; } = 39 | #if DEBUG 40 | LogVerbosity.Trace; 41 | #else 42 | LogVerbosity.Info; 43 | #endif 44 | 45 | public static event LogMessageHandler Message; 46 | 47 | private static object mutex = new object(); 48 | 49 | public static void Trace(string format, params object[] args) 50 | { 51 | Write(LogVerbosity.Trace, Category.Common, string.Format(format, args), ConsoleColor.DarkGray); 52 | } 53 | public static void Debug(string format, params object[] args) 54 | { 55 | Write(LogVerbosity.Debug, Category.Common, string.Format(format, args), ConsoleColor.Gray); 56 | } 57 | public static void Info(string format, params object[] args) 58 | { 59 | Write(LogVerbosity.Info, Category.Common, string.Format(format, args), ConsoleColor.White); 60 | } 61 | public static void Warning(string format, params object[] args) 62 | { 63 | Write(LogVerbosity.Warning, Category.Common, string.Format(format, args), ConsoleColor.DarkYellow); 64 | } 65 | public static void Error(string format, params object[] args) 66 | { 67 | Write(LogVerbosity.Error, Category.Common, string.Format(format, args), ConsoleColor.DarkRed); 68 | } 69 | 70 | public static void Trace(Category category, string format, params object[] args) 71 | { 72 | Write(LogVerbosity.Trace, category, string.Format(format, args), ConsoleColor.DarkGray); 73 | } 74 | public static void Debug(Category category, string format, params object[] args) 75 | { 76 | Write(LogVerbosity.Debug, category, string.Format(format, args), ConsoleColor.Gray); 77 | } 78 | public static void Info(Category category, string format, params object[] args) 79 | { 80 | Write(LogVerbosity.Info, category, string.Format(format, args), ConsoleColor.White); 81 | } 82 | public static void Warning(Category category, string format, params object[] args) 83 | { 84 | Write(LogVerbosity.Warning, category, string.Format(format, args), ConsoleColor.DarkYellow); 85 | } 86 | public static void Error(Category category, string format, params object[] args) 87 | { 88 | Write(LogVerbosity.Error, category, string.Format(format, args), ConsoleColor.DarkRed); 89 | } 90 | 91 | private static void Write(LogVerbosity verbosity, Category category, string message, ConsoleColor color = ConsoleColor.Gray) 92 | { 93 | if (Verbosity <= verbosity) 94 | { 95 | lock (mutex) 96 | { 97 | ConsoleColor lastColor = Console.ForegroundColor; 98 | 99 | Console.ForegroundColor = color; 100 | Console.Write("[{0}] ", verbosity.ToString()[0]); 101 | Console.ForegroundColor = lastColor; 102 | 103 | Console.WriteLine(message); 104 | } 105 | } 106 | 107 | if (Message != null) 108 | Message(verbosity, category, message); 109 | } 110 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Model/Choice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public abstract class Choice : Node 10 | { 11 | } 12 | 13 | public abstract class BinaryChoice : Choice 14 | { 15 | public sealed override IEnumerable Slots 16 | { 17 | get 18 | { 19 | return new[] { TrueSlot, FalseSlot }; 20 | } 21 | } 22 | 23 | protected Slot TrueSlot { get; } = new Slot("True"); 24 | protected Slot FalseSlot { get; } = new Slot("False"); 25 | } 26 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Model/EditableFlow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace FlowTomator.Common 11 | { 12 | public abstract class EditableFlow : Flow 13 | { 14 | public override IEnumerable Origins 15 | { 16 | get 17 | { 18 | return Nodes.OfType(); 19 | } 20 | } 21 | public override IEnumerable Inputs 22 | { 23 | get 24 | { 25 | return Variables; 26 | } 27 | } 28 | 29 | public virtual IList Nodes { get; } = new List(); 30 | public virtual IList Variables { get; } = new List(); 31 | 32 | public override IEnumerable GetAllNodes() 33 | { 34 | return Nodes; 35 | } 36 | 37 | public abstract void Save(string path); 38 | public static EditableFlow Load(string path) 39 | { 40 | FileInfo fileInfo = new FileInfo(path); 41 | if (!fileInfo.Exists) 42 | throw new FileNotFoundException("The specified file path could not be found", path); 43 | 44 | string extension = fileInfo.Extension; 45 | Type[] types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) 46 | .Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(EditableFlow))) 47 | .Where(t => t.GetCustomAttribute()?.Extensions?.Contains(extension) == true) 48 | .ToArray(); 49 | 50 | if (types.Length == 0) 51 | throw new FormatException("Unable to find any loader for extension " + extension); 52 | if (types.Length > 1) 53 | throw new FormatException("Several loaders exist for extension " + extension); 54 | 55 | return Load(path, types[0]); 56 | } 57 | public static EditableFlow Load(string path) where T : EditableFlow 58 | { 59 | return Load(path, typeof(T)); 60 | } 61 | public static EditableFlow Load(string path, Type type) 62 | { 63 | if (type == null || type.IsAbstract || !type.IsSubclassOf(typeof(EditableFlow))) 64 | throw new TypeLoadException("The specified type " + type + " is not a valid flow loader"); 65 | 66 | MethodInfo loaderMethod = type.GetMethod("Load", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string) }, new ParameterModifier[0] ); 67 | if (loaderMethod == null || (loaderMethod.ReturnType != typeof(EditableFlow) && !loaderMethod.ReturnType.IsSubclassOf(typeof(EditableFlow)))) 68 | throw new TypeLoadException("Could not find a Load method in type " + type); 69 | 70 | return loaderMethod.Invoke(null, new object[] { path }) as EditableFlow; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Model/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public abstract class Event : Node 10 | { 11 | public override IEnumerable Inputs 12 | { 13 | get 14 | { 15 | yield return timeout; 16 | } 17 | } 18 | public sealed override IEnumerable Slots 19 | { 20 | get 21 | { 22 | return new[] { slot }; 23 | } 24 | } 25 | 26 | protected Variable timeout = new Variable("Timeout", TimeSpan.MaxValue, "The timeout after this event will be skipped"); 27 | private Slot slot = new Slot("Callbacks"); 28 | 29 | public abstract NodeResult Check(); 30 | public sealed override NodeStep Evaluate() 31 | { 32 | return new NodeStep(Check(), slot); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Model/Flow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | public class Flow : Task 11 | { 12 | public virtual IEnumerable Origins { get; } = new List(); 13 | 14 | public override void Reset() 15 | { 16 | base.Reset(); 17 | 18 | foreach (Node node in GetAllNodes()) 19 | node.Reset(); 20 | } 21 | public override NodeResult Run() 22 | { 23 | if (!Origins.Any()) 24 | return NodeResult.Success; 25 | 26 | BasicNodesEvaluator nodesEvaluator = new BasicNodesEvaluator(); 27 | 28 | foreach (Origin origin in Origins) 29 | nodesEvaluator.Nodes.Add(origin); 30 | 31 | return nodesEvaluator.Evaluate(); 32 | } 33 | 34 | public virtual IEnumerable GetAllNodes() 35 | { 36 | List knownNodes = new List(); 37 | return Origins.SelectMany(n => GetAllNodes(n, knownNodes)).Distinct(); 38 | } 39 | private IEnumerable GetAllNodes(Node node, List knownNodes) 40 | { 41 | if (knownNodes.Contains(node)) 42 | yield break; 43 | 44 | yield return node; 45 | knownNodes.Add(node); 46 | 47 | foreach (Slot slot in node.Slots) 48 | foreach (Node slotNode in slot.Nodes) 49 | foreach (Node subNode in GetAllNodes(slotNode, knownNodes)) 50 | { 51 | if (knownNodes.Contains(subNode)) 52 | continue; 53 | 54 | yield return subNode; 55 | knownNodes.Add(subNode); 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Model/Node.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public enum NodeResult 10 | { 11 | /// 12 | /// Return value if the node evaluation has succeeded 13 | /// 14 | Success, 15 | 16 | /// 17 | /// Return value if the runtime should skip further thread evaluation 18 | /// 19 | Skip, 20 | 21 | /// 22 | /// Return value if the flow should stop its evaluation 23 | /// 24 | Stop, 25 | 26 | /// 27 | /// Return value if the node evaluation has failed 28 | /// 29 | Fail 30 | } 31 | public class NodeStep 32 | { 33 | public NodeResult Result { get; private set; } 34 | public Slot Slot { get; private set; } 35 | 36 | public NodeStep(NodeResult result, Slot slot) 37 | { 38 | Result = result; 39 | Slot = slot; 40 | } 41 | public NodeStep(NodeResult result) 42 | { 43 | Result = result; 44 | } 45 | } 46 | 47 | public abstract class Node 48 | { 49 | public virtual IEnumerable Inputs { get; } = Enumerable.Empty(); 50 | public virtual IEnumerable Outputs { get; } = Enumerable.Empty(); 51 | public virtual IEnumerable Slots { get; } = Enumerable.Empty(); 52 | 53 | public virtual Dictionary Metadata { get; } = new Dictionary(); 54 | 55 | public virtual void Reset() { } 56 | public abstract NodeStep Evaluate(); 57 | } 58 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Model/Slot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public class Slot 10 | { 11 | public string Name { get; private set; } 12 | public string Description { get; private set; } 13 | 14 | public List Nodes { get; } = new List(); 15 | 16 | public Slot(string name) 17 | { 18 | Name = name; 19 | } 20 | public Slot(string name, string description) 21 | { 22 | Name = name; 23 | Description = description; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Model/Task.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public abstract class Task : Node 10 | { 11 | public sealed override IEnumerable Slots 12 | { 13 | get 14 | { 15 | return new[] { slot }; 16 | } 17 | } 18 | 19 | private Slot slot = new Slot("Out"); 20 | 21 | public abstract NodeResult Run(); 22 | public sealed override NodeStep Evaluate() 23 | { 24 | return new NodeStep(Run(), slot); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /FlowTomator.Common/NodeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public class NodeAttribute : Attribute 10 | { 11 | public string Name { get; private set; } 12 | public string Category { get; private set; } 13 | public string Description { get; private set; } 14 | 15 | public NodeAttribute(string name, string category = null, string description = null) 16 | { 17 | Name = name; 18 | Category = category; 19 | Description = description; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/DateTime/CheckTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace FlowTomator.Common 12 | { 13 | [Node("Check time", "Date / Time", "Check if the current date/time match the specified criteria")] 14 | public class CheckTime : BinaryChoice 15 | { 16 | public override IEnumerable Inputs 17 | { 18 | get 19 | { 20 | yield return year; 21 | yield return month; 22 | yield return day; 23 | yield return hour; 24 | yield return minute; 25 | yield return second; 26 | } 27 | } 28 | 29 | private Variable year = new Variable("Year", NumberPattern.All); 30 | private Variable month = new Variable("Month", NumberPattern.All); 31 | private Variable day = new Variable("Day", NumberPattern.All); 32 | private Variable hour = new Variable("Hour", NumberPattern.All); 33 | private Variable minute = new Variable("Minute", NumberPattern.All); 34 | private Variable second = new Variable("Second", NumberPattern.All); 35 | 36 | public override NodeStep Evaluate() 37 | { 38 | DateTime now = DateTime.Now; 39 | 40 | if (year.Value.Check(now.Year) && month.Value.Check(now.Month) && day.Value.Check(now.Day) && hour.Value.Check(now.Hour) && minute.Value.Check(now.Minute) && second.Value.Check(now.Second)) 41 | return new NodeStep(NodeResult.Success, TrueSlot); 42 | else 43 | return new NodeStep(NodeResult.Success, FalseSlot); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/DateTime/TimedEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace FlowTomator.Common 12 | { 13 | [Node("Timed event", "Date / Time", "Triggers the following nodes when the specified date and time conditions are met")] 14 | public class TimedEvent : Event 15 | { 16 | public override IEnumerable Inputs 17 | { 18 | get 19 | { 20 | foreach (Variable variable in base.Inputs) 21 | yield return variable; 22 | 23 | yield return year; 24 | yield return month; 25 | yield return day; 26 | yield return hour; 27 | yield return minute; 28 | yield return second; 29 | } 30 | } 31 | 32 | private Variable year = new Variable("Year", NumberPattern.All); 33 | private Variable month = new Variable("Month", NumberPattern.All); 34 | private Variable day = new Variable("Day", NumberPattern.All); 35 | private Variable hour = new Variable("Hour", NumberPattern.All); 36 | private Variable minute = new Variable("Minute", NumberPattern.All); 37 | private Variable second = new Variable("Second", NumberPattern.All); 38 | 39 | private DateTime nextUpdate; 40 | 41 | public override NodeResult Check() 42 | { 43 | DateTime end; 44 | 45 | nextUpdate = DateTime.Now; 46 | nextUpdate = nextUpdate.AddMilliseconds(1000 - nextUpdate.Millisecond); 47 | 48 | if (timeout.Value == TimeSpan.MaxValue) 49 | end = DateTime.MaxValue; 50 | else 51 | end = DateTime.Now + timeout.Value; 52 | 53 | while (true) 54 | { 55 | DateTime now = DateTime.Now; 56 | 57 | if (now < nextUpdate) 58 | { 59 | Thread.Sleep(500); 60 | continue; 61 | } 62 | if (now > end) 63 | return NodeResult.Skip; 64 | 65 | if (year.Value.Check(nextUpdate.Year) && month.Value.Check(nextUpdate.Month) && day.Value.Check(nextUpdate.Day) && hour.Value.Check(nextUpdate.Hour) && minute.Value.Check(nextUpdate.Minute) && second.Value.Check(nextUpdate.Second)) 66 | return NodeResult.Success; 67 | 68 | nextUpdate = nextUpdate.AddSeconds(1); 69 | } 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/Devices/Inputs/MouseMove.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | [Node("MouseMove", "Devices")] 10 | public class MouseMoveEvent : Event 11 | { 12 | public override NodeResult Check() 13 | { 14 | return NodeResult.Fail; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/Devices/Network/NetworkSpeed.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | class NetworkSpeed 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/End.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | [Node("End", "General", "Exits this flow")] 10 | public class End : Node 11 | { 12 | public override NodeStep Evaluate() 13 | { 14 | return new NodeStep(NodeResult.Stop, null); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/General/Debug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | [Node("Debug", "General", "Returns the specified result flag")] 10 | public class Debug : Task 11 | { 12 | public override IEnumerable Inputs 13 | { 14 | get 15 | { 16 | yield return result; 17 | } 18 | } 19 | 20 | private Variable result = new Variable("Result", NodeResult.Success, "The result flag to return"); 21 | 22 | public override NodeResult Run() 23 | { 24 | return result.Value; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/General/Nope.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | [Node("Nope", "General", "Does nothing")] 10 | public class Nope : Task 11 | { 12 | public override NodeResult Run() 13 | { 14 | return NodeResult.Success; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/General/Sleep.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | [Node("Sleep", "General", "Wait for the specified amount of time before resuming")] 11 | public class Sleep : Task 12 | { 13 | public override IEnumerable Inputs 14 | { 15 | get 16 | { 17 | return new Variable[] { duration }; 18 | } 19 | } 20 | 21 | private Variable duration = new Variable("Duration", 1000, "The duration to sleep in milliseconds"); 22 | 23 | public override NodeResult Run() 24 | { 25 | Thread.Sleep(duration.Value); 26 | 27 | return NodeResult.Success; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/General/Wait.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | [Node("Wait", "General", "Wait for the specified count of input flows to succeed")] 11 | public class Wait : Task 12 | { 13 | public override IEnumerable Inputs 14 | { 15 | get 16 | { 17 | yield return count; 18 | } 19 | } 20 | 21 | private Variable count = new Variable("Count", 2, "Number of input flows to wait before resuming"); 22 | 23 | private object mutex = new object(); 24 | private uint actualCount = 0; 25 | private ManualResetEvent waitEvent = new ManualResetEvent(false); 26 | 27 | public override void Reset() 28 | { 29 | base.Reset(); 30 | 31 | actualCount = 0; 32 | waitEvent.Reset(); 33 | } 34 | public override NodeResult Run() 35 | { 36 | uint lastCount; 37 | 38 | lock (mutex) 39 | { 40 | actualCount++; 41 | Log.Debug("[Wait] {0}/{1}", actualCount, count.Value); 42 | 43 | lastCount = actualCount; 44 | } 45 | 46 | if (lastCount < count.Value) 47 | { 48 | waitEvent.WaitOne(); 49 | return NodeResult.Skip; 50 | } 51 | else 52 | { 53 | lock (mutex) 54 | actualCount = 0; 55 | 56 | waitEvent.Set(); 57 | return NodeResult.Success; 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/AppendFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace FlowTomator.Common 10 | { 11 | [Node("AppendFile", "IO", "Appends the specified content in the specified file")] 12 | public class AppendFile : Task 13 | { 14 | public override IEnumerable Inputs 15 | { 16 | get 17 | { 18 | yield return file; 19 | yield return content; 20 | } 21 | } 22 | 23 | private Variable file = new Variable("File", null, "The file to be written"); 24 | private Variable content = new Variable("Content", typeof(object), null, "The content of the file to append"); 25 | 26 | public override NodeResult Run() 27 | { 28 | if (file.Value == null || content.Value == null) 29 | return NodeResult.Skip; 30 | 31 | try 32 | { 33 | string text = content.Value.ToString(); 34 | File.AppendAllText(file.Value.FullName, text); 35 | } 36 | catch 37 | { 38 | return NodeResult.Fail; 39 | } 40 | 41 | return NodeResult.Success; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/ChooseFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace FlowTomator.Common 11 | { 12 | [Node("PickFile", "IO", "Asks the user to pick a file")] 13 | public class PickFile : Node 14 | { 15 | public override IEnumerable Outputs 16 | { 17 | get 18 | { 19 | yield return file; 20 | } 21 | } 22 | public override IEnumerable Slots 23 | { 24 | get 25 | { 26 | yield return okSlot; 27 | yield return cancelSlot; 28 | } 29 | } 30 | 31 | private Variable file = new Variable("File", null, "The file picked by the user"); 32 | 33 | private Slot okSlot = new Slot("OK"); 34 | private Slot cancelSlot = new Slot("Cancel"); 35 | 36 | public override NodeStep Evaluate() 37 | { 38 | DialogResult result = DialogResult.Cancel; 39 | string fileName = ""; 40 | 41 | ManualResetEvent mre = new ManualResetEvent(false); 42 | 43 | Thread thread = new Thread(() => 44 | { 45 | OpenFileDialog openFileDialog = new OpenFileDialog(); 46 | 47 | openFileDialog.Filter = "All files (*.*)|*.*"; 48 | openFileDialog.FilterIndex = 1; 49 | openFileDialog.FileName = file.Value?.FullName; 50 | 51 | result = openFileDialog.ShowDialog(); 52 | fileName = openFileDialog.FileName; 53 | 54 | mre.Set(); 55 | }); 56 | thread.SetApartmentState(ApartmentState.STA); 57 | thread.Start(); 58 | 59 | mre.WaitOne(); 60 | if (result != DialogResult.OK) 61 | return new NodeStep(NodeResult.Success, cancelSlot); 62 | 63 | file.Value = new FileInfo(fileName); 64 | return new NodeStep(NodeResult.Success, okSlot); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/CreateDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | [Node("CreateDirectory", "IO", "Create a directory at the specified location")] 11 | public class CreateDirectory : Task 12 | { 13 | public override IEnumerable Inputs 14 | { 15 | get 16 | { 17 | yield return directory; 18 | } 19 | } 20 | 21 | private Variable directory = new Variable("Directory", null, "The directory to be created"); 22 | 23 | public override NodeResult Run() 24 | { 25 | if (directory.Value == null || directory.Value.Exists) 26 | return NodeResult.Skip; 27 | 28 | try 29 | { 30 | Directory.CreateDirectory(directory.Value.FullName); 31 | } 32 | catch 33 | { 34 | return NodeResult.Fail; 35 | } 36 | 37 | return NodeResult.Success; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/CreateFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace FlowTomator.Common 10 | { 11 | [Node("CreateFile", "IO", "Create a file at the specified location")] 12 | public class CreateFile : Task 13 | { 14 | public override IEnumerable Inputs 15 | { 16 | get 17 | { 18 | yield return file; 19 | } 20 | } 21 | 22 | private Variable file = new Variable("File", null, "The file to be created"); 23 | 24 | public override NodeResult Run() 25 | { 26 | if (file.Value == null || file.Value.Exists) 27 | return NodeResult.Skip; 28 | 29 | try 30 | { 31 | File.Create(file.Value.FullName).Close(); 32 | } 33 | catch 34 | { 35 | return NodeResult.Fail; 36 | } 37 | 38 | return NodeResult.Success; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/DeleteFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace FlowTomator.Common 10 | { 11 | [Node("DeleteFile", "IO", "Delete the specified file")] 12 | public class DeleteFile : Task 13 | { 14 | public override IEnumerable Inputs 15 | { 16 | get 17 | { 18 | yield return file; 19 | } 20 | } 21 | 22 | private Variable file = new Variable("File", null, "The file to be deleted"); 23 | 24 | public override NodeResult Run() 25 | { 26 | if (file.Value == null || !file.Value.Exists) 27 | return NodeResult.Skip; 28 | 29 | try 30 | { 31 | File.Delete(file.Value.FullName); 32 | } 33 | catch 34 | { 35 | return NodeResult.Fail; 36 | } 37 | 38 | return NodeResult.Success; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/DirectoryExists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | [Node("DirectoryExists", "IO", "Checks if the specified directory exists")] 11 | public class DirectoryExists : BinaryChoice 12 | { 13 | public override IEnumerable Inputs 14 | { 15 | get 16 | { 17 | yield return directory; 18 | } 19 | } 20 | 21 | private Variable directory = new Variable("Directory", null, "The directory to check"); 22 | 23 | public override NodeStep Evaluate() 24 | { 25 | if (directory.Value == null) 26 | return new NodeStep(NodeResult.Fail); 27 | 28 | directory.Value.Refresh(); 29 | 30 | return new NodeStep(NodeResult.Success, directory.Value?.Exists == true ? TrueSlot : FalseSlot); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/FileChanged.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace FlowTomator.Common 11 | { 12 | [Node("FileChanged", "IO", "Resume the flow if a file is changed in the specified directory")] 13 | public class FileChanged : Event 14 | { 15 | public override IEnumerable Inputs 16 | { 17 | get 18 | { 19 | yield return directory; 20 | yield return filter; 21 | } 22 | } 23 | public override IEnumerable Outputs 24 | { 25 | get 26 | { 27 | yield break; 28 | } 29 | } 30 | 31 | private Variable directory = new Variable("Directory", null, "The directory to watch for changes"); 32 | private Variable filter = new Variable("Filter", "*", "The filter used to monitor changes"); 33 | 34 | private FileSystemWatcher watcher; 35 | private AutoResetEvent resetEvent = new AutoResetEvent(false); 36 | private Mutex mutex = new Mutex(); 37 | 38 | public FileChanged() 39 | { 40 | watcher = new FileSystemWatcher(); 41 | watcher.NotifyFilter = NotifyFilters.LastWrite; 42 | watcher.Changed += Watcher_Changed; 43 | } 44 | 45 | private void Watcher_Changed(object sender, FileSystemEventArgs e) 46 | { 47 | new Thread(() => 48 | { 49 | if (!mutex.WaitOne(0)) 50 | return; 51 | 52 | Thread.Sleep(250); 53 | 54 | resetEvent.Set(); 55 | mutex.ReleaseMutex(); 56 | }).Start(); 57 | } 58 | 59 | public override NodeResult Check() 60 | { 61 | DateTime start = DateTime.Now; 62 | 63 | watcher.Path = directory.Value.FullName; 64 | watcher.Filter = filter.Value; 65 | watcher.EnableRaisingEvents = true; 66 | 67 | while (!resetEvent.WaitOne(500)) 68 | { 69 | if (timeout.Value == TimeSpan.MaxValue) 70 | continue; 71 | 72 | if (DateTime.Now > start + timeout.Value) 73 | return NodeResult.Skip; 74 | } 75 | 76 | watcher.EnableRaisingEvents = false; 77 | return NodeResult.Success; 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/FileExists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | [Node("FileExists", "IO", "Checks if the specified file exists")] 11 | public class FileExists : BinaryChoice 12 | { 13 | public override IEnumerable Inputs 14 | { 15 | get 16 | { 17 | yield return file; 18 | } 19 | } 20 | 21 | private Variable file = new Variable("File", null, "The file to be created"); 22 | 23 | public override NodeStep Evaluate() 24 | { 25 | if (file.Value == null) 26 | return new NodeStep(NodeResult.Fail); 27 | 28 | return new NodeStep(NodeResult.Success, file.Value?.Exists == true ? TrueSlot : FalseSlot); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/ReadFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace FlowTomator.Common 10 | { 11 | [Node("ReadFile", "IO", "Reads the content of the specified file")] 12 | public class ReadFile : Task 13 | { 14 | public override IEnumerable Inputs 15 | { 16 | get 17 | { 18 | yield return file; 19 | } 20 | } 21 | public override IEnumerable Outputs 22 | { 23 | get 24 | { 25 | yield return content; 26 | } 27 | } 28 | 29 | private Variable file = new Variable("File", null, "The file to be read"); 30 | private Variable content = new Variable("Content", typeof(object), null, "The content of the file to read"); 31 | 32 | public override NodeResult Run() 33 | { 34 | if (file.Value == null) 35 | return NodeResult.Skip; 36 | 37 | try 38 | { 39 | content.Value = File.ReadAllText(file.Value.FullName); 40 | } 41 | catch 42 | { 43 | return NodeResult.Fail; 44 | } 45 | 46 | return NodeResult.Success; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/IO/WriteFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace FlowTomator.Common 10 | { 11 | [Node("WriteFile", "IO", "Writes the specified content in the specified file")] 12 | public class WriteFile : Task 13 | { 14 | public override IEnumerable Inputs 15 | { 16 | get 17 | { 18 | yield return file; 19 | yield return content; 20 | } 21 | } 22 | 23 | private Variable file = new Variable("File", null, "The file to be written"); 24 | private Variable content = new Variable("Content", typeof(object), null, "The content of the file to write"); 25 | 26 | public override NodeResult Run() 27 | { 28 | if (file.Value == null || content.Value == null) 29 | return NodeResult.Skip; 30 | 31 | try 32 | { 33 | if (content.Value.GetType() == typeof(Bitmap) || content.Value.GetType().IsSubclassOf(typeof(Bitmap))) 34 | (content.Value as Bitmap).Save(file.Value.FullName); 35 | else 36 | { 37 | string text = content.Value.ToString(); 38 | File.WriteAllText(file.Value.FullName, text); 39 | } 40 | } 41 | catch 42 | { 43 | return NodeResult.Fail; 44 | } 45 | 46 | return NodeResult.Success; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/Origin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | [Node("Origin", "General", "A new flow origin")] 10 | public class Origin : Task 11 | { 12 | public override NodeResult Run() 13 | { 14 | return NodeResult.Success; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/System/Clipboard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace FlowTomator.Common 10 | { 11 | [Node("SetClipboard", "System", "Replace clipboard content with the specified content")] 12 | public class SetClipboard : Task 13 | { 14 | public override IEnumerable Inputs 15 | { 16 | get 17 | { 18 | yield return content; 19 | } 20 | } 21 | 22 | private Variable content = new Variable("Content", typeof(object), null, "The content of the clipboard to replace"); 23 | 24 | public override NodeResult Run() 25 | { 26 | Thread thread = new Thread(() => 27 | { 28 | Clipboard.SetDataObject(content.Value, true); 29 | }); 30 | 31 | thread.SetApartmentState(ApartmentState.STA); 32 | thread.Start(); 33 | 34 | return NodeResult.Success; 35 | } 36 | } 37 | 38 | public enum ClipboardDataType 39 | { 40 | String, 41 | Image 42 | } 43 | 44 | [Node("GetClipboard", "System", "Get the current clipboard content")] 45 | public class GetClipboard : Task 46 | { 47 | public override IEnumerable Inputs 48 | { 49 | get 50 | { 51 | yield return dataType; 52 | } 53 | } 54 | public override IEnumerable Outputs 55 | { 56 | get 57 | { 58 | yield return content; 59 | } 60 | } 61 | 62 | private Variable dataType = new Variable("DataType", ClipboardDataType.String, "The type of the content to get"); 63 | private Variable content = new Variable("Content", typeof(object), null, "The content of the clipboard"); 64 | 65 | public override NodeResult Run() 66 | { 67 | if (dataType.Value == ClipboardDataType.String && Clipboard.ContainsText()) 68 | { 69 | content.Value = Clipboard.GetText(); 70 | return NodeResult.Success; 71 | } 72 | else if (dataType.Value == ClipboardDataType.Image && Clipboard.ContainsImage()) 73 | { 74 | content.Value = Clipboard.GetImage(); 75 | return NodeResult.Success; 76 | } 77 | else 78 | return NodeResult.Fail; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/System/Desktop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace FlowTomator.Common 10 | { 11 | // Solution from 12 | // http://maruf-dotnetdeveloper.blogspot.fr/2012/08/c-refreshing-system-tray-icon.html 13 | 14 | [Node("CleanTrayIcons", "System", "Clean the ghost icons in the tray bar")] 15 | public class CleanTrayIconsTask : Task 16 | { 17 | [StructLayout(LayoutKind.Sequential)] 18 | public struct RECT 19 | { 20 | public int left; 21 | public int top; 22 | public int right; 23 | public int bottom; 24 | } 25 | 26 | [DllImport("user32.dll")] 27 | private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 28 | [DllImport("user32.dll")] 29 | private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 30 | [DllImport("user32.dll")] 31 | private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); 32 | [DllImport("user32.dll")] 33 | private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam); 34 | 35 | public override NodeResult Run() 36 | { 37 | IntPtr systemTrayContainerHandle = FindWindow("Shell_TrayWnd", null); 38 | IntPtr systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null); 39 | IntPtr sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null); 40 | IntPtr notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area"); 41 | 42 | if (notificationAreaHandle == IntPtr.Zero) 43 | { 44 | notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area"); 45 | if (notificationAreaHandle == IntPtr.Zero) 46 | notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Zone de notification utilisateur promue"); 47 | 48 | IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null); 49 | IntPtr overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area"); 50 | if (overflowNotificationAreaHandle == IntPtr.Zero) 51 | overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Zone de notification de dépassement"); 52 | 53 | RefreshTrayArea(overflowNotificationAreaHandle); 54 | } 55 | 56 | RefreshTrayArea(notificationAreaHandle); 57 | 58 | return NodeResult.Success; 59 | } 60 | 61 | private static void RefreshTrayArea(IntPtr windowHandle) 62 | { 63 | const uint WM_MOUSEMOVE = 0x0200; 64 | 65 | RECT rect; 66 | GetClientRect(windowHandle, out rect); 67 | 68 | for (var x = 0; x < rect.right; x += 12) 69 | for (var y = 0; y < rect.bottom; y += 12) 70 | SendMessage(windowHandle, WM_MOUSEMOVE, 0, (y << 16) + x); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/System/Device/Lock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | using Microsoft.Win32; 10 | 11 | namespace FlowTomator.Common 12 | { 13 | [Node("LockDevice", "System", "Lock the current device")] 14 | public class LockDevice : Task 15 | { 16 | [DllImport("user32.dll")] 17 | public static extern bool LockWorkStation(); 18 | 19 | public override NodeResult Run() 20 | { 21 | if (LockWorkStation()) 22 | return NodeResult.Success; 23 | else 24 | return NodeResult.Fail; 25 | } 26 | } 27 | 28 | [Node("DeviceLock", "System", "Triggers when the system session is locked")] 29 | public class DeviceLockEvent : Event 30 | { 31 | private ManualResetEvent deviceLockEvent = new ManualResetEvent(false); 32 | 33 | public DeviceLockEvent() 34 | { 35 | DeviceEvents.DeviceLocked += DeviceEvents_DeviceLocked; 36 | } 37 | 38 | public override NodeResult Check() 39 | { 40 | DateTime start = DateTime.Now; 41 | 42 | while (!deviceLockEvent.WaitOne(500)) 43 | { 44 | if (timeout.Value == TimeSpan.MaxValue) 45 | continue; 46 | 47 | if (DateTime.Now > start + timeout.Value) 48 | return NodeResult.Skip; 49 | } 50 | 51 | deviceLockEvent.Reset(); 52 | 53 | return NodeResult.Success; 54 | } 55 | 56 | private void DeviceEvents_DeviceLocked() 57 | { 58 | deviceLockEvent.Set(); 59 | } 60 | } 61 | 62 | [Node("DeviceUnlock", "System", "Triggers when the system session is unlocked")] 63 | public class DeviceUnlockEvent : Event 64 | { 65 | private ManualResetEvent deviceUnlockEvent = new ManualResetEvent(false); 66 | 67 | public DeviceUnlockEvent() 68 | { 69 | DeviceEvents.DeviceUnlocked += DeviceEvents_DeviceUnlocked; 70 | } 71 | 72 | public override NodeResult Check() 73 | { 74 | DateTime start = DateTime.Now; 75 | 76 | while (!deviceUnlockEvent.WaitOne(500)) 77 | { 78 | if (timeout.Value == TimeSpan.MaxValue) 79 | continue; 80 | 81 | if (DateTime.Now > start + timeout.Value) 82 | return NodeResult.Skip; 83 | } 84 | 85 | deviceUnlockEvent.Reset(); 86 | 87 | return NodeResult.Success; 88 | } 89 | 90 | private void DeviceEvents_DeviceUnlocked() 91 | { 92 | deviceUnlockEvent.Set(); 93 | } 94 | } 95 | 96 | [Node("IsDeviceLocked", "System", "Detects wether the system session is locked or unlocked")] 97 | public class IsDeviceLocked : BinaryChoice 98 | { 99 | private bool sessionLocked = false; 100 | 101 | public IsDeviceLocked() 102 | { 103 | SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; 104 | } 105 | 106 | public override NodeStep Evaluate() 107 | { 108 | return new NodeStep(NodeResult.Success, sessionLocked ? TrueSlot : FalseSlot); 109 | } 110 | 111 | private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) 112 | { 113 | if (e.Reason == SessionSwitchReason.SessionLock) 114 | sessionLocked = true; 115 | else if (e.Reason == SessionSwitchReason.SessionUnlock) 116 | sessionLocked = false; 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/System/Screenshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Imaging; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace FlowTomator.Common 11 | { 12 | [Node("Screenshot", "System", "Takes a screenshot of the specified screen")] 13 | public class Screenshot : Task 14 | { 15 | public override IEnumerable Outputs 16 | { 17 | get 18 | { 19 | yield return bitmap; 20 | } 21 | } 22 | 23 | private Variable bitmap = new Variable("Bitmap", null, "The newly captured screenshot"); 24 | 25 | public override NodeResult Run() 26 | { 27 | // Setup the bitmap 28 | Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb); 29 | Graphics graphcis = Graphics.FromImage(bitmap); 30 | 31 | // Take the screenshot 32 | graphcis.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy); 33 | 34 | // Output the bitmap 35 | this.bitmap.Value = bitmap; 36 | 37 | return NodeResult.Success; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/Text/Regex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | [Node("MatchRegex", "Text", "Test the specified value against the specified pattern")] 11 | public class MatchRegex : BinaryChoice 12 | { 13 | public override IEnumerable Inputs 14 | { 15 | get 16 | { 17 | yield return value; 18 | yield return pattern; 19 | } 20 | } 21 | 22 | private Variable value = new Variable("Value"); 23 | private Variable pattern = new Variable("Pattern"); 24 | 25 | public override NodeStep Evaluate() 26 | { 27 | try 28 | { 29 | bool result = Regex.IsMatch(value.Value, pattern.Value); 30 | return new NodeStep(NodeResult.Success, result ? TrueSlot : FalseSlot); 31 | } 32 | catch 33 | { 34 | return new NodeStep(NodeResult.Fail); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Nodes/Web/WebRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Common 9 | { 10 | public class WebRequest : Task 11 | { 12 | public override IEnumerable Inputs 13 | { 14 | get 15 | { 16 | yield return address; 17 | } 18 | } 19 | public override IEnumerable Outputs 20 | { 21 | get 22 | { 23 | yield return result; 24 | } 25 | } 26 | 27 | private Variable address = new Variable("Address", null, "Address to query"); 28 | private Variable result = new Variable("Result"); 29 | 30 | private WebClient webClient = new WebClient(); 31 | 32 | public override NodeResult Run() 33 | { 34 | try 35 | { 36 | result.Value = webClient.DownloadString(address.Value); 37 | } 38 | catch 39 | { 40 | return NodeResult.Fail; 41 | } 42 | 43 | return NodeResult.Success; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FlowTomator.Common")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("FlowTomator.Common")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6c68ae0d-ae83-442b-9ab9-42a0cde65f02")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /FlowTomator.Common/Storage/FlowStorageAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public class FlowStorageAttribute : Attribute 10 | { 11 | public string Description { get; set; } 12 | public string[] Extensions { get; set; } 13 | 14 | public FlowStorageAttribute(string description, params string[] extensions) 15 | { 16 | Description = description; 17 | Extensions = extensions; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Storage/XDependencyFlow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common.Storage 8 | { 9 | class XDependencyFlow 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /FlowTomator.Common/Utilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | class Utilities 8 | { 9 | public static string MakeRelativePath(string directory, string target) 10 | { 11 | if (string.IsNullOrEmpty(directory)) throw new ArgumentNullException("fromPath"); 12 | if (string.IsNullOrEmpty(target)) throw new ArgumentNullException("toPath"); 13 | 14 | Uri fromUri = new Uri(directory + "/"); 15 | Uri toUri = new Uri(target); 16 | 17 | if (fromUri.Scheme != toUri.Scheme) 18 | return target; // Path can't be made relative. 19 | 20 | Uri relativeUri = fromUri.MakeRelativeUri(toUri); 21 | string relativePath = Uri.UnescapeDataString(relativeUri.ToString()); 22 | 23 | if (toUri.Scheme.ToUpperInvariant() == "FILE") 24 | relativePath = relativePath.Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar); 25 | 26 | return relativePath; 27 | } 28 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Utils/DeviceEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.AccessControl; 5 | using System.Security.Principal; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | using Microsoft.Win32; 11 | 12 | namespace FlowTomator.Common 13 | { 14 | public static class DeviceEvents 15 | { 16 | public static event Action DeviceLocked; 17 | public static event Action DeviceUnlocked; 18 | 19 | static DeviceEvents() 20 | { 21 | if (Environment.UserInteractive) 22 | { 23 | SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; 24 | } 25 | } 26 | 27 | private static void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) 28 | { 29 | switch (e.Reason) 30 | { 31 | case SessionSwitchReason.SessionLock: OnDeviceLocked(); break; 32 | case SessionSwitchReason.SessionUnlock: OnDeviceUnlocked(); break; 33 | } 34 | } 35 | 36 | public static void OnDeviceLocked() 37 | { 38 | if (DeviceLocked != null) 39 | DeviceLocked(); 40 | } 41 | public static void OnDeviceUnlocked() 42 | { 43 | if (DeviceUnlocked != null) 44 | DeviceUnlocked(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /FlowTomator.Common/Utils/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.AccessControl; 5 | using System.Security.Principal; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace FlowTomator.Common 11 | { 12 | public static class Utils 13 | { 14 | public static EventWaitHandle GetOrCreateEvent(string name) 15 | { 16 | EventWaitHandle eventWaitHandle = null; 17 | 18 | if (!EventWaitHandle.TryOpenExisting(@"Global\" + name, out eventWaitHandle)) 19 | { 20 | SecurityIdentifier users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null); 21 | EventWaitHandleAccessRule rule = new EventWaitHandleAccessRule(users, EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify, AccessControlType.Allow); 22 | EventWaitHandleSecurity security = new EventWaitHandleSecurity(); 23 | security.AddAccessRule(rule); 24 | 25 | bool created; 26 | eventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset, @"Global\" + name, out created, security); 27 | } 28 | 29 | return eventWaitHandle; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /FlowTomator.Data/DataSet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Common 8 | { 9 | public class DataSet 10 | { 11 | public string Name { get; set; } 12 | public string[] Columns { get; set; } 13 | public List Rows { get; set; } = new List(); 14 | 15 | public DataSet(string name, params string[] columns) 16 | { 17 | Name = name; 18 | Columns = columns; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /FlowTomator.Data/DumpData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | using FlowTomator.Common; 8 | 9 | namespace FlowTomator.Data 10 | { 11 | public enum DataFormat 12 | { 13 | Csv, 14 | //Sql, 15 | //BGeo, 16 | //Bson, 17 | } 18 | 19 | [Node(nameof(DumpData), "Data", "Dumps the specified data into the specified file")] 20 | public class DumpData : Task 21 | { 22 | public override IEnumerable Inputs 23 | { 24 | get 25 | { 26 | yield return data; 27 | yield return file; 28 | yield return format; 29 | } 30 | } 31 | 32 | private Variable data = new Variable("Data", null, "The data to dump"); 33 | private Variable file = new Variable("File", null, "The file where the data will be dumped"); 34 | private Variable format = new Variable("Format", DataFormat.Csv, "The format used to dump the data"); 35 | 36 | public override NodeResult Run() 37 | { 38 | if (data.Value == null || file.Value == null) 39 | return NodeResult.Fail; 40 | 41 | try 42 | { 43 | if (!file.Value.Exists) 44 | File.Create(file.Value.FullName).Close(); 45 | 46 | switch (format.Value) 47 | { 48 | case DataFormat.Csv: return DumpCsv(); 49 | } 50 | } 51 | catch 52 | { 53 | return NodeResult.Fail; 54 | } 55 | 56 | return NodeResult.Fail; 57 | } 58 | 59 | private NodeResult DumpCsv() 60 | { 61 | using (StreamWriter writer = new StreamWriter(file.Value.FullName)) 62 | { 63 | writer.WriteLine(string.Join(";", data.Value.Columns)); 64 | 65 | foreach (object[] rows in data.Value.Rows) 66 | writer.WriteLine(string.Join(";", rows)); 67 | } 68 | 69 | return NodeResult.Success; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /FlowTomator.Data/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FlowTomator.Data")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("FlowTomator.Data")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5dbb54c6-b165-4551-ab90-17185ce97562")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /FlowTomator.Data/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /FlowTomator.Data/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/Action.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Desktop 8 | { 9 | public abstract class Action 10 | { 11 | public abstract void Do(); 12 | public abstract void Undo(); 13 | } 14 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/ActionGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Desktop 8 | { 9 | public class ActionGroup : Action 10 | { 11 | public Action[] Actions { get; private set; } 12 | 13 | public ActionGroup(params Action[] actions) 14 | { 15 | Actions = actions; 16 | } 17 | public ActionGroup(IEnumerable actions) 18 | { 19 | Actions = actions.ToArray(); 20 | } 21 | 22 | public override void Do() 23 | { 24 | foreach (Action action in Actions) 25 | action.Do(); 26 | } 27 | 28 | public override void Undo() 29 | { 30 | foreach (Action action in Actions.Reverse()) 31 | action.Undo(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/AddLink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Desktop 8 | { 9 | public class AddLinkAction : Action 10 | { 11 | public SlotInfo SlotInfo { get; private set; } 12 | public NodeInfo NodeInfo { get; private set; } 13 | 14 | public AddLinkAction(SlotInfo slotInfo, NodeInfo nodeInfo) 15 | { 16 | SlotInfo = slotInfo; 17 | NodeInfo = nodeInfo; 18 | } 19 | 20 | public override void Do() 21 | { 22 | SlotInfo.Slot.Nodes.Add(NodeInfo.Node); 23 | NodeInfo.FlowInfo.Update(); 24 | } 25 | 26 | public override void Undo() 27 | { 28 | SlotInfo.Slot.Nodes.Remove(NodeInfo.Node); 29 | NodeInfo.FlowInfo.Update(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/AddNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using FlowTomator.Common; 8 | 9 | namespace FlowTomator.Desktop 10 | { 11 | public class AddNodeAction : Action 12 | { 13 | public FlowInfo FlowInfo { get; private set; } 14 | public Node Node { get; private set; } 15 | 16 | public AddNodeAction(FlowInfo flow, Node node) 17 | { 18 | FlowInfo = flow; 19 | Node = node; 20 | } 21 | 22 | public override void Do() 23 | { 24 | FlowInfo.Flow.Nodes.Add(Node); 25 | FlowInfo.Update(); 26 | } 27 | 28 | public override void Undo() 29 | { 30 | FlowInfo.Flow.Nodes.Remove(Node); 31 | FlowInfo.Update(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/DeleteLink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Desktop 8 | { 9 | public class DeleteLinkAction : Action 10 | { 11 | public LinkInfo LinkInfo { get; private set; } 12 | 13 | public DeleteLinkAction(LinkInfo linkInfo) 14 | { 15 | LinkInfo = linkInfo; 16 | } 17 | 18 | public override void Do() 19 | { 20 | LinkInfo.Slot.Nodes.Remove(LinkInfo.Node); 21 | LinkInfo.NodeInfo.FlowInfo.Update(); 22 | } 23 | 24 | public override void Undo() 25 | { 26 | LinkInfo.Slot.Nodes.Add(LinkInfo.Node); 27 | LinkInfo.NodeInfo.FlowInfo.Update(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/DeleteNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using FlowTomator.Common; 8 | 9 | namespace FlowTomator.Desktop 10 | { 11 | public class DeleteNodeAction : Action 12 | { 13 | public FlowInfo FlowInfo { get; private set; } 14 | public Node Node { get; private set; } 15 | 16 | private List slots = new List(); 17 | 18 | public DeleteNodeAction(NodeInfo nodeInfo) 19 | { 20 | FlowInfo = nodeInfo.FlowInfo; 21 | Node = nodeInfo.Node; 22 | } 23 | 24 | public override void Do() 25 | { 26 | slots.Clear(); 27 | 28 | // Remove the node 29 | FlowInfo.Flow.Nodes.Remove(Node); 30 | 31 | // Remove all links to this node 32 | foreach (Node node in FlowInfo.Flow.Nodes) 33 | foreach (Slot slot in node.Slots) 34 | while (slot.Nodes.Contains(Node)) 35 | { 36 | slot.Nodes.Remove(Node); 37 | slots.Add(slot); 38 | } 39 | 40 | FlowInfo.Update(); 41 | } 42 | 43 | public override void Undo() 44 | { 45 | // Add the node 46 | FlowInfo.Flow.Nodes.Add(Node); 47 | 48 | // Restore all links to this node 49 | foreach (Slot slot in slots) 50 | slot.Nodes.Add(Node); 51 | 52 | FlowInfo.Update(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/EditVariable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using FlowTomator.Common; 8 | 9 | namespace FlowTomator.Desktop 10 | { 11 | public class EditVariableAction : Action 12 | { 13 | public VariableInfo VariableInfo { get; private set; } 14 | public Variable OldLink { get; private set; } 15 | public object OldValue { get; private set; } 16 | public object NewValue { get; private set; } 17 | 18 | public EditVariableAction(VariableInfo variableInfo, object newValue) 19 | { 20 | VariableInfo = variableInfo; 21 | OldLink = variableInfo.Variable.Linked; 22 | OldValue = variableInfo.Value; 23 | NewValue = newValue; 24 | } 25 | 26 | public override void Do() 27 | { 28 | VariableInfo.Variable.Link(null); 29 | VariableInfo.Variable.Value = NewValue; 30 | VariableInfo.Update(); 31 | } 32 | 33 | public override void Undo() 34 | { 35 | if (OldLink != null) 36 | VariableInfo.Variable.Link(OldLink); 37 | else 38 | VariableInfo.Variable.Value = OldValue; 39 | 40 | VariableInfo.Update(); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/HistoryInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FlowTomator.Desktop 9 | { 10 | public class HistoryInfo : DependencyModel 11 | { 12 | public IEnumerable Actions 13 | { 14 | get 15 | { 16 | return actions.AsReadOnly(); 17 | } 18 | } 19 | 20 | [DependsOn(nameof(Actions))] 21 | public bool CanUndo 22 | { 23 | get 24 | { 25 | return actionIndex > 0; 26 | } 27 | } 28 | [DependsOn(nameof(Actions))] 29 | public bool CanRedo 30 | { 31 | get 32 | { 33 | return actionIndex < actions.Count; 34 | } 35 | } 36 | 37 | private List actions = new List(); 38 | private int actionIndex = 0; 39 | 40 | public void Do(Action action) 41 | { 42 | while (actions.Count > actionIndex) 43 | actions.RemoveAt(actionIndex); 44 | 45 | actions.Add(action); 46 | Redo(); 47 | 48 | NotifyPropertyChanged(nameof(Actions)); 49 | } 50 | 51 | public void Undo() 52 | { 53 | if (actionIndex > 0) 54 | actions[--actionIndex].Undo(); 55 | 56 | NotifyPropertyChanged(nameof(CanUndo), nameof(CanRedo)); 57 | } 58 | public void Redo() 59 | { 60 | if (actionIndex < actions.Count) 61 | actions[actionIndex++].Do(); 62 | 63 | NotifyPropertyChanged(nameof(CanUndo), nameof(CanRedo)); 64 | } 65 | 66 | public void Clear() 67 | { 68 | actions.Clear(); 69 | actionIndex = 0; 70 | 71 | NotifyPropertyChanged(nameof(Actions)); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/LinkVariable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using FlowTomator.Common; 8 | 9 | namespace FlowTomator.Desktop 10 | { 11 | public class LinkVariableAction : Action 12 | { 13 | public VariableInfo VariableInfo { get; private set; } 14 | public Variable OldLink { get; private set; } 15 | public object OldValue { get; private set; } 16 | public Variable NewLink { get; private set; } 17 | 18 | public LinkVariableAction(VariableInfo variableInfo, Variable linkedVariable) 19 | { 20 | VariableInfo = variableInfo; 21 | OldLink = variableInfo.Variable.Linked; 22 | OldValue = variableInfo.Value; 23 | NewLink = linkedVariable; 24 | } 25 | 26 | public override void Do() 27 | { 28 | VariableInfo.Variable.Link(NewLink); 29 | VariableInfo.Update(); 30 | } 31 | 32 | public override void Undo() 33 | { 34 | VariableInfo.Variable.Link(OldLink); 35 | VariableInfo.Variable.Value = OldValue; 36 | 37 | VariableInfo.Update(); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/MoveNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | 8 | namespace FlowTomator.Desktop 9 | { 10 | public class MoveNodeAction : Action 11 | { 12 | public NodeInfo NodeInfo { get; private set; } 13 | 14 | public Point OldPosition { get; private set; } 15 | public Point NewPosition { get; private set; } 16 | 17 | public MoveNodeAction(NodeInfo nodeInfo, Point position) 18 | { 19 | NodeInfo = nodeInfo; 20 | 21 | OldPosition = new Point(NodeInfo.X, NodeInfo.Y); 22 | NewPosition = position; 23 | } 24 | public MoveNodeAction(NodeInfo nodeInfo, Point oldPosition, Point newPosition) 25 | { 26 | NodeInfo = nodeInfo; 27 | 28 | OldPosition = oldPosition; 29 | NewPosition = newPosition; 30 | } 31 | 32 | public override void Do() 33 | { 34 | NodeInfo.X = NewPosition.X; 35 | NodeInfo.Y = NewPosition.Y; 36 | } 37 | 38 | public override void Undo() 39 | { 40 | NodeInfo.X = OldPosition.X; 41 | NodeInfo.Y = OldPosition.Y; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Actions/RenameVariable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using FlowTomator.Common; 8 | 9 | namespace FlowTomator.Desktop 10 | { 11 | public class RenameVariableAction : Action 12 | { 13 | public VariableInfo VariableInfo { get; private set; } 14 | 15 | public RenameVariableAction(VariableInfo variableInfo, string name) 16 | { 17 | VariableInfo = variableInfo; 18 | } 19 | 20 | public override void Do() 21 | { 22 | VariableInfo.Update(); 23 | } 24 | 25 | public override void Undo() 26 | { 27 | VariableInfo.Update(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | -------------------------------------------------------------------------------- /FlowTomator.Desktop/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | 10 | namespace FlowTomator.Desktop 11 | { 12 | public partial class App : Application 13 | { 14 | public static string Name { get; } = "FlowTomator"; 15 | } 16 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/FlowEditorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Desktop 8 | { 9 | public class FlowEditorAttribute : Attribute 10 | { 11 | public Type[] Types { get; private set; } 12 | 13 | public FlowEditorAttribute(params Type[] types) 14 | { 15 | Types = types; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/FlowEditorTemplateSelector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | 10 | using FlowTomator.Common; 11 | 12 | namespace FlowTomator.Desktop 13 | { 14 | public class FlowEditorTemplateSelector : DataTemplateSelector 15 | { 16 | public override DataTemplate SelectTemplate(object item, DependencyObject container) 17 | { 18 | FlowInfo flowInfo = item as FlowInfo; 19 | Type flowType = flowInfo.Type; 20 | 21 | Type editorType = Assembly.GetExecutingAssembly().GetTypes() 22 | .Where(t => t.GetCustomAttribute() != null) 23 | .FirstOrDefault(t => t.GetCustomAttribute().Types.Contains(flowType)); 24 | 25 | DataTemplate dataTemplate = new DataTemplate(); 26 | dataTemplate.VisualTree = new FrameworkElementFactory(editorType); 27 | 28 | return dataTemplate; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/Flows/FlowEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Collections.Specialized; 5 | using System.ComponentModel; 6 | using System.Linq; 7 | using System.Runtime.CompilerServices; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using System.Windows.Controls; 12 | using System.Windows.Data; 13 | using System.Windows.Documents; 14 | using System.Windows.Input; 15 | using System.Windows.Media; 16 | using System.Windows.Media.Imaging; 17 | using System.Windows.Navigation; 18 | using System.Windows.Shapes; 19 | 20 | using FlowTomator.Common; 21 | 22 | namespace FlowTomator.Desktop 23 | { 24 | public abstract class FlowEditor : UserControl, INotifyPropertyChanged 25 | { 26 | public abstract FlowInfo FlowInfo { get; } 27 | public abstract ObservableCollection SelectedNodes { get; } 28 | 29 | [DependsOn(nameof(SelectedNodes))] 30 | public virtual ICommand CutCommand 31 | { 32 | get 33 | { 34 | return disabledCommand; 35 | } 36 | } 37 | [DependsOn(nameof(SelectedNodes))] 38 | public virtual ICommand CopyCommand 39 | { 40 | get 41 | { 42 | return disabledCommand; 43 | } 44 | } 45 | [DependsOn(nameof(SelectedNodes))] 46 | public virtual ICommand PasteCommand 47 | { 48 | get 49 | { 50 | return disabledCommand; 51 | } 52 | } 53 | 54 | private DependencyManager dependencyManager; 55 | private DelegateCommand disabledCommand = new DelegateCommand(p => { }, p => false); 56 | 57 | public FlowEditor() 58 | { 59 | dependencyManager = new DependencyManager(this, (s, e) => NotifyPropertyChanged(e.PropertyName)); 60 | } 61 | 62 | public event PropertyChangedEventHandler PropertyChanged; 63 | protected virtual void NotifyPropertyChanged([CallerMemberName]string property = null) 64 | { 65 | if (property != null && PropertyChanged != null) 66 | PropertyChanged(this, new PropertyChangedEventArgs(property)); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/VariableEditorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FlowTomator.Desktop 8 | { 9 | public class VariableEditorAttribute : Attribute 10 | { 11 | public Type[] Types { get; private set; } 12 | 13 | public VariableEditorAttribute(params Type[] types) 14 | { 15 | Types = types; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/VariableEditorTemplateSelector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | 11 | using FlowTomator.Common; 12 | 13 | namespace FlowTomator.Desktop 14 | { 15 | public class VariableEditorTemplateSelector : DataTemplateSelector 16 | { 17 | public override DataTemplate SelectTemplate(object item, DependencyObject container) 18 | { 19 | VariableInfo variableInfo = item as VariableInfo; 20 | Type variableType = variableInfo.Variable.GetType(); 21 | 22 | DataTemplate dataTemplate = new DataTemplate(); 23 | 24 | if (variableType.IsGenericType && variableType.GetGenericTypeDefinition() == typeof(EnumVariable<>)) 25 | dataTemplate.VisualTree = new FrameworkElementFactory(typeof(DynamicEnumerableVariableEditor)); 26 | else if (variableInfo.Type.IsEnum) 27 | dataTemplate.VisualTree = new FrameworkElementFactory(typeof(EnumerableVariableEditor)); 28 | else 29 | { 30 | Type variableEditorType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) 31 | .FirstOrDefault(t => !t.IsAbstract && t.GetCustomAttribute()?.Types?.Any(v => v.IsAssignableFrom(variableInfo.Type)) == true); 32 | 33 | dataTemplate.VisualTree = new FrameworkElementFactory(variableEditorType ?? typeof(TextVariableEditor)); 34 | } 35 | 36 | return dataTemplate; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/Variables/BooleanVariableEditor.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/Variables/BooleanVariableEditor.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace FlowTomator.Desktop 17 | { 18 | [VariableEditor(typeof(bool))] 19 | public partial class BooleanVariableEditor : UserControl 20 | { 21 | public BooleanVariableEditor() 22 | { 23 | InitializeComponent(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/Variables/DateTimeVariableEditor.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/Variables/DateTimeVariableEditor.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | using FlowTomator.Common; 17 | 18 | namespace FlowTomator.Desktop 19 | { 20 | [VariableEditor(typeof(DateTime))] 21 | public partial class DateTimeVariableEditor : UserControl 22 | { 23 | public VariableInfo VariableInfo 24 | { 25 | get 26 | { 27 | return DataContext as VariableInfo; 28 | } 29 | } 30 | public Variable Variable 31 | { 32 | get 33 | { 34 | return VariableInfo.Variable as Variable; 35 | } 36 | } 37 | 38 | public string Text 39 | { 40 | get 41 | { 42 | if (Variable.Value == DateTime.MinValue) 43 | return "MinValue"; 44 | else if (Variable.Value == DateTime.MaxValue) 45 | return "MaxValue"; 46 | 47 | return Variable.Value.ToString(); 48 | } 49 | set 50 | { 51 | 52 | } 53 | } 54 | 55 | public DateTimeVariableEditor() 56 | { 57 | InitializeComponent(); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /FlowTomator.Desktop/Editors/Variables/DirectoryInfoVariableEditor.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |