aboutsummaryrefslogtreecommitdiffstats
path: root/Software
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2017-11-01 14:51:06 +0200
committerRoy Ben-Shabat <Roy@Twine-s.com>2017-11-01 14:51:06 +0200
commite2c57e31379cad583f5a7b4f8815d2bc972c62a5 (patch)
tree8ea1e637efcb09ad9104efb53dd9c29f128f33aa /Software
parentec0c395263dafed2cd17bf756c9891525efcc13c (diff)
downloadTango-e2c57e31379cad583f5a7b4f8815d2bc972c62a5.tar.gz
Tango-e2c57e31379cad583f5a7b4f8815d2bc972c62a5.zip
Implemented .NET logging library
Completed protobuf compilation library. Implemented GUI app for protobuf compilation. Implemented CLI app for protobuf compilation.
Diffstat (limited to 'Software')
-rw-r--r--Software/PMR/Messages/.settings/com.google.eclipse.protobuf.Protobuf.prefs4
-rw-r--r--Software/PMR/Messages/Job/Segment.proto2
-rw-r--r--Software/Visual Studio/Tango.Core/Commands/RelayCommand.cs128
-rw-r--r--Software/Visual Studio/Tango.Core/ExtendedObject.cs53
-rw-r--r--Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs18
-rw-r--r--Software/Visual Studio/Tango.Core/Helpers/AssemblyHelper.cs (renamed from Software/Visual Studio/Tango.Core/AssemblyHelper.cs)2
-rw-r--r--Software/Visual Studio/Tango.Core/Helpers/PathHelper.cs (renamed from Software/Visual Studio/Tango.Core/PathHelper.cs)2
-rw-r--r--Software/Visual Studio/Tango.Core/Tango.Core.csproj14
-rw-r--r--Software/Visual Studio/Tango.Logging/ApplicationCrashedEventArgs.cs34
-rw-r--r--Software/Visual Studio/Tango.Logging/ExceptionLogItem.cs34
-rw-r--r--Software/Visual Studio/Tango.Logging/FileLogger.cs82
-rw-r--r--Software/Visual Studio/Tango.Logging/GlobalExceptionTrapper.cs106
-rw-r--r--Software/Visual Studio/Tango.Logging/IGlobalExceptionTrapper.cs19
-rw-r--r--Software/Visual Studio/Tango.Logging/ILogger.cs36
-rw-r--r--Software/Visual Studio/Tango.Logging/LogItemBase.cs39
-rw-r--r--Software/Visual Studio/Tango.Logging/LogManager.cs220
-rw-r--r--Software/Visual Studio/Tango.Logging/MessageLogItem.cs28
-rw-r--r--Software/Visual Studio/Tango.Logging/Properties/AssemblyInfo.cs6
-rw-r--r--Software/Visual Studio/Tango.Logging/Tango.Logging.csproj69
-rw-r--r--Software/Visual Studio/Tango.Logging/VSOutputLogger.cs64
-rw-r--r--Software/Visual Studio/Tango.Protobuf/CompilerException.cs41
-rw-r--r--Software/Visual Studio/Tango.Protobuf/CompilerFactory.cs35
-rw-r--r--Software/Visual Studio/Tango.Protobuf/CompilerFileResult.cs27
-rw-r--r--Software/Visual Studio/Tango.Protobuf/CompilerFolderResult.cs40
-rw-r--r--Software/Visual Studio/Tango.Protobuf/Compilers/CCompiler.cs41
-rw-r--r--Software/Visual Studio/Tango.Protobuf/Compilers/CppCompiler.cs29
-rw-r--r--Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs29
-rw-r--r--Software/Visual Studio/Tango.Protobuf/Compilers/PythonCompiler.cs29
-rw-r--r--Software/Visual Studio/Tango.Protobuf/ICompilerResult.cs15
-rw-r--r--Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs94
-rw-r--r--Software/Visual Studio/Tango.Protobuf/Tango.Protobuf.csproj13
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Converters/BooleanInverseConverter.cs46
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityConverter.cs44
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityInverseConverter.cs44
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Converters/EnumToDescriptionConverter.cs64
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Converters/NullObjectToBooleanConverter.cs46
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Converters/PathToShortPathConverter.cs37
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Properties/AssemblyInfo.cs6
-rw-r--r--Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj60
-rw-r--r--Software/Visual Studio/Tango.sln30
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.CLI/App.config6
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Options.cs32
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Program.cs88
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Properties/AssemblyInfo.cs6
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Tango.Protobuf.CLI.csproj65
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.CLI/packages.config4
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.config6
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml20
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml.cs59
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/DirectoryItem.cs18
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml40
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml.cs31
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/FileItem.cs17
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/Item.cs15
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/ItemProvider.cs44
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml144
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml.cs148
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/AssemblyInfo.cs6
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.Designer.cs71
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.resx117
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.Designer.cs30
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.settings7
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/Tango.Protobuf.UI.csproj151
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/packages.config7
-rw-r--r--Software/Visual Studio/Utilities/Tango.Protobuf.UI/proto.icobin0 -> 370070 bytes
65 files changed, 2819 insertions, 43 deletions
diff --git a/Software/PMR/Messages/.settings/com.google.eclipse.protobuf.Protobuf.prefs b/Software/PMR/Messages/.settings/com.google.eclipse.protobuf.Protobuf.prefs
new file mode 100644
index 000000000..ae5e40a11
--- /dev/null
+++ b/Software/PMR/Messages/.settings/com.google.eclipse.protobuf.Protobuf.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+paths.directoryPaths=${workspace_loc\:/${project}/Common},${workspace_loc\:/${project}/Job},${workspace_loc\:/${project}}
+paths.filesInMultipleDirectories=true
+paths.filesInOneDirectoryOnly=false
diff --git a/Software/PMR/Messages/Job/Segment.proto b/Software/PMR/Messages/Job/Segment.proto
index 7487dfcaf..7ad58da7d 100644
--- a/Software/PMR/Messages/Job/Segment.proto
+++ b/Software/PMR/Messages/Job/Segment.proto
@@ -1,6 +1,6 @@
syntax = "proto3";
-import "../Common/RGB.proto";
+import "RGB.proto";
package PMR.Job;
diff --git a/Software/Visual Studio/Tango.Core/Commands/RelayCommand.cs b/Software/Visual Studio/Tango.Core/Commands/RelayCommand.cs
new file mode 100644
index 000000000..f57a8699f
--- /dev/null
+++ b/Software/Visual Studio/Tango.Core/Commands/RelayCommand.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace Tango.Core.Commands
+{
+ /// <summary>
+ /// RelayCommand is a very easy-to-use implementation of ICommand. You can use a RelayCommand to expose viewmodel functionality as a command, and
+ /// supply the condition that determines the command's availability. A control in the view bound to a command can execute an available command will</summary>
+ /// update its enabled state in response to the availability of the command.
+ /// <seealso cref="System.Windows.Input.ICommand" />
+ public sealed class RelayCommand : ICommand
+ {
+ #region fields
+ readonly Predicate<object> canExecute;
+ readonly Action<object> execute;
+ #endregion fields
+
+ #region constructors
+ public RelayCommand(Action<object> execute) : this(execute, null) { }
+
+ public RelayCommand(Action<object> execute, Predicate<object> canExecute)
+ {
+ this.execute = execute;
+ this.canExecute = canExecute;
+ }
+
+ public RelayCommand(Action execute)
+ : this((x) => execute())
+ {
+
+ }
+
+ public RelayCommand(Action execute, Predicate<object> canExecute)
+ : this((x) => execute(), canExecute)
+ {
+
+ }
+
+ #endregion constructors
+
+ #region methods
+ public void RaiseCanExecuteChanged()
+ {
+ if (this.CanExecuteChanged != null)
+ {
+ this.CanExecuteChanged(this, EventArgs.Empty);
+ }
+ }
+ #endregion methods
+
+ #region ICommand events
+ public event EventHandler CanExecuteChanged;
+ #endregion ICommand events
+
+ #region ICommand methods
+ public bool CanExecute(object parameter)
+ {
+ return this.canExecute != null ? this.canExecute(parameter) : true;
+ }
+
+ public void Execute(object parameter)
+ {
+ if (this.execute != null)
+ {
+ this.execute(parameter);
+ }
+ }
+ #endregion ICommand methods
+ }
+
+ public sealed class RelayCommand<T> : ICommand
+ {
+ #region fields
+ readonly Predicate<object> canExecute;
+ readonly Action<T> execute;
+ #endregion fields
+
+ #region constructors
+
+ public RelayCommand(Action<T> execute) : this(execute, null) { }
+
+ public RelayCommand(Action<T> execute, Predicate<object> canExecute)
+ {
+ this.execute = execute;
+ this.canExecute = canExecute;
+ }
+
+ public RelayCommand(Action execute)
+ : this((x) => execute())
+ {
+
+ }
+ #endregion constructors
+
+ #region methods
+ public void RaiseCanExecuteChanged()
+ {
+ if (this.CanExecuteChanged != null)
+ {
+ this.CanExecuteChanged(this, EventArgs.Empty);
+ }
+ }
+ #endregion methods
+
+ #region ICommand events
+ public event EventHandler CanExecuteChanged;
+ #endregion ICommand events
+
+ #region ICommand methods
+ public bool CanExecute(object parameter)
+ {
+ return this.canExecute != null ? this.canExecute(parameter) : true;
+ }
+
+ public void Execute(object parameter)
+ {
+ if (this.execute != null)
+ {
+ this.execute((T)parameter);
+ }
+ }
+ #endregion ICommand methods
+ }
+}
diff --git a/Software/Visual Studio/Tango.Core/ExtendedObject.cs b/Software/Visual Studio/Tango.Core/ExtendedObject.cs
new file mode 100644
index 000000000..1452f1f0d
--- /dev/null
+++ b/Software/Visual Studio/Tango.Core/ExtendedObject.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using Tango.Core.Commands;
+
+namespace Tango.Core
+{
+ /// <summary>
+ /// Represents an extension to the standard core object with support for property and relay commands changed event.
+ /// </summary>
+ /// <seealso cref="System.ComponentModel.INotifyPropertyChanged" />
+ [Serializable]
+ public class ExtendedObject : INotifyPropertyChanged
+ {
+ /// <summary>
+ /// Occurs when a property has changed.
+ /// </summary>
+ [field: NonSerialized]
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ /// <summary>
+ /// Raises the property changed event.
+ /// </summary>
+ /// <param name="propName">Name of the property.</param>
+ protected virtual void RaisePropertyChanged(String propName)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
+ }
+
+ /// <summary>
+ /// Raises all relay commands CanExecute methods in the current instance.
+ /// </summary>
+ protected virtual void InvalidateRelayCommands()
+ {
+ Application.Current.Dispatcher.BeginInvoke(new Action(() =>
+ {
+ foreach (var prop in this.GetType().GetProperties().Where(x => x.PropertyType == typeof(RelayCommand)))
+ {
+ var value = prop.GetValue(this) as RelayCommand;
+
+ if (value != null)
+ {
+ value.RaiseCanExecuteChanged();
+ }
+ }
+ }));
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs b/Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs
new file mode 100644
index 000000000..5baaac72b
--- /dev/null
+++ b/Software/Visual Studio/Tango.Core/ExtensionMethods/StringExtensions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+public static class StringExtensions
+{
+ /// <summary>
+ /// Normal ToString conversion with null checking.
+ /// </summary>
+ /// <param name="obj">The object.</param>
+ /// <returns></returns>
+ public static String ToStringSafe(this object obj)
+ {
+ return obj != null ? obj.ToString() : String.Empty;
+ }
+}
diff --git a/Software/Visual Studio/Tango.Core/AssemblyHelper.cs b/Software/Visual Studio/Tango.Core/Helpers/AssemblyHelper.cs
index 5a78f9fe3..405020e66 100644
--- a/Software/Visual Studio/Tango.Core/AssemblyHelper.cs
+++ b/Software/Visual Studio/Tango.Core/Helpers/AssemblyHelper.cs
@@ -6,7 +6,7 @@ using System.Reflection;
using System.Text;
using System.Threading.Tasks;
-namespace Tango.Core
+namespace Tango.Core.Helpers
{
public static class AssemblyHelper
{
diff --git a/Software/Visual Studio/Tango.Core/PathHelper.cs b/Software/Visual Studio/Tango.Core/Helpers/PathHelper.cs
index 08dbf1c16..fa52eb42b 100644
--- a/Software/Visual Studio/Tango.Core/PathHelper.cs
+++ b/Software/Visual Studio/Tango.Core/Helpers/PathHelper.cs
@@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Tango.Core
+namespace Tango.Core.Helpers
{
public static class PathHelper
{
diff --git a/Software/Visual Studio/Tango.Core/Tango.Core.csproj b/Software/Visual Studio/Tango.Core/Tango.Core.csproj
index 803d9e3e6..1653d5cb9 100644
--- a/Software/Visual Studio/Tango.Core/Tango.Core.csproj
+++ b/Software/Visual Studio/Tango.Core/Tango.Core.csproj
@@ -30,18 +30,28 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
+ <Reference Include="System.Windows" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
- <Compile Include="AssemblyHelper.cs" />
- <Compile Include="PathHelper.cs" />
+ <Compile Include="..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="ExtensionMethods\StringExtensions.cs" />
+ <Compile Include="Helpers\AssemblyHelper.cs" />
+ <Compile Include="Commands\RelayCommand.cs" />
+ <Compile Include="ExtendedObject.cs" />
+ <Compile Include="Helpers\PathHelper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
diff --git a/Software/Visual Studio/Tango.Logging/ApplicationCrashedEventArgs.cs b/Software/Visual Studio/Tango.Logging/ApplicationCrashedEventArgs.cs
new file mode 100644
index 000000000..9a6e03351
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/ApplicationCrashedEventArgs.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents an application crash event arguments
+ /// </summary>
+ /// <seealso cref="System.EventArgs" />
+ public class ApplicationCrashedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Gets or sets the error.
+ /// </summary>
+ public String Error { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to attempt recovering from this crash and ignoring the exception.
+ /// </summary>
+ public bool TryRecover { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ApplicationCrashedEventArgs"/> class.
+ /// </summary>
+ /// <param name="error">The error.</param>
+ public ApplicationCrashedEventArgs(String error)
+ {
+ Error = error;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/ExceptionLogItem.cs b/Software/Visual Studio/Tango.Logging/ExceptionLogItem.cs
new file mode 100644
index 000000000..de526f954
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/ExceptionLogItem.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents an exception log item.
+ /// </summary>
+ public class ExceptionLogItem : LogItemBase
+ {
+ /// <summary>
+ /// Gets or sets the log item exception.
+ /// </summary>
+ public Exception InnerException { get; set; }
+
+ /// <summary>
+ /// Gets or sets the error description.
+ /// </summary>
+ public String Description { get; set; }
+
+ /// <summary>
+ /// Returns a formatted string of the log item.
+ /// </summary>
+ public override string ToString()
+ {
+ return String.Format("[{0}] [{1}] [{2}] [Line {3}]: {4}{5}", TimeStamp.ToString("HH:mm:ss.ff"), Path.GetFileNameWithoutExtension(CallerFile), CallerMethodName, CallerLineNumber, Description, Environment.NewLine + InnerException.Message);
+ }
+
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/FileLogger.cs b/Software/Visual Studio/Tango.Logging/FileLogger.cs
new file mode 100644
index 000000000..6d31fc154
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/FileLogger.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents an <see cref="ILogger"/> file logger.
+ /// </summary>
+ /// <seealso cref="Tango.Logging.ILogger" />
+ public class FileLogger : ILogger
+ {
+
+ /// <summary>
+ /// Gets or sets the log file.
+ /// </summary>
+ public String LogFile { get; private set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FileLogger"/> class.
+ /// </summary>
+ public FileLogger()
+ {
+ _isEnabled = true;
+ String logsFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "logs");
+ Directory.CreateDirectory(logsFolder);
+ LogFile = Path.Combine(logsFolder, string.Format("{1}-{0:yyyy-MM-dd_hh-mm-ss}.log", DateTime.Now, Path.GetFileNameWithoutExtension(System.AppDomain.CurrentDomain.FriendlyName)));
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FileLogger"/> class.
+ /// </summary>
+ /// <param name="logFile">The log file.</param>
+ public FileLogger(String logFile)
+ : this()
+ {
+ LogFile = logFile;
+ }
+
+ /// <summary>
+ /// Called when a new library trace is available.
+ /// </summary>
+ /// <param name="output">The output.</param>
+ public void OnTrace(LogItemBase output)
+ {
+ OnError(output);
+ }
+
+ /// <summary>
+ /// Called when a new library exception is available.
+ /// </summary>
+ /// <param name="output">The output.</param>
+ public void OnError(LogItemBase output)
+ {
+ File.AppendAllText(LogFile, output.ToString() + Environment.NewLine);
+ }
+
+ private bool _isEnabled;
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="ILogger" /> is enabled.
+ /// </summary>
+ public bool Enabled
+ {
+ get
+ {
+ return _isEnabled;
+ }
+ set
+ {
+ _isEnabled = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="ILogger" /> will be notified about logs without waiting for the logs queue.
+ /// </summary>
+ public bool Immediate { get; set; }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/GlobalExceptionTrapper.cs b/Software/Visual Studio/Tango.Logging/GlobalExceptionTrapper.cs
new file mode 100644
index 000000000..a0b52b077
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/GlobalExceptionTrapper.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+using Tango.Logging;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents an optimized WPF global exception trapper.
+ /// </summary>
+ /// <seealso cref="Tango.Logging.IGlobalExceptionTrapper" />
+ public class WpfGlobalExceptionTrapper : IGlobalExceptionTrapper
+ {
+ private DateTime _lastGlobalExceptionTime = DateTime.Now;
+
+ /// <summary>
+ /// Occurs when the global exception trapper has detected an unhandled exception.
+ /// </summary>
+ public event EventHandler<ApplicationCrashedEventArgs> ApplicationCrashed;
+
+ /// <summary>
+ /// Initializes the specified application.
+ /// </summary>
+ /// <param name="app">The application.</param>
+ public void Initialize(Application app)
+ {
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ app.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
+ Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
+ TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
+ }
+
+ /// <summary>
+ /// Handles the UnobservedTaskException event of the TaskScheduler control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="UnobservedTaskExceptionEventArgs"/> instance containing the event data.</param>
+ private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
+ {
+ OnApplicationCrash(e.Exception.ToStringSafe());
+ }
+
+ /// <summary>
+ /// Handles the DispatcherUnhandledException event of the Current control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="System.Windows.Threading.DispatcherUnhandledExceptionEventArgs"/> instance containing the event data.</param>
+ private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
+ {
+ e.Handled = OnApplicationCrash(e.Exception.ToStringSafe());
+ }
+
+ /// <summary>
+ /// Handles the UnhandledException event of the Dispatcher control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="System.Windows.Threading.DispatcherUnhandledExceptionEventArgs"/> instance containing the event data.</param>
+ private void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
+ {
+ e.Handled = OnApplicationCrash(e.Exception.ToStringSafe());
+ }
+
+ /// <summary>
+ /// Handles the UnhandledException event of the CurrentDomain control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="UnhandledExceptionEventArgs"/> instance containing the event data.</param>
+ private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ OnApplicationCrash(e.ExceptionObject.ToStringSafe());
+ }
+
+ /// <summary>
+ /// Called when any unhandled application exception has occurred and write to log.
+ /// </summary>
+ /// <param name="error">The error.</param>
+ private bool OnApplicationCrash(String error)
+ {
+ if (DateTime.Now - _lastGlobalExceptionTime > TimeSpan.FromSeconds(1))
+ {
+ _lastGlobalExceptionTime = DateTime.Now;
+ return true;
+ }
+
+ _lastGlobalExceptionTime = DateTime.Now;
+ LogManager.OverrideQueue = true;
+ LogManager.Log("Application Crash!" + Environment.NewLine + error);
+
+ ApplicationCrashedEventArgs e = new ApplicationCrashedEventArgs(error);
+
+ ApplicationCrashed?.Invoke(this, e);
+
+ if (e.TryRecover)
+ {
+ LogManager.Log("Trying application recovery. Ignoring exception...");
+ }
+
+ LogManager.OverrideQueue = false;
+ return e.TryRecover;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/IGlobalExceptionTrapper.cs b/Software/Visual Studio/Tango.Logging/IGlobalExceptionTrapper.cs
new file mode 100644
index 000000000..6ef59ec4d
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/IGlobalExceptionTrapper.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents a global exception trapper.
+ /// </summary>
+ public interface IGlobalExceptionTrapper
+ {
+ /// <summary>
+ /// Occurs when the global exception trapper has detected an unhandled exception.
+ /// </summary>
+ event EventHandler<ApplicationCrashedEventArgs> ApplicationCrashed;
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/ILogger.cs b/Software/Visual Studio/Tango.Logging/ILogger.cs
new file mode 100644
index 000000000..61108962a
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/ILogger.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents a logging mechanism capable of being registered as a logger on the library <see cref="LogManager"/>.
+ /// </summary>
+ public interface ILogger
+ {
+ /// <summary>
+ /// Called when a new library trace is available.
+ /// </summary>
+ /// <param name="output">The output.</param>
+ void OnTrace(LogItemBase output);
+
+ /// <summary>
+ /// Called when a new library exception is available.
+ /// </summary>
+ /// <param name="output">The output.</param>
+ void OnError(LogItemBase output);
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="ILogger"/> is enabled.
+ /// </summary>
+ bool Enabled { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="ILogger"/> will be notified about logs without waiting for the logs queue.
+ /// </summary>
+ bool Immediate { get; set; }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/LogItemBase.cs b/Software/Visual Studio/Tango.Logging/LogItemBase.cs
new file mode 100644
index 000000000..38e78d3ac
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/LogItemBase.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents a base class for log items.
+ /// </summary>
+ public abstract class LogItemBase
+ {
+ /// <summary>
+ /// Gets or sets the caller method adding the exception.
+ /// </summary>
+ public String CallerMethodName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the caller file.
+ /// </summary>
+ public String CallerFile { get; set; }
+
+ /// <summary>
+ /// Gets or sets the caller line number.
+ /// </summary>
+ public int CallerLineNumber { get; set; }
+
+ /// <summary>
+ /// Gets or sets the DateTime for the log.
+ /// </summary>
+ public DateTime TimeStamp { get; set; }
+
+ /// <summary>
+ /// Returns a formatted string of the log item.
+ /// </summary>
+ public abstract override String ToString();
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/LogManager.cs b/Software/Visual Studio/Tango.Logging/LogManager.cs
new file mode 100644
index 000000000..3ada76104
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/LogManager.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents a helper class for logging information and errors.
+ /// </summary>
+ public static class LogManager
+ {
+ private static List<ILogger> _loggers;
+ private static ConcurrentQueue<LogItemBase> _logs;
+ private static Thread _loggingThread;
+ private static bool _isStarted;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to propagate logs instantly (Warning - not thread safe).
+ /// </summary>
+ public static bool OverrideQueue { get; set; }
+
+ /// <summary>
+ /// Initializes the <see cref="LogManager"/> class.
+ /// </summary>
+ static LogManager()
+ {
+ _loggers = new List<ILogger>();
+ _logs = new ConcurrentQueue<LogItemBase>();
+ }
+
+ /// <summary>
+ /// Registers a logger.
+ /// </summary>
+ /// <param name="logger">The logger.</param>
+ public static void RegisterLogger(ILogger logger)
+ {
+ if (logger != null && !_loggers.Contains(logger))
+ {
+ _loggers.Add(logger);
+ }
+ }
+
+ /// <summary>
+ /// Unregisters a logger.
+ /// </summary>
+ /// <param name="logger">The logger.</param>
+ public static void UnregisterLogger(ILogger logger)
+ {
+ if (logger != null && _loggers.Contains(logger))
+ {
+ _loggers.Remove(logger);
+ }
+ }
+
+ /// <summary>
+ /// Add new exception log item.
+ /// </summary>
+ /// <param name="e">Exception.</param>
+ /// <param name="description">Error description.</param>
+ public static Exception Log(Exception e, String description = null, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0)
+ {
+ ExceptionLogItem log = new ExceptionLogItem();
+ log.CallerMethodName = caller;
+ log.CallerFile = file;
+ log.CallerLineNumber = lineNumber;
+ log.TimeStamp = DateTime.Now;
+ log.InnerException = e;
+ log.Description = description != null ? description : e.ToString();
+
+ if (!OverrideQueue)
+ {
+ AppendLog(log);
+ }
+ else
+ {
+ AppendLogInstantly(log);
+ }
+
+ return e;
+ }
+
+ /// <summary>
+ /// Add new message log item.
+ /// </summary>
+ /// <param name="message">Message.</param>
+ public static void Log(String message, [CallerMemberName] string caller = null, [CallerFilePath] string file = null, [CallerLineNumber] int lineNumber = 0)
+ {
+ MessageLogItem log = new MessageLogItem();
+ log.CallerMethodName = caller;
+ log.CallerFile = file;
+ log.CallerLineNumber = lineNumber;
+ log.TimeStamp = DateTime.Now;
+ log.Message = message;
+
+ if (!OverrideQueue)
+ {
+ AppendLog(log);
+ }
+ else
+ {
+ AppendLogInstantly(log);
+ }
+ }
+
+ /// <summary>
+ /// Appends the log.
+ /// </summary>
+ /// <param name="log">The log.</param>
+ private static void AppendLog(LogItemBase log)
+ {
+ if (log != null)
+ {
+ if (log.GetType() == typeof(ExceptionLogItem))
+ {
+ _loggers.Where(x => x.Enabled && x.Immediate).ToList().ForEach(x => x.OnError(log));
+ }
+ else
+ {
+ _loggers.Where(x => x.Enabled && x.Immediate).ToList().ForEach(x => x.OnTrace(log));
+ }
+ }
+
+ _logs.Enqueue(log);
+ StartLoggingThread();
+ }
+
+ /// <summary>
+ /// Starts the logging thread.
+ /// </summary>
+ private static void StartLoggingThread()
+ {
+ if (!_isStarted)
+ {
+ _isStarted = true;
+ _loggingThread = new Thread(LoggingThreadMethod);
+ _loggingThread.IsBackground = true;
+ _loggingThread.Start();
+ }
+ }
+
+ /// <summary>
+ /// Loggings thread method.
+ /// </summary>
+ [DebuggerStepThrough]
+ [DebuggerHidden]
+ private static void LoggingThreadMethod()
+ {
+ while (_logs.Count > 0)
+ {
+ LogItemBase log;
+
+ if (_logs.TryDequeue(out log))
+ {
+ if (log != null)
+ {
+ if (log.GetType() == typeof(ExceptionLogItem))
+ {
+ _loggers.Where(x => x.Enabled && !x.Immediate).ToList().ForEach(x => x.OnError(log));
+ }
+ else
+ {
+ _loggers.Where(x => x.Enabled && !x.Immediate).ToList().ForEach(x => x.OnTrace(log));
+ }
+ }
+ }
+
+ Thread.Sleep(10);
+ }
+
+ Thread.Sleep(400);
+
+ if (_logs.Count > 0)
+ {
+ LoggingThreadMethod();
+ return;
+ }
+
+ _isStarted = false;
+ }
+
+ /// <summary>
+ /// Appends the log instantly.
+ /// </summary>
+ /// <param name="log">The log.</param>
+ [DebuggerStepThrough]
+ [DebuggerHidden]
+ private static void AppendLogInstantly(LogItemBase log)
+ {
+ bool wroteLog = false;
+
+ while (!wroteLog)
+ {
+ try
+ {
+ if (log.GetType() == typeof(ExceptionLogItem))
+ {
+ _loggers.Where(x => x.Enabled).ToList().ForEach(x => x.OnError(log));
+ }
+ else
+ {
+ _loggers.Where(x => x.Enabled).ToList().ForEach(x => x.OnTrace(log));
+ }
+
+ wroteLog = true;
+ }
+ catch
+ {
+ Thread.Sleep(5);
+ }
+ }
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/MessageLogItem.cs b/Software/Visual Studio/Tango.Logging/MessageLogItem.cs
new file mode 100644
index 000000000..44cb2c575
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/MessageLogItem.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents an exception log item.
+ /// </summary>
+ public class MessageLogItem : LogItemBase
+ {
+ /// <summary>
+ /// Gets or sets the log message.
+ /// </summary>
+ public String Message { get; set; }
+
+ /// <summary>
+ /// Returns a formatted string of the log item.
+ /// </summary>
+ public override string ToString()
+ {
+ return String.Format("[{0}] [{1}] [{2}] [Line {3}]: {4}", TimeStamp.ToString("HH:mm:ss.ff"), Path.GetFileNameWithoutExtension(CallerFile), CallerMethodName, CallerLineNumber, Message);
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Logging/Properties/AssemblyInfo.cs b/Software/Visual Studio/Tango.Logging/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..9155db1b4
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Twine - Logging Library")]
+[assembly: ComVisible(false)] \ No newline at end of file
diff --git a/Software/Visual Studio/Tango.Logging/Tango.Logging.csproj b/Software/Visual Studio/Tango.Logging/Tango.Logging.csproj
new file mode 100644
index 000000000..2012f609f
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/Tango.Logging.csproj
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{BC932DBD-7CDB-488C-99E4-F02CF441F55E}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.Logging</RootNamespace>
+ <AssemblyName>Tango.Logging</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\Build\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Windows" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="ApplicationCrashedEventArgs.cs" />
+ <Compile Include="ExceptionLogItem.cs" />
+ <Compile Include="FileLogger.cs" />
+ <Compile Include="GlobalExceptionTrapper.cs" />
+ <Compile Include="IGlobalExceptionTrapper.cs" />
+ <Compile Include="ILogger.cs" />
+ <Compile Include="LogItemBase.cs" />
+ <Compile Include="LogManager.cs" />
+ <Compile Include="MessageLogItem.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="VSOutputLogger.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/Software/Visual Studio/Tango.Logging/VSOutputLogger.cs b/Software/Visual Studio/Tango.Logging/VSOutputLogger.cs
new file mode 100644
index 000000000..80de5292f
--- /dev/null
+++ b/Software/Visual Studio/Tango.Logging/VSOutputLogger.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Logging
+{
+ /// <summary>
+ /// Represents a library logger for routing logs to the Visual Studio output window.
+ /// </summary>
+ public class VSOutputLogger : ILogger
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="VSOutputLogger"/> class.
+ /// </summary>
+ public VSOutputLogger()
+ {
+ Immediate = true;
+ Enabled = true;
+ }
+
+ /// <summary>
+ /// Called when a new library trace is available.
+ /// </summary>
+ /// <param name="output">The output.</param>
+ public void OnTrace(LogItemBase output)
+ {
+ Debug.WriteLine(output.ToString());
+ }
+
+ /// <summary>
+ /// Called when a new library exception is available.
+ /// </summary>
+ /// <param name="output">The output.</param>
+ public void OnError(LogItemBase output)
+ {
+ Debug.WriteLine(output.ToString());
+ }
+
+
+ private bool _isEnabled;
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="ILogger" /> is enabled.
+ /// </summary>
+ public bool Enabled
+ {
+ get
+ {
+ return _isEnabled;
+ }
+ set
+ {
+ _isEnabled = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="ILogger" /> will be notified about logs without waiting for the logs queue.
+ /// </summary>
+ public bool Immediate { get; set; }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Protobuf/CompilerException.cs b/Software/Visual Studio/Tango.Protobuf/CompilerException.cs
new file mode 100644
index 000000000..8e50e405e
--- /dev/null
+++ b/Software/Visual Studio/Tango.Protobuf/CompilerException.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf
+{
+ /// <summary>
+ /// Represents an <see cref="IProtoCompiler"/> compilation exception.
+ /// </summary>
+ /// <seealso cref="System.Exception" />
+ public class CompilerException : Exception
+ {
+ /// <summary>
+ /// Gets the collection of compilation errors.
+ /// </summary>
+ public List<String> Issues { get; internal set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CompilerException"/> class.
+ /// </summary>
+ public CompilerException()
+ {
+ Issues = new List<string>();
+ }
+
+ public override string Message => this.ToString();
+
+ /// <summary>
+ /// Returns a <see cref="System.String" /> that represents this instance.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="System.String" /> that represents this instance.
+ /// </returns>
+ public override string ToString()
+ {
+ return String.Join(Environment.NewLine, Issues);
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Protobuf/CompilerFactory.cs b/Software/Visual Studio/Tango.Protobuf/CompilerFactory.cs
new file mode 100644
index 000000000..269ca4cef
--- /dev/null
+++ b/Software/Visual Studio/Tango.Protobuf/CompilerFactory.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.Logging;
+
+namespace Tango.Protobuf
+{
+ /// <summary>
+ /// Factory class for protobuf compilers.
+ /// </summary>
+ public static class CompilerFactory
+ {
+ /// <summary>
+ /// Creates a protobuf compiler instance by the specified language.
+ /// </summary>
+ /// <param name="language">The language.</param>
+ /// <returns></returns>
+ /// <exception cref="ArgumentException">Could not locate protobuf compiler for language " + language.ToString()</exception>
+ public static IProtoCompiler CreateCompiler(CompilerLanguage language)
+ {
+ LogManager.Log("Generating protobuf compiler for " + language.ToString() + "...");
+
+ foreach (var cType in typeof(CompilerFactory).Assembly.GetTypes().Where(x => x.IsClass && !x.IsAbstract && typeof(IProtoCompiler).IsAssignableFrom(x)))
+ {
+ var instance = Activator.CreateInstance(cType) as IProtoCompiler;
+ if (instance.Language == language) return instance;
+ }
+
+ throw LogManager.Log(new ArgumentException("Could not locate protobuf compiler for language " + language.ToString()));
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Protobuf/CompilerFileResult.cs b/Software/Visual Studio/Tango.Protobuf/CompilerFileResult.cs
index 864c5f67a..05ded3b26 100644
--- a/Software/Visual Studio/Tango.Protobuf/CompilerFileResult.cs
+++ b/Software/Visual Studio/Tango.Protobuf/CompilerFileResult.cs
@@ -14,19 +14,19 @@ namespace Tango.Protobuf
public class CompilerFileResult : ICompilerResult
{
/// <summary>
- /// Gets the compiled language.
+ /// Gets the result language.
/// </summary>
public CompilerLanguage Language { get; private set; }
/// <summary>
- /// Gets the name of the file.
- /// </summary
- public String FileName { get; private set; }
+ /// Gets the result name.
+ /// </summary>
+ public String Name { get; private set; }
/// <summary>
- /// Gets the file path.
+ /// Gets the result source path.
/// </summary>
- public String FilePath { get; private set; }
+ public String SourcePath { get; private set; }
/// <summary>
/// Gets the file content.
@@ -36,15 +36,16 @@ namespace Tango.Protobuf
/// <summary>
/// Initializes a new instance of the <see cref="CompilerFileResult"/> class.
/// </summary>
- /// <param name="fileName">Name of the file.</param>
- /// <param name="content">The content.</param>
/// <param name="language">The language.</param>
- public CompilerFileResult(String filePath, String content, CompilerLanguage language)
+ /// <param name="sourcePath">The source path.</param>
+ /// <param name="fileName">Name of the file.</param>
+ /// <param name="content">File contents.</param>
+ public CompilerFileResult(CompilerLanguage language, String sourcePath, String fileName, String content)
{
- FilePath = filePath;
- FileName = Path.GetFileName(filePath);
- Content = content;
Language = language;
+ SourcePath = sourcePath;
+ Name = fileName;
+ Content = content;
}
/// <summary>
@@ -54,7 +55,7 @@ namespace Tango.Protobuf
public void Save(String folder)
{
Directory.CreateDirectory(folder);
- File.WriteAllText(Path.Combine(folder, FileName), Content);
+ File.WriteAllText(Path.Combine(folder, Name), Content);
}
}
}
diff --git a/Software/Visual Studio/Tango.Protobuf/CompilerFolderResult.cs b/Software/Visual Studio/Tango.Protobuf/CompilerFolderResult.cs
index b3e7078b8..d1f36c47a 100644
--- a/Software/Visual Studio/Tango.Protobuf/CompilerFolderResult.cs
+++ b/Software/Visual Studio/Tango.Protobuf/CompilerFolderResult.cs
@@ -17,29 +17,42 @@ namespace Tango.Protobuf
/// Initializes a new instance of the <see cref="CompilerFolderResult"/> class.
/// </summary>
/// <param name="results">The results.</param>
- /// <param name="language">Compiler language.</param>
- /// <param name="sourceFolder">Source folder.</param>
- public CompilerFolderResult(IEnumerable<CompilerFileResult> results, CompilerLanguage language, String sourceFolder)
+ /// <param name="language">The language.</param>
+ /// <param name="sourcePath">The source path.</param>
+ /// <param name="relativePath">The relative path.</param>
+ public CompilerFolderResult(IEnumerable<ICompilerResult> results, CompilerLanguage language, String sourcePath, String relativePath)
{
Results = results;
Language = language;
- SourceFolder = sourceFolder;
+ SourcePath = sourcePath;
+ RelativePath = relativePath;
+ Name = Path.GetFileName(sourcePath);
}
/// <summary>
/// Gets the compiler results.
/// </summary>
- public IEnumerable<CompilerFileResult> Results { get; private set; }
+ public IEnumerable<ICompilerResult> Results { get; private set; }
/// <summary>
- /// Gets the compiler language.
+ /// Gets the result language.
/// </summary>
public CompilerLanguage Language { get; private set; }
/// <summary>
- /// Gets the source folder.
+ /// Gets the result source path.
/// </summary>
- public String SourceFolder { get; private set; }
+ public String SourcePath { get; private set; }
+
+ /// <summary>
+ /// Gets the result name.
+ /// </summary>
+ public String Name { get; private set; }
+
+ /// <summary>
+ /// Gets the result relative path.
+ /// </summary>
+ public String RelativePath { get; private set; }
/// <summary>
/// Saves the result to the specified folder.
@@ -47,13 +60,14 @@ namespace Tango.Protobuf
/// <param name="folder">The folder.</param>
public void Save(string folder)
{
- Directory.CreateDirectory(folder);
+ foreach (var fileResult in Results.OfType<CompilerFileResult>())
+ {
+ fileResult.Save(folder);
+ }
- foreach (var result in Results)
+ foreach (var folderResult in Results.OfType<CompilerFolderResult>())
{
- String targetFolder = Path.GetDirectoryName(result.FilePath.Replace(SourceFolder, folder));
- Directory.CreateDirectory(targetFolder);
- result.Save(targetFolder);
+ folderResult.Save(Path.Combine(folder, folderResult.RelativePath.TrimStart('\\','\\')));
}
}
}
diff --git a/Software/Visual Studio/Tango.Protobuf/Compilers/CCompiler.cs b/Software/Visual Studio/Tango.Protobuf/Compilers/CCompiler.cs
new file mode 100644
index 000000000..18aab84c6
--- /dev/null
+++ b/Software/Visual Studio/Tango.Protobuf/Compilers/CCompiler.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.Compilers
+{
+ /// <summary>
+ /// Represents a protobuf C Compiler.
+ /// </summary>
+ /// <seealso cref="Tango.Protobuf.ProtoCompiler" />
+ public class CCompiler : ProtoCompiler
+ {
+ /// <summary>
+ /// Gets the compiler language.
+ /// </summary>
+ public override CompilerLanguage Language => CompilerLanguage.C;
+
+ /// <summary>
+ /// Gets the protobuf compiler CLI arguments (without input/output files!).
+ /// </summary>
+ /// <returns></returns>
+ protected override string GetProtoArguments()
+ {
+ return "--c_out";
+ }
+
+ /// <summary>
+ /// Gets the protobuf compiler CLI file name (override when using a compiler other than the default 'protoc.exe').
+ /// </summary>
+ /// <returns></returns>
+ /// <remarks>
+ /// The compiler program must be located in the compilers folder.
+ /// </remarks>
+ protected override string GetProtoCompilerName()
+ {
+ return "protoc-c";
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Protobuf/Compilers/CppCompiler.cs b/Software/Visual Studio/Tango.Protobuf/Compilers/CppCompiler.cs
new file mode 100644
index 000000000..54069d41a
--- /dev/null
+++ b/Software/Visual Studio/Tango.Protobuf/Compilers/CppCompiler.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.Compilers
+{
+ /// <summary>
+ /// Represents a protobuf C# Compiler.
+ /// </summary>
+ /// <seealso cref="Tango.Protobuf.ProtoCompiler" />
+ public class CppCompiler : ProtoCompiler
+ {
+ /// <summary>
+ /// Gets the compiler language.
+ /// </summary>
+ public override CompilerLanguage Language => CompilerLanguage.CPP;
+
+ /// <summary>
+ /// Gets the protobuf compiler CLI arguments (without input/output files!).
+ /// </summary>
+ /// <returns></returns>
+ protected override string GetProtoArguments()
+ {
+ return "--cpp_out";
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs b/Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs
new file mode 100644
index 000000000..78d754aa5
--- /dev/null
+++ b/Software/Visual Studio/Tango.Protobuf/Compilers/JavaCompiler.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.Compilers
+{
+ /// <summary>
+ /// Represents a protobuf Java Compiler.
+ /// </summary>
+ /// <seealso cref="Tango.Protobuf.ProtoCompiler" />
+ public class JavaCompiler : ProtoCompiler
+ {
+ /// <summary>
+ /// Gets the compiler language.
+ /// </summary>
+ public override CompilerLanguage Language => CompilerLanguage.Java;
+
+ /// <summary>
+ /// Gets the protobuf compiler CLI arguments (without input/output files!).
+ /// </summary>
+ /// <returns></returns>
+ protected override string GetProtoArguments()
+ {
+ return "--java_out";
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Protobuf/Compilers/PythonCompiler.cs b/Software/Visual Studio/Tango.Protobuf/Compilers/PythonCompiler.cs
new file mode 100644
index 000000000..e3c3ebbd7
--- /dev/null
+++ b/Software/Visual Studio/Tango.Protobuf/Compilers/PythonCompiler.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.Compilers
+{
+ /// <summary>
+ /// Represents a protobuf Python Compiler.
+ /// </summary>
+ /// <seealso cref="Tango.Protobuf.ProtoCompiler" />
+ public class PythonCompiler : ProtoCompiler
+ {
+ /// <summary>
+ /// Gets the compiler language.
+ /// </summary>
+ public override CompilerLanguage Language => CompilerLanguage.Python;
+
+ /// <summary>
+ /// Gets the protobuf compiler CLI arguments (without input/output files!).
+ /// </summary>
+ /// <returns></returns>
+ protected override string GetProtoArguments()
+ {
+ return "--python_out";
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.Protobuf/ICompilerResult.cs b/Software/Visual Studio/Tango.Protobuf/ICompilerResult.cs
index ec6f95b02..866ce64d0 100644
--- a/Software/Visual Studio/Tango.Protobuf/ICompilerResult.cs
+++ b/Software/Visual Studio/Tango.Protobuf/ICompilerResult.cs
@@ -16,5 +16,20 @@ namespace Tango.Protobuf
/// </summary>
/// <param name="folder">The folder.</param>
void Save(String folder);
+
+ /// <summary>
+ /// Gets the result language.
+ /// </summary>
+ CompilerLanguage Language { get; }
+
+ /// <summary>
+ /// Gets the result name.
+ /// </summary>
+ String Name { get ; }
+
+ /// <summary>
+ /// Gets the result source path.
+ /// </summary>
+ String SourcePath { get; }
}
}
diff --git a/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs b/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs
index 0335bada9..684248209 100644
--- a/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs
+++ b/Software/Visual Studio/Tango.Protobuf/ProtoCompiler.cs
@@ -7,6 +7,8 @@ using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Tango.Core;
+using Tango.Core.Helpers;
+using Tango.Logging;
namespace Tango.Protobuf
{
@@ -34,6 +36,7 @@ namespace Tango.Protobuf
/// </summary>
public ProtoCompiler()
{
+ ImportsFolders = new List<string>();
_compilersPath = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), COMPILERS_FOLDER_NAME);
}
@@ -46,17 +49,33 @@ namespace Tango.Protobuf
/// </returns>
public virtual IEnumerable<CompilerFileResult> CompileFile(string inputFile)
{
+ LogManager.Log("Compiling file " + inputFile);
+
String tmpPath = PathHelper.GetTempFolderPath();
+ LogManager.Log("Temp path: " + tmpPath);
+
String importsString = "--proto_path \"" + Path.GetDirectoryName(inputFile) + "\" ";
+ LogManager.Log("Added import string: " + importsString);
+
foreach (var path in ImportsFolders)
{
- importsString += "--proto_path \"" + path + "\" ";
+ String importStr = "--proto_path \"" + path + "\" ";
+ importsString += importStr;
+ LogManager.Log("Added import string: " + importStr);
}
Process p = new Process();
- p.StartInfo.FileName = Path.Combine(_compilersPath, GetProtoCompilerName());
+
+ LogManager.Log("Compilers folder path: " + _compilersPath);
+
+ p.StartInfo.WorkingDirectory = _compilersPath;
+ Environment.CurrentDirectory = _compilersPath;
+ p.StartInfo.FileName = GetProtoCompilerName();
+
+ LogManager.Log("Protobuf executable path: " + p.StartInfo.FileName);
+
p.StartInfo.Arguments = String.Format(
"{0} {1}=\"{2}\" \"{3}\"",
importsString,
@@ -64,21 +83,48 @@ namespace Tango.Protobuf
tmpPath,
inputFile);
+ LogManager.Log("Final arguments:\n" + p.StartInfo.Arguments);
+
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ p.StartInfo.RedirectStandardError = true;
+ p.StartInfo.RedirectStandardOutput = true;
+
+
+ LogManager.Log("Executing compilation...");
+
p.Start();
p.WaitForExit(5000);
+ String error = p.StandardError.ReadToEnd();
+
+ if (!String.IsNullOrWhiteSpace(error))
+ {
+ var lines = error.Split(new[] { '\r', '\n' });
+ throw LogManager.Log(new CompilerException() { Issues = lines.Where(x => x.Length > 0).ToList() });
+ }
+
List<CompilerFileResult> results = new List<CompilerFileResult>();
- foreach (var file in Directory.GetFiles(tmpPath))
+ foreach (var file in Directory.GetFiles(tmpPath, "*.*", SearchOption.AllDirectories))
{
- CompilerFileResult result = new CompilerFileResult(file, File.ReadAllText(file), Language);
+ CompilerFileResult result = new CompilerFileResult(Language, inputFile, Path.GetFileName(file), File.ReadAllText(file));
+ results.Add(result);
}
- PathHelper.TryDeleteFolder(tmpPath);
+
+ if (PathHelper.TryDeleteFolder(tmpPath))
+ {
+ LogManager.Log("Removed temp path: " + tmpPath);
+ }
+ else
+ {
+ LogManager.Log("Could not remove temp path: " + tmpPath);
+ }
+
+ LogManager.Log(Path.GetFileName(inputFile) + "compiled!");
return results;
}
@@ -104,18 +150,42 @@ namespace Tango.Protobuf
/// </returns>
public virtual CompilerFolderResult CompileFolder(string sourceFolder)
{
- var files = Directory.GetFiles(sourceFolder, "*", SearchOption.AllDirectories);
+ LogManager.Log("Compiling folder: " + sourceFolder);
- List<CompilerFileResult> results = new List<CompilerFileResult>();
+ ImportsFolders.Clear();
+ ImportsFolders.AddRange(Directory.GetDirectories(sourceFolder, "*.*", SearchOption.AllDirectories));
+ var result = CompileFolder(sourceFolder, sourceFolder);
+
+ LogManager.Log(Path.GetFileName(sourceFolder) + "compiled!");
+
+ return result;
+ }
- foreach (var file in files)
+ /// <summary>
+ /// Compiles all files in the specified folder recursively.
+ /// </summary>
+ /// <param name="sourceFolder">The source folder</param>
+ /// <returns>
+ /// Compilation result.
+ /// </returns>
+ private CompilerFolderResult CompileFolder(string rootFolder, string sourceFolder)
+ {
+ List<ICompilerResult> currentFolderResults = new List<ICompilerResult>();
+ CompilerFolderResult currentFolder = new CompilerFolderResult(currentFolderResults, Language, sourceFolder, sourceFolder.Replace(rootFolder, ""));
+
+ foreach (String file in Directory.GetFiles(sourceFolder, "*.proto"))
{
- results.AddRange(CompileFile(file));
+ currentFolderResults.AddRange(CompileFile(file));
+ }
+ foreach (string folder in Directory.GetDirectories(sourceFolder))
+ {
+ if (Directory.GetFiles(folder, "*.proto").Length > 0)
+ {
+ currentFolderResults.Add(CompileFolder(rootFolder, folder));
+ }
}
- CompilerFolderResult result = new CompilerFolderResult(results, Language, sourceFolder);
-
- return result;
+ return currentFolder;
}
/// <summary>
diff --git a/Software/Visual Studio/Tango.Protobuf/Tango.Protobuf.csproj b/Software/Visual Studio/Tango.Protobuf/Tango.Protobuf.csproj
index 335fce325..8f10ba195 100644
--- a/Software/Visual Studio/Tango.Protobuf/Tango.Protobuf.csproj
+++ b/Software/Visual Studio/Tango.Protobuf/Tango.Protobuf.csproj
@@ -40,8 +40,17 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="CompilerException.cs" />
+ <Compile Include="CompilerFactory.cs" />
<Compile Include="CompilerFolderResult.cs" />
+ <Compile Include="Compilers\CCompiler.cs" />
+ <Compile Include="Compilers\CppCompiler.cs" />
<Compile Include="Compilers\CSharpCompiler.cs" />
+ <Compile Include="Compilers\JavaCompiler.cs" />
+ <Compile Include="Compilers\PythonCompiler.cs" />
<Compile Include="ICompilerResult.cs" />
<Compile Include="ProtoCompiler.cs" />
<Compile Include="IProtoCompiler.cs" />
@@ -54,6 +63,10 @@
<Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
<Name>Tango.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="..\..\External Repositories\Protobuf\protoc-1.0M4.jar">
diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/BooleanInverseConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/BooleanInverseConverter.cs
new file mode 100644
index 000000000..be0d9ed48
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Converters/BooleanInverseConverter.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Tango.SharedUI.Converters
+{
+ /// <summary>
+ /// Represents a binding converter for reversing a boolean value.
+ /// </summary>
+ /// <seealso cref="System.Windows.Data.IValueConverter" />
+ public class BooleanInverseConverter : IValueConverter
+ {
+ /// <summary>
+ /// Converts a value.
+ /// </summary>
+ /// <param name="value">The value produced by the binding source.</param>
+ /// <param name="targetType">The type of the binding target property.</param>
+ /// <param name="parameter">The converter parameter to use.</param>
+ /// <param name="culture">The culture to use in the converter.</param>
+ /// <returns>
+ /// A converted value. If the method returns null, the valid null value is used.
+ /// </returns>
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return !(bool)value;
+ }
+
+ /// <summary>
+ /// Converts a value.
+ /// </summary>
+ /// <param name="value">The value that is produced by the binding target.</param>
+ /// <param name="targetType">The type to convert to.</param>
+ /// <param name="parameter">The converter parameter to use.</param>
+ /// <param name="culture">The culture to use in the converter.</param>
+ /// <returns>
+ /// A converted value. If the method returns null, the valid null value is used.
+ /// </returns>
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return !(bool)value;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityConverter.cs
new file mode 100644
index 000000000..e3b43e7f2
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityConverter.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Tango.SharedUI.Converters
+{
+ /// <summary>
+ /// Binding converter for standard boolean to visibility and back.
+ /// </summary>
+ public class BooleanToVisibilityConverter : IValueConverter
+ {
+ /// <summary>
+ /// Converts a boolean value to visibility enumeration.
+ /// </summary>
+ /// <param name="value">Boolean value.</param>
+ /// <param name="targetType"></param>
+ /// <param name="parameter"></param>
+ /// <param name="culture"></param>
+ /// <returns></returns>
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if ((bool)value) return Visibility.Visible;
+ return Visibility.Collapsed;
+ }
+
+ /// <summary>
+ /// Converts a visibility enumeration to boolean value.
+ /// </summary>
+ /// <param name="value">Visibility enumeration.</param>
+ /// <param name="targetType"></param>
+ /// <param name="parameter"></param>
+ /// <param name="culture"></param>
+ /// <returns></returns>
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if ((Visibility)value == Visibility.Visible) return true;
+ else return false;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityInverseConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityInverseConverter.cs
new file mode 100644
index 000000000..475d2fca7
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Converters/BooleanToVisibilityInverseConverter.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Tango.SharedUI.Converters
+{
+ /// <summary>
+ /// Inversed binding converter for standard boolean to visibility and back.
+ /// </summary>
+ public class BooleanToVisibilityInverseConverter : IValueConverter
+ {
+ /// <summary>
+ /// Converts a boolean value to visibility enumeration.
+ /// </summary>
+ /// <param name="value">Boolean value.</param>
+ /// <param name="targetType"></param>
+ /// <param name="parameter"></param>
+ /// <param name="culture"></param>
+ /// <returns></returns>
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if ((bool)value) return Visibility.Collapsed;
+ return Visibility.Visible;
+ }
+
+ /// <summary>
+ /// Converts a visibility enumeration to boolean value.
+ /// </summary>
+ /// <param name="value">Visibility enumeration</param>
+ /// <param name="targetType"></param>
+ /// <param name="parameter"></param>
+ /// <param name="culture"></param>
+ /// <returns></returns>
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if ((Visibility)value == Visibility.Visible) return false;
+ else return true;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/EnumToDescriptionConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/EnumToDescriptionConverter.cs
new file mode 100644
index 000000000..797d5c2e4
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Converters/EnumToDescriptionConverter.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Tango.SharedUI.Converters
+{
+ /// <summary>
+ /// Represents a binding converter for converting enum value to the associated description attribute if found.
+ /// </summary>
+ /// <seealso cref="System.Windows.Data.IValueConverter" />
+ public class EnumToDescriptionConverter : IValueConverter
+ {
+ /// <summary>
+ /// Converts a value.
+ /// </summary>
+ /// <param name="value">The value produced by the binding source.</param>
+ /// <param name="targetType">The type of the binding target property.</param>
+ /// <param name="parameter">The converter parameter to use.</param>
+ /// <param name="culture">The culture to use in the converter.</param>
+ /// <returns>
+ /// A converted value. If the method returns null, the valid null value is used.
+ /// </returns>
+ /// <exception cref="System.NotImplementedException"></exception>
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return GetDescription(value, value.ToString());
+ }
+
+ public static string GetDescription(object enumValue, string defDesc)
+ {
+ FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());
+
+ if (null != fi)
+ {
+ object[] attrs = fi.GetCustomAttributes(typeof(DescriptionAttribute), true);
+ if (attrs != null && attrs.Length > 0)
+ return ((DescriptionAttribute)attrs[0]).Description;
+ }
+
+ return defDesc;
+ }
+
+ /// <summary>
+ /// Converts a value.
+ /// </summary>
+ /// <param name="value">The value that is produced by the binding target.</param>
+ /// <param name="targetType">The type to convert to.</param>
+ /// <param name="parameter">The converter parameter to use.</param>
+ /// <param name="culture">The culture to use in the converter.</param>
+ /// <returns>
+ /// A converted value. If the method returns null, the valid null value is used.
+ /// </returns>
+ /// <exception cref="System.NotImplementedException"></exception>
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return value;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/NullObjectToBooleanConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/NullObjectToBooleanConverter.cs
new file mode 100644
index 000000000..5046ee127
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Converters/NullObjectToBooleanConverter.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Tango.SharedUI.Converters
+{
+ /// <summary>
+ /// Represents a binding converter for returning true for valid object instances and false for null object reference.
+ /// </summary>
+ public class NullObjectToBooleanConverter : IValueConverter
+ {
+ /// <summary>
+ /// Converts a value.
+ /// </summary>
+ /// <param name="value">The value produced by the binding source.</param>
+ /// <param name="targetType">The type of the binding target property.</param>
+ /// <param name="parameter">The converter parameter to use.</param>
+ /// <param name="culture">The culture to use in the converter.</param>
+ /// <returns>
+ /// A converted value. If the method returns null, the valid null value is used.
+ /// </returns>
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if (value != null) return true;
+ return false;
+ }
+
+ /// <summary>
+ /// Converts a value.
+ /// </summary>
+ /// <param name="value">The value that is produced by the binding target.</param>
+ /// <param name="targetType">The type to convert to.</param>
+ /// <param name="parameter">The converter parameter to use.</param>
+ /// <param name="culture">The culture to use in the converter.</param>
+ /// <returns>
+ /// A converted value. If the method returns null, the valid null value is used.
+ /// </returns>
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return value;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.SharedUI/Converters/PathToShortPathConverter.cs b/Software/Visual Studio/Tango.SharedUI/Converters/PathToShortPathConverter.cs
new file mode 100644
index 000000000..f6ef0152a
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Converters/PathToShortPathConverter.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Tango.SharedUI.Converters
+{
+ public class PathToShortPathConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if (value != null)
+ {
+ String path = value.ToString();
+
+ if (!String.IsNullOrWhiteSpace(path) && path.Length > 10)
+ {
+ return "..\\" + Path.GetFileName(path);
+ }
+ else
+ {
+ return path;
+ }
+ }
+
+ return null;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual Studio/Tango.SharedUI/Properties/AssemblyInfo.cs b/Software/Visual Studio/Tango.SharedUI/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..ee384bb30
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Twine - Shared UI Components")]
+[assembly: ComVisible(false)] \ No newline at end of file
diff --git a/Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj b/Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj
new file mode 100644
index 000000000..4c78bf44a
--- /dev/null
+++ b/Software/Visual Studio/Tango.SharedUI/Tango.SharedUI.csproj
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{AC489889-6E50-4F16-9DBA-FF4C6F9EC72B}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.SharedUI</RootNamespace>
+ <AssemblyName>Tango.SharedUI</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\Build\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Windows" />
+ <Reference Include="System.Xaml" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="Converters\BooleanInverseConverter.cs" />
+ <Compile Include="Converters\BooleanToVisibilityConverter.cs" />
+ <Compile Include="Converters\BooleanToVisibilityInverseConverter.cs" />
+ <Compile Include="Converters\EnumToDescriptionConverter.cs" />
+ <Compile Include="Converters\NullObjectToBooleanConverter.cs" />
+ <Compile Include="Converters\PathToShortPathConverter.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/Software/Visual Studio/Tango.sln b/Software/Visual Studio/Tango.sln
index dbcaa7e2a..db4dbfff4 100644
--- a/Software/Visual Studio/Tango.sln
+++ b/Software/Visual Studio/Tango.sln
@@ -12,6 +12,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Versioning", "Versioning",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.Core", "Tango.Core\Tango.Core.csproj", "{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utilities", "Utilities", "{5F6BBAA8-EAD0-4B18-97E5-55B4F56DD760}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.Protobuf.UI", "Utilities\Tango.Protobuf.UI\Tango.Protobuf.UI.csproj", "{37E45CE1-A0F6-4ED7-9791-A1BED947602F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.SharedUI", "Tango.SharedUI\Tango.SharedUI.csproj", "{AC489889-6E50-4F16-9DBA-FF4C6F9EC72B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.Protobuf.CLI", "Utilities\Tango.Protobuf.CLI\Tango.Protobuf.CLI.csproj", "{DE5AB980-A9AD-4273-8272-C4E1E062E3EC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tango.Logging", "Tango.Logging\Tango.Logging.csproj", "{BC932DBD-7CDB-488C-99E4-F02CF441F55E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -26,8 +36,28 @@ Global
{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {37E45CE1-A0F6-4ED7-9791-A1BED947602F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {37E45CE1-A0F6-4ED7-9791-A1BED947602F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {37E45CE1-A0F6-4ED7-9791-A1BED947602F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {37E45CE1-A0F6-4ED7-9791-A1BED947602F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AC489889-6E50-4F16-9DBA-FF4C6F9EC72B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AC489889-6E50-4F16-9DBA-FF4C6F9EC72B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AC489889-6E50-4F16-9DBA-FF4C6F9EC72B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AC489889-6E50-4F16-9DBA-FF4C6F9EC72B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DE5AB980-A9AD-4273-8272-C4E1E062E3EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DE5AB980-A9AD-4273-8272-C4E1E062E3EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DE5AB980-A9AD-4273-8272-C4E1E062E3EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DE5AB980-A9AD-4273-8272-C4E1E062E3EC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BC932DBD-7CDB-488C-99E4-F02CF441F55E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BC932DBD-7CDB-488C-99E4-F02CF441F55E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BC932DBD-7CDB-488C-99E4-F02CF441F55E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BC932DBD-7CDB-488C-99E4-F02CF441F55E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {37E45CE1-A0F6-4ED7-9791-A1BED947602F} = {5F6BBAA8-EAD0-4B18-97E5-55B4F56DD760}
+ {DE5AB980-A9AD-4273-8272-C4E1E062E3EC} = {5F6BBAA8-EAD0-4B18-97E5-55B4F56DD760}
+ EndGlobalSection
EndGlobal
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/App.config b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/App.config
new file mode 100644
index 000000000..8e1564635
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/App.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+ </startup>
+</configuration> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Options.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Options.cs
new file mode 100644
index 000000000..321ab4494
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Options.cs
@@ -0,0 +1,32 @@
+using CommandLine;
+using CommandLine.Text;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.CLI
+{
+ public class Options
+ {
+ [Option('i', Required = true, HelpText = "Source folder to compile.")]
+ public String SourceFolder { get; set; }
+
+ [Option('o', Required = true, HelpText = "Output folder to save the compiled files.")]
+ public String OutputFolder { get; set; }
+
+ [Option('l', Required = true, HelpText = "Target language.")]
+ public String Language { get; set; }
+
+ [ParserState]
+ public IParserState LastParserState { get; set; }
+
+ [HelpOption]
+ public string GetUsage()
+ {
+ return HelpText.AutoBuild(this,
+ (HelpText current) => HelpText.DefaultParsingErrorsHandler(this, current));
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Program.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Program.cs
new file mode 100644
index 000000000..96d42d10c
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Program.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.CLI
+{
+ class Program
+ {
+ static int Main(string[] args)
+ {
+ if (args.Length == 0)
+ {
+ return ExitHelp();
+ }
+
+ var options = new Options();
+
+ if (CommandLine.Parser.Default.ParseArguments(args, options))
+ {
+ if (!Directory.Exists(options.SourceFolder))
+ {
+ return ExitError("Could not locate source folder.");
+ }
+ if (!Directory.Exists(options.OutputFolder))
+ {
+ return ExitError("Could not locate output folder.");
+ }
+
+ CompilerLanguage language;
+ if (!Enum.TryParse<CompilerLanguage>(options.Language, out language))
+ {
+ return ExitError("Invalid language: " + options.Language);
+ }
+
+ try
+ {
+ var compiler = CompilerFactory.CreateCompiler(language);
+ var result = compiler.CompileFolder(options.SourceFolder);
+ result.Save(options.OutputFolder);
+ }
+ catch (Exception ex)
+ {
+ return ExitError(ex.Message);
+ }
+ }
+
+ return ExitSuccess();
+ }
+
+ private static int ExitSuccess()
+ {
+ Console.WriteLine("Done!");
+ return 0;
+ }
+
+ private static int ExitError(String error)
+ {
+ Console.WriteLine(error);
+ return -1;
+ }
+
+ private static int ExitHelp()
+ {
+ Console.WriteLine(
+@"
+ Example: proto-tc -i <source folder> -o <output folder> -l <language>
+
+ Available -l arguments:
+
+ CSharp
+ Java
+ JavaNano
+ CPP
+ C
+ EmbeddedC
+ JS
+ Python
+ PHP
+ Ruby
+");
+
+ return -1;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Properties/AssemblyInfo.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..00ace1d5d
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Twine - Protobuf Compilation CLI")]
+[assembly: ComVisible(false)] \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Tango.Protobuf.CLI.csproj b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Tango.Protobuf.CLI.csproj
new file mode 100644
index 000000000..537920dac
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/Tango.Protobuf.CLI.csproj
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{DE5AB980-A9AD-4273-8272-C4E1E062E3EC}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Tango.Protobuf.CLI</RootNamespace>
+ <AssemblyName>proto-tc</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\Build\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="CommandLine, Version=1.9.71.2, Culture=neutral, PublicKeyToken=de6f01bd326f8c32, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="Options.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Tango.Protobuf\Tango.Protobuf.csproj">
+ <Project>{40073806-914e-4e78-97ab-fa9639308ebe}</Project>
+ <Name>Tango.Protobuf</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/packages.config b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/packages.config
new file mode 100644
index 000000000..0d9f59112
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.CLI/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="CommandLineParser" version="1.9.71" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.config b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.config
new file mode 100644
index 000000000..8e1564635
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+ </startup>
+</configuration> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml
new file mode 100644
index 000000000..d9f8d9bfa
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml
@@ -0,0 +1,20 @@
+<Application x:Class="Tango.Protobuf.UI.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="clr-namespace:Tango.Protobuf.UI"
+ StartupUri="MainWindow.xaml">
+ <Application.Resources>
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
+ <!-- Accent and AppTheme setting -->
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Steel.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
+ <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/FlatButton.xaml" />
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
+ </Application.Resources>
+</Application>
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml.cs
new file mode 100644
index 000000000..d2560005a
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/App.xaml.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using Tango.Logging;
+
+namespace Tango.Protobuf.UI
+{
+ /// <summary>
+ /// Interaction logic for App.xaml
+ /// </summary>
+ public partial class App : Application
+ {
+ private WpfGlobalExceptionTrapper exceptionTrapper;
+
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ base.OnStartup(e);
+
+ //Register Loggers.
+ LogManager.RegisterLogger(new FileLogger());
+ LogManager.RegisterLogger(new VSOutputLogger());
+
+ LogManager.Log("Application Started!");
+
+ exceptionTrapper = new WpfGlobalExceptionTrapper();
+ exceptionTrapper.Initialize(this);
+ exceptionTrapper.ApplicationCrashed += ExceptionTrapper_ApplicationCrashed;
+ }
+
+ #region Global Exception Trapping
+
+ /// <summary>
+ /// Handles the ApplicationCrashed event of the ExceptionTrapper control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="ApplicationCrashedEventArgs"/> instance containing the event data.</param>
+ private void ExceptionTrapper_ApplicationCrashed(object sender, ApplicationCrashedEventArgs e)
+ {
+ if (MessageBox.Show("The system has encountered and unhandled exception and it is recommended that you restart the application. Do you wish to restart the application?", "Twine", MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No, MessageBoxOptions.DefaultDesktopOnly) == MessageBoxResult.Yes)
+ {
+ e.TryRecover = false;
+ LogManager.Log("User selection was to restart the application. Restarting...");
+ Process.Start(Application.ResourceAssembly.Location);
+ Environment.Exit(0);
+ }
+ else
+ {
+ e.TryRecover = true;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/DirectoryItem.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/DirectoryItem.cs
new file mode 100644
index 000000000..3d272ac43
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/DirectoryItem.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.UI
+{
+ public class DirectoryItem : Item
+ {
+ public List<Item> Items { get; set; }
+
+ public DirectoryItem()
+ {
+ Items = new List<Item>();
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml
new file mode 100644
index 000000000..938697ceb
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml
@@ -0,0 +1,40 @@
+<mahapps:MetroWindow x:Class="Tango.Protobuf.UI.ExceptionWindow"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls"
+ xmlns:fa="http://schemas.fontawesome.io/icons/"
+ xmlns:local="clr-namespace:Tango.Protobuf.UI"
+ mc:Ignorable="d"
+ Title="Tango" Height="352" Width="566" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ShowMaxRestoreButton="False" ShowMinButton="False" Background="#202020" Foreground="Gainsboro" DataContext="{Binding RelativeSource={RelativeSource Self}}" >
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="59"/>
+ <RowDefinition Height="210*"/>
+ </Grid.RowDefinitions>
+
+ <TextBlock VerticalAlignment="Center" Margin="10" FontSize="16">Compilation Failed</TextBlock>
+
+ <Grid Grid.Row="1" Margin="10">
+ <DataGrid ItemsSource="{Binding Issues}" AutoGenerateColumns="False">
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header="#">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <fa:ImageAwesome Icon="ExclamationTriangle" Width="16" Height="16" Foreground="Red"></fa:ImageAwesome>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTemplateColumn Header="Description" Width="*">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding}" TextWrapping="Wrap"></TextBlock>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </DataGrid>
+ </Grid>
+ </Grid>
+</mahapps:MetroWindow>
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml.cs
new file mode 100644
index 000000000..566f13bb5
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ExceptionWindow.xaml.cs
@@ -0,0 +1,31 @@
+using MahApps.Metro.Controls;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace Tango.Protobuf.UI
+{
+ /// <summary>
+ /// Interaction logic for ExceptionWindow.xaml
+ /// </summary>
+ public partial class ExceptionWindow : MetroWindow
+ {
+ public List<String> Issues { get; set; }
+
+ public ExceptionWindow(List<String> issues)
+ {
+ Issues = issues;
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/FileItem.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/FileItem.cs
new file mode 100644
index 000000000..c60e3fb0f
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/FileItem.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.UI
+{
+ public class FileItem : Item
+ {
+ public override string ToString()
+ {
+ return File.ReadAllText(Path);
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Item.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Item.cs
new file mode 100644
index 000000000..69523aec5
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Item.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.UI
+{
+ public class Item
+ {
+ public string Name { get; set; }
+ public string Path { get; set; }
+ public Object Object { get; set; }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ItemProvider.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ItemProvider.cs
new file mode 100644
index 000000000..1758a8543
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/ItemProvider.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.Protobuf.UI
+{
+ public static class ItemProvider
+ {
+ public static List<Item> GetItems(string path)
+ {
+ var items = new List<Item>();
+
+ var dirInfo = new DirectoryInfo(path);
+
+ foreach (var directory in dirInfo.GetDirectories())
+ {
+ var item = new DirectoryItem
+ {
+ Name = directory.Name,
+ Path = directory.FullName,
+ Items = GetItems(directory.FullName)
+ };
+
+ items.Add(item);
+ }
+
+ foreach (var file in dirInfo.GetFiles("*.proto"))
+ {
+ var item = new FileItem
+ {
+ Name = file.Name,
+ Path = file.FullName
+ };
+
+ items.Add(item);
+ }
+
+ return items;
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml
new file mode 100644
index 000000000..3c0592736
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml
@@ -0,0 +1,144 @@
+<mahapps:MetroWindow x:Class="Tango.Protobuf.UI.MainWindow"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:local="clr-namespace:Tango.Protobuf.UI"
+ xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls"
+ xmlns:System="clr-namespace:System;assembly=mscorlib"
+ xmlns:proto="clr-namespace:Tango.Protobuf;assembly=Tango.Protobuf"
+ xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI"
+ xmlns:fa="http://schemas.fontawesome.io/icons/"
+ mc:Ignorable="d"
+ Title="Tango Protobuf Compilation Utility" Height="600" Width="1000" TitleCaps="False" BorderBrush="Gray" BorderThickness="1" WindowStartupLocation="CenterScreen" Background="#202020" Foreground="Gainsboro" DataContext="{Binding RelativeSource={RelativeSource Self}}">
+
+ <Window.Resources>
+
+ <converters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter"></converters:EnumToDescriptionConverter>
+
+ <ObjectDataProvider x:Key="languages" MethodName="GetValues"
+ ObjectType="{x:Type System:Enum}">
+ <ObjectDataProvider.MethodParameters>
+ <x:Type TypeName="proto:CompilerLanguage"/>
+ </ObjectDataProvider.MethodParameters>
+ </ObjectDataProvider>
+ </Window.Resources>
+
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="80" />
+ <RowDefinition Height="1*"/>
+ </Grid.RowDefinitions>
+
+ <Grid>
+ <Polygon Fill="#151515" HorizontalAlignment="Right" VerticalAlignment="Top" Points="80,0 400,0 400,80 0,80"></Polygon>
+
+ <Polygon Fill="#151515" HorizontalAlignment="Left" VerticalAlignment="Top" Points="0,0 100,0 200,80 0,80"></Polygon>
+ </Grid>
+
+ <Grid Margin="15 0 15 0" VerticalAlignment="Center">
+ <StackPanel Orientation="Horizontal">
+ <Menu HorizontalAlignment="Left" Width="100" VerticalAlignment="Center" Background="Transparent">
+ <MenuItem Header="File" Background="Transparent">
+ <MenuItem Header="Load File"/>
+ <MenuItem Header="Load Folder" Command="{Binding LoadFolderCommand}" />
+ </MenuItem>
+ </Menu>
+ </StackPanel>
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
+ <Button Margin="5" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding CompileCommand}">
+ <StackPanel Orientation="Horizontal">
+ <fa:ImageAwesome Icon="Code" Width="16"></fa:ImageAwesome>
+ <TextBlock VerticalAlignment="Center" Margin="10 0 10 0">Compile</TextBlock>
+ </StackPanel>
+ </Button>
+ <ComboBox Margin="5" Width="80" BorderThickness="0" ItemsSource="{Binding Source={StaticResource languages}}" SelectedItem="{Binding CompilerLanguage,Mode=TwoWay}">
+ <ComboBox.ItemTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Converter={StaticResource EnumToDescriptionConverter}}"></TextBlock>
+ </DataTemplate>
+ </ComboBox.ItemTemplate>
+ </ComboBox>
+ <Button Margin="30 5 5 5" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding SaveCommand}">
+ <StackPanel Orientation="Horizontal">
+ <fa:ImageAwesome Icon="Save" Width="16"></fa:ImageAwesome>
+ <TextBlock VerticalAlignment="Center" Margin="20 0 20 0">Save</TextBlock>
+ </StackPanel>
+ </Button>
+ </StackPanel>
+ </Grid>
+
+ <Grid Grid.Row="1" Margin="10">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="224*"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="195*"/>
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="100*"/>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="100*"/>
+ </Grid.ColumnDefinitions>
+
+ <Grid>
+ <GroupBox Header="Proto Files">
+ <TreeView Background="Transparent">
+ <TreeView.Resources>
+ <HierarchicalDataTemplate DataType="{x:Type local:DirectoryItem}"
+ ItemsSource="{Binding Items}">
+ <StackPanel Orientation="Horizontal">
+ <fa:ImageAwesome Icon="Folder" Foreground="Orange" Width="16" Height="16"></fa:ImageAwesome>
+ <TextBlock Margin="5 0 0 0" Text="{Binding Path=Name}" ToolTip="{Binding Path=Path}" />
+ </StackPanel>
+ </HierarchicalDataTemplate>
+
+ <DataTemplate DataType="{x:Type local:FileItem}">
+ <StackPanel Orientation="Horizontal">
+ <fa:ImageAwesome Icon="File" Foreground="Gainsboro" Width="16" Height="16"></fa:ImageAwesome>
+ <TextBlock Margin="5 0 0 0" Text="{Binding Path=Name}" ToolTip="{Binding Path=Path}" />
+ </StackPanel>
+ </DataTemplate>
+ </TreeView.Resources>
+
+ <TreeView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Left" ItemsSource="{Binding SourceItems}" SelectedItemChanged="Source_TreeView_SelectedItemChanged" />
+ </TreeView>
+ </GroupBox>
+ </Grid>
+
+ <GridSplitter Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Stretch" Width="5" Background="#151515"></GridSplitter>
+
+ <Grid Grid.Column="2">
+ <GroupBox Header="Compiled Files">
+ <TreeView Background="Transparent">
+ <TreeView.Resources>
+ <HierarchicalDataTemplate DataType="{x:Type proto:CompilerFolderResult}"
+ ItemsSource="{Binding Results}">
+ <StackPanel Orientation="Horizontal">
+ <fa:ImageAwesome Icon="Folder" Foreground="Orange" Width="16" Height="16"></fa:ImageAwesome>
+ <TextBlock Margin="5 0 0 0" Text="{Binding Path=Name}" ToolTip="{Binding Path=RelativePath}" />
+ </StackPanel>
+ </HierarchicalDataTemplate>
+
+ <DataTemplate DataType="{x:Type proto:CompilerFileResult}">
+ <StackPanel Orientation="Horizontal">
+ <fa:ImageAwesome Icon="Code" Foreground="Gainsboro" Width="16" Height="16"></fa:ImageAwesome>
+ <TextBlock Margin="5 0 0 0" Text="{Binding Path=Name}" />
+ </StackPanel>
+ </DataTemplate>
+ </TreeView.Resources>
+
+ <TreeView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Left" ItemsSource="{Binding TargetItems}" SelectedItemChanged="Source_TreeView_SelectedItemChanged" />
+ </TreeView>
+ </GroupBox>
+ </Grid>
+
+ <GridSplitter Grid.Row="1" Grid.ColumnSpan="3" Height="5" Background="#151515" VerticalAlignment="Center" HorizontalAlignment="Stretch"></GridSplitter>
+
+ <Grid Grid.Row="2" Grid.ColumnSpan="3">
+ <GroupBox Header="Preview">
+ <TextBox Text="{Binding CurrentContent}" Background="#101010" FontFamily="Lucida Console" BorderThickness="0" Padding="5" AcceptsReturn="True" TextWrapping="NoWrap" IsReadOnly="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"></TextBox>
+ </GroupBox>
+ </Grid>
+ </Grid>
+ </Grid>
+</mahapps:MetroWindow>
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml.cs
new file mode 100644
index 000000000..d530b439c
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/MainWindow.xaml.cs
@@ -0,0 +1,148 @@
+using MahApps.Metro.Controls;
+using Microsoft.WindowsAPICodePack.Dialogs;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Tango.Core.Commands;
+using Tango.Protobuf.Compilers;
+
+namespace Tango.Protobuf.UI
+{
+ /// <summary>
+ /// Interaction logic for MainWindow.xaml
+ /// </summary>
+ public partial class MainWindow : MetroWindow
+ {
+ private String _sourceFolder;
+ private CompilerFolderResult _lastFolderResult;
+
+ public RelayCommand LoadFileCommand { get; set; }
+ public RelayCommand LoadFolderCommand { get; set; }
+ public RelayCommand CompileCommand { get; set; }
+ public RelayCommand SaveCommand { get; set; }
+
+ public List<Item> SourceItems
+ {
+ get { return (List<Item>)GetValue(SourceItemsProperty); }
+ set { SetValue(SourceItemsProperty, value); }
+ }
+ public static readonly DependencyProperty SourceItemsProperty =
+ DependencyProperty.Register("SourceItems", typeof(List<Item>), typeof(MainWindow), new PropertyMetadata(null));
+
+ public String CurrentContent
+ {
+ get { return (String)GetValue(CurrentContentProperty); }
+ set { SetValue(CurrentContentProperty, value); }
+ }
+ public static readonly DependencyProperty CurrentContentProperty =
+ DependencyProperty.Register("CurrentContent", typeof(String), typeof(MainWindow), new PropertyMetadata(null));
+
+ public List<ICompilerResult> TargetItems
+ {
+ get { return (List<ICompilerResult>)GetValue(TargetItemsProperty); }
+ set { SetValue(TargetItemsProperty, value); }
+ }
+ public static readonly DependencyProperty TargetItemsProperty =
+ DependencyProperty.Register("TargetItems", typeof(List<ICompilerResult>), typeof(MainWindow), new PropertyMetadata(null));
+
+ public CompilerLanguage CompilerLanguage
+ {
+ get { return (CompilerLanguage)GetValue(CompilerLanguageProperty); }
+ set { SetValue(CompilerLanguageProperty, value); }
+ }
+ public static readonly DependencyProperty CompilerLanguageProperty =
+ DependencyProperty.Register("CompilerLanguage", typeof(CompilerLanguage), typeof(MainWindow), new PropertyMetadata(CompilerLanguage.CSharp));
+
+ public MainWindow()
+ {
+ SourceItems = new List<Item>();
+ TargetItems = new List<ICompilerResult>();
+
+ LoadFileCommand = new RelayCommand(LoadFile);
+ LoadFolderCommand = new RelayCommand(LoadFolder);
+ CompileCommand = new RelayCommand(Compile);
+ SaveCommand = new RelayCommand(Save);
+
+ InitializeComponent();
+ }
+
+ private void LoadFolder()
+ {
+ var dialog = new CommonOpenFileDialog();
+ dialog.IsFolderPicker = true;
+ CommonFileDialogResult result = dialog.ShowDialog();
+ if (result == CommonFileDialogResult.Ok)
+ {
+ _sourceFolder = dialog.FileName;
+ SourceItems = ItemProvider.GetItems(_sourceFolder);
+ }
+ }
+
+ private void LoadFile()
+ {
+ throw new NotImplementedException();
+ }
+
+ private void Source_TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
+ {
+ if (e.NewValue is FileItem)
+ {
+ CurrentContent = File.ReadAllText((e.NewValue as FileItem).Path);
+ }
+ else if (e.NewValue is CompilerFileResult)
+ {
+ CurrentContent = (e.NewValue as CompilerFileResult).Content;
+ }
+ else
+ {
+ CurrentContent = String.Empty;
+ }
+ }
+
+ private void Compile()
+ {
+ IProtoCompiler compiler = CompilerFactory.CreateCompiler(CompilerLanguage);
+
+
+ try
+ {
+ _lastFolderResult = compiler.CompileFolder(_sourceFolder);
+ TargetItems = _lastFolderResult.Results.ToList();
+ }
+ catch (CompilerException ex)
+ {
+ ExceptionWindow exWin = new ExceptionWindow(ex.Issues);
+ exWin.Owner = this;
+ exWin.ShowDialog();
+ }
+ }
+
+ private void Save()
+ {
+ if (_lastFolderResult != null)
+ {
+ var dialog = new CommonOpenFileDialog();
+ dialog.IsFolderPicker = true;
+ CommonFileDialogResult result = dialog.ShowDialog();
+ if (result == CommonFileDialogResult.Ok)
+ {
+ _lastFolderResult.Save(dialog.FileName);
+ }
+ }
+ }
+
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/AssemblyInfo.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..002635e32
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Twine - Protobuf Compilation Utility")]
+[assembly: ComVisible(false)] \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.Designer.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.Designer.cs
new file mode 100644
index 000000000..452dd71b0
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.Protobuf.UI.Properties
+{
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.Protobuf.UI.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.resx b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.resx
new file mode 100644
index 000000000..af7dbebba
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.Designer.cs b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.Designer.cs
new file mode 100644
index 000000000..281a586b2
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.Protobuf.UI.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.settings b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.settings
new file mode 100644
index 000000000..033d7a5e9
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Tango.Protobuf.UI.csproj b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Tango.Protobuf.UI.csproj
new file mode 100644
index 000000000..f85fe33ae
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/Tango.Protobuf.UI.csproj
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{37E45CE1-A0F6-4ED7-9791-A1BED947602F}</ProjectGuid>
+ <OutputType>WinExe</OutputType>
+ <RootNamespace>Tango.Protobuf.UI</RootNamespace>
+ <AssemblyName>TangoProtoGUI</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\Build\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <ApplicationIcon>proto.ico</ApplicationIcon>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath>
+ </Reference>
+ <Reference Include="MahApps.Metro, Version=1.5.0.23, Culture=neutral, PublicKeyToken=f4fb5a3c4d1e5b4f, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\MahApps.Metro.1.5.0\lib\net45\MahApps.Metro.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\WindowsAPICodePack-Core.1.1.1\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\MahApps.Metro.1.5.0\lib\net45\System.Windows.Interactivity.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Xml" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xaml">
+ <RequiredTargetFramework>4.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </ApplicationDefinition>
+ <Page Include="ExceptionWindow.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="MainWindow.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Compile Include="..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="DirectoryItem.cs" />
+ <Compile Include="ExceptionWindow.xaml.cs">
+ <DependentUpon>ExceptionWindow.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="FileItem.cs" />
+ <Compile Include="Item.cs" />
+ <Compile Include="ItemProvider.cs" />
+ <Compile Include="MainWindow.xaml.cs">
+ <DependentUpon>MainWindow.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>
+ </SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Protobuf\Tango.Protobuf.csproj">
+ <Project>{40073806-914e-4e78-97ab-fa9639308ebe}</Project>
+ <Name>Tango.Protobuf</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.SharedUI\Tango.SharedUI.csproj">
+ <Project>{ac489889-6e50-4f16-9dba-ff4c6f9ec72b}</Project>
+ <Name>Tango.SharedUI</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="proto.ico" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/packages.config b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/packages.config
new file mode 100644
index 000000000..e7f9bf0ff
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/packages.config
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net45" />
+ <package id="MahApps.Metro" version="1.5.0" targetFramework="net45" />
+ <package id="WindowsAPICodePack-Core" version="1.1.1" targetFramework="net45" />
+ <package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/Software/Visual Studio/Utilities/Tango.Protobuf.UI/proto.ico b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/proto.ico
new file mode 100644
index 000000000..08c24170e
--- /dev/null
+++ b/Software/Visual Studio/Utilities/Tango.Protobuf.UI/proto.ico
Binary files differ