aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-28 10:02:12 +0300
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-28 10:02:12 +0300
commit3d6a882cf14f36297d8b379e0fdf65376064edf7 (patch)
tree91728997624076d0eb0d6b38df011851e559a838 /Software/Visual_Studio
parent888d3037722f80b00c12e140ba101f58661ec4b6 (diff)
downloadTango-3d6a882cf14f36297d8b379e0fdf65376064edf7.tar.gz
Tango-3d6a882cf14f36297d8b379e0fdf65376064edf7.zip
Many changes and improvements.
Diffstat (limited to 'Software/Visual_Studio')
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs105
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MonitoringViewVM.cs18
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/FileSystemView.xaml11
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml12
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/FileSystemControl.xaml13
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs13
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs4
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/MessageType.cs1
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml2
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Storage/IStorageProvider.cs1
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs264
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs2
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/DefaultStorageProvider.cs40
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml164
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml.cs218
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.cs20
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.designer.cs109
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.resx120
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj20
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs2
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Views/MainView.xaml4
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config1
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs41
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs98
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest2
-rw-r--r--Software/Visual_Studio/Tango.Core/Helpers/FileHelper.cs2
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/FileExplorerControl.cs26
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs59
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/Network/ChunkDownloadRequest.cs2
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/Network/ChunkUploadRequest.cs1
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadRequest.cs13
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadResponse.cs13
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationRequest.cs12
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationResponse.cs13
-rw-r--r--Software/Visual_Studio/Tango.FileSystem/Tango.FileSystem.csproj8
-rw-r--r--Software/Visual_Studio/Tango.Transport/Adapters/SignalRTransportAdapter.cs23
-rw-r--r--Software/Visual_Studio/Tango.Transport/Adapters/UsbTransportAdapter.cs1
-rw-r--r--Software/Visual_Studio/Tango.Transport/ITransportAdapter.cs5
-rw-r--r--Software/Visual_Studio/Tango.Transport/TransportAdapterBase.cs5
-rw-r--r--Software/Visual_Studio/Tango.Transport/TransporterBase.cs8
40 files changed, 1412 insertions, 64 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs
index e10cc0ad1..3a4a87884 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/FileSystemViewVM.cs
@@ -9,6 +9,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Tango.Core.Commands;
+using Tango.Core.Helpers;
using Tango.FileSystem;
using Tango.FSE.Common;
using Tango.FSE.Common.Connection;
@@ -57,6 +58,7 @@ namespace Tango.FSE.PPCConsole.ViewModels
public RelayCommand<List<FileSystemItem>> CopyPasteCommand { get; set; }
public RelayCommand<List<FileSystemItem>> CutPasteCommand { get; set; }
public RelayCommand<List<FileSystemItem>> DownloadCommand { get; set; }
+ public RelayCommand UploadCommand { get; set; }
public RelayCommand<FileSystemItem> RenameCommand { get; set; }
public RelayCommand NewFolderCommand { get; set; }
@@ -72,6 +74,7 @@ namespace Tango.FSE.PPCConsole.ViewModels
NavigateToFolderCommand = new RelayCommand<string>(async (x) => await Navigate(x));
DeleteCommand = new RelayCommand<IList<FileSystemItem>>(DeleteSelectedItems);
DragCommand = new RelayCommand<List<DragItem>>(OnItemsDraggedOut);
+ DropCommand = new RelayCommand<List<FileSystemItem>>(OnItemsDroppedIn);
DeleteFileSystemHandlerCommand = new RelayCommand<FileSystemHandler>(DeleteFileSystemHandler);
OpenFileSystemHandlerDestinationCommand = new RelayCommand<FileSystemHandler>(OpenFileSystemHandlerDestination);
RetryFailedFileSystemHandlerCommand = new RelayCommand<FileSystemHandler>(RetryFailedFileSystemHandler);
@@ -80,6 +83,7 @@ namespace Tango.FSE.PPCConsole.ViewModels
DownloadCommand = new RelayCommand<List<FileSystemItem>>(DownloadSelectedItems);
RenameCommand = new RelayCommand<FileSystemItem>(RenameFileSystemItem);
NewFolderCommand = new RelayCommand(CreateNewFolder);
+ UploadCommand = new RelayCommand(UploadFilesAndFolder);
}
private async void NavigateBack()
@@ -114,9 +118,12 @@ namespace Tango.FSE.PPCConsole.ViewModels
}
}
- private async void NavigateToCurrentPath()
+ private void NavigateToCurrentPath()
{
- await Navigate(CurrentPath);
+ InvokeUI(async () =>
+ {
+ await Navigate(CurrentPath);
+ });
}
private async void OpenFileSystemItem(FileSystemItem item)
@@ -195,6 +202,36 @@ namespace Tango.FSE.PPCConsole.ViewModels
}
}
+ private async void OnItemsDroppedIn(List<FileSystemItem> items)
+ {
+ String currentPathBefore = CurrentPath;
+
+ foreach (var item in items.Where(x => x.Type != FileSystemItemType.Drive))
+ {
+ Debug.WriteLine($"Dropped in: {item.Name} => {CurrentItem.Path}");
+
+ if ((CurrentItem as IFileSystemContainer).Items.ToList().Exists(x => x.Name.ToLower() == item.Name.ToLower()))
+ {
+ if (!await NotificationProvider.ShowWarningQuestion($"'{item.Name}' already exists on '{CurrentItem.Name}'. Do you want to overwrite?"))
+ {
+ continue;
+ }
+ }
+
+ var handler = await FileSystemProvider.Upload(item.Path, CurrentItem);
+
+ handler.StatusChanged += (x, status) =>
+ {
+ if (status == FileSystemHandlerStatus.Completed && currentPathBefore == CurrentPath)
+ {
+ NavigateToCurrentPath();
+ }
+ };
+
+ FileSystemHandlers.Insert(0, handler);
+ }
+ }
+
private async void DeleteFileSystemHandler(FileSystemHandler handler)
{
if (handler.Status != FileSystemHandlerStatus.Completed && handler.Status != FileSystemHandlerStatus.Failed)
@@ -216,19 +253,26 @@ namespace Tango.FSE.PPCConsole.ViewModels
}
}
- private void OpenFileSystemHandlerDestination(FileSystemHandler handler)
+ private async void OpenFileSystemHandlerDestination(FileSystemHandler handler)
{
String destination = String.Empty;
- if (File.Exists(handler.Destination) || Directory.Exists(handler.Destination))
+ if (handler.Type == FileSystemHandlerType.FileDownload || handler.Type == FileSystemHandlerType.FolderDownload)
{
- destination = handler.Destination;
- Process.Start("explorer.exe", string.Format("/select,\"{0}\"", destination));
+ if (File.Exists(handler.Destination) || Directory.Exists(handler.Destination))
+ {
+ destination = handler.Destination;
+ Process.Start("explorer.exe", string.Format("/select,\"{0}\"", destination));
+ }
+ else
+ {
+ destination = Path.GetDirectoryName(handler.Destination);
+ Process.Start("explorer.exe", destination);
+ }
}
else
{
- destination = Path.GetDirectoryName(handler.Destination);
- Process.Start("explorer.exe", destination);
+ await Navigate(Path.GetDirectoryName(handler.Destination));
}
}
@@ -364,6 +408,49 @@ namespace Tango.FSE.PPCConsole.ViewModels
}
}
+ private async void UploadFilesAndFolder()
+ {
+ var result = await StorageProvider.SelectFilesAndFolders("Select files and folders to upload");
+ if (result)
+ {
+ String currentPathBefore = CurrentPath;
+
+ foreach (var item in result.SelectedItems)
+ {
+ if (!File.Exists(item) && !Directory.Exists(item))
+ {
+ await NotificationProvider.ShowError($"File or folder '{item}' cannot be uploaded.");
+ return;
+ }
+ }
+
+ foreach (var item in result.SelectedItems)
+ {
+ String itemName = Path.GetFileName(item);
+
+ if ((CurrentItem as IFileSystemContainer).Items.ToList().Exists(x => x.Name.ToLower() == itemName.ToLower()))
+ {
+ if (!await NotificationProvider.ShowWarningQuestion($"'{itemName}' already exists on '{CurrentItem.Name}'. Do you want to overwrite?"))
+ {
+ continue;
+ }
+ }
+
+ var handler = await FileSystemProvider.Upload(item, CurrentItem);
+
+ handler.StatusChanged += (x, status) =>
+ {
+ if (status == FileSystemHandlerStatus.Completed && currentPathBefore == CurrentPath)
+ {
+ NavigateToCurrentPath();
+ }
+ };
+
+ FileSystemHandlers.Insert(0, handler);
+ }
+ }
+ }
+
private async void RenameFileSystemItem(FileSystemItem item)
{
if (item.Type != FileSystemItemType.Drive)
@@ -423,7 +510,7 @@ namespace Tango.FSE.PPCConsole.ViewModels
}
catch (Exception ex)
{
- LogManager.Log(ex, $"Error creating new folder '{Path.Combine(CurrentItem.Path,result.Input)}.");
+ LogManager.Log(ex, $"Error creating new folder '{Path.Combine(CurrentItem.Path, result.Input)}.");
await NotificationProvider.ShowError($"Error creating folder '{result.Input}'.\n{ex.FlattenMessage()}");
}
}
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MonitoringViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MonitoringViewVM.cs
index eb59b2c9a..890adcf54 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MonitoringViewVM.cs
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MonitoringViewVM.cs
@@ -8,6 +8,8 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
+using Tango.Core.Commands;
+using Tango.Core.Helpers;
using Tango.FSE.Common;
using Tango.FSE.Common.Graphs;
using Tango.FSE.Common.Performance;
@@ -74,6 +76,8 @@ namespace Tango.FSE.PPCConsole.ViewModels
}
}
+ public RelayCommand PerformDiskSpaceOptimizationCommand { get; set; }
+
public MonitoringViewVM()
{
CPUController = CreateController(CreateSeries("Total", GraphHelper.GraphColor.White), CreateSeries("Application", GraphHelper.GraphColor.Red));
@@ -84,6 +88,8 @@ namespace Tango.FSE.PPCConsole.ViewModels
{
return $"{(point.Y / 1000d).ToString("0.0")} GB";
};
+
+ PerformDiskSpaceOptimizationCommand = new RelayCommand(PerformDiskSpaceOptimization);
}
private WpfGraphController<DateTimeDataPoint, DoubleDataPoint> CreateController(params WpfGraphDataSeries[] seriesCollection)
@@ -207,5 +213,17 @@ namespace Tango.FSE.PPCConsole.ViewModels
}
}
}
+
+ private async void PerformDiskSpaceOptimization()
+ {
+ if (await NotificationProvider.ShowQuestion("The following stage will try to optimize the disk space on the remote machine panel PC. Do you wish to continue?", "RUN OPTIMIZATION", "NO"))
+ {
+ using (NotificationProvider.PushTaskItem("Performing disk space optimization, please wait..."))
+ {
+ var response = await FileSystemProvider.PerformDiskSpaceOptimization();
+ await NotificationProvider.ShowSuccess($"Disk space optimization completed successfully.\n{FileHelper.GetFriendlyFileSize(response.DeletedBytes)} cleared!");
+ }
+ }
+ }
}
}
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/FileSystemView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/FileSystemView.xaml
index 67f1dc1c5..d8b82f6c3 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/FileSystemView.xaml
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/FileSystemView.xaml
@@ -118,7 +118,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="1*" MinHeight="100" />
<RowDefinition Height="5" />
- <RowDefinition Height="100" MinHeight="0" />
+ <RowDefinition Height="105" MinHeight="0" />
</Grid.RowDefinitions>
<controls:FileSystemControl
x:Name="fileSystemControl"
@@ -135,6 +135,7 @@
CutPasteCommand="{Binding CutPasteCommand}"
CopyPasteCommand="{Binding CopyPasteCommand}"
DownloadCommand="{Binding DownloadCommand}"
+ UploadCommand="{Binding UploadCommand}"
BackCommand="{Binding BackCommand}"
RenameCommand="{Binding RenameCommand}"
NewFolderCommand="{Binding NewFolderCommand}"/>
@@ -217,7 +218,7 @@
<Grid DockPanel.Dock="Right" Width="140" Margin="20 0 0 0">
<UniformGrid Columns="3">
<Grid>
- <controls:ToggleIconButton Width="24" Height="24" UncheckedForeground="{StaticResource FSE_OrangeBrush}" CheckedForeground="{StaticResource FSE_GreenBrush}" UncheckedIcon="Pause" CheckedIcon="Play" Cursor="Hand" IsChecked="{Binding IsPaused,Mode=TwoWay}">
+ <controls:ToggleIconButton ToolTip="Pause/Resume" Width="24" Height="24" UncheckedForeground="{StaticResource FSE_OrangeBrush}" CheckedForeground="{StaticResource FSE_GreenBrush}" UncheckedIcon="Pause" CheckedIcon="Play" Cursor="Hand" IsChecked="{Binding IsPaused,Mode=TwoWay}">
<controls:ToggleIconButton.Style>
<Style TargetType="controls:ToggleIconButton" BasedOn="{StaticResource {x:Type controls:ToggleIconButton}}">
<Setter Property="IsEnabled" Value="False"></Setter>
@@ -243,7 +244,7 @@
</Style>
</controls:ToggleIconButton.Style>
</controls:ToggleIconButton>
- <controls:IconButton Icon="Restart" Cursor="Hand" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RetryFailedFileSystemHandlerCommand}" CommandParameter="{Binding}">
+ <controls:IconButton Icon="Restart" ToolTip="Try again" Cursor="Hand" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RetryFailedFileSystemHandlerCommand}" CommandParameter="{Binding}">
<controls:IconButton.Style>
<Style TargetType="controls:IconButton" BasedOn="{StaticResource {x:Type controls:IconButton}}">
<Setter Property="Visibility" Value="Hidden"></Setter>
@@ -256,8 +257,8 @@
</controls:IconButton.Style>
</controls:IconButton>
</Grid>
- <controls:IconButton Icon="FolderOpen" Cursor="Hand" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.OpenFileSystemHandlerDestinationCommand}" CommandParameter="{Binding}" />
- <controls:IconButton Icon="DeleteForever" Foreground="{StaticResource FSE_RedBrush}" Cursor="Hand" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.DeleteFileSystemHandlerCommand}" CommandParameter="{Binding}" />
+ <controls:IconButton Icon="FolderOpen" ToolTip="Open containing folder" Cursor="Hand" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.OpenFileSystemHandlerDestinationCommand}" CommandParameter="{Binding}" />
+ <controls:IconButton Icon="DeleteForever" ToolTip="Remove from queue" Foreground="{StaticResource FSE_RedBrush}" Cursor="Hand" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.DeleteFileSystemHandlerCommand}" CommandParameter="{Binding}" />
</UniformGrid>
</Grid>
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml
index 22e2566b5..397a07377 100644
--- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml
+++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml
@@ -1,6 +1,7 @@
<UserControl x:Class="Tango.FSE.PPCConsole.Views.MonitoringView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:graphs="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common"
@@ -103,7 +104,7 @@
<Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="0 40 0 0">
<Grid.ColumnDefinitions>
- <ColumnDefinition Width="2*"/>
+ <ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="8*"/>
</Grid.ColumnDefinitions>
@@ -112,7 +113,14 @@
<TextBlock DockPanel.Dock="Top" Foreground="{StaticResource FSE_GrayBrush}" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="{StaticResource FSE_LargeFontSize}" FontWeight="SemiBold">AVAILABLE DISK SPACE</TextBlock>
- <lvc:PieChart Opacity="0.7" DisableAnimations="True" LegendLocation="Bottom" Hoverable="False" DataTooltip="{x:Null}" HorizontalAlignment="Left" Width="250">
+ <Button ToolTip="Perform automatic disk space optimization" Command="{Binding PerformDiskSpaceOptimizationCommand}" IsEnabled="{Binding MachineProvider.IsConnected}" DockPanel.Dock="Right" FontSize="{StaticResource FSE_SmallFontSize}" Background="Transparent" VerticalAlignment="Top" Margin="0 12 10 0" Style="{StaticResource FSE_Button_Orange}">
+ <StackPanel Orientation="Horizontal">
+ <material:PackIcon Kind="Recycle" Margin="0 -2 0 0" />
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" Visibility="{Binding ResolutionService.IsHighResolution,Converter={StaticResource BooleanToVisibilityConverter}}">FREE SPACE</TextBlock>
+ </StackPanel>
+ </Button>
+
+ <lvc:PieChart Opacity="0.7" Margin="-20 0 0 0" DisableAnimations="True" LegendLocation="Bottom" Hoverable="False" DataTooltip="{x:Null}" HorizontalAlignment="Left" Width="250">
<lvc:PieChart.Series>
<lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_PrimaryBackgroundBrush}" Fill="#F47FD121" FontSize="16" Title="Free" Values="{Binding AvailableDiskSpace,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="True"
LabelPoint="{Binding DiskSpacePointLabel}"/>
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/FileSystemControl.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/FileSystemControl.xaml
index 5bc75ca54..63d90c171 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/FileSystemControl.xaml
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/FileSystemControl.xaml
@@ -43,7 +43,7 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Border.ContextMenu>
- <ContextMenu Width="250" IsOpen="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=IsContextMenuOpened,Mode=TwoWay}">
+ <ContextMenu FontSize="13" Width="250" IsOpen="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=IsContextMenuOpened,Mode=TwoWay}">
<MenuItem Header="Open" InputGestureText="Enter" Command="{TemplateBinding OpenCommand}">
<MenuItem.Icon>
<material:PackIcon Kind="SubdirectoryArrowRight" />
@@ -66,7 +66,6 @@
<material:PackIcon Kind="ContentCut" />
</MenuItem.Icon>
</MenuItem>
- <Separator/>
<MenuItem Header="Paste" InputGestureText="Ctrl+V" Command="{TemplateBinding PasteCommandInternal}">
<MenuItem.Icon>
<material:PackIcon Kind="ContentPaste" />
@@ -78,7 +77,6 @@
<material:PackIcon Kind="Rename" />
</MenuItem.Icon>
</MenuItem>
- <Separator/>
<MenuItem Header="Delete" InputGestureText="DEL" Command="{TemplateBinding DeleteCommandInternal}">
<MenuItem.Icon>
<material:PackIcon Kind="DeleteForever" />
@@ -90,6 +88,11 @@
<material:PackIcon Kind="Download" />
</MenuItem.Icon>
</MenuItem>
+ <MenuItem Header="Upload" InputGestureText="Ctrl+U" Command="{TemplateBinding UploadCommandInternal}">
+ <MenuItem.Icon>
+ <material:PackIcon Kind="Upload" />
+ </MenuItem.Icon>
+ </MenuItem>
<Separator/>
<MenuItem Header="Select All" InputGestureText="Ctrl+A" Command="{TemplateBinding SelectAllCommand}">
<MenuItem.Icon>
@@ -100,7 +103,7 @@
</Border.ContextMenu>
<Grid Background="Transparent">
- <ListBox x:Name="PART_listbox" IsTextSearchEnabled="True" TextSearch.TextPath="Name" Background="Transparent" SelectionMode="{TemplateBinding SelectionMode}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=CurrentItem.Items}">
+ <ListBox x:Name="PART_listbox" ScrollViewer.CanContentScroll="False" IsTextSearchEnabled="True" TextSearch.TextPath="Name" Background="Transparent" SelectionMode="{TemplateBinding SelectionMode}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=CurrentItem.Items}">
<ListBox.Style>
<Style TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="Visibility" Value="Collapsed"></Setter>
@@ -171,7 +174,7 @@
</Style.Triggers>
</Style>
</Grid.Style>
- <local:FileSystemDataGrid x:Name="PART_datagrid" IsTextSearchEnabled="True" TextSearch.TextPath="Name" ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=CurrentItem.Items}" CellStyle="{StaticResource FileSystemCellStyle}">
+ <local:FileSystemDataGrid x:Name="PART_datagrid" ScrollViewer.CanContentScroll="False" IsTextSearchEnabled="True" TextSearch.TextPath="Name" ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=CurrentItem.Items}" CellStyle="{StaticResource FileSystemCellStyle}">
<DataGrid.Style>
<Style TargetType="DataGrid" BasedOn="{StaticResource {x:Type DataGrid}}">
<Setter Property="Background" Value="Transparent"></Setter>
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs
index a748a63cc..e74395ade 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/FileSystemHandler.cs
@@ -15,6 +15,8 @@ namespace Tango.FSE.Common.FileSystem
private System.Timers.Timer _transferRateTimer;
private double _lastPosition;
+ public event EventHandler<FileSystemHandlerStatus> StatusChanged;
+
public FileSystemHandlerType Type { get; set; }
private FileSystemHandlerStatus _status;
@@ -23,8 +25,12 @@ namespace Tango.FSE.Common.FileSystem
get { return _status; }
set
{
- _status = value;
- RaisePropertyChangedAuto();
+ if (_status != value)
+ {
+ _status = value;
+ RaisePropertyChangedAuto();
+ StatusChanged?.Invoke(this, _status);
+ }
}
}
@@ -85,8 +91,9 @@ namespace Tango.FSE.Common.FileSystem
public String Destination { get; set; }
public String OperationId { get; set; }
- public FileSystemHandler(FileSystemItem fileSystemItem, String destination, Action abortAction)
+ public FileSystemHandler(FileSystemHandlerType type, FileSystemItem fileSystemItem, String destination, Action abortAction)
{
+ Type = type;
FileSystemItem = fileSystemItem;
Destination = destination;
_abortAction = abortAction;
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs
index 00546094e..7580fd9c8 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.FileSystem;
+using Tango.FileSystem.Network;
using static System.Environment;
namespace Tango.FSE.Common.FileSystem
@@ -16,11 +17,12 @@ namespace Tango.FSE.Common.FileSystem
Task<IFileSystemContainer> GetSpecialFolder(SpecialFolder specialFolder);
Task<IFileSystemContainer> GetThisPC();
Task<FileSystemHandler> Download(FileSystemItem item, String localTargetFolder);
- Task<FileSystemHandler> Upload(String sourcePath, String remoteTargetFolder);
+ Task<FileSystemHandler> Upload(String localSourcePath, FileSystemItem remoteFolder);
Task Copy(FileSystemItem source, FileSystemItem target);
Task Move(FileSystemItem source, FileSystemItem target);
Task Rename(FileSystemItem source, String newName);
Task Delete(FileSystemItem item);
Task<FolderItem> CreateFolder(FileSystemItem parent, String folderName);
+ Task<PerformDiskSpaceOptimizationResponse> PerformDiskSpaceOptimization();
}
}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/MessageType.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/MessageType.cs
index 2d9edcfd3..c4090865e 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/MessageType.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/MessageType.cs
@@ -9,6 +9,7 @@ namespace Tango.FSE.Common.Notifications
public enum MessageType
{
Info,
+ Question,
Warning,
Error,
Success
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml
index 1a355ebf0..0c234fda4 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml
@@ -26,7 +26,7 @@
<Color x:Key="FSE_RedColor">#FF6F6F</Color>
<Color x:Key="FSE_GreenColor">#8EFF6F</Color>
- <Color x:Key="FSE_OrangeColor">#FA9252</Color>
+ <Color x:Key="FSE_OrangeColor">#FF7C2B</Color>
<Color x:Key="FSE_YellowColor">#FFB84B</Color>
<Color x:Key="FSE_RealTimeGraph_White">#18FFFFFF</Color>
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Storage/IStorageProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Storage/IStorageProvider.cs
index 602e6057c..8a511a56c 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Storage/IStorageProvider.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Storage/IStorageProvider.cs
@@ -35,6 +35,7 @@ namespace Tango.FSE.Common.Storage
Task<SingleStorageResult> OpenFile(String title, String filter = null, String initialFolder = null);
Task<MultiStorageResult> OpenFiles(String title, String filter = null, String initialFolder = null);
+ Task<MultiStorageResult> SelectFilesAndFolders(String title, String filter = null, String initialFolder = null);
Task<SingleStorageResult> SaveFile(String title, String filter = null, String defaultFileName = null, String defaultExtension = null, String initialFolder = null);
Task<SingleStorageResult> SelectFolder(String title, String initialFolder = null);
}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs
index 6f25e1774..86ee2a73e 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs
@@ -8,6 +8,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.Core;
+using Tango.Core.IO;
using Tango.Core.Threading;
using Tango.FileSystem;
using Tango.FileSystem.Network;
@@ -24,7 +25,8 @@ namespace Tango.FSE.UI.FileSystem
private IMachineProvider _machineProvider;
private BasicTransporter _webRtcTransporter;
private const string WEB_RTC_CHANNEL_NAME = "FileSystemChannel";
- private const long MAX_CHUNK_SIZE = 1024 * 10;
+ private const long MAX_CHUNK_SIZE = 1024 * 100;
+ private const long MIN_CHUNK_SIZE = 1024;
private const long MAX_CHUNK_SIZE_WEB_RTC = 1024 * 50;
private const int WEB_RTC_MAX_RETRIES = 8;
private List<FileSystemHandler> _activeHandlers;
@@ -170,7 +172,7 @@ namespace Tango.FSE.UI.FileSystem
destination = Path.Combine(localTargetFolder, item.Name);
- handler = new FileSystemHandler(item, destination, async () =>
+ handler = new FileSystemHandler(item.Type == FileSystemItemType.Folder ? FileSystemHandlerType.FolderDownload : FileSystemHandlerType.FileDownload, item, destination, async () =>
{
if (!aborted)
{
@@ -239,6 +241,7 @@ namespace Tango.FSE.UI.FileSystem
long position = 0;
bool webRtcFailed = false;
int webRtcRetries = WEB_RTC_MAX_RETRIES;
+ long dynamixMaxChunkSizeSignalR = MAX_CHUNK_SIZE;
var tempFile = TemporaryManager.CreateFile();
@@ -288,11 +291,29 @@ namespace Tango.FSE.UI.FileSystem
}
else
{
+ request.MaxChunkSize = dynamixMaxChunkSizeSignalR;
+
+ Stopwatch watch = new Stopwatch();
+ watch.Start();
+
response = await _machineProvider.MachineOperator.SendGenericRequest<ChunkDownloadRequest, ChunkDownloadResponse>(request, new TransportRequestConfig()
{
Timeout = TimeSpan.FromSeconds(30),
Priority = QueuePriority.Low
});
+
+ watch.Stop();
+
+ if (watch.Elapsed.TotalSeconds < 1)
+ {
+ dynamixMaxChunkSizeSignalR += 1024 * 10;
+ }
+ else if (watch.Elapsed.TotalSeconds > 1)
+ {
+ dynamixMaxChunkSizeSignalR -= 1024 * 10;
+ }
+
+ dynamixMaxChunkSizeSignalR = Math.Max(dynamixMaxChunkSizeSignalR, MIN_CHUNK_SIZE);
}
using (FileStream fs = new FileStream(tempFile, FileMode.Append))
@@ -323,7 +344,11 @@ namespace Tango.FSE.UI.FileSystem
}
else if (item.Type == FileSystemItemType.Folder)
{
- ZipFile.ExtractToDirectory(tempFile, destination);
+ using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(tempFile))
+ {
+ zip.ExtractAll(destination, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently);
+ }
+
tempFile.Delete();
}
@@ -345,9 +370,225 @@ namespace Tango.FSE.UI.FileSystem
return Task.FromResult(handler);
}
- public Task<FileSystemHandler> Upload(string sourcePath, string remoteTargetFolder)
+ public Task<FileSystemHandler> Upload(String localSourcePath, FileSystemItem remoteFolder)
{
- throw new NotImplementedException();
+ String operationId = String.Empty;
+ String destination = Path.Combine(remoteFolder.Path, Path.GetFileName(localSourcePath));
+ bool isFolder = false;
+ bool aborted = false;
+
+ FileSystemItem sourceItem = null;
+
+ if (Directory.Exists(localSourcePath))
+ {
+ sourceItem = new FolderItem() { Path = localSourcePath };
+ isFolder = true;
+ }
+ else if (File.Exists(localSourcePath))
+ {
+ sourceItem = new FileItem() { Path = localSourcePath };
+ isFolder = false;
+ }
+ else
+ {
+ throw new FileNotFoundException("Could not locate the local file or directory to upload.");
+ }
+
+ FileSystemHandler handler = null;
+
+ handler = new FileSystemHandler(isFolder ? FileSystemHandlerType.FolderUpload : FileSystemHandlerType.FileUpload, sourceItem, destination, async () =>
+ {
+ if (!aborted)
+ {
+ aborted = true;
+ try
+ {
+ var response = await _machineProvider.MachineOperator.SendGenericRequest<AbortOperationRequest, AbortOperationResponse>(
+ new AbortOperationRequest()
+ {
+ OperationId = operationId
+ }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(30) });
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error aborting the upload operation.");
+ }
+ finally
+ {
+ handler.RaiseAborted();
+ }
+ }
+ });
+
+ _activeHandlers.Add(handler);
+
+ ThreadFactory.StartNew(async () =>
+ {
+ try
+ {
+ if (!isFolder)
+ {
+ var response = await _machineProvider.MachineOperator.SendGenericRequest<FileUploadRequest, FileUploadResponse>(
+ new FileUploadRequest()
+ {
+ Path = destination
+ }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(20) });
+
+ operationId = response.OperationId;
+ handler.OperationId = operationId;
+ }
+ else
+ {
+ var response = await _machineProvider.MachineOperator.SendGenericRequest<FolderUploadRequest, FolderUploadResponse>(
+ new FolderUploadRequest()
+ {
+ Path = destination
+ }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(20) });
+
+ operationId = response.OperationId;
+ handler.OperationId = operationId;
+ }
+
+ if (isFolder)
+ {
+ var originalPath = localSourcePath;
+ localSourcePath = TemporaryManager.CreateImaginaryFile().Path;
+ ZipFile.CreateFromDirectory(originalPath, localSourcePath);
+ }
+ }
+ catch (Exception ex)
+ {
+ _activeHandlers.Remove(handler);
+ handler.RaiseFailed(ex);
+ return;
+ }
+
+ long position = 0;
+ bool webRtcFailed = false;
+ int webRtcRetries = WEB_RTC_MAX_RETRIES;
+ long dynamixMaxChunkSizeSignalR = MAX_CHUNK_SIZE;
+
+ using (FileStream fs = new FileStream(localSourcePath, FileMode.Open))
+ {
+ while (position < fs.Length && !aborted)
+ {
+ fs.Position = position;
+
+ if (handler.IsPaused)
+ {
+ Thread.Sleep(1000);
+ continue;
+ }
+
+ try
+ {
+ ChunkUploadResponse response = null;
+ ChunkUploadRequest request = new ChunkUploadRequest()
+ {
+ OperationId = operationId,
+ };
+
+ if (_webRtcTransporter != null && _webRtcTransporter.State == TransportComponentState.Connected && EnableWebRTC && !webRtcFailed)
+ {
+ try
+ {
+ byte[] data = new byte[Math.Min(MAX_CHUNK_SIZE_WEB_RTC, fs.Length - fs.Position)];
+ fs.Read(data, 0, data.Length);
+ request.Data = data;
+ request.IsCompleted = fs.Position == fs.Length;
+
+ response = await _webRtcTransporter.SendGenericRequest<ChunkUploadRequest, ChunkUploadResponse>(request, new TransportRequestConfig()
+ {
+ Timeout = request.IsCompleted ? TimeSpan.FromSeconds(120) : TimeSpan.FromSeconds(2),
+ Priority = QueuePriority.Low
+ });
+
+ webRtcRetries = WEB_RTC_MAX_RETRIES;
+ }
+ catch (Exception ex)
+ {
+ webRtcRetries--;
+
+ if (webRtcRetries == 0)
+ {
+ webRtcFailed = true;
+ LogManager.Log(ex, "WebRTC chunk upload failed. Falling back to standard upload...");
+ }
+
+ continue;
+ }
+ }
+ else
+ {
+ byte[] data = new byte[Math.Min(dynamixMaxChunkSizeSignalR, fs.Length - fs.Position)];
+ fs.Read(data, 0, data.Length);
+ request.Data = data;
+ request.IsCompleted = fs.Position == fs.Length;
+
+ Stopwatch watch = new Stopwatch();
+ watch.Start();
+
+ response = await _machineProvider.MachineOperator.SendGenericRequest<ChunkUploadRequest, ChunkUploadResponse>(request, new TransportRequestConfig()
+ {
+ Timeout = request.IsCompleted ? TimeSpan.FromSeconds(120) : TimeSpan.FromSeconds(30),
+ Priority = QueuePriority.Low
+ });
+
+ watch.Stop();
+
+ if (watch.Elapsed.TotalSeconds < 1)
+ {
+ dynamixMaxChunkSizeSignalR += 1024 * 10;
+ }
+ else if (watch.Elapsed.TotalSeconds > 1)
+ {
+ dynamixMaxChunkSizeSignalR -= 1024 * 10;
+ }
+
+ dynamixMaxChunkSizeSignalR = Math.Max(dynamixMaxChunkSizeSignalR, MIN_CHUNK_SIZE);
+ }
+
+ position = fs.Position;
+ handler.InvalidateProgress(position, fs.Length);
+ }
+ catch (Exception ex)
+ {
+ _activeHandlers.Remove(handler);
+ handler.RaiseFailed(ex);
+
+ if (isFolder)
+ {
+ try
+ {
+ fs.Dispose();
+ File.Delete(localSourcePath);
+ }
+ catch { }
+ }
+
+ return;
+ }
+ }
+
+ if (!aborted)
+ {
+ handler.RaiseCompleted();
+ }
+
+ if (isFolder)
+ {
+ try
+ {
+ File.Delete(localSourcePath);
+ }
+ catch { }
+ }
+ }
+
+ _activeHandlers.Remove(handler);
+ });
+
+ return Task.FromResult(handler);
}
public async Task Copy(FileSystemItem source, FileSystemItem target)
@@ -439,5 +680,18 @@ namespace Tango.FSE.UI.FileSystem
return FileSystemItem.FromDTO(response.FolderItem) as FolderItem;
}
+
+ public async Task<PerformDiskSpaceOptimizationResponse> PerformDiskSpaceOptimization()
+ {
+ var response = await _machineProvider.MachineOperator.SendGenericRequest<PerformDiskSpaceOptimizationRequest, PerformDiskSpaceOptimizationResponse>(new PerformDiskSpaceOptimizationRequest()
+ {
+
+ }, new TransportRequestConfig()
+ {
+ Timeout = TimeSpan.FromMinutes(5)
+ });
+
+ return response;
+ }
}
}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs
index 666619b59..861a8c4d4 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs
@@ -245,7 +245,7 @@ namespace Tango.FSE.UI.Notifications
Message = message,
Title = "Confirm",
HasCancel = true,
- Type = MessageType.Info,
+ Type = MessageType.Question,
OKText = okText != null ? okText : "YES",
CancelText = cancelText != null ? cancelText : "NO"
});
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/DefaultStorageProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/DefaultStorageProvider.cs
index 627b380da..80c08fb2e 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/DefaultStorageProvider.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/DefaultStorageProvider.cs
@@ -135,7 +135,7 @@ namespace Tango.FSE.UI.Storage
}
else
{
- return null;
+ throw new NotImplementedException();
}
}
@@ -147,7 +147,19 @@ namespace Tango.FSE.UI.Storage
}
else
{
- return null;
+ throw new NotImplementedException();
+ }
+ }
+
+ public Task<MultiStorageResult> SelectFilesAndFolders(string title, string filter = null, string initialFolder = null)
+ {
+ if (UseNativeDialogs)
+ {
+ return OpenFilesAndFoldersNative(title, filter, initialFolder);
+ }
+ else
+ {
+ throw new NotImplementedException();
}
}
@@ -159,7 +171,7 @@ namespace Tango.FSE.UI.Storage
}
else
{
- return null;
+ throw new NotImplementedException();
}
}
@@ -364,6 +376,28 @@ namespace Tango.FSE.UI.Storage
return Task.FromResult(result);
}
+ public Task<MultiStorageResult> OpenFilesAndFoldersNative(string title, string filter = null, string initialFolder = null)
+ {
+ MultiStorageResult result = new MultiStorageResult();
+
+ ExplorerControlDialog dlg = new ExplorerControlDialog();
+ dlg.Owner = Application.Current.MainWindow;
+ dlg.Title = title;
+
+ if (initialFolder != null)
+ {
+ dlg.InitialDirectory = initialFolder;
+ }
+
+ if (dlg.ShowDialog().Value)
+ {
+ result.Confirmed = true;
+ result.SelectedItems = dlg.SelectedItems.ToList();
+ }
+
+ return Task.FromResult(result);
+ }
+
public Task<SingleStorageResult> SaveFileNative(string title, string filter = null, string defaultFileName = null, string defaultExtension = null, string initialFolder = null)
{
SingleStorageResult result = new SingleStorageResult();
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml
new file mode 100644
index 000000000..2a3831742
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml
@@ -0,0 +1,164 @@
+<Window x:Class="Tango.FSE.UI.Storage.ExplorerControlDialog"
+ 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:material="http://materialdesigninxaml.net/winfx/xaml/themes"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:WindowsAPICodePackPresentation="clr-namespace:Microsoft.WindowsAPICodePack.Controls.WindowsPresentationFoundation;assembly=Microsoft.WindowsAPICodePack.Shell"
+ xmlns:WindowsAPICodePackShell="clr-namespace:Microsoft.WindowsAPICodePack.Shell;assembly=Microsoft.WindowsAPICodePack.Shell"
+ xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
+ xmlns:local="clr-namespace:Tango.FSE.Storage.UI"
+ mc:Ignorable="d"
+ Title="Select Files And Folder" Height="530" Width="943" DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
+
+ <Window.Resources>
+ <Style TargetType="Button" x:Key="FlatButton">
+ <Setter Property="Background" Value="Transparent"/>
+ <Setter Property="BorderThickness" Value="0"></Setter>
+ <Setter Property="BorderBrush" Value="Gainsboro"></Setter>
+ <Setter Property="VerticalAlignment" Value="Center"></Setter>
+ <Setter Property="Foreground" Value="Gray"></Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Button}">
+ <Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
+ <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <Trigger Property="IsMouseOver" Value="True">
+ <Setter Property="Background" Value="#E5F3FF"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Foreground" Value="Gainsboro"/>
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+
+ <Style TargetType="Button" x:Key="FlatButtonIcon">
+ <Setter Property="Background" Value="White"></Setter>
+ <Setter Property="Padding" Value="4"></Setter>
+ <Setter Property="VerticalAlignment" Value="Center"></Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="Button">
+ <Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
+ <Border.Style>
+ <Style TargetType="Border">
+ <Setter Property="TextElement.Foreground" Value="Gray"></Setter>
+ <Style.Triggers>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="TextElement.Foreground" Value="Gainsboro"/>
+ </Trigger>
+ <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=IsMouseOver}" Value="True">
+ <Setter Property="TextElement.Foreground" Value="DodgerBlue"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Style>
+ <ContentPresenter/>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </Window.Resources>
+
+ <Grid>
+ <DockPanel>
+ <Grid DockPanel.Dock="Top" Height="40">
+ <DockPanel Margin="10 0 0 0">
+ <Button Style="{StaticResource FlatButtonIcon}" Width="24" Height="24" x:Name="btnBack" Click="BtnBack_Click">
+ <material:PackIcon Kind="ArrowLeft" Width="Auto" Height="Auto" Foreground="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource AncestorType=ContentPresenter}}" />
+ </Button>
+ <Button Style="{StaticResource FlatButtonIcon}" Margin="10 0 0 0" Width="24" Height="24" x:Name="btnForward" Click="BtnForward_Click">
+ <material:PackIcon Kind="ArrowRight" Width="Auto" Height="Auto" Foreground="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource AncestorType=ContentPresenter}}" />
+ </Button>
+
+ <material:PackIcon Margin="10 0 0 0" VerticalAlignment="Center" Foreground="Gainsboro" Kind="ChevronDown" Width="16" Height="16" />
+
+ <Button Style="{StaticResource FlatButton}" Margin="10 0 0 0" Width="24" Height="24" Padding="2" x:Name="btnUp" Click="BtnUp_Click">
+ <material:PackIcon Kind="ArrowUp" Width="Auto" Height="Auto" />
+ </Button>
+
+ <Grid>
+ <DockPanel Margin="10 0 10 0">
+ <Button Style="{StaticResource FlatButton}" DockPanel.Dock="Right" Width="24" Height="20" BorderThickness="0 1 1 1" x:Name="btnRefresh">
+ <material:PackIcon Kind="Refresh" Width="Auto" Height="Auto" />
+ </Button>
+
+ <Grid>
+ <TextBox Style="{x:Null}" VerticalAlignment="Center" GotKeyboardFocus="TxtLocation_GotKeyboardFocus" LostKeyboardFocus="TxtLocation_LostKeyboardFocus" x:Name="txtLocation" Background="White" BorderBrush="Gainsboro" VerticalContentAlignment="Center" Padding="2 0 0 0" Height="20"></TextBox>
+ <ItemsControl x:Name="listHistory" HorizontalAlignment="Left" ItemsSource="{Binding ShellHistory}" Background="White" Height="18" Margin="5 0 0 0">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <StackPanel Margin="5 0 0 0" IsItemsHost="True" Orientation="Horizontal"></StackPanel>
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <StackPanel Orientation="Horizontal">
+ <material:PackIcon Foreground="Gray" VerticalAlignment="Center" Width="13" Height="13" Kind="ChevronRight" />
+ <Button Click="OnHistoryItemClicked" Padding="5 0" Style="{StaticResource FlatButton}">
+ <TextBlock Foreground="Black" Text="{Binding}"></TextBlock>
+ </Button>
+ </StackPanel>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </Grid>
+ </DockPanel>
+ </Grid>
+ </DockPanel>
+ </Grid>
+ <Grid DockPanel.Dock="Bottom" Height="70" Background="#F5F6F7">
+ <DockPanel>
+ <Button Style="{x:Null}" BorderBrush="#A8A8A8" Margin="0 0 20 0" DockPanel.Dock="Right" VerticalAlignment="Center" Padding="40 5" x:Name="btnCancel" Click="BtnCancel_Click">Cancel</Button>
+ <Button Style="{x:Null}" Margin="0 0 10 0" IsDefault="True" BorderThickness="2" BorderBrush="#1EB7FF" DockPanel.Dock="Right" VerticalAlignment="Center" Padding="40 5" x:Name="btnSelect" Click="BtnSelect_Click">Select</Button>
+ <Grid>
+
+ </Grid>
+ </DockPanel>
+ </Grid>
+
+ <Grid>
+ <!--<WindowsAPICodePackPresentation:ExplorerBrowser x:Name="explorerBrowser"
+ Margin="-5"
+ BorderThickness="0"
+ AutoArrange="False"
+ CheckSelect="False"
+ ExtendedTiles="False"
+ FullRowSelect="False"
+ HideFileNames="False"
+ NoBrowserViewState="False"
+ NoColumnHeader="False"
+ NoHeaderInAllViews="False"
+ NoIcons="False"
+ NoSubfolders="False"
+ SingleClickActivate="False"
+ SingleSelection="False"
+ AlwaysNavigate="False"
+ NavigateOnce="False"
+ ViewMode="Auto"
+ CommandsPane="Show"
+ CommandsOrganizePane="Show"
+ CommandsViewPane="Show"
+ DetailsPane="Hide"
+ NavigationPane="Show"
+ PreviewPane="Hide"
+ AdvancedQueryPane="Show"
+ QueryPane="Show"/>-->
+
+ <WindowsFormsHost>
+ <WindowsFormsHost.Child>
+ <local:ExplorerControlForms x:Name="explorer">
+
+ </local:ExplorerControlForms>
+ </WindowsFormsHost.Child>
+ </WindowsFormsHost>
+ </Grid>
+ </DockPanel>
+ </Grid>
+</Window>
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml.cs
new file mode 100644
index 000000000..db12a70f1
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlDialog.xaml.cs
@@ -0,0 +1,218 @@
+using Microsoft.WindowsAPICodePack.Controls;
+using Microsoft.WindowsAPICodePack.Shell;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+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.FSE.UI.Storage
+{
+ /// <summary>
+ /// Interaction logic for ExplorerControlWindow.xaml
+ /// </summary>
+ public partial class ExplorerControlDialog : Window
+ {
+ private static string _lastDirectory;
+ private static Point? _lastLocation;
+
+ private string _currentLocation;
+
+ public List<String> SelectedItems { get; set; }
+ public String InitialDirectory { get; set; }
+
+ public ObservableCollection<ShellObject> ShellHistory
+ {
+ get { return (ObservableCollection<ShellObject>)GetValue(ShellHistoryProperty); }
+ set { SetValue(ShellHistoryProperty, value); }
+ }
+ public static readonly DependencyProperty ShellHistoryProperty =
+ DependencyProperty.Register("ShellHistory", typeof(ObservableCollection<ShellObject>), typeof(ExplorerControlDialog), new PropertyMetadata(null));
+
+ public ExplorerControlDialog()
+ {
+ SelectedItems = new List<string>();
+ ShellHistory = new ObservableCollection<ShellObject>();
+
+ InitializeComponent();
+ Loaded += ExplorerControlWindow_Loaded;
+ SourceInitialized += ExplorerControlWindow_SourceInitialized;
+ explorer.browser.SelectionChanged += Browser_SelectionChanged;
+ explorer.browser.NavigationComplete += Browser_NavigationComplete;
+ btnSelect.IsEnabled = false;
+ btnBack.IsEnabled = false;
+ btnForward.IsEnabled = false;
+
+ if (_lastLocation != null)
+ {
+ WindowStartupLocation = WindowStartupLocation.Manual;
+ Left = _lastLocation.Value.X;
+ Top = _lastLocation.Value.Y;
+ }
+ else
+ {
+ WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ }
+ }
+
+ private void FillShellHistory(ShellObject current)
+ {
+ ShellHistory.Clear();
+
+ ShellObject parent = current;
+
+ while (parent != null)
+ {
+ ShellHistory.Insert(0, parent);
+
+ if (parent.ToString() == "This PC") break;
+
+ parent = parent.Parent;
+ }
+ }
+
+ private void Browser_NavigationComplete(object sender, Microsoft.WindowsAPICodePack.Controls.NavigationCompleteEventArgs e)
+ {
+ _currentLocation = e.NewLocation.ParsingName;
+ ShellObject shell = ShellObject.FromParsingName(_currentLocation);
+
+ if (shell.ToString() != "This PC")
+ {
+ btnUp.IsEnabled = true;
+ txtLocation.Text = shell.GetDisplayName(DisplayNameType.FileSystemPath);
+ }
+ else
+ {
+ btnUp.IsEnabled = false;
+ txtLocation.Text = "";
+ }
+
+ FillShellHistory(shell);
+
+ btnBack.IsEnabled = explorer.browser.NavigationLog.CanNavigateBackward;
+ btnForward.IsEnabled = explorer.browser.NavigationLog.CanNavigateForward;
+ }
+
+ private void Browser_SelectionChanged(object sender, EventArgs e)
+ {
+ if (explorer.browser.SelectedItems.OfType<ShellObject>().ToList().Count > 0)
+ {
+ btnSelect.IsEnabled = true;
+ }
+ else
+ {
+ btnSelect.IsEnabled = false;
+ }
+ }
+
+ private void ExplorerControlWindow_SourceInitialized(object sender, EventArgs e)
+ {
+ this.HideMinimizeAndMaximizeButtons();
+ }
+
+ private void ExplorerControlWindow_Loaded(object sender, RoutedEventArgs e)
+ {
+ ShellObject initialShellObject = (ShellObject)KnownFolders.Desktop;
+
+ if (InitialDirectory != null && Directory.Exists(InitialDirectory))
+ {
+ initialShellObject = ShellObject.FromParsingName(InitialDirectory);
+ }
+ else if (_lastDirectory != null && Directory.Exists(_lastDirectory))
+ {
+ initialShellObject = ShellObject.FromParsingName(_lastDirectory);
+ }
+
+ explorer.browser.Navigate(initialShellObject);
+ }
+
+ private void BtnSelect_Click(object sender, RoutedEventArgs e)
+ {
+ SelectedItems.Clear();
+
+ foreach (var item in explorer.browser.SelectedItems.OfType<ShellObject>())
+ {
+ SelectedItems.Add(item.ParsingName);
+ }
+
+ _lastDirectory = _currentLocation;
+ _lastLocation = new Point(Left, Top);
+
+
+ DialogResult = true;
+ Close();
+ }
+
+ private void BtnCancel_Click(object sender, RoutedEventArgs e)
+ {
+ _lastLocation = new Point(Left, Top);
+ Close();
+ }
+
+ private void BtnBack_Click(object sender, RoutedEventArgs e)
+ {
+ explorer.browser.NavigateLogLocation(NavigationLogDirection.Backward);
+ }
+
+ private void BtnForward_Click(object sender, RoutedEventArgs e)
+ {
+ explorer.browser.NavigateLogLocation(NavigationLogDirection.Forward);
+ }
+
+ private void BtnUp_Click(object sender, RoutedEventArgs e)
+ {
+ ShellObject currentLocation = ShellObject.FromParsingName(_currentLocation);
+ explorer.browser.Navigate(currentLocation.Parent);
+ }
+
+ private void TxtLocation_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
+ {
+ listHistory.Visibility = Visibility.Collapsed;
+ }
+
+ private void TxtLocation_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
+ {
+ listHistory.Visibility = Visibility.Visible;
+ }
+
+ private void OnHistoryItemClicked(object sender, RoutedEventArgs e)
+ {
+ ShellObject shell = (sender as Button).DataContext as ShellObject;
+ explorer.browser.Navigate(shell);
+ }
+ }
+
+ internal static class WindowExtensions
+ {
+ // from winuser.h
+ private const int GWL_STYLE = -16,
+ WS_MAXIMIZEBOX = 0x10000,
+ WS_MINIMIZEBOX = 0x20000;
+
+ [DllImport("user32.dll")]
+ extern private static int GetWindowLong(IntPtr hwnd, int index);
+
+ [DllImport("user32.dll")]
+ extern private static int SetWindowLong(IntPtr hwnd, int index, int value);
+
+ internal static void HideMinimizeAndMaximizeButtons(this Window window)
+ {
+ IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
+ var currentStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ SetWindowLong(hwnd, GWL_STYLE, (currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX));
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.cs
new file mode 100644
index 000000000..928baa201
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Tango.FSE.Storage.UI
+{
+ public partial class ExplorerControlForms : UserControl
+ {
+ public ExplorerControlForms()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.designer.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.designer.cs
new file mode 100644
index 000000000..f77fdd5cc
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.designer.cs
@@ -0,0 +1,109 @@
+namespace Tango.FSE.Storage.UI
+{
+ partial class ExplorerControlForms
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.browser = new Microsoft.WindowsAPICodePack.Controls.WindowsForms.ExplorerBrowser();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.panel3 = new System.Windows.Forms.Panel();
+ this.panel4 = new System.Windows.Forms.Panel();
+ this.SuspendLayout();
+ //
+ // browser
+ //
+ this.browser.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.browser.Location = new System.Drawing.Point(0, 0);
+ this.browser.Name = "browser";
+ this.browser.PropertyBagName = "Microsoft.WindowsAPICodePack.Controls.WindowsForms.ExplorerBrowser";
+ this.browser.Size = new System.Drawing.Size(398, 311);
+ this.browser.TabIndex = 1;
+ //
+ // panel1
+ //
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
+ this.panel1.Location = new System.Drawing.Point(0, 0);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(398, 1);
+ this.panel1.TabIndex = 2;
+ //
+ // panel2
+ //
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.panel2.Location = new System.Drawing.Point(0, 310);
+ this.panel2.Margin = new System.Windows.Forms.Padding(0);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(398, 1);
+ this.panel2.TabIndex = 3;
+ //
+ // panel3
+ //
+ this.panel3.BackColor = System.Drawing.Color.White;
+ this.panel3.Dock = System.Windows.Forms.DockStyle.Left;
+ this.panel3.Location = new System.Drawing.Point(0, 1);
+ this.panel3.Margin = new System.Windows.Forms.Padding(0);
+ this.panel3.Name = "panel3";
+ this.panel3.Size = new System.Drawing.Size(1, 309);
+ this.panel3.TabIndex = 4;
+ //
+ // panel4
+ //
+ this.panel4.BackColor = System.Drawing.Color.White;
+ this.panel4.Dock = System.Windows.Forms.DockStyle.Right;
+ this.panel4.Location = new System.Drawing.Point(397, 1);
+ this.panel4.Margin = new System.Windows.Forms.Padding(0);
+ this.panel4.Name = "panel4";
+ this.panel4.Size = new System.Drawing.Size(1, 309);
+ this.panel4.TabIndex = 5;
+ //
+ // ExplorerControlForms
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.panel4);
+ this.Controls.Add(this.panel3);
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.browser);
+ this.Name = "ExplorerControlForms";
+ this.Size = new System.Drawing.Size(398, 311);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ public Microsoft.WindowsAPICodePack.Controls.WindowsForms.ExplorerBrowser browser;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Panel panel2;
+ private System.Windows.Forms.Panel panel3;
+ private System.Windows.Forms.Panel panel4;
+ }
+}
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.resx b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.resx
new file mode 100644
index 000000000..1af7de150
--- /dev/null
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Storage/ExplorerControlForms.resx
@@ -0,0 +1,120 @@
+<?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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <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" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </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" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj
index 12b4c9d45..b4854db5a 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj
@@ -53,6 +53,9 @@
<Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<HintPath>..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
+ <Reference Include="Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Ionic.Zip.1.9.1.8\lib\Ionic.Zip.dll</HintPath>
+ </Reference>
<Reference Include="MahApps.Metro, Version=1.6.5.1, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\MahApps.Metro.1.6.5\lib\net46\MahApps.Metro.dll</HintPath>
</Reference>
@@ -110,6 +113,7 @@
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
+ <Reference Include="WindowsFormsIntegration" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
@@ -169,6 +173,15 @@
<Compile Include="RemoteDesktop\DefaultRemoteDesktopProvider.cs" />
<Compile Include="Resolution\DefaultResolutionService.cs" />
<Compile Include="Storage\DefaultStorageProvider.cs" />
+ <Compile Include="Storage\ExplorerControlDialog.xaml.cs">
+ <DependentUpon>ExplorerControlDialog.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Storage\ExplorerControlForms.cs">
+ <SubType>UserControl</SubType>
+ </Compile>
+ <Compile Include="Storage\ExplorerControlForms.designer.cs">
+ <DependentUpon>ExplorerControlForms.cs</DependentUpon>
+ </Compile>
<Compile Include="SystemInfo\DefaultSystemInfoProvider.cs" />
<Compile Include="Threading\DefaultDispatcherProvider.cs" />
<Compile Include="ViewModelLocator.cs" />
@@ -248,6 +261,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Storage\ExplorerControlDialog.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Views\SettingsView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -299,6 +316,9 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
+ <EmbeddedResource Include="Storage\ExplorerControlForms.resx">
+ <DependentUpon>ExplorerControlForms.cs</DependentUpon>
+ </EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs
index 9ed73afb2..130839534 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LayoutViewVM.cs
@@ -178,7 +178,7 @@ namespace Tango.FSE.UI.ViewModels
private void DiagnosticsProvider_FrameReceived(object sender, Common.Diagnostics.DiagnosticsFrameReceivedEventArgs e)
{
- Debug.WriteLine("Diagnostics Received...");
+ //Debug.WriteLine("Diagnostics Received...");
}
private void Logout()
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/MainView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/MainView.xaml
index 6941b830a..0f16697ad 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/MainView.xaml
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Views/MainView.xaml
@@ -579,6 +579,10 @@
<Setter Property="Foreground" Value="{StaticResource FSE_InfoBrush}"></Setter>
<Setter Property="Kind" Value="InfoOutline"></Setter>
<Style.Triggers>
+ <DataTrigger Binding="{Binding Type}" Value="Question">
+ <Setter Property="Foreground" Value="{StaticResource FSE_InfoBrush}"></Setter>
+ <Setter Property="Kind" Value="QuestionMarkCircleOutline"></Setter>
+ </DataTrigger>
<DataTrigger Binding="{Binding Type}" Value="Warning">
<Setter Property="Foreground" Value="{StaticResource FSE_WarningBrush}"></Setter>
<Setter Property="Kind" Value="AlertOutline"></Setter>
diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config b/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config
index fda2f4d3f..a55bb6f29 100644
--- a/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config
+++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config
@@ -4,6 +4,7 @@
<package id="Dragablz" version="0.0.3.203" targetFramework="net461" />
<package id="EntityFramework" version="6.2.0" targetFramework="net461" />
<package id="Google.Protobuf" version="3.4.1" targetFramework="net461" />
+ <package id="Ionic.Zip" version="1.9.1.8" targetFramework="net461" />
<package id="MahApps.Metro" version="1.6.5" targetFramework="net461" />
<package id="MaterialDesignColors" version="1.2.2" targetFramework="net461" />
<package id="MaterialDesignThemes" version="3.0.1" targetFramework="net461" />
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs
index acdf20fa8..1c0c52196 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs
@@ -34,6 +34,7 @@ namespace Tango.PPC.Common.Connection
private bool _isInitialized;
private Thread _connection_thread;
private ObservablesContext _context;
+ private bool disableConnectionFileLogging;
private Machine _machine;
/// <summary>
@@ -106,11 +107,18 @@ namespace Tango.PPC.Common.Connection
{
if (MachineOperator.State != TransportComponentState.Connected)
{
+ var fileLogger = LogManager.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger));
+
try
{
Thread.Sleep(2000);
- LogManager.Log("Starting machine connection procedure...", LogCategory.Debug);
+ if (fileLogger != null && disableConnectionFileLogging)
+ {
+ fileLogger.Enabled = false;
+ }
+
+ LogManager.Log("Starting machine connection procedure...", LogCategory.Info);
var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
@@ -120,19 +128,19 @@ namespace Tango.PPC.Common.Connection
{
TimeSpan timeout = TimeSpan.FromSeconds(SettingsManager.Default.GetOrCreate<PPCSettings>().MachineScanningTimeoutSeconds);
- LogManager.Log("Scanning for machine on available serial ports...", LogCategory.Debug);
+ LogManager.Log("Scanning for machine on available serial ports...", LogCategory.Info);
Transport.Discovery.UsbCommunicationScanner<ConnectRequest, ConnectResponse> scanner = new Transport.Discovery.UsbCommunicationScanner<ConnectRequest, ConnectResponse>(UsbSerialBaudRates.BR_115200);
var response = await scanner.Scan(new ConnectRequest() { Password = "1234" }, settings.EmbeddedDeviceHint, timeout);
- LogManager.Log("Machine discovered on port: " + response.Adapter.Address, LogCategory.Debug);
+ LogManager.Log("Machine discovered on port: " + response.Adapter.Address, LogCategory.Info);
LogManager.Log("Device Information:", LogCategory.Debug);
- LogManager.Log(response.Response.DeviceInformation.ToJsonString(), LogCategory.Debug);
+ LogManager.Log(response.Response.DeviceInformation.ToJsonString(), LogCategory.Info);
- LogManager.Log("Disconnecting machine operator...", LogCategory.Debug);
+ LogManager.Log("Disconnecting machine operator...", LogCategory.Info);
await MachineOperator.Disconnect();
MachineOperator.Adapter = response.Adapter;
MachineOperator.JobHandlingMode = JobHandlerModes.SettingUp;
- LogManager.Log("Connecting machine operator...", LogCategory.Debug);
+ LogManager.Log("Connecting machine operator...", LogCategory.Info);
try
{
await MachineOperator.Connect();
@@ -142,6 +150,8 @@ namespace Tango.PPC.Common.Connection
settings.FirmwareVersion = MachineOperator.DeviceInformation.Version;
settings.Save();
}
+
+ disableConnectionFileLogging = false;
}
catch (Exception)
{
@@ -156,7 +166,7 @@ namespace Tango.PPC.Common.Connection
}
else
{
- LogManager.Log($"Connecting to machine on {settings.EmbeddedComPort}...", LogCategory.Debug);
+ LogManager.Log($"Connecting to machine on {settings.EmbeddedComPort}...", LogCategory.Info);
UsbTransportAdapter adapter = new UsbTransportAdapter(settings.EmbeddedComPort, UsbSerialBaudRates.BR_115200);
MachineOperator.Adapter = adapter;
@@ -170,6 +180,8 @@ namespace Tango.PPC.Common.Connection
settings.FirmwareVersion = MachineOperator.DeviceInformation.Version;
settings.Save();
}
+
+ disableConnectionFileLogging = false;
}
catch (Exception)
{
@@ -200,6 +212,8 @@ namespace Tango.PPC.Common.Connection
LogManager.Log("Connecting machine operator...");
await MachineOperator.Connect();
+ disableConnectionFileLogging = false;
+
if (MachineOperator.DeviceInformation != null)
{
settings.FirmwareVersion = MachineOperator.DeviceInformation.Version;
@@ -212,7 +226,18 @@ namespace Tango.PPC.Common.Connection
}
catch (Exception ex)
{
- LogManager.Log(ex, LogCategory.Debug, "Error while trying to scan and connect to the machine.");
+ LogManager.Log(ex, "Error while trying to scan and connect to the machine.");
+ LogManager.Log("File logging of further connection attempts is now disabled and will resume when connection is successful.");
+ disableConnectionFileLogging = true;
+ }
+ finally
+ {
+ await Task.Delay(100);
+
+ if (fileLogger != null)
+ {
+ fileLogger.Enabled = true;
+ }
}
}
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs
index edb004344..a7f77855a 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs
@@ -33,6 +33,7 @@ namespace Tango.PPC.Common.FileSystem
public String Id { get; set; }
public String Path { get; set; }
public bool IsPathTempZip { get; set; }
+ public String UploadPostPath { get; set; }
public FileSystemOperation(FileSystemOperationMode mode, String path)
{
@@ -84,6 +85,7 @@ namespace Tango.PPC.Common.FileSystem
webRtcTransporter.ComponentName = "File System Passive WebRTC Transporter";
webRtcTransporter.UseKeepAlive = false;
webRtcTransporter.RegisterRequestHandler<ChunkDownloadRequest>(WebRtcChunkDownloadRequestReceived);
+ webRtcTransporter.RegisterRequestHandler<ChunkUploadRequest>(WebRtcChunkUploadRequestReceived);
await webRtcTransporter.Connect();
await receiver.SendGenericResponse(new InitWebRtcResponse(), token);
_webRtcClients[receiver] = webRtcTransporter;
@@ -99,6 +101,11 @@ namespace Tango.PPC.Common.FileSystem
OnChunkDownloadRequest(request, token, transporter);
}
+ private void WebRtcChunkUploadRequestReceived(ITransporter transporter, ChunkUploadRequest request, string token)
+ {
+ OnChunkUploadRequest(request, token, transporter);
+ }
+
[ExternalBridgeRequestHandlerMethod(typeof(GetFileSystemItemRequest))]
public async void OnGetFileSystemItemRequest(GetFileSystemItemRequest request, String token, ExternalBridgeReceiver receiver)
{
@@ -118,9 +125,10 @@ namespace Tango.PPC.Common.FileSystem
{
try
{
- using (var stream = new FileStream(request.Path, FileMode.Create)) { }
+ var tempFile = TemporaryManager.CreateFile();
+ using (var stream = new FileStream(tempFile, FileMode.Create)) { }
- FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, request.Path);
+ FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path };
_operations.Add(operation.Id, operation);
await receiver.SendGenericResponse(new FileUploadResponse() { OperationId = operation.Id }, token);
@@ -131,6 +139,25 @@ namespace Tango.PPC.Common.FileSystem
}
}
+ [ExternalBridgeRequestHandlerMethod(typeof(FolderUploadRequest))]
+ public async void OnFolderUploadRequest(FolderUploadRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ try
+ {
+ var tempFile = TemporaryManager.CreateFile();
+ using (var stream = new FileStream(tempFile, FileMode.Create)) { }
+
+ FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path, IsPathTempZip = true };
+ _operations.Add(operation.Id, operation);
+
+ await receiver.SendGenericResponse(new FolderUploadResponse() { OperationId = operation.Id }, token);
+ }
+ catch (Exception ex)
+ {
+ await receiver.SendErrorResponse(ex, token);
+ }
+ }
+
[ExternalBridgeRequestHandlerMethod(typeof(FileDownloadRequest))]
public async void OnFileDownloadRequest(FileDownloadRequest request, String token, ExternalBridgeReceiver receiver)
{
@@ -191,7 +218,7 @@ namespace Tango.PPC.Common.FileSystem
}
[ExternalBridgeRequestHandlerMethod(typeof(ChunkUploadRequest))]
- public async void OnChunkUploadRequest(ChunkUploadRequest request, String token, ExternalBridgeReceiver receiver)
+ public async void OnChunkUploadRequest(ChunkUploadRequest request, String token, ITransporter receiver)
{
try
{
@@ -209,6 +236,32 @@ namespace Tango.PPC.Common.FileSystem
stream.Write(request.Data, 0, request.Data.Length);
}
+ if (request.IsCompleted)
+ {
+ if (!operation.IsPathTempZip)
+ {
+ File.Copy(operation.Path, operation.UploadPostPath, true);
+ try
+ {
+ File.Delete(operation.Path);
+ }
+ catch { }
+ }
+ else
+ {
+ using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(operation.Path))
+ {
+ zip.ExtractAll(operation.UploadPostPath, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently);
+ }
+
+ try
+ {
+ File.Delete(operation.Path);
+ }
+ catch { }
+ }
+ }
+
await receiver.SendGenericResponse(new ChunkUploadResponse(), token, new TransportResponseConfig() { Priority = QueuePriority.Low });
}
catch (Exception ex)
@@ -230,12 +283,19 @@ namespace Tango.PPC.Common.FileSystem
}
FileStream stream = null;
+ bool removeTempZipFile = false;
try
{
stream = new FileStream(operation.Path, FileMode.Open);
stream.Position = request.Position;
byte[] data = new byte[Math.Min(request.MaxChunkSize, stream.Length - stream.Position)];
+
+ if (stream.Position + data.Length == stream.Length)
+ {
+ removeTempZipFile = true;
+ }
+
await stream.ReadAsync(data, 0, data.Length);
stream.Dispose();
stream = null;
@@ -249,6 +309,20 @@ namespace Tango.PPC.Common.FileSystem
stream?.Dispose();
await receiver.SendErrorResponse(ex, token);
}
+ finally
+ {
+ if (operation.IsPathTempZip && removeTempZipFile)
+ {
+ try
+ {
+ if (File.Exists(operation.Path))
+ {
+ File.Delete(operation.Path);
+ }
+ }
+ catch { }
+ }
+ }
}
[ExternalBridgeRequestHandlerMethod(typeof(AbortOperationRequest))]
@@ -271,10 +345,6 @@ namespace Tango.PPC.Common.FileSystem
{
File.Delete(operation.Path);
}
- else if (Directory.Exists(operation.Path))
- {
- Directory.Delete(operation.Path, true);
- }
}
else if (operation.IsPathTempZip)
{
@@ -348,6 +418,20 @@ namespace Tango.PPC.Common.FileSystem
}
}
+ [ExternalBridgeRequestHandlerMethod(typeof(PerformDiskSpaceOptimizationRequest))]
+ public async void OnPerformDiskSpaceOptimizationRequest(PerformDiskSpaceOptimizationRequest request, String token, ExternalBridgeReceiver receiver)
+ {
+ try
+ {
+ var deletedBytes = _manager.PerformDiskSpaceOptimization();
+ await receiver.SendGenericResponse(new PerformDiskSpaceOptimizationResponse() { DeletedBytes = deletedBytes }, token);
+ }
+ catch (Exception ex)
+ {
+ await receiver.SendErrorResponse(ex, token);
+ }
+ }
+
public void OnReceiverDisconnected(ExternalBridgeReceiver receiver)
{
if (_webRtcClients.ContainsKey(receiver))
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest b/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest
index d72e75011..efc5f8179 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest
@@ -16,7 +16,7 @@
Remove this element if your application requires this virtualization for backwards
compatibility.
-->
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
+ <!--<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />-->
</requestedPrivileges>
</security>
</trustInfo>
diff --git a/Software/Visual_Studio/Tango.Core/Helpers/FileHelper.cs b/Software/Visual_Studio/Tango.Core/Helpers/FileHelper.cs
index 0b65de64d..8ee0f4b8f 100644
--- a/Software/Visual_Studio/Tango.Core/Helpers/FileHelper.cs
+++ b/Software/Visual_Studio/Tango.Core/Helpers/FileHelper.cs
@@ -16,7 +16,7 @@ namespace Tango.Core.Helpers
long bytes = Math.Abs(fileSize);
int place = System.Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
double num = Math.Round(bytes / Math.Pow(1024, place), 1);
- return (Math.Sign(fileSize) * num).ToString() + suf[place];
+ return (Math.Sign(fileSize) * num).ToString() + " " + suf[place];
}
}
}
diff --git a/Software/Visual_Studio/Tango.FileSystem/FileExplorerControl.cs b/Software/Visual_Studio/Tango.FileSystem/FileExplorerControl.cs
index 3660a18f0..0769b3576 100644
--- a/Software/Visual_Studio/Tango.FileSystem/FileExplorerControl.cs
+++ b/Software/Visual_Studio/Tango.FileSystem/FileExplorerControl.cs
@@ -233,6 +233,22 @@ namespace Tango.FileSystem
public static readonly DependencyProperty RenameCommandInternalProperty =
DependencyProperty.Register("RenameCommandInternal", typeof(ICommand), typeof(FileExplorerControl), new PropertyMetadata(null));
+ public ICommand UploadCommandInternal
+ {
+ get { return (ICommand)GetValue(UploadCommandInternalProperty); }
+ set { SetValue(UploadCommandInternalProperty, value); }
+ }
+ public static readonly DependencyProperty UploadCommandInternalProperty =
+ DependencyProperty.Register("UploadCommandInternal", typeof(ICommand), typeof(FileExplorerControl), new PropertyMetadata(null));
+
+ public ICommand UploadCommand
+ {
+ get { return (ICommand)GetValue(UploadCommandProperty); }
+ set { SetValue(UploadCommandProperty, value); }
+ }
+ public static readonly DependencyProperty UploadCommandProperty =
+ DependencyProperty.Register("UploadCommand", typeof(ICommand), typeof(FileExplorerControl), new PropertyMetadata(null));
+
public bool IsContextMenuOpened
{
get { return (bool)GetValue(IsContextMenuOpenedProperty); }
@@ -395,6 +411,11 @@ namespace Tango.FileSystem
return true;
});
+
+ UploadCommandInternal = new RelayCommand(() =>
+ {
+ UploadCommand?.Execute(null);
+ });
}
private void OnIsContextMenuOpenedChanged()
@@ -408,6 +429,7 @@ namespace Tango.FileSystem
(DeleteCommandInternal as RelayCommand)?.RaiseCanExecuteChanged();
(RenameCommandInternal as RelayCommand)?.RaiseCanExecuteChanged();
(NewFolderCommandInternal as RelayCommand)?.RaiseCanExecuteChanged();
+ (UploadCommandInternal as RelayCommand)?.RaiseCanExecuteChanged();
if (IsContextMenuOpened)
{
@@ -808,6 +830,7 @@ namespace Tango.FileSystem
try
{
+ Debug.WriteLine("Drag Started...");
var ef = DragDrop.DoDragDrop(this, new DataObject(DataFormats.FileDrop, files, false), DragDropEffects.Copy);
}
catch (Exception ex)
@@ -816,6 +839,8 @@ namespace Tango.FileSystem
Debugger.Break();
}
+ Debug.WriteLine("Drag Stopped...");
+
await Task.Delay(3000);
foreach (var watcher in watchers)
@@ -838,6 +863,7 @@ namespace Tango.FileSystem
{
if (IsVisible)
{
+ AllowDrop = true;
await Task.Delay(100);
this.Focus();
Keyboard.Focus(this);
diff --git a/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs b/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs
index 46ca080a2..c08304ca8 100644
--- a/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs
+++ b/Software/Visual_Studio/Tango.FileSystem/FileSystemManager.cs
@@ -7,6 +7,7 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Tango.Core.Helpers;
using Tango.FileSystem.Network;
+using Tango.Logging;
namespace Tango.FileSystem
{
@@ -22,7 +23,7 @@ namespace Tango.FileSystem
{
Path = x.RootDirectory.FullName,
DriveType = x.DriveType,
- DriveLabel = x.Name,
+ DriveLabel = $"{x.VolumeLabel} ({x.Name.Replace("\\", "")})",
Type = FileSystemItemType.Drive,
}).Cast<FileSystemItemDTO>().ToList();
@@ -198,5 +199,61 @@ namespace Tango.FileSystem
Path = fullPath
});
}
+
+ public long PerformDiskSpaceOptimization()
+ {
+ var tempDir = Path.GetTempPath();
+ var logsFolder = FileLogger.DefaultLogsFolder;
+
+ long sizeBefore = GetDirectorySize(new DirectoryInfo(tempDir)) + GetDirectorySize(new DirectoryInfo(logsFolder));
+
+ foreach (var file in Directory.GetFiles(tempDir, "*.*", SearchOption.AllDirectories))
+ {
+ try
+ {
+ FileInfo fileInfo = new FileInfo(file);
+ if (fileInfo.LastWriteTime < DateTime.Now.AddDays(-1))
+ {
+ File.Delete(file);
+ }
+ }
+ catch { }
+ }
+
+ foreach (var file in Directory.GetFiles(logsFolder, "*.*", SearchOption.AllDirectories))
+ {
+ try
+ {
+ FileInfo fileInfo = new FileInfo(file);
+ if (fileInfo.LastWriteTime < DateTime.Now.AddDays(-2))
+ {
+ File.Delete(file);
+ }
+ }
+ catch { }
+ }
+
+ long sizeAfter = GetDirectorySize(new DirectoryInfo(tempDir)) + GetDirectorySize(new DirectoryInfo(logsFolder));
+
+ return Math.Max(sizeBefore - sizeAfter, 0);
+ }
+
+ public static long GetDirectorySize(DirectoryInfo d)
+ {
+ long size = 0;
+ // Add file sizes.
+ FileInfo[] fis = d.GetFiles();
+ foreach (FileInfo fi in fis)
+ {
+ size += fi.Length;
+ }
+ // Add subdirectory sizes.
+ DirectoryInfo[] dis = d.GetDirectories();
+ foreach (DirectoryInfo di in dis)
+ {
+ size += GetDirectorySize(di);
+ }
+ return size;
+ }
}
}
diff --git a/Software/Visual_Studio/Tango.FileSystem/Network/ChunkDownloadRequest.cs b/Software/Visual_Studio/Tango.FileSystem/Network/ChunkDownloadRequest.cs
index 16951930e..caedad88b 100644
--- a/Software/Visual_Studio/Tango.FileSystem/Network/ChunkDownloadRequest.cs
+++ b/Software/Visual_Studio/Tango.FileSystem/Network/ChunkDownloadRequest.cs
@@ -10,6 +10,6 @@ namespace Tango.FileSystem.Network
{
public String OperationId { get; set; }
public long Position { get; set; }
- public long MaxChunkSize { get; set; } = 1024 * 1024;
+ public long MaxChunkSize { get; set; } = 1024 * 10;
}
}
diff --git a/Software/Visual_Studio/Tango.FileSystem/Network/ChunkUploadRequest.cs b/Software/Visual_Studio/Tango.FileSystem/Network/ChunkUploadRequest.cs
index 98a27efd2..ed6b3e45f 100644
--- a/Software/Visual_Studio/Tango.FileSystem/Network/ChunkUploadRequest.cs
+++ b/Software/Visual_Studio/Tango.FileSystem/Network/ChunkUploadRequest.cs
@@ -10,5 +10,6 @@ namespace Tango.FileSystem.Network
{
public String OperationId { get; set; }
public byte[] Data { get; set; }
+ public bool IsCompleted { get; set; }
}
}
diff --git a/Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadRequest.cs b/Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadRequest.cs
new file mode 100644
index 000000000..79a93eff3
--- /dev/null
+++ b/Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadRequest.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.FileSystem.Network
+{
+ public class FolderUploadRequest
+ {
+ public String Path { get; set; }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadResponse.cs b/Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadResponse.cs
new file mode 100644
index 000000000..dc661dc95
--- /dev/null
+++ b/Software/Visual_Studio/Tango.FileSystem/Network/FolderUploadResponse.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.FileSystem.Network
+{
+ public class FolderUploadResponse
+ {
+ public String OperationId { get; set; }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationRequest.cs b/Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationRequest.cs
new file mode 100644
index 000000000..bd69bf9d8
--- /dev/null
+++ b/Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationRequest.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.FileSystem.Network
+{
+ public class PerformDiskSpaceOptimizationRequest
+ {
+ }
+}
diff --git a/Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationResponse.cs b/Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationResponse.cs
new file mode 100644
index 000000000..73cbbf566
--- /dev/null
+++ b/Software/Visual_Studio/Tango.FileSystem/Network/PerformDiskSpaceOptimizationResponse.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.FileSystem.Network
+{
+ public class PerformDiskSpaceOptimizationResponse
+ {
+ public long DeletedBytes { get; set; }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.FileSystem/Tango.FileSystem.csproj b/Software/Visual_Studio/Tango.FileSystem/Tango.FileSystem.csproj
index a31af216c..d78419b7f 100644
--- a/Software/Visual_Studio/Tango.FileSystem/Tango.FileSystem.csproj
+++ b/Software/Visual_Studio/Tango.FileSystem/Tango.FileSystem.csproj
@@ -64,10 +64,14 @@
<Compile Include="Network\CreateFolderResponse.cs" />
<Compile Include="Network\DeleteRequest.cs" />
<Compile Include="Network\DeleteResponse.cs" />
+ <Compile Include="Network\FolderUploadRequest.cs" />
+ <Compile Include="Network\FolderUploadResponse.cs" />
<Compile Include="Network\InitWebRtcRequest.cs" />
<Compile Include="Network\InitWebRtcResponse.cs" />
<Compile Include="Network\MoveRequest.cs" />
<Compile Include="Network\MoveResponse.cs" />
+ <Compile Include="Network\PerformDiskSpaceOptimizationRequest.cs" />
+ <Compile Include="Network\PerformDiskSpaceOptimizationResponse.cs" />
<Compile Include="VirtualFileDataObject.cs" />
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
@@ -131,6 +135,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>
<ProjectReference Include="..\Tango.SharedUI\Tango.SharedUI.csproj">
<Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project>
<Name>Tango.SharedUI</Name>
diff --git a/Software/Visual_Studio/Tango.Transport/Adapters/SignalRTransportAdapter.cs b/Software/Visual_Studio/Tango.Transport/Adapters/SignalRTransportAdapter.cs
index def4cd741..de472d993 100644
--- a/Software/Visual_Studio/Tango.Transport/Adapters/SignalRTransportAdapter.cs
+++ b/Software/Visual_Studio/Tango.Transport/Adapters/SignalRTransportAdapter.cs
@@ -30,7 +30,7 @@ namespace Tango.Transport.Adapters
public String Hub { get; set; }
/// <summary>
- /// Gets or sets the serial number of the remote machine (Use onlt for <see cref="SignalRTransportAdapterMode.CreateSession"/>) mode.
+ /// Gets or sets the serial number of the remote machine (Use only for <see cref="SignalRTransportAdapterMode.CreateSession"/>) mode.
/// </summary>
public String SerialNumber { get; set; }
@@ -66,7 +66,7 @@ namespace Tango.Transport.Adapters
public SignalRTransportAdapter() : base()
{
ConnectionTimeout = TimeSpan.FromSeconds(30);
- WriteInterval = TimeSpan.FromMilliseconds(10);
+ WriteInterval = TimeSpan.FromMilliseconds(1);
ComponentName = $"SignalR Adapter {_component_counter++}";
}
@@ -161,9 +161,10 @@ namespace Tango.Transport.Adapters
{
if (!completed)
{
+ completed = true;
+
LogManager.Log($"SignalR adapter session created ({SessionID})...");
LogManager.Log("SingalR adapter connected.");
- completed = true;
State = TransportComponentState.Connected;
StartPushThread();
@@ -173,8 +174,12 @@ namespace Tango.Transport.Adapters
}
catch (Exception ex)
{
- LogManager.Log(ex, "Error occurred after session created.");
- completionSource.SetException(ex);
+ if (!completed)
+ {
+ LogManager.Log(ex, "Error occurred after session created.");
+ completed = true;
+ completionSource.SetException(ex);
+ }
}
});
}
@@ -211,8 +216,12 @@ namespace Tango.Transport.Adapters
}
catch (Exception ex)
{
- LogManager.Log(ex, "Error occurred on connection state changed event.");
- completionSource.SetException(ex);
+ if (!completed)
+ {
+ completed = true;
+ LogManager.Log(ex, "Error occurred on connection state changed event.");
+ completionSource.SetException(ex);
+ }
}
};
diff --git a/Software/Visual_Studio/Tango.Transport/Adapters/UsbTransportAdapter.cs b/Software/Visual_Studio/Tango.Transport/Adapters/UsbTransportAdapter.cs
index 485eda628..4785e11c8 100644
--- a/Software/Visual_Studio/Tango.Transport/Adapters/UsbTransportAdapter.cs
+++ b/Software/Visual_Studio/Tango.Transport/Adapters/UsbTransportAdapter.cs
@@ -290,7 +290,6 @@ namespace Tango.Transport.Adapters
{
try
{
- LogManager.Log($"Finalizing USB transport adapter ({Address}).");
_serialPort.Close();
_serialPort.Dispose();
}
diff --git a/Software/Visual_Studio/Tango.Transport/ITransportAdapter.cs b/Software/Visual_Studio/Tango.Transport/ITransportAdapter.cs
index d77ad1ed4..1c397aae3 100644
--- a/Software/Visual_Studio/Tango.Transport/ITransportAdapter.cs
+++ b/Software/Visual_Studio/Tango.Transport/ITransportAdapter.cs
@@ -16,6 +16,11 @@ namespace Tango.Transport
public interface ITransportAdapter : ITransportComponent, INotifyPropertyChanged
{
/// <summary>
+ /// Gets the last failed state exception/reason.
+ /// </summary>
+ Exception FailedStateException { get; }
+
+ /// <summary>
/// Gets the total bytes received.
/// </summary>
long TotalBytesReceived { get; }
diff --git a/Software/Visual_Studio/Tango.Transport/TransportAdapterBase.cs b/Software/Visual_Studio/Tango.Transport/TransportAdapterBase.cs
index bdcf0ee64..ebae5855a 100644
--- a/Software/Visual_Studio/Tango.Transport/TransportAdapterBase.cs
+++ b/Software/Visual_Studio/Tango.Transport/TransportAdapterBase.cs
@@ -87,6 +87,10 @@ namespace Tango.Transport
set { _address = value; RaisePropertyChangedAuto(); }
}
+ /// <summary>
+ /// Gets the last failed state exception/reason.
+ /// </summary>
+ public Exception FailedStateException { get; private set; }
private TransportComponentState _state;
/// <summary>
@@ -115,6 +119,7 @@ namespace Tango.Transport
/// <param name="ex">The ex.</param>
protected virtual void OnFailed(Exception ex)
{
+ FailedStateException = ex;
LogManager.Log(ex, $"{ComponentName}: Adapter failed.");
Disconnect().Wait();
State = TransportComponentState.Failed;
diff --git a/Software/Visual_Studio/Tango.Transport/TransporterBase.cs b/Software/Visual_Studio/Tango.Transport/TransporterBase.cs
index 916992bc3..5e076738c 100644
--- a/Software/Visual_Studio/Tango.Transport/TransporterBase.cs
+++ b/Software/Visual_Studio/Tango.Transport/TransporterBase.cs
@@ -241,7 +241,7 @@ namespace Tango.Transport
{
if (e == TransportComponentState.Failed && FailsWithAdapter)
{
- OnFailed(new CommunicationException("The adapter has failed. Going into a failed state..."));
+ OnFailed(new CommunicationException($"The adapter has failed with exception '{Adapter.FailedStateException.Message}' and the transporter is configured to fail with the adapter."));
}
}
@@ -1382,6 +1382,12 @@ namespace Tango.Transport
message.SetResult(true, true);
}
}
+ catch (ThreadAbortException)
+ {
+ Exception requestException = FailedStateException != null ? FailedStateException : new TransporterDisconnectedException("The transporter push thread has been aborted.");
+ OnRequestFailed(message, requestException);
+ message.SetException(requestException);
+ }
catch (Exception ex)
{
OnRequestFailed(message, ex);