added dialog popup on extraction errors.

looks like Ookii.Dialogs have to be replaced with manual progress dialog
implementation, as i have no control over progress dialog window once
extraction has begun.

frankly, i just need to be able to call StopProgressDialog and
StartProgressDialog from IProgressDialog interface, but Ookii does not
provide such low-level access.
This commit is contained in:
morkt 2017-02-01 16:47:48 +04:00
parent 5c9d56c841
commit 154699160b
4 changed files with 190 additions and 41 deletions

20
GUI/FileErrorDialog.xaml Normal file
View File

@ -0,0 +1,20 @@
<w:ModalWindow x:Class="GARbro.GUI.FileErrorDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:Rnd.Windows"
Title="{Binding Title}" ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
ResizeMode="NoResize" SizeToContent="WidthAndHeight"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<StackPanel Orientation="Vertical">
<TextBox x:Name="ErrorText" Text="{Binding Text}" IsReadOnly="True" Background="Transparent" BorderThickness="0" Margin="10"/>
<Separator/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
<CheckBox x:Name="IgnoreErrors" Content="_Ignore further errors" Margin="10" VerticalAlignment="Center"/>
<Button Content="_Continue" Margin="10" Width="75" Height="25" IsDefault="True" Click="ContinueButton_Click"/>
<Button Content="_Abort" Margin="10" Width="75" Height="25" IsCancel="True" Click="AbortButton_Click"/>
</StackPanel>
</StackPanel>
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+C" Command="{Binding CopyCommand}"/>
</Window.InputBindings>
</w:ModalWindow>

View File

