aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2017-11-26 17:23:38 +0200
committerRoy Ben-Shabat <Roy@Twine-s.com>2017-11-26 17:23:38 +0200
commit262c1efc9d53b8b70fe677dc7d2d173896ffcee8 (patch)
treee404dc914bee89101f50963ff018225c897244fd
parent0a8af16821cfbb52fe02881921695d378f6578d7 (diff)
downloadTango-262c1efc9d53b8b70fe677dc7d2d173896ffcee8.tar.gz
Tango-262c1efc9d53b8b70fe677dc7d2d173896ffcee8.zip
Implemented Tango SQLite DB Synchronizer.
-rw-r--r--Software/Visual_Studio/Tango.Core/ExtensionMethods/DateTimeExtensions.cs19
-rw-r--r--Software/Visual_Studio/Tango.Core/Tango.Core.csproj1
-rw-r--r--Software/Visual_Studio/Tango.Logging/ExceptionLogItem.cs9
-rw-r--r--Software/Visual_Studio/Tango.Logging/LogItemBase.cs6
-rw-r--r--Software/Visual_Studio/Tango.Logging/MessageLogItem.cs9
-rw-r--r--Software/Visual_Studio/Tango.SharedUI/ExtendedObject.cs18
-rw-r--r--Software/Visual_Studio/Tango.Synchronization/ISqlDataBase.cs5
-rw-r--r--Software/Visual_Studio/Tango.Synchronization/SqlDataBaseComparer.cs55
-rw-r--r--Software/Visual_Studio/Tango.Synchronization/SqliteDataBase.cs6
-rw-r--r--Software/Visual_Studio/Tango.Synchronization/Tango.Synchronization.csproj6
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/App.xaml19
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Images/server.pngbin0 -> 2176 bytes
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml13
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml.cs5
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Tango.Synchronization.UI.csproj39
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/ViewModels/MainViewVM.cs331
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml251
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml.cs28
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Synchronization.UI/packages.config5
-rw-r--r--Software/Visual_Studio/Web/Tango.MachineService/packages.config2
20 files changed, 814 insertions, 13 deletions
diff --git a/Software/Visual_Studio/Tango.Core/ExtensionMethods/DateTimeExtensions.cs b/Software/Visual_Studio/Tango.Core/ExtensionMethods/DateTimeExtensions.cs
new file mode 100644
index 000000000..2c413b787
--- /dev/null
+++ b/Software/Visual_Studio/Tango.Core/ExtensionMethods/DateTimeExtensions.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+
+public static class DateTimeExtensions
+{
+ /// <summary>
+ /// Converts the DateTime instance to an accurate time string.
+ /// </summary>
+ /// <param name="date">The date.</param>
+ /// <returns></returns>
+ public static String ToTimeString(this DateTime date)
+ {
+ return date.ToString("HH:mm:ss.ff");
+ }
+}
diff --git a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj
index 7b1074a3d..5963a7cc6 100644
--- a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj
+++ b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj
@@ -52,6 +52,7 @@
<Link>GlobalVersionInfo.cs</Link>
</Compile>
<Compile Include="ConcurrentList.cs" />
+ <Compile Include="ExtensionMethods\DateTimeExtensions.cs" />
<Compile Include="ExtensionMethods\DependencyObjectExtensions.cs" />
<Compile Include="ExtensionMethods\EnumExtensions.cs" />
<Compile Include="ExtensionMethods\IMessageExtensions.cs" />
diff --git a/Software/Visual_Studio/Tango.Logging/ExceptionLogItem.cs b/Software/Visual_Studio/Tango.Logging/ExceptionLogItem.cs
index de526f954..acebc2856 100644
--- a/Software/Visual_Studio/Tango.Logging/ExceptionLogItem.cs
+++ b/Software/Visual_Studio/Tango.Logging/ExceptionLogItem.cs
@@ -23,6 +23,15 @@ namespace Tango.Logging
public String Description { get; set; }
/// <summary>
+ /// Gets the log message.
+ /// </summary>
+ /// <returns></returns>
+ public override string GetMessage()
+ {
+ return InnerException.Message;
+ }
+
+ /// <summary>
/// Returns a formatted string of the log item.
/// </summary>
public override string ToString()
diff --git a/Software/Visual_Studio/Tango.Logging/LogItemBase.cs b/Software/Visual_Studio/Tango.Logging/LogItemBase.cs
index 38e78d3ac..aab78c63d 100644
--- a/Software/Visual_Studio/Tango.Logging/LogItemBase.cs
+++ b/Software/Visual_Studio/Tango.Logging/LogItemBase.cs
@@ -32,6 +32,12 @@ namespace Tango.Logging
public DateTime TimeStamp { get; set; }
/// <summary>
+ /// Gets the log message.
+ /// </summary>
+ /// <returns></returns>
+ public abstract String GetMessage();
+
+ /// <summary>
/// Returns a formatted string of the log item.
/// </summary>
public abstract override String ToString();
diff --git a/Software/Visual_Studio/Tango.Logging/MessageLogItem.cs b/Software/Visual_Studio/Tango.Logging/MessageLogItem.cs
index 44cb2c575..445706779 100644
--- a/Software/Visual_Studio/Tango.Logging/MessageLogItem.cs
+++ b/Software/Visual_Studio/Tango.Logging/MessageLogItem.cs
@@ -18,6 +18,15 @@ namespace Tango.Logging
public String Message { get; set; }
/// <summary>
+ /// Gets the log message.
+ /// </summary>
+ /// <returns></returns>
+ public override string GetMessage()
+ {
+ return Message;
+ }
+
+ /// <summary>
/// Returns a formatted string of the log item.
/// </summary>
public override string ToString()
diff --git a/Software/Visual_Studio/Tango.SharedUI/ExtendedObject.cs b/Software/Visual_Studio/Tango.SharedUI/ExtendedObject.cs
index 8e00f2e61..9068fc883 100644
--- a/Software/Visual_Studio/Tango.SharedUI/ExtendedObject.cs
+++ b/Software/Visual_Studio/Tango.SharedUI/ExtendedObject.cs
@@ -49,5 +49,23 @@ namespace Tango.SharedUI
}
}));
}
+
+ /// <summary>
+ /// Invokes the specified action on the UI Thread.
+ /// </summary>
+ /// <param name="action">The action.</param>
+ protected virtual void InvokeUI(Action action)
+ {
+ Application.Current.Dispatcher.BeginInvoke(action);
+ }
+
+ /// <summary>
+ /// Invokes the specified action on the UI Thread.
+ /// </summary>
+ /// <param name="action">The action.</param>
+ protected virtual void InvokeUINow(Action action)
+ {
+ Application.Current.Dispatcher.Invoke(action);
+ }
}
}
diff --git a/Software/Visual_Studio/Tango.Synchronization/ISqlDataBase.cs b/Software/Visual_Studio/Tango.Synchronization/ISqlDataBase.cs
index f087dfd15..fa4e018be 100644
--- a/Software/Visual_Studio/Tango.Synchronization/ISqlDataBase.cs
+++ b/Software/Visual_Studio/Tango.Synchronization/ISqlDataBase.cs
@@ -24,6 +24,11 @@ namespace Tango.Synchronization
List<DataTable> Tables { get; }
/// <summary>
+ /// Loads the tables (Must be done before any synchronization).
+ /// </summary>
+ void LoadTables();
+
+ /// <summary>
/// Clones a table from another database into this database.
/// </summary>
/// <param name="otherDB">The other database.</param>
diff --git a/Software/Visual_Studio/Tango.Synchronization/SqlDataBaseComparer.cs b/Software/Visual_Studio/Tango.Synchronization/SqlDataBaseComparer.cs
index 07c94045b..980a23f1e 100644
--- a/Software/Visual_Studio/Tango.Synchronization/SqlDataBaseComparer.cs
+++ b/Software/Visual_Studio/Tango.Synchronization/SqlDataBaseComparer.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Data;
+using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Tango.Logging;
namespace Tango.Synchronization
{
@@ -40,28 +42,47 @@ namespace Tango.Synchronization
/// <returns></returns>
public List<SqlDiff> Compare()
{
+ LogManager.Log("Comparing databases " + Path.GetFileName(MasterSQL.Source) + " <=> " + Path.GetFileName(SlaveSQL.Source));
+
+ LogManager.Log("Loading master tables...");
+ MasterSQL.LoadTables();
+
+ LogManager.Log("Loading slave tables...");
+ SlaveSQL.LoadTables();
+
List<SqlDiff> diffs = new List<SqlDiff>();
foreach (var masterTable in MasterSQL.Tables)
{
+ LogManager.Log("Comparing table " + masterTable.TableName);
+ LogManager.Log("Searching table " + masterTable.TableName + " on slave...");
+
var slaveTable = SlaveSQL.Tables.SingleOrDefault(x => x.TableName == masterTable.TableName); //Get matching slave table on slave db.
if (slaveTable == null) //Table not found on slave.
{
+ LogManager.Log("Table not found on slave, adding difference.");
//Clone table from slave db to master db including records!
diffs.Add(new SqlDiff(SqlDiffAction.AddTableToSlave, String.Format("Add table {0} to slave", masterTable.TableName), () => SlaveSQL.CloneTableFrom(MasterSQL, masterTable), SlaveSQL.GetCloneTableFromCommand(MasterSQL, masterTable)));
continue;
}
+ LogManager.Log("Table found, comparing columns...");
+
foreach (DataColumn masterColumn in masterTable.Columns)
{
+ LogManager.Log("Searching for column " + masterColumn.ColumnName + " on slave...");
+
var slaveColumn = slaveTable.Columns[masterColumn.ColumnName]; //Get matching slave column on slave table.
if (slaveColumn == null) //Slave column not found.
{
+ LogManager.Log("Column not found on slave, adding difference.");
//Add column to slave table.
diffs.Add(new SqlDiff(SqlDiffAction.AddColumnToSlave, String.Format("Add column {0} to slave table", masterColumn.ColumnName), () => SlaveSQL.AddColumn(masterTable, masterColumn), SlaveSQL.GetAddColumnCommand(masterTable, masterColumn)));
}
+
+ LogManager.Log("Column found.");
}
List<DataRow> addToSlave = new List<DataRow>();
@@ -69,46 +90,76 @@ namespace Tango.Synchronization
List<DataRow> addToMaster = new List<DataRow>();
List<DataRow> updateMaster = new List<DataRow>();
+ LogManager.Log("Comparing rows...");
+
+ int count = 0;
+
foreach (DataRow masterRow in masterTable.Rows)
{
+ LogManager.Log("Comparing row " + count++);
+
String guid = masterRow.Field<String>(Constants.GUID);
+ LogManager.Log("Searching for row with GUID " + guid + " on slave table...");
+
//Get Matching slave row.
DataRow slaveRow = slaveTable.AsEnumerable().SingleOrDefault(x => x.Field<String>(Constants.GUID) == guid);
if (slaveRow != null)
{
+ LogManager.Log("Slave row found, comparing dates...");
+
DateTime masterDate = masterRow.Field<DateTime>(Constants.LAST_UPDATED);
DateTime slaveDate = slaveRow.Field<DateTime>(Constants.LAST_UPDATED);
if (masterDate > slaveDate)
{
+ LogManager.Log("Master => Slave Update " + masterDate.ToSQLiteDateString() + ", adding difference.");
updateSlave.Add(masterRow);
}
else if (slaveDate > masterDate)
{
+ LogManager.Log("Master <= Slave Update " + masterDate.ToSQLiteDateString() + ", adding difference.");
updateMaster.Add(slaveRow);
}
+ else
+ {
+ LogManager.Log("Master <=> Slave No Update.");
+ }
}
else
{
+ LogManager.Log("Slave row not found, adding difference.");
addToSlave.Add(masterRow);
}
}
+ LogManager.Log("Done comparing rows...");
+
+ LogManager.Log("Searching for missing rows on master...");
+
foreach (DataRow slaveRow in slaveTable.Rows)
{
String guid = slaveRow.Field<String>(Constants.GUID);
+ LogManager.Log("Searching for row with GUID " + guid + " on master table...");
+
//Get Matching slave row.
DataRow masterRow = masterTable.AsEnumerable().SingleOrDefault(x => x.Field<String>(Constants.GUID) == guid);
if (masterRow == null)
{
+ LogManager.Log("Master row not found, adding difference.");
addToMaster.Add(slaveRow);
}
+ else
+ {
+ LogManager.Log("Master row found.");
+ }
}
+ LogManager.Log("Done searching for missing rows on master...");
+
foreach (var row in addToSlave)
{
diffs.Add(new SqlDiff(SqlDiffAction.AddRowToSlave, String.Format("Add row to slave table {0}", slaveTable.TableName), () => SlaveSQL.AddRow(slaveTable, row), SlaveSQL.GetAddRowCommand(slaveTable, row)));
@@ -128,8 +179,12 @@ namespace Tango.Synchronization
{
diffs.Add(new SqlDiff(SqlDiffAction.UpdateRowInMaster, String.Format("Update row in master table {0}", masterTable.TableName), () => MasterSQL.UpdateRow(masterTable, row), MasterSQL.GetUpdateRowCommand(masterTable, row)));
}
+
+ LogManager.Log("Done comparing table " + masterTable.TableName);
}
+ LogManager.Log("Databases comparison completed.");
+
return diffs;
}
diff --git a/Software/Visual_Studio/Tango.Synchronization/SqliteDataBase.cs b/Software/Visual_Studio/Tango.Synchronization/SqliteDataBase.cs
index 3802232e0..75259fc28 100644
--- a/Software/Visual_Studio/Tango.Synchronization/SqliteDataBase.cs
+++ b/Software/Visual_Studio/Tango.Synchronization/SqliteDataBase.cs
@@ -43,14 +43,12 @@ namespace Tango.Synchronization
));
_connection.Open();
-
- InitializeTables();
}
/// <summary>
- /// Initializes the tables.
+ /// Loads the tables (Must be done before any synchronization).
/// </summary>
- private void InitializeTables()
+ public void LoadTables()
{
Tables = new List<DataTable>();
diff --git a/Software/Visual_Studio/Tango.Synchronization/Tango.Synchronization.csproj b/Software/Visual_Studio/Tango.Synchronization/Tango.Synchronization.csproj
index b702c5335..6b19b8521 100644
--- a/Software/Visual_Studio/Tango.Synchronization/Tango.Synchronization.csproj
+++ b/Software/Visual_Studio/Tango.Synchronization/Tango.Synchronization.csproj
@@ -74,6 +74,12 @@
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\System.Data.SQLite.Core.1.0.106.0\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.106.0\build\net45\System.Data.SQLite.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/App.xaml b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/App.xaml
index 19bd64b04..c4d813ee4 100644
--- a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/App.xaml
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/App.xaml
@@ -1,9 +1,26 @@
<Application x:Class="Tango.Synchronization.UI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:vm="clr-namespace:Tango.Synchronization.UI.ViewModels"
xmlns:local="clr-namespace:Tango.Synchronization.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" />
+
+ <!--View Models-->
+ <ResourceDictionary>
+ <vm:MainViewVM x:Key="MainViewVM" />
+ </ResourceDictionary>
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
</Application.Resources>
</Application>
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Images/server.png b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Images/server.png
new file mode 100644
index 000000000..3f856bfb8
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Images/server.png
Binary files differ
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml
index c52dbc88b..41dd9d9e3 100644
--- a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml
@@ -1,12 +1,17 @@
-<Window x:Class="Tango.Synchronization.UI.MainWindow"
+<mahapps:MetroWindow x:Class="Tango.Synchronization.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:mahapps="http://metro.mahapps.com/winfx/xaml/controls"
+ xmlns:System="clr-namespace:System;assembly=mscorlib"
+ xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI"
+ xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:local="clr-namespace:Tango.Synchronization.UI"
+ xmlns:views="clr-namespace:Tango.Synchronization.UI.Views"
mc:Ignorable="d"
- Title="MainWindow" Height="350" Width="525">
+ Title="Tango DataBase Synchronization Utility" Height="600" Width="1000" TitleCaps="False" BorderBrush="Gray" BorderThickness="1" WindowStartupLocation="CenterScreen" Background="#202020" Foreground="Gainsboro" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
-
+ <views:MainView DataContext="{StaticResource MainViewVM}"></views:MainView>
</Grid>
-</Window>
+</mahapps:MetroWindow>
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml.cs b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml.cs
index cf4ebe4fa..6544b1f28 100644
--- a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml.cs
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/MainWindow.xaml.cs
@@ -1,4 +1,5 @@
-using System;
+using MahApps.Metro.Controls;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -18,7 +19,7 @@ namespace Tango.Synchronization.UI
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
- public partial class MainWindow : Window
+ public partial class MainWindow : MetroWindow
{
public MainWindow()
{
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Tango.Synchronization.UI.csproj b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Tango.Synchronization.UI.csproj
index fa9da15f8..9cd8db74a 100644
--- a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Tango.Synchronization.UI.csproj
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Tango.Synchronization.UI.csproj
@@ -36,8 +36,17 @@
<ApplicationIcon>server.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="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" />
@@ -56,6 +65,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
+ <Compile Include="ViewModels\MainViewVM.cs" />
+ <Compile Include="Views\MainView.xaml.cs">
+ <DependentUpon>MainView.xaml</DependentUpon>
+ </Compile>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -71,6 +84,10 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
+ <Page Include="Views\MainView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
@@ -91,6 +108,7 @@
<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>
@@ -102,6 +120,27 @@
<ItemGroup>
<Resource Include="server.ico" />
</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.SharedUI\Tango.SharedUI.csproj">
+ <Project>{ac489889-6e50-4f16-9dba-ff4c6f9ec72b}</Project>
+ <Name>Tango.SharedUI</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Synchronization\Tango.Synchronization.csproj">
+ <Project>{7ada4e86-cad7-4968-a210-3a8a9e5153ab}</Project>
+ <Name>Tango.Synchronization</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\server.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>$(TargetDir)linkgen.exe -s "$(TargetPath)" -d "$(TargetDir)Utilities\DB Sync.lnk"</PostBuildEvent>
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/ViewModels/MainViewVM.cs b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/ViewModels/MainViewVM.cs
new file mode 100644
index 000000000..d388d761f
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/ViewModels/MainViewVM.cs
@@ -0,0 +1,331 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using Tango.Logging;
+using Tango.SharedUI;
+using Tango.SharedUI.Commands;
+
+namespace Tango.Synchronization.UI.ViewModels
+{
+ public class MainViewVM : ExtendedObject
+ {
+ private String _masterDBFile;
+ private String _slaveDBFile;
+ private SqlDataBaseComparer _comparer;
+
+ #region Properties
+
+ private bool _isBusy;
+ /// <summary>
+ /// Gets or sets a value indicating whether an operation is in progress.
+ /// </summary>
+ public bool IsBusy
+ {
+ get { return _isBusy; }
+ set { _isBusy = value; RaisePropertyChanged(nameof(IsBusy)); }
+ }
+
+ private String _status;
+ /// <summary>
+ /// Gets or sets the current operation status.
+ /// </summary>
+ public String Status
+ {
+ get { return _status; }
+ set { _status = value; RaisePropertyChanged(nameof(Status)); }
+ }
+
+ private String _log;
+ /// <summary>
+ /// Gets or sets the current application log text.
+ /// </summary>
+ public String Log
+ {
+ get { return _log; }
+ set { _log = value; RaisePropertyChanged(nameof(Log)); }
+ }
+
+ private ObservableCollection<SqlDiff> _differences;
+ /// <summary>
+ /// Gets or sets the differences.
+ /// </summary>
+ public ObservableCollection<SqlDiff> Differences
+ {
+ get { return _differences; }
+ set { _differences = value; RaisePropertyChanged(nameof(Differences)); }
+ }
+
+ private SqlDiff _selectedDifference;
+ /// <summary>
+ /// Gets or sets the selected difference.
+ /// </summary>
+ public SqlDiff SelectedDifference
+ {
+ get { return _selectedDifference; }
+ set { _selectedDifference = value; RaisePropertyChanged(nameof(SelectedDifference)); InvalidateRelayCommands(); }
+ }
+
+ private String _masterDBName;
+ /// <summary>
+ /// Gets or sets the name of the master database.
+ /// </summary>
+ public String MasterDBName
+ {
+ get { return _masterDBName; }
+ set { _masterDBName = value; RaisePropertyChanged(nameof(MasterDBName)); }
+ }
+
+ private String _slaveDBName;
+ /// <summary>
+ /// Gets or sets the name of the slave database.
+ /// </summary>
+ public String SlaveDBName
+ {
+ get { return _slaveDBName; }
+ set { _slaveDBName = value; RaisePropertyChanged(nameof(SlaveDBName)); }
+ }
+
+ #endregion
+
+ #region Commands
+
+ /// <summary>
+ /// Gets or sets the browse master database command.
+ /// </summary>
+ public RelayCommand BrowseMasterDBCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the browse slave database command.
+ /// </summary>
+ public RelayCommand BrowseSlaveDBCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the compare command.
+ /// </summary>
+ public RelayCommand CompareCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the commit command.
+ /// </summary>
+ public RelayCommand CommitCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the commit all command.
+ /// </summary>
+ public RelayCommand CommitAllCommand { get; set; }
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MainViewVM"/> class.
+ /// </summary>
+ public MainViewVM()
+ {
+ MainViewLogger logger = new MainViewLogger();
+ logger.NewLog += (output) =>
+ {
+ Log += output + Environment.NewLine;
+ };
+
+ LogManager.RegisterLogger(logger);
+
+ LogManager.Log("DB Synchronizer Started!");
+
+ Differences = new ObservableCollection<SqlDiff>();
+
+ BrowseMasterDBCommand = new RelayCommand(BrowseMasterDB);
+ BrowseSlaveDBCommand = new RelayCommand(BrowseSlaveDB);
+ CompareCommand = new RelayCommand(Compare, (x) => _masterDBFile != null && _slaveDBFile != null);
+ CommitCommand = new RelayCommand(Commit, (x) => SelectedDifference != null);
+ CommitAllCommand = new RelayCommand(CommitAll, (x) => Differences.Count > 0);
+
+ Task.Factory.StartNew(() =>
+ {
+ OpenStatus("Loading components, please wait...");
+ Thread.Sleep(1000);
+ CloseStatus();
+ });
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private void Compare()
+ {
+ _comparer = new SqlDataBaseComparer(new SqliteDataBase(_masterDBFile), new SqliteDataBase(_slaveDBFile));
+
+ OpenStatus("Comparing DataBase...");
+
+ Task.Factory.StartNew(() =>
+ {
+ try
+ {
+ Thread.Sleep(1500);
+ var diffs = _comparer.Compare();
+ Differences = new ObservableCollection<SqlDiff>(diffs);
+ }
+ catch (Exception ex)
+ {
+ ShowError(ex.Message);
+ }
+ finally
+ {
+ SelectedDifference = null;
+ InvalidateRelayCommands();
+ CloseStatus();
+ }
+ });
+ }
+
+ private void Commit()
+ {
+ OpenStatus("Committing difference...");
+
+ Task.Factory.StartNew(() =>
+ {
+ try
+ {
+ Thread.Sleep(1500);
+ SelectedDifference.Commit();
+
+ InvokeUINow(() => Differences.Remove(SelectedDifference));
+ }
+ catch (Exception ex)
+ {
+ ShowError(ex.Message);
+ }
+ finally
+ {
+ SelectedDifference = null;
+ InvalidateRelayCommands();
+ CloseStatus();
+ }
+ });
+ }
+
+ private void CommitAll()
+ {
+ OpenStatus("Committing all differences...");
+
+ Task.Factory.StartNew(() =>
+ {
+ try
+ {
+ Thread.Sleep(1500);
+
+ for (int i = 0; i < Differences.Count; i++)
+ {
+ var diff = Differences[i];
+ OpenStatus("Committing difference " + (Differences.IndexOf(diff) + 1) + "...");
+ diff.Commit();
+ InvokeUINow(() => Differences.Remove(diff));
+ i--;
+ }
+ }
+ catch (Exception ex)
+ {
+ ShowError(ex.Message);
+ }
+ finally
+ {
+ SelectedDifference = null;
+ InvalidateRelayCommands();
+ CloseStatus();
+ }
+ });
+ }
+
+ private void BrowseSlaveDB()
+ {
+ String file = BrowseForFilePath();
+ if (file != null)
+ {
+ _slaveDBFile = file;
+ SlaveDBName = Path.GetFileName(file);
+ InvalidateRelayCommands();
+ }
+ }
+
+ private void BrowseMasterDB()
+ {
+ String file = BrowseForFilePath();
+ if (file != null)
+ {
+ _masterDBFile = file;
+ MasterDBName = Path.GetFileName(file);
+ InvalidateRelayCommands();
+ }
+ }
+
+ private String BrowseForFilePath()
+ {
+ OpenFileDialog dlg = new OpenFileDialog();
+ dlg.Title = "Select SQLite DataBase File";
+ dlg.Filter = "SQLite DataBase|*.db";
+ if (dlg.ShowDialog().Value)
+ {
+ return dlg.FileName;
+ }
+ return null;
+ }
+
+ private void OpenStatus(String status)
+ {
+ IsBusy = true;
+ Status = status;
+ }
+
+ private void CloseStatus()
+ {
+ IsBusy = false;
+ }
+
+ private void ShowError(String message)
+ {
+ MessageBox.Show(message, "Tango", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.No, MessageBoxOptions.DefaultDesktopOnly);
+ }
+
+ private void ShowInfo(String message)
+ {
+ MessageBox.Show(message, "Tango", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.No, MessageBoxOptions.DefaultDesktopOnly);
+ }
+ #endregion
+
+ #region Custom Logger
+
+ public class MainViewLogger : ILogger
+ {
+ public bool Enabled { get; set; }
+ public bool Immediate { get; set; }
+ public event Action<String> NewLog;
+
+ public MainViewLogger()
+ {
+ Enabled = true;
+ Immediate = true;
+ }
+
+ public void OnError(LogItemBase output)
+ {
+ NewLog?.Invoke(output.TimeStamp.ToTimeString() + ": " + output.GetMessage());
+ }
+
+ public void OnTrace(LogItemBase output)
+ {
+ NewLog?.Invoke(output.TimeStamp.ToTimeString() + ": " + output.GetMessage());
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml
new file mode 100644
index 000000000..bc927399b
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml
@@ -0,0 +1,251 @@
+<UserControl x:Class="Tango.Synchronization.UI.Views.MainView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls"
+ xmlns:System="clr-namespace:System;assembly=mscorlib"
+ xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI"
+ xmlns:fa="http://schemas.fontawesome.io/icons/"
+ xmlns:local="clr-namespace:Tango.Synchronization.UI.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="600" d:DesignWidth="1000" Background="#202020">
+
+ <UserControl.Resources>
+ <VisualBrush x:Key="badgeBackground">
+ <VisualBrush.Visual>
+ <Border>
+ <Path Stretch="Fill" RenderTransformOrigin="0.5,0.5">
+ <Path.RenderTransform>
+ <ScaleTransform ScaleX="-1"></ScaleTransform>
+ </Path.RenderTransform>
+ <Path.Fill>
+ <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
+ <GradientStop Color="#202020" Offset="0.4" />
+ <GradientStop Color="#FF4E4E4E" Offset="1"/>
+ </LinearGradientBrush>
+ </Path.Fill>
+ <Path.Data>
+ <PathGeometry Figures="M 53.868 43.913 H 19.511 c -0.444 0 -0.875 -0.151 -1.221 -0.428 L 0.734 29.439 c -0.978 -0.783 -0.978 -2.271 0 -3.053 L 18.29 12.341 c 0.347 -0.277 0.777 -0.428 1.221 -0.428 h 34.356 c 1.081 0 1.958 0.877 1.958 1.958 v 28.084 c 0 1.081 -0.876 1.958 -1.957 1.958 z" FillRule="NonZero"/>
+ </Path.Data>
+ </Path>
+ </Border>
+ </VisualBrush.Visual>
+ </VisualBrush>
+
+ <converters:BooleanInverseConverter x:Key="BooleanInverseConverter"></converters:BooleanInverseConverter>
+ </UserControl.Resources>
+
+ <Grid>
+ <Grid.Style>
+ <Style TargetType="Grid">
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsBusy}" Value="True">
+ <Setter Property="Cursor" Value="AppStarting"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsBusy}" Value="False">
+ <Setter Property="Cursor" Value="Arrow"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Grid.Style>
+
+ <Grid.RowDefinitions>
+ <RowDefinition Height="100"/>
+ <RowDefinition Height="1*"/>
+ </Grid.RowDefinitions>
+
+ <Grid>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="20 15">
+ <Image Source="/Images/server.png" RenderOptions.BitmapScalingMode="Fant"></Image>
+ <TextBlock Text="Tango DB Synchronizer" VerticalAlignment="Center" Margin="20 0 0 0" FontSize="36" Foreground="Silver">
+ <TextBlock.Effect>
+ <DropShadowEffect/>
+ </TextBlock.Effect>
+ </TextBlock>
+ </StackPanel>
+
+ <Rectangle VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Margin="20 0 50 0" Stroke="DimGray" StrokeThickness="1" StrokeDashArray="5"></Rectangle>
+ </Grid>
+
+ <Grid Grid.Row="1" Margin="10">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="218*"/>
+ <RowDefinition Height="5"/>
+ <RowDefinition Height="151*"/>
+ </Grid.RowDefinitions>
+
+ <Grid IsEnabled="{Binding IsBusy,Converter={StaticResource BooleanInverseConverter}}">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="600"/>
+ <ColumnDefinition Width="1*"/>
+ </Grid.ColumnDefinitions>
+
+ <Grid Margin="5">
+ <GroupBox Header="Compare">
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="57*"/>
+ <RowDefinition Height="50"/>
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition MaxWidth="250" />
+ <ColumnDefinition/>
+ </Grid.ColumnDefinitions>
+
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition/>
+ <RowDefinition/>
+ </Grid.RowDefinitions>
+
+ <StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Margin="20 0 0 0">
+ <TextBlock Background="{StaticResource badgeBackground}" Padding="5" Width="200" FontSize="11" HorizontalAlignment="Left">Master DataBase</TextBlock>
+ <StackPanel Orientation="Horizontal" Margin="0 5 0 0">
+ <TextBox IsReadOnly="True" Width="130" BorderBrush="#4E4E4E" Text="{Binding MasterDBName}"></TextBox>
+ <Button Margin="5 0 0 0" Cursor="Hand" VerticalAlignment="Center" Style="{DynamicResource MetroCircleButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding BrowseMasterDBCommand}">
+ <fa:ImageAwesome Icon="FolderOpen" Width="24" Foreground="Gray"></fa:ImageAwesome>
+ </Button>
+ </StackPanel>
+ </StackPanel>
+
+ <StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Row="1" Margin="20 0 0 0">
+ <TextBlock Background="{StaticResource badgeBackground}" Padding="5" Width="200" FontSize="11" HorizontalAlignment="Left">Slave DataBase</TextBlock>
+ <StackPanel Orientation="Horizontal" Margin="0 5 0 0">
+ <TextBox IsReadOnly="True" Width="130" BorderBrush="#4E4E4E" Text="{Binding SlaveDBName}"></TextBox>
+ <Button Margin="5 0 0 0" Cursor="Hand" VerticalAlignment="Center" Style="{DynamicResource MetroCircleButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding BrowseSlaveDBCommand}">
+ <fa:ImageAwesome Icon="FolderOpen" Width="24" Foreground="Gray"></fa:ImageAwesome>
+ </Button>
+ </StackPanel>
+ </StackPanel>
+ </Grid>
+
+ <Button Margin="20 10" Grid.Row="1" Width="130" HorizontalAlignment="Left" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding CompareCommand}">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock VerticalAlignment="Center" Margin="10 0 10 0">COMPARE</TextBlock>
+ <fa:ImageAwesome Icon="LongArrowRight" VerticalAlignment="Center" Foreground="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=Foreground}" Width="16"></fa:ImageAwesome>
+ </StackPanel>
+ </Button>
+
+ <Grid Grid.Column="1" Grid.RowSpan="2">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="20"/>
+ <RowDefinition Height="205*"/>
+ </Grid.RowDefinitions>
+ <TextBlock Margin="10 5 0 0">Differences</TextBlock>
+ <ListBox Margin="10" Background="#151515" Grid.Row="1" ItemsSource="{Binding Differences}" SelectedItem="{Binding SelectedDifference,Mode=TwoWay}">
+ <ListBox.ItemTemplate>
+ <DataTemplate>
+ <Border Padding="10">
+ <StackPanel Orientation="Horizontal">
+ <fa:ImageAwesome Icon="Cog" Width="20" Height="20" Foreground="Gray"></fa:ImageAwesome>
+ <TextBlock VerticalAlignment="Center" Margin="10 0 0 0" Text="{Binding Description}"></TextBlock>
+ </StackPanel>
+ </Border>
+ </DataTemplate>
+ </ListBox.ItemTemplate>
+ </ListBox>
+ </Grid>
+ </Grid>
+ </GroupBox>
+ </Grid>
+
+ <Grid Grid.Column="1">
+ <GroupBox Header="Synchronize" Margin="10">
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="1*"/>
+ <RowDefinition Height="50"/>
+ </Grid.RowDefinitions>
+
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="20"/>
+ <RowDefinition Height="71*"/>
+ </Grid.RowDefinitions>
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Bottom">SQL Command</TextBlock>
+ <TextBox Margin="10" Foreground="Gray" FontSize="11" Text="{Binding SelectedDifference.Command,Mode=OneWay}" BorderThickness="0" IsReadOnly="True" Background="#151515" Padding="5" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" AcceptsReturn="True" Grid.Row="1"></TextBox>
+ </Grid>
+
+ <Grid Grid.Row="1">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
+ <Button Margin="10 10" Grid.Row="1" Width="120" HorizontalAlignment="Right" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding CommitCommand}">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock VerticalAlignment="Center" Margin="10 0 10 0">COMMIT</TextBlock>
+ <fa:ImageAwesome Icon="Bolt" VerticalAlignment="Center" Foreground="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=Foreground}" Width="16"></fa:ImageAwesome>
+ </StackPanel>
+ </Button>
+ <Button Margin="10 10" Grid.Row="1" Width="120" HorizontalAlignment="Right" Style="{StaticResource AccentedSquareButtonStyle}" mahapps:ButtonHelper.PreserveTextCase="True" BorderThickness="0" Command="{Binding CommitAllCommand}">
+ <StackPanel Orientation="Horizontal">
+ <TextBlock VerticalAlignment="Center" Margin="10 0 10 0">COMMIT ALL</TextBlock>
+ <fa:ImageAwesome Icon="SortAmountAsc" VerticalAlignment="Center" Foreground="{Binding RelativeSource={RelativeSource AncestorType=Button},Path=Foreground}" Width="16"></fa:ImageAwesome>
+ </StackPanel>
+ </Button>
+ </StackPanel>
+ </Grid>
+ </Grid>
+ </GroupBox>
+ </Grid>
+ </Grid>
+
+ <GridSplitter Margin="5 0 5 0" Grid.Row="1" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Center">
+ <GridSplitter.Background>
+ <LinearGradientBrush>
+ <GradientStop/>
+ <GradientStop Color="#FF848484" Offset="0.5"/>
+ <GradientStop Offset="1"/>
+ </LinearGradientBrush>
+ </GridSplitter.Background>
+ </GridSplitter>
+
+ <Grid Grid.Row="2" Background="Black" Margin="10 5">
+
+ <TextBox Text="{Binding Log,Mode=OneWay}" Background="Transparent" IsReadOnly="True" Padding="5" BorderThickness="0" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" FontSize="11" Foreground="Silver">
+
+ </TextBox>
+
+ <Border HorizontalAlignment="Right" Margin="0 0 10 0" VerticalAlignment="Top" Width="300" Height="40" Padding="5" CornerRadius="0 0 30 30" BorderThickness="1 0 1 1" BorderBrush="DimGray">
+ <Border.Style>
+ <Style TargetType="Border">
+ <Setter Property="RenderTransform">
+ <Setter.Value>
+ <ScaleTransform ScaleX="1" ScaleY="1"></ScaleTransform>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsBusy}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" To="1" Duration="00:00:0.2"></DoubleAnimation>
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" To="0" BeginTime="00:00:01" Duration="00:00:0.5"></DoubleAnimation>
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Style>
+ <Border.Background>
+ <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
+ <GradientStop Color="#FF272727"/>
+ <GradientStop Color="#FF777777" Offset="1"/>
+ </LinearGradientBrush>
+ </Border.Background>
+
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="20 0 0 0">
+ <mahapps:ProgressRing Width="24" Height="24" Foreground="Gainsboro"></mahapps:ProgressRing>
+ <TextBlock Text="{Binding Status}" Foreground="Gainsboro" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
+ </StackPanel>
+ </Border>
+
+ </Grid>
+ </Grid>
+ </Grid>
+</UserControl>
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml.cs b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml.cs
new file mode 100644
index 000000000..5316ade21
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/Views/MainView.xaml.cs
@@ -0,0 +1,28 @@
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace Tango.Synchronization.UI.Views
+{
+ /// <summary>
+ /// Interaction logic for MainView.xaml
+ /// </summary>
+ public partial class MainView : UserControl
+ {
+ public MainView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/packages.config b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/packages.config
new file mode 100644
index 000000000..e3961b62a
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Synchronization.UI/packages.config
@@ -0,0 +1,5 @@
+<?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" />
+</packages> \ No newline at end of file
diff --git a/Software/Visual_Studio/Web/Tango.MachineService/packages.config b/Software/Visual_Studio/Web/Tango.MachineService/packages.config
index 0b8287c43..80a6fd594 100644
--- a/Software/Visual_Studio/Web/Tango.MachineService/packages.config
+++ b/Software/Visual_Studio/Web/Tango.MachineService/packages.config
@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Antlr" version="3.4.1.9004" targetFramework="net45" />
- <package id="bootstrap" version="3.0.0" targetFramework="net45" />
- <package id="jQuery" version="1.10.2" targetFramework="net45" />
<package id="Microsoft.ApplicationInsights" version="2.2.0" targetFramework="net45" />
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.0.6" targetFramework="net45" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.2.0" targetFramework="net45" />