async archive loading

This commit is contained in:
Paddy Xu
2017-12-22 13:19:49 +02:00
parent dedac98702
commit 97b749e64f
5 changed files with 157 additions and 55 deletions

View File

@@ -46,7 +46,7 @@ namespace QuickLook.Plugin.ArchiveViewer
{ {
treeGrid.DataContext = context; treeGrid.DataContext = context;
treeView.Loaded += (sender, e) => treeView.LayoutUpdated += (sender, e) =>
{ {
// return when empty // return when empty
if (treeView.Items.Count == 0) if (treeView.Items.Count == 0)

View File

@@ -7,7 +7,27 @@
mc:Ignorable="d" mc:Ignorable="d"
x:Name="infoPanel" x:Name="infoPanel"
d:DesignHeight="600" d:DesignWidth="800"> d:DesignHeight="600" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- only for design -->
<ResourceDictionary Source="/QuickLook;component/Styles/MainWindowStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
<local:Percent100ToVisibilityVisibleConverter x:Key="Percent100ToVisibilityVisibleConverter" />
<local:Percent100ToVisibilityCollapsedConverter x:Key="Percent100ToVisibilityCollapsedConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid> <Grid>
<Grid ZIndex="9999"
Visibility="{Binding ElementName=infoPanel, Path=LoadPercent, Mode=OneWay, Converter={StaticResource Percent100ToVisibilityCollapsedConverter}}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Label FontSize="14" HorizontalAlignment="Center">Loading archive ...</Label>
<ProgressBar Height="13" Width="150"
Value="{Binding ElementName=infoPanel, Path=LoadPercent, Mode=OneWay}" />
</StackPanel>
</Grid>
<Grid
Visibility="{Binding ElementName=infoPanel, Path=LoadPercent, Mode=OneWay, Converter={StaticResource Percent100ToVisibilityVisibleConverter}}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition Height="30" /> <RowDefinition Height="30" />
@@ -19,9 +39,10 @@
<ColumnDefinition Width="30*" /> <ColumnDefinition Width="30*" />
<ColumnDefinition Width="30*" /> <ColumnDefinition Width="30*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label x:Name="archiveCount" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center">9 folders and 10 files, solid, password-protected</Label> <Label x:Name="archiveCount" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center">0 folders and 0 files, solid, password-protected</Label>
<Label x:Name="archiveSizeC" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">Compressed size 9999 bytes</Label> <Label x:Name="archiveSizeC" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">Compressed size 0 bytes</Label>
<Label x:Name="archiveSizeU" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center">Uncompressed size 99999 bytes</Label> <Label x:Name="archiveSizeU" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center">Uncompressed size 0 bytes</Label>
</Grid>
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -17,9 +17,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Controls; using System.Windows.Controls;
using QuickLook.Annotations;
using QuickLook.ExtensionMethods; using QuickLook.ExtensionMethods;
using SharpCompress.Archives; using SharpCompress.Archives;
using SharpCompress.Common; using SharpCompress.Common;
@@ -30,9 +34,11 @@ namespace QuickLook.Plugin.ArchiveViewer
/// <summary> /// <summary>
/// Interaction logic for ArchiveInfoPanel.xaml /// Interaction logic for ArchiveInfoPanel.xaml
/// </summary> /// </summary>
public partial class ArchiveInfoPanel : UserControl, IDisposable public partial class ArchiveInfoPanel : UserControl, IDisposable, INotifyPropertyChanged
{ {
private readonly Dictionary<string, ArchiveFileEntry> _fileEntries = new Dictionary<string, ArchiveFileEntry>(); private readonly Dictionary<string, ArchiveFileEntry> _fileEntries = new Dictionary<string, ArchiveFileEntry>();
private bool _disposed;
private double _loadPercent;
private ulong _totalZippedSize; private ulong _totalZippedSize;
private string _type; private string _type;
@@ -40,28 +46,48 @@ namespace QuickLook.Plugin.ArchiveViewer
{ {
InitializeComponent(); InitializeComponent();
LoadArchive(path); // design-time only
Resources.MergedDictionaries.Clear();
fileListView.SetDataContext(_fileEntries[""].Children.Keys); BeginLoadArchive(path);
}
public double LoadPercent
{
get => _loadPercent;
private set
{
if (value == _loadPercent) return;
_loadPercent = value;
OnPropertyChanged();
}
} }
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
_fileEntries.Clear(); _disposed = true;
fileListView.Dispose(); fileListView.Dispose();
} }
public event PropertyChangedEventHandler PropertyChanged;
~ArchiveInfoPanel() ~ArchiveInfoPanel()
{ {
Dispose(); Dispose();
} }
private void LoadArchive(string path) private void BeginLoadArchive(string path)
{
new Task(() =>
{ {
_totalZippedSize = (ulong) new FileInfo(path).Length; _totalZippedSize = (ulong) new FileInfo(path).Length;
var root = new ArchiveFileEntry(Path.GetFileName(path), true);
_fileEntries.Add("", root);
LoadItemsFromArchive(path); LoadItemsFromArchive(path);
var folders = -1; // do not count root node var folders = -1; // do not count root node
@@ -87,11 +113,21 @@ namespace QuickLook.Plugin.ArchiveViewer
else else
t = $", {d}{f}"; t = $", {d}{f}";
Dispatcher.Invoke(() =>
{
if (_disposed)
return;
fileListView.SetDataContext(_fileEntries[""].Children.Keys);
archiveCount.Content = archiveCount.Content =
$"{_type} archive{t}"; $"{_type} archive{t}";
archiveSizeC.Content = archiveSizeC.Content =
$"Compressed size {((long) _totalZippedSize).ToPrettySize(2)}"; $"Compressed size {((long) _totalZippedSize).ToPrettySize(2)}";
archiveSizeU.Content = $"Uncompressed size {((long) sizeU).ToPrettySize(2)}"; archiveSizeU.Content = $"Uncompressed size {((long) sizeU).ToPrettySize(2)}";
});
LoadPercent = 100d;
}).Start();
} }
private void LoadItemsFromArchive(string path) private void LoadItemsFromArchive(string path)
@@ -107,26 +143,30 @@ namespace QuickLook.Plugin.ArchiveViewer
_type = reader.ArchiveType.ToString(); _type = reader.ArchiveType.ToString();
var root = new ArchiveFileEntry(Path.GetFileName(path), true);
_fileEntries.Add("", root);
while (reader.MoveToNextEntry()) while (reader.MoveToNextEntry())
{
if (_disposed)
return;
LoadPercent = 100d * stream.Position / stream.Length;
ProcessByLevel(reader.Entry); ProcessByLevel(reader.Entry);
} }
}
else else
{ {
var archive = ArchiveFactory.Open(stream, new ChardetReaderOptions()); var archive = ArchiveFactory.Open(stream, new ChardetReaderOptions());
_type = archive.Type.ToString(); _type = archive.Type.ToString();
var root = new ArchiveFileEntry(Path.GetFileName(path), true);
_fileEntries.Add("", root);
foreach (var entry in archive.Entries) foreach (var entry in archive.Entries)
{
if (_disposed)
return;
LoadPercent = 100d * stream.Position / stream.Length;
ProcessByLevel(entry); ProcessByLevel(entry);
} }
} }
} }
}
private void ProcessByLevel(IEntry entry) private void ProcessByLevel(IEntry entry)
{ {
@@ -140,7 +180,7 @@ namespace QuickLook.Plugin.ArchiveViewer
if (_fileEntries.ContainsKey(f)) if (_fileEntries.ContainsKey(f))
return; return;
_fileEntries.TryGetValue(GetDirectoryName(f), out ArchiveFileEntry parent); _fileEntries.TryGetValue(GetDirectoryName(f), out var parent);
var afe = new ArchiveFileEntry(Path.GetFileName(f), true, parent); var afe = new ArchiveFileEntry(Path.GetFileName(f), true, parent);
@@ -152,7 +192,7 @@ namespace QuickLook.Plugin.ArchiveViewer
{ {
var file = pf.Last(); var file = pf.Last();
_fileEntries.TryGetValue(GetDirectoryName(file), out ArchiveFileEntry parent); _fileEntries.TryGetValue(GetDirectoryName(file), out var parent);
_fileEntries.Add(file, new ArchiveFileEntry(Path.GetFileName(entry.Key), false, parent) _fileEntries.Add(file, new ArchiveFileEntry(Path.GetFileName(entry.Key), false, parent)
{ {
@@ -179,5 +219,11 @@ namespace QuickLook.Plugin.ArchiveViewer
return frags.Select((s, i) => frags.Take(i + 1).Aggregate((a, b) => a + "\\" + b)).ToArray(); return frags.Select((s, i) => frags.Take(i + 1).Aggregate((a, b) => a + "\\" + b)).ToArray();
} }
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
} }
} }

View File

@@ -23,6 +23,40 @@ using QuickLook.ExtensionMethods;
namespace QuickLook.Plugin.ArchiveViewer namespace QuickLook.Plugin.ArchiveViewer
{ {
public class Percent100ToVisibilityVisibleConverter : DependencyObject, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
value = 0;
var percent = (double) value;
return Math.Abs(percent - 100) < 0.00001 ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class Percent100ToVisibilityCollapsedConverter : DependencyObject, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
value = 0;
var percent = (double) value;
return Math.Abs(percent - 100) < 0.00001 ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class LevelToIndentConverter : DependencyObject, IMultiValueConverter public class LevelToIndentConverter : DependencyObject, IMultiValueConverter
{ {
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="SharpCompress" version="0.18.2" targetFramework="net462" /> <package id="SharpCompress" version="0.18.2" targetFramework="net462" />
<package id="UTF.Unknown" version="1.0.0-beta1" targetFramework="net462" /> <package id="UTF.Unknown" version="1.0.0-beta1" targetFramework="net462" />