@ -0,0 +1,76 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace GARbro.GUI
{
/// <summary>
/// Interaction logic for FileErrorDialog.xaml
/// </summary>
public partial class FileErrorDialog : Rnd.Windows.ModalWindow
{
public FileErrorDialog (string title, string error_text)
{
InitializeComponent();
this.DataContext = new ViewModel { Title = title, Text = error_text };
}
private void ContinueButton_Click (object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
private void AbortButton_Click (object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
private class ViewModel
{
public string Title { get; set; }
public string Text { get; set; }
public ICommand CopyCommand { get; private set; }
public ViewModel ()
{
CopyCommand = new ActionCommand (CopyText);
}
private void CopyText ()
{
try
{
Clipboard.SetText (Text);
}
catch (Exception X)
{
System.Diagnostics.Trace.WriteLine (X.Message, "Clipboard error");
}
}
}
private class ActionCommand : ICommand
{
readonly Action m_action;
public ActionCommand (Action action)
{
m_action = action;
}
public void Execute (object parameter)
{
m_action();
}
public bool CanExecute (object parameter)
{
return true;
}
#pragma warning disable 67
public event EventHandler CanExecuteChanged;
}
}
}

View File

@ -147,6 +147,9 @@
<Compile Include="ExtractFile.xaml.cs"> <Compile Include="ExtractFile.xaml.cs">
<DependentUpon>ExtractFile.xaml</DependentUpon> <DependentUpon>ExtractFile.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="FileErrorDialog.xaml.cs">
<DependentUpon>FileErrorDialog.xaml</DependentUpon>
</Compile>
<Compile Include="GarConvert.cs" /> <Compile Include="GarConvert.cs" />
<Compile Include="GarCreate.cs" /> <Compile Include="GarCreate.cs" />
<Compile Include="GarExtract.cs" /> <Compile Include="GarExtract.cs" />
@ -195,6 +198,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="FileErrorDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>

View File

@ -28,13 +28,13 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Runtime.InteropServices;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Ookii.Dialogs.Wpf; using Ookii.Dialogs.Wpf;
using GameRes; using GameRes;
using GameRes.Strings;
using GARbro.GUI.Strings; using GARbro.GUI.Strings;
using GARbro.GUI.Properties; using GARbro.GUI.Properties;
@ -116,6 +116,7 @@ namespace GARbro.GUI
private bool m_convert_audio; private bool m_convert_audio;
private ImageFormat m_image_format; private ImageFormat m_image_format;
private int m_extract_count; private int m_extract_count;
private int m_skip_count;
private bool m_extract_in_progress = false; private bool m_extract_in_progress = false;
private ProgressDialog m_progress_dialog; private ProgressDialog m_progress_dialog;
private Exception m_pending_error; private Exception m_pending_error;
@ -269,7 +270,6 @@ namespace GARbro.GUI
m_progress_dialog.ProgressBarStyle = ProgressBarStyle.MarqueeProgressBar; m_progress_dialog.ProgressBarStyle = ProgressBarStyle.MarqueeProgressBar;
} }
m_convert_audio = !m_skip_audio && Settings.Default.appConvertAudio; m_convert_audio = !m_skip_audio && Settings.Default.appConvertAudio;
m_extract_count = 0;
m_pending_error = null; m_pending_error = null;
m_progress_dialog.DoWork += (s, e) => ExtractWorker (file_list); m_progress_dialog.DoWork += (s, e) => ExtractWorker (file_list);
m_progress_dialog.RunWorkerCompleted += OnExtractComplete; m_progress_dialog.RunWorkerCompleted += OnExtractComplete;
@ -279,16 +279,20 @@ namespace GARbro.GUI
void ExtractWorker (IEnumerable<Entry> file_list) void ExtractWorker (IEnumerable<Entry> file_list)
{ {
try m_extract_count = 0;
m_skip_count = 0;
var arc = m_fs.Source;
int total = file_list.Count();
int progress_count = 0;
bool ignore_errors = false;
foreach (var entry in file_list)
{ {
var arc = m_fs.Source; if (m_progress_dialog.CancellationPending)
int total = file_list.Count(); break;
foreach (var entry in file_list) if (total > 1)
m_progress_dialog.ReportProgress (progress_count++*100/total, null, entry.Name);
try
{ {
if (m_progress_dialog.CancellationPending)
break;
if (total > 1)
m_progress_dialog.ReportProgress (m_extract_count*100/total, null, entry.Name);
if (null != m_image_format && entry.Type == "image") if (null != m_image_format && entry.Type == "image")
ExtractImage (arc, entry, m_image_format); ExtractImage (arc, entry, m_image_format);
else if (m_convert_audio && entry.Type == "audio") else if (m_convert_audio && entry.Type == "audio")
@ -297,43 +301,85 @@ namespace GARbro.GUI
arc.Extract (entry); arc.Extract (entry);
++m_extract_count; ++m_extract_count;
} }
catch (Exception X)
{
if (!ignore_errors)
{
IntPtr progress_handle = IntPtr.Zero;
try
{
var error_text = string.Format ("{0}\n{1}\n{2}", "Failed to extract file",
entry.Name, X.Message);
bool dialog_result = false;
m_main.Dispatcher.Invoke (() => {
progress_handle = HideProgressDialog();
var dialog = new FileErrorDialog ("File extraction error", error_text);
dialog.Owner = m_main;
dialog_result = dialog.ShowDialog() ?? false;
ignore_errors = dialog.IgnoreErrors.IsChecked ?? false;
});
if (!dialog_result)
break;
}
finally
{
if (progress_handle != IntPtr.Zero)
ShowWindow (progress_handle, SW_SHOW);
}
}
++m_skip_count;
}
} }
catch (Exception X) }
{
m_pending_error = X; const int SW_HIDE = 0;
} const int SW_SHOW = 5;
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx (IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow (IntPtr hWnd, int nCmdShow);
IntPtr HideProgressDialog ()
{
// IntPtr parent = new WindowInteropHelper (m_main).Handle;
// var found = FindWindowEx (parent, IntPtr.Zero, null, m_progress_dialog.WindowTitle);
var found = FindWindowEx (IntPtr.Zero, IntPtr.Zero, null, m_progress_dialog.WindowTitle);
if (IntPtr.Zero != found)
ShowWindow (found, SW_HIDE);
return found;
}
bool ShowErrorDialog (string error_text)
{
var dialog = new FileErrorDialog ("File extraction error", error_text);
dialog.Owner = m_main;
return dialog.ShowDialog() ?? false;
} }
void ExtractImage (ArcFile arc, Entry entry, ImageFormat target_format) void ExtractImage (ArcFile arc, Entry entry, ImageFormat target_format)
{ {
try using (var decoder = arc.OpenImage (entry))
{ {
using (var decoder = arc.OpenImage (entry)) var src_format = decoder.SourceFormat; // could be null
string target_ext = target_format.Extensions.FirstOrDefault() ?? "";
string outname = FindUniqueFileName (entry.Name, target_ext);
if (src_format == target_format)
{ {
var src_format = decoder.SourceFormat; // could be null // source format is the same as a target, copy file as is
string target_ext = target_format.Extensions.FirstOrDefault() ?? ""; using (var output = ArchiveFormat.CreateFile (outname))
string outname = FindUniqueFileName (entry.Name, target_ext); decoder.Source.CopyTo (output);
if (src_format == target_format) return;
{ }
// source format is the same as a target, copy file as is ImageData image = decoder.Image;
using (var output = ArchiveFormat.CreateFile (outname)) if (m_adjust_image_offset)
decoder.Source.CopyTo (output); {
return; image = AdjustImageOffset (image);
} }
ImageData image = decoder.Image; using (var outfile = ArchiveFormat.CreateFile (outname))
if (m_adjust_image_offset) {
{ target_format.Write (outfile, image);
image = AdjustImageOffset (image);
}
using (var outfile = ArchiveFormat.CreateFile (outname))
{
target_format.Write (outfile, image);
}
} }
}
catch
{
throw new InvalidFormatException (string.Format ("{1}: {0}", guiStrings.MsgUnableInterpretImage, entry.Name));
} }
} }
@ -372,7 +418,7 @@ namespace GARbro.GUI
using (var sound = AudioFormat.Read (file)) using (var sound = AudioFormat.Read (file))
{ {
if (null == sound) if (null == sound)
throw new InvalidFormatException (string.Format ("{1}: {0}", guiStrings.MsgUnableInterpretAudio, entry.Name)); throw new InvalidFormatException (guiStrings.MsgUnableInterpretAudio);
ConvertAudio (entry.Name, sound); ConvertAudio (entry.Name, sound);
} }
} }