mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 15:44:00 +08:00
Merge remote-tracking branch 'refs/remotes/origin/gui-dialogs'
This commit is contained in:
commit
85c9468f08
25
GUI/FileErrorDialog.xaml
Normal file
25
GUI/FileErrorDialog.xaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<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"
|
||||||
|
xmlns:s="clr-namespace:GARbro.GUI.Strings"
|
||||||
|
Title="{Binding Title}" ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||||
|
ResizeMode="NoResize" SizeToContent="WidthAndHeight" ShowActivated="True"
|
||||||
|
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Image Source="Images/64x64/alert.png" Width="64" Height="64" Margin="10"
|
||||||
|
SnapsToDevicePixels="True" VerticalAlignment="Top" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBox x:Name="ErrorText" Text="{Binding Text}" IsReadOnly="True" Background="Transparent" BorderThickness="0" Margin="0,10,10,10"/>
|
||||||
|
<Separator/>
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||||
|
<CheckBox x:Name="IgnoreErrors" Content="{x:Static s:guiStrings.LabelIgnoreErrors}" Margin="0,10,10,10" VerticalAlignment="Center"/>
|
||||||
|
<Button Content="{x:Static s:guiStrings.ButtonContinue}" Margin="10" MinWidth="75" Height="25" IsDefault="True" Click="ContinueButton_Click"/>
|
||||||
|
<Button Content="{x:Static s:guiStrings.ButtonAbort}" Margin="10" MinWidth="75" Height="25" IsCancel="True" Click="AbortButton_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
<Window.InputBindings>
|
||||||
|
<KeyBinding Gesture="Ctrl+C" Command="{Binding CopyCommand}"/>
|
||||||
|
</Window.InputBindings>
|
||||||
|
</w:ModalWindow>
|
92
GUI/FileErrorDialog.xaml.cs
Normal file
92
GUI/FileErrorDialog.xaml.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
new public FileErrorDialogResult ShowDialog ()
|
||||||
|
{
|
||||||
|
bool dialog_result = base.ShowDialog() ?? false;
|
||||||
|
return new FileErrorDialogResult
|
||||||
|
{
|
||||||
|
Continue = dialog_result,
|
||||||
|
IgnoreErrors = IgnoreErrors.IsChecked ?? false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct FileErrorDialogResult
|
||||||
|
{
|
||||||
|
public bool Continue;
|
||||||
|
public bool IgnoreErrors;
|
||||||
|
}
|
||||||
|
}
|
25
GUI/FileExistsDialog.xaml
Normal file
25
GUI/FileExistsDialog.xaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<w:ModalWindow x:Class="GARbro.GUI.FileExistsDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:w="clr-namespace:Rnd.Windows"
|
||||||
|
xmlns:s="clr-namespace:GARbro.GUI.Strings"
|
||||||
|
Title="File already exists" ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||||
|
ResizeMode="NoResize" SizeToContent="WidthAndHeight" ShowActivated="True"
|
||||||
|
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Image Source="Images/64x64/actions.png" Width="64" Height="64" Margin="10"
|
||||||
|
SnapsToDevicePixels="True" VerticalAlignment="Top" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock x:Name="Notice" Text="File named {0} already exists in destination folder." Margin="0,10,10,10"/>
|
||||||
|
<TextBlock Text="{x:Static s:guiStrings.LabelDuplicateFileQuestion}" Margin="0,0,10,10"/>
|
||||||
|
<Separator/>
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||||
|
<Button Content="{x:Static s:guiStrings.ButtonSkip}" Margin="0,10,10,10" MinWidth="75" Height="25" IsDefault="True" Click="SkipButton_Click"/>
|
||||||
|
<Button Content="{x:Static s:guiStrings.ButtonOverwrite}" Margin="10" MinWidth="75" Height="25" Click="OverwriteButton_Click"/>
|
||||||
|
<Button Content="{x:Static s:guiStrings.ButtonRename}" Margin="10" MinWidth="75" Height="25" Click="RenameButton_Click"/>
|
||||||
|
<Button Content="{x:Static s:guiStrings.ButtonAbort}" Margin="10" MinWidth="75" Height="25" IsCancel="True" Click="AbortButton_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox x:Name="ApplyToAll" Content="{x:Static s:guiStrings.LabelApplyToAll}" Margin="0,10,10,10"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</w:ModalWindow>
|
72
GUI/FileExistsDialog.xaml.cs
Normal file
72
GUI/FileExistsDialog.xaml.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace GARbro.GUI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for FileExistsDialog.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class FileExistsDialog : Rnd.Windows.ModalWindow
|
||||||
|
{
|
||||||
|
public FileExistsDialog (string title, string text)
|
||||||
|
{
|
||||||
|
InitializeComponent ();
|
||||||
|
this.Title = title;
|
||||||
|
this.Notice.Text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
new public FileExistsDialogResult ShowDialog ()
|
||||||
|
{
|
||||||
|
bool dialog_result = base.ShowDialog() ?? false;
|
||||||
|
if (!dialog_result)
|
||||||
|
FileAction = ExistingFileAction.Abort;
|
||||||
|
return new FileExistsDialogResult
|
||||||
|
{
|
||||||
|
Action = FileAction,
|
||||||
|
ApplyToAll = ApplyToAll.IsChecked ?? false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExistingFileAction FileAction { get; set; }
|
||||||
|
|
||||||
|
private void SkipButton_Click (object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.DialogResult = true;
|
||||||
|
this.FileAction = ExistingFileAction.Skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OverwriteButton_Click (object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.DialogResult = true;
|
||||||
|
this.FileAction = ExistingFileAction.Overwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameButton_Click (object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.DialogResult = true;
|
||||||
|
this.FileAction = ExistingFileAction.Rename;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AbortButton_Click (object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.DialogResult = false;
|
||||||
|
this.FileAction = ExistingFileAction.Abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ExistingFileAction
|
||||||
|
{
|
||||||
|
Skip,
|
||||||
|
Overwrite,
|
||||||
|
Rename,
|
||||||
|
Abort
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct FileExistsDialogResult
|
||||||
|
{
|
||||||
|
public ExistingFileAction Action;
|
||||||
|
public bool ApplyToAll;
|
||||||
|
}
|
||||||
|
}
|
@ -95,9 +95,6 @@
|
|||||||
<HintPath>..\packages\NAudio.1.8.0\lib\net35\NAudio.dll</HintPath>
|
<HintPath>..\packages\NAudio.1.8.0\lib\net35\NAudio.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Ookii.Dialogs.Wpf">
|
|
||||||
<HintPath>..\packages\Ookii.Dialogs.1.0\lib\net35\Ookii.Dialogs.Wpf.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Windows.Controls.Input.Toolkit">
|
<Reference Include="System.Windows.Controls.Input.Toolkit">
|
||||||
@ -147,14 +144,25 @@
|
|||||||
<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="FileExistsDialog.xaml.cs">
|
||||||
|
<DependentUpon>FileExistsDialog.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" />
|
||||||
|
<Compile Include="GarOperation.cs" />
|
||||||
<Compile Include="HistoryStack.cs" />
|
<Compile Include="HistoryStack.cs" />
|
||||||
<Compile Include="ImagePreview.cs" />
|
<Compile Include="ImagePreview.cs" />
|
||||||
<Compile Include="ListViewEx.cs" />
|
<Compile Include="ListViewEx.cs" />
|
||||||
<Compile Include="ModalWindow.cs" />
|
<Compile Include="ModalWindow.cs" />
|
||||||
<Compile Include="NAudio.cs" />
|
<Compile Include="NAudio.cs" />
|
||||||
|
<Compile Include="ProgressDialog\IProgressDialog.cs" />
|
||||||
|
<Compile Include="ProgressDialog\ProgressDialog.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Settings.cs" />
|
<Compile Include="Settings.cs" />
|
||||||
<Compile Include="Shell.cs" />
|
<Compile Include="Shell.cs" />
|
||||||
<Compile Include="Strings\guiStrings.Designer.cs">
|
<Compile Include="Strings\guiStrings.Designer.cs">
|
||||||
@ -195,6 +203,14 @@
|
|||||||
<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="FileExistsDialog.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>
|
||||||
@ -284,6 +300,12 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="Images\Cursors\grabbing.cur" />
|
<Resource Include="Images\Cursors\grabbing.cur" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="Images\64x64\actions.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="Images\64x64\alert.png" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PreBuildEvent>perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName) "$(SolutionDir)\"
|
<PreBuildEvent>perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName) "$(SolutionDir)\"
|
||||||
|
@ -34,7 +34,6 @@ using System.Diagnostics;
|
|||||||
using GameRes;
|
using GameRes;
|
||||||
using GARbro.GUI.Strings;
|
using GARbro.GUI.Strings;
|
||||||
using GARbro.GUI.Properties;
|
using GARbro.GUI.Properties;
|
||||||
using Ookii.Dialogs.Wpf;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace GARbro.GUI
|
namespace GARbro.GUI
|
||||||
@ -107,21 +106,17 @@ namespace GARbro.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class GarConvertMedia
|
internal class GarConvertMedia : GarOperation
|
||||||
{
|
{
|
||||||
private MainWindow m_main;
|
|
||||||
private ProgressDialog m_progress_dialog;
|
|
||||||
private IEnumerable<Entry> m_source;
|
private IEnumerable<Entry> m_source;
|
||||||
private ImageFormat m_image_format;
|
private ImageFormat m_image_format;
|
||||||
private Exception m_pending_error;
|
|
||||||
private List<Tuple<string,string>> m_failed = new List<Tuple<string,string>>();
|
private List<Tuple<string,string>> m_failed = new List<Tuple<string,string>>();
|
||||||
|
|
||||||
public bool IgnoreErrors { get; set; }
|
public bool IgnoreErrors { get; set; }
|
||||||
public IEnumerable<Tuple<string,string>> FailedFiles { get { return m_failed; } }
|
public IEnumerable<Tuple<string,string>> FailedFiles { get { return m_failed; } }
|
||||||
|
|
||||||
public GarConvertMedia (MainWindow parent)
|
public GarConvertMedia (MainWindow parent) : base (parent, guiStrings.TextMediaConvertError)
|
||||||
{
|
{
|
||||||
m_main = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Convert (IEnumerable<Entry> images, ImageFormat format)
|
public void Convert (IEnumerable<Entry> images, ImageFormat format)
|
||||||
@ -144,14 +139,15 @@ namespace GARbro.GUI
|
|||||||
void ConvertWorker (object sender, DoWorkEventArgs e)
|
void ConvertWorker (object sender, DoWorkEventArgs e)
|
||||||
{
|
{
|
||||||
m_pending_error = null;
|
m_pending_error = null;
|
||||||
try
|
|
||||||
{
|
|
||||||
int total = m_source.Count();
|
int total = m_source.Count();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (var entry in m_source)
|
foreach (var entry in m_source)
|
||||||
{
|
{
|
||||||
if (m_progress_dialog.CancellationPending)
|
if (m_progress_dialog.CancellationPending)
|
||||||
throw new OperationCanceledException();
|
{
|
||||||
|
m_pending_error = new OperationCanceledException();
|
||||||
|
break;
|
||||||
|
}
|
||||||
var filename = entry.Name;
|
var filename = entry.Name;
|
||||||
int progress = i++*100/total;
|
int progress = i++*100/total;
|
||||||
m_progress_dialog.ReportProgress (progress, string.Format (guiStrings.MsgConvertingFile,
|
m_progress_dialog.ReportProgress (progress, string.Format (guiStrings.MsgConvertingFile,
|
||||||
@ -163,25 +159,29 @@ namespace GARbro.GUI
|
|||||||
else if ("audio" == entry.Type)
|
else if ("audio" == entry.Type)
|
||||||
ConvertAudio (filename);
|
ConvertAudio (filename);
|
||||||
}
|
}
|
||||||
catch (NotImplementedException X)
|
catch (SkipExistingFileException)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException X)
|
||||||
{
|
{
|
||||||
// target format creation not implemented
|
|
||||||
m_pending_error = X;
|
m_pending_error = X;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (Exception X)
|
catch (Exception X)
|
||||||
{
|
{
|
||||||
if (!IgnoreErrors)
|
if (!IgnoreErrors)
|
||||||
throw;
|
{
|
||||||
|
var error_text = string.Format (guiStrings.TextErrorConverting, entry.Name, X.Message);
|
||||||
|
var result = ShowErrorDialog (error_text);
|
||||||
|
if (!result.Continue)
|
||||||
|
break;
|
||||||
|
IgnoreErrors = result.IgnoreErrors;
|
||||||
|
}
|
||||||
m_failed.Add (Tuple.Create (Path.GetFileName (filename), X.Message));
|
m_failed.Add (Tuple.Create (Path.GetFileName (filename), X.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception X)
|
|
||||||
{
|
|
||||||
m_pending_error = X;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly HashSet<string> CommonAudioFormats = new HashSet<string> { "wav", "mp3", "ogg" };
|
public static readonly HashSet<string> CommonAudioFormats = new HashSet<string> { "wav", "mp3", "ogg" };
|
||||||
|
|
||||||
@ -232,41 +232,20 @@ namespace GARbro.GUI
|
|||||||
return;
|
return;
|
||||||
file.Position = 0;
|
file.Position = 0;
|
||||||
var image = src_format.Item1.Read (file, src_format.Item2);
|
var image = src_format.Item1.Read (file, src_format.Item2);
|
||||||
|
var output = CreateNewFile (target_name);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var output = CreateNewFile (target_name))
|
|
||||||
m_image_format.Write (output, image);
|
m_image_format.Write (output, image);
|
||||||
}
|
}
|
||||||
catch // delete destination file on conversion failure
|
catch // delete destination file on conversion failure
|
||||||
{
|
{
|
||||||
|
// FIXME if user chooses to overwrite file, and conversion results in error,
|
||||||
|
// then original file will be lost.
|
||||||
|
output.Dispose();
|
||||||
File.Delete (target_name);
|
File.Delete (target_name);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
output.Dispose();
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates new file with specified filename, or, if it's already exists, tries to open
|
|
||||||
/// files named "FILENAME.1.EXT", "FILENAME.2.EXT" and so on.
|
|
||||||
/// <exception cref="System.IOException">Throws exception after 100th failed attempt.</exception>
|
|
||||||
/// </summary>
|
|
||||||
|
|
||||||
public static Stream CreateNewFile (string filename)
|
|
||||||
{
|
|
||||||
string name = filename;
|
|
||||||
var ext = new Lazy<string> (() => Path.GetExtension (filename));
|
|
||||||
for (int attempt = 1; ; ++attempt)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return File.Open (name, FileMode.CreateNew);
|
|
||||||
}
|
|
||||||
catch (IOException) // file already exists
|
|
||||||
{
|
|
||||||
if (100 == attempt) // limit number of attempts
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
name = Path.ChangeExtension (filename, attempt.ToString()+ext.Value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ using System.Windows.Input;
|
|||||||
using GameRes;
|
using GameRes;
|
||||||
using GARbro.GUI.Strings;
|
using GARbro.GUI.Strings;
|
||||||
using GARbro.GUI.Properties;
|
using GARbro.GUI.Properties;
|
||||||
using Ookii.Dialogs.Wpf;
|
|
||||||
|
|
||||||
namespace GARbro.GUI
|
namespace GARbro.GUI
|
||||||
{
|
{
|
||||||
@ -57,21 +56,17 @@ namespace GARbro.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class GarCreate
|
internal class GarCreate : GarOperation
|
||||||
{
|
{
|
||||||
private MainWindow m_main;
|
|
||||||
private string m_arc_name;
|
private string m_arc_name;
|
||||||
private IList<Entry> m_file_list;
|
private IList<Entry> m_file_list;
|
||||||
private ProgressDialog m_progress_dialog;
|
|
||||||
private ArchiveFormat m_format;
|
private ArchiveFormat m_format;
|
||||||
private ResourceOptions m_options;
|
private ResourceOptions m_options;
|
||||||
private Exception m_pending_error;
|
|
||||||
|
|
||||||
delegate void AddFilesEnumerator (IList<Entry> list, string path, DirectoryInfo path_info);
|
delegate void AddFilesEnumerator (IList<Entry> list, string path, DirectoryInfo path_info);
|
||||||
|
|
||||||
public GarCreate (MainWindow parent)
|
public GarCreate (MainWindow parent) : base (parent, guiStrings.TextCreateArchiveError)
|
||||||
{
|
{
|
||||||
m_main = parent;
|
|
||||||
m_arc_name = Settings.Default.appLastCreatedArchive;
|
m_arc_name = Settings.Default.appLastCreatedArchive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//! \date Fri Jul 25 05:52:27 2014
|
//! \date Fri Jul 25 05:52:27 2014
|
||||||
//! \brief Extract archive frontend.
|
//! \brief Extract archive frontend.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2014-2015 by morkt
|
// Copyright (C) 2014-2017 by morkt
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
@ -28,13 +28,12 @@ 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 GameRes;
|
using GameRes;
|
||||||
using GameRes.Strings;
|
|
||||||
using GARbro.GUI.Strings;
|
using GARbro.GUI.Strings;
|
||||||
using GARbro.GUI.Properties;
|
using GARbro.GUI.Properties;
|
||||||
|
|
||||||
@ -103,9 +102,8 @@ namespace GARbro.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed internal class GarExtract : IDisposable
|
sealed internal class GarExtract : GarOperation, IDisposable
|
||||||
{
|
{
|
||||||
private MainWindow m_main;
|
|
||||||
private string m_arc_name;
|
private string m_arc_name;
|
||||||
private ArchiveFileSystem m_fs;
|
private ArchiveFileSystem m_fs;
|
||||||
private readonly bool m_should_ascend;
|
private readonly bool m_should_ascend;
|
||||||
@ -116,13 +114,12 @@ 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 Exception m_pending_error;
|
|
||||||
|
|
||||||
public bool IsActive { get { return m_extract_in_progress; } }
|
public bool IsActive { get { return m_extract_in_progress; } }
|
||||||
|
|
||||||
public GarExtract (MainWindow parent, string source)
|
public GarExtract (MainWindow parent, string source) : base (parent, guiStrings.TextExtractionError)
|
||||||
{
|
{
|
||||||
m_arc_name = Path.GetFileName (source);
|
m_arc_name = Path.GetFileName (source);
|
||||||
try
|
try
|
||||||
@ -135,15 +132,13 @@ namespace GARbro.GUI
|
|||||||
throw new OperationCanceledException (string.Format ("{1}: {0}", X.Message, m_arc_name));
|
throw new OperationCanceledException (string.Format ("{1}: {0}", X.Message, m_arc_name));
|
||||||
}
|
}
|
||||||
m_fs = VFS.Top as ArchiveFileSystem;
|
m_fs = VFS.Top as ArchiveFileSystem;
|
||||||
m_main = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GarExtract (MainWindow parent, string source, ArchiveFileSystem fs)
|
public GarExtract (MainWindow parent, string source, ArchiveFileSystem fs) : base (parent, guiStrings.TextExtractionError)
|
||||||
{
|
{
|
||||||
if (null == fs)
|
if (null == fs)
|
||||||
throw new UnknownFormatException();
|
throw new UnknownFormatException();
|
||||||
m_fs = fs;
|
m_fs = fs;
|
||||||
m_main = parent;
|
|
||||||
m_arc_name = Path.GetFileName (source);
|
m_arc_name = Path.GetFileName (source);
|
||||||
m_should_ascend = false;
|
m_should_ascend = false;
|
||||||
}
|
}
|
||||||
@ -245,6 +240,7 @@ namespace GARbro.GUI
|
|||||||
|
|
||||||
private void ExtractFilesFromArchive (string text, IEnumerable<Entry> file_list)
|
private void ExtractFilesFromArchive (string text, IEnumerable<Entry> file_list)
|
||||||
{
|
{
|
||||||
|
file_list = file_list.Where (e => e.Offset >= 0);
|
||||||
if (file_list.Skip (1).Any() // file_list.Count() > 1
|
if (file_list.Skip (1).Any() // file_list.Count() > 1
|
||||||
&& (m_skip_images || m_skip_script || m_skip_audio))
|
&& (m_skip_images || m_skip_script || m_skip_audio))
|
||||||
file_list = file_list.Where (f => !(m_skip_images && f.Type == "image") &&
|
file_list = file_list.Where (f => !(m_skip_images && f.Type == "image") &&
|
||||||
@ -269,8 +265,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_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;
|
||||||
m_progress_dialog.ShowDialog (m_main);
|
m_progress_dialog.ShowDialog (m_main);
|
||||||
@ -279,44 +273,70 @@ 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;
|
var arc = m_fs.Source;
|
||||||
int total = file_list.Count();
|
int total = file_list.Count();
|
||||||
|
int progress_count = 0;
|
||||||
|
bool ignore_errors = false;
|
||||||
foreach (var entry in file_list)
|
foreach (var entry in file_list)
|
||||||
{
|
{
|
||||||
if (m_progress_dialog.CancellationPending)
|
if (m_progress_dialog.CancellationPending)
|
||||||
break;
|
break;
|
||||||
if (total > 1)
|
if (total > 1)
|
||||||
m_progress_dialog.ReportProgress (m_extract_count*100/total, null, entry.Name);
|
m_progress_dialog.ReportProgress (progress_count++*100/total, null, entry.Name);
|
||||||
|
try
|
||||||
|
{
|
||||||
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")
|
||||||
ExtractAudio (arc, entry);
|
ExtractAudio (arc, entry);
|
||||||
else
|
else
|
||||||
arc.Extract (entry);
|
ExtractEntryAsIs (arc, entry);
|
||||||
++m_extract_count;
|
++m_extract_count;
|
||||||
}
|
}
|
||||||
|
catch (SkipExistingFileException)
|
||||||
|
{
|
||||||
|
++m_skip_count;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
catch (Exception X)
|
catch (Exception X)
|
||||||
{
|
{
|
||||||
m_pending_error = X;
|
if (!ignore_errors)
|
||||||
|
{
|
||||||
|
var error_text = string.Format (guiStrings.TextErrorExtracting, entry.Name, X.Message);
|
||||||
|
var result = ShowErrorDialog (error_text);
|
||||||
|
if (!result.Continue)
|
||||||
|
break;
|
||||||
|
ignore_errors = result.IgnoreErrors;
|
||||||
|
}
|
||||||
|
++m_skip_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtractImage (ArcFile arc, Entry entry, ImageFormat target_format)
|
void ExtractEntryAsIs (ArcFile arc, Entry entry)
|
||||||
{
|
{
|
||||||
try
|
using (var input = arc.OpenEntry (entry))
|
||||||
|
using (var output = CreateNewFile (entry.Name, true))
|
||||||
|
input.CopyTo (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractImage (ArcFile arc, Entry entry, ImageFormat target_format)
|
||||||
{
|
{
|
||||||
using (var decoder = arc.OpenImage (entry))
|
using (var decoder = arc.OpenImage (entry))
|
||||||
{
|
{
|
||||||
var src_format = decoder.SourceFormat; // could be null
|
var src_format = decoder.SourceFormat; // could be null
|
||||||
string target_ext = target_format.Extensions.FirstOrDefault() ?? "";
|
string target_ext = target_format.Extensions.FirstOrDefault() ?? "";
|
||||||
string outname = FindUniqueFileName (entry.Name, target_ext);
|
string outname = Path.ChangeExtension (entry.Name, target_ext);
|
||||||
if (src_format == target_format)
|
if (src_format == target_format)
|
||||||
{
|
{
|
||||||
// source format is the same as a target, copy file as is
|
// source format is the same as a target, copy file as is
|
||||||
using (var output = ArchiveFormat.CreateFile (outname))
|
using (var output = CreateNewFile (outname, true))
|
||||||
decoder.Source.CopyTo (output);
|
decoder.Source.CopyTo (output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -325,17 +345,12 @@ namespace GARbro.GUI
|
|||||||
{
|
{
|
||||||
image = AdjustImageOffset (image);
|
image = AdjustImageOffset (image);
|
||||||
}
|
}
|
||||||
using (var outfile = ArchiveFormat.CreateFile (outname))
|
using (var outfile = CreateNewFile (outname, true))
|
||||||
{
|
{
|
||||||
target_format.Write (outfile, image);
|
target_format.Write (outfile, image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw new InvalidFormatException (string.Format ("{1}: {0}", guiStrings.MsgUnableInterpretImage, entry.Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ImageData AdjustImageOffset (ImageData image)
|
static ImageData AdjustImageOffset (ImageData image)
|
||||||
{
|
{
|
||||||
@ -366,24 +381,24 @@ namespace GARbro.GUI
|
|||||||
return new ImageData (bitmap);
|
return new ImageData (bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExtractAudio (ArcFile arc, Entry entry)
|
void ExtractAudio (ArcFile arc, Entry entry)
|
||||||
{
|
{
|
||||||
using (var file = arc.OpenBinaryEntry (entry))
|
using (var file = arc.OpenBinaryEntry (entry))
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ConvertAudio (string entry_name, SoundInput input)
|
public void ConvertAudio (string filename, SoundInput input)
|
||||||
{
|
{
|
||||||
string source_format = input.SourceFormat;
|
string source_format = input.SourceFormat;
|
||||||
if (GarConvertMedia.CommonAudioFormats.Contains (source_format))
|
if (GarConvertMedia.CommonAudioFormats.Contains (source_format))
|
||||||
{
|
{
|
||||||
string output_name = FindUniqueFileName (entry_name, source_format);
|
var output_name = Path.ChangeExtension (filename, source_format);
|
||||||
using (var output = ArchiveFormat.CreateFile (output_name))
|
using (var output = CreateNewFile (output_name, true))
|
||||||
{
|
{
|
||||||
input.Source.Position = 0;
|
input.Source.Position = 0;
|
||||||
input.Source.CopyTo (output);
|
input.Source.CopyTo (output);
|
||||||
@ -391,25 +406,12 @@ namespace GARbro.GUI
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string output_name = FindUniqueFileName (entry_name, "wav");
|
var output_name = Path.ChangeExtension (filename, "wav");
|
||||||
using (var output = ArchiveFormat.CreateFile (output_name))
|
using (var output = CreateNewFile (output_name, true))
|
||||||
AudioFormat.Wav.Write (input, output);
|
AudioFormat.Wav.Write (input, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string FindUniqueFileName (string source_filename, string target_ext)
|
|
||||||
{
|
|
||||||
string ext = target_ext;
|
|
||||||
for (int attempt = 1; attempt < 100; ++attempt)
|
|
||||||
{
|
|
||||||
string filename = Path.ChangeExtension (source_filename, ext);
|
|
||||||
if (!File.Exists (filename))
|
|
||||||
return filename;
|
|
||||||
ext = string.Format ("{0}.{1}", attempt, target_ext);
|
|
||||||
}
|
|
||||||
throw new IOException ("File aready exists");
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnExtractComplete (object sender, RunWorkerCompletedEventArgs e)
|
void OnExtractComplete (object sender, RunWorkerCompletedEventArgs e)
|
||||||
{
|
{
|
||||||
m_extract_in_progress = false;
|
m_extract_in_progress = false;
|
||||||
@ -420,17 +422,6 @@ namespace GARbro.GUI
|
|||||||
m_main.Dispatcher.Invoke (m_main.RefreshView);
|
m_main.Dispatcher.Invoke (m_main.RefreshView);
|
||||||
}
|
}
|
||||||
m_main.SetStatusText (Localization.Format ("MsgExtractedFiles", m_extract_count));
|
m_main.SetStatusText (Localization.Format ("MsgExtractedFiles", m_extract_count));
|
||||||
if (null != m_pending_error)
|
|
||||||
{
|
|
||||||
if (m_pending_error is OperationCanceledException)
|
|
||||||
m_main.SetStatusText (m_pending_error.Message);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string message = string.Format (guiStrings.TextErrorExtracting,
|
|
||||||
m_progress_dialog.Description, m_pending_error.Message);
|
|
||||||
m_main.PopupError (message, guiStrings.MsgErrorExtracting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.Dispose();
|
this.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
122
GUI/GarOperation.cs
Normal file
122
GUI/GarOperation.cs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
//! \file GarOperation.cs
|
||||||
|
//! \date Fri Feb 03 19:06:52 2017
|
||||||
|
//! \brief Base class for GARbro file operation.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2017 by morkt
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using GARbro.GUI.Strings;
|
||||||
|
|
||||||
|
namespace GARbro.GUI
|
||||||
|
{
|
||||||
|
internal class GarOperation
|
||||||
|
{
|
||||||
|
internal MainWindow m_main;
|
||||||
|
internal ProgressDialog m_progress_dialog;
|
||||||
|
internal Exception m_pending_error;
|
||||||
|
internal FileExistsDialogResult m_duplicate_action;
|
||||||
|
internal string m_title;
|
||||||
|
|
||||||
|
const int MaxRenameAttempts = 100;
|
||||||
|
|
||||||
|
protected GarOperation (MainWindow parent, string dialog_title)
|
||||||
|
{
|
||||||
|
m_main = parent;
|
||||||
|
m_title = dialog_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create file <paramref name="filename"/>. Also create path to file if <paramref name="create_path"/> is true.
|
||||||
|
/// If file aready exists, popup dialog asking for necessary action.
|
||||||
|
/// WARNING: path to file should be relative, ArchiveFormat.CreatePath strips drive/root specification.
|
||||||
|
/// </summary>
|
||||||
|
protected Stream CreateNewFile (string filename, bool create_path = false)
|
||||||
|
{
|
||||||
|
if (create_path)
|
||||||
|
filename = GameRes.ArchiveFormat.CreatePath (filename);
|
||||||
|
FileMode open_mode = FileMode.CreateNew;
|
||||||
|
if (m_duplicate_action.ApplyToAll &&
|
||||||
|
m_duplicate_action.Action == ExistingFileAction.Overwrite)
|
||||||
|
open_mode = FileMode.Create;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return File.Open (filename, open_mode);
|
||||||
|
}
|
||||||
|
catch (IOException) // file already exists?
|
||||||
|
{
|
||||||
|
if (!File.Exists (filename) || FileMode.Create == open_mode) // some unforseen I/O error, give up
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
if (!m_duplicate_action.ApplyToAll)
|
||||||
|
{
|
||||||
|
var msg_text = string.Format (guiStrings.TextFileAlreadyExists, Path.GetFileName (filename));
|
||||||
|
m_duplicate_action = m_main.Dispatcher.Invoke (() => m_main.ShowFileExistsDialog (m_title, msg_text, m_progress_dialog.GetWindowHandle()));
|
||||||
|
}
|
||||||
|
switch (m_duplicate_action.Action)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case ExistingFileAction.Abort:
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
case ExistingFileAction.Skip:
|
||||||
|
throw new SkipExistingFileException();
|
||||||
|
case ExistingFileAction.Rename:
|
||||||
|
return CreateRenamedFile (filename);
|
||||||
|
case ExistingFileAction.Overwrite:
|
||||||
|
return File.Open (filename, FileMode.Create);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates new file with specified filename, or, if it's already exists, tries to open
|
||||||
|
/// files named "FILENAME.1.EXT", "FILENAME.2.EXT" and so on.
|
||||||
|
/// <exception cref="System.IOException">Throws exception after 100th failed attempt.</exception>
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public static Stream CreateRenamedFile (string filename)
|
||||||
|
{
|
||||||
|
var ext = Path.GetExtension (filename);
|
||||||
|
for (int attempt = 1; ; ++attempt)
|
||||||
|
{
|
||||||
|
var name = Path.ChangeExtension (filename, attempt.ToString()+ext);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return File.Open (name, FileMode.CreateNew);
|
||||||
|
}
|
||||||
|
catch (IOException) // file already exists
|
||||||
|
{
|
||||||
|
if (MaxRenameAttempts == attempt) // limit number of attempts
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FileErrorDialogResult ShowErrorDialog (string error_text)
|
||||||
|
{
|
||||||
|
return m_main.Dispatcher.Invoke (() => m_main.ShowErrorDialog (m_title, error_text, m_progress_dialog.GetWindowHandle()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class SkipExistingFileException : ApplicationException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
BIN
GUI/Images/64x64/actions.png
Normal file
BIN
GUI/Images/64x64/actions.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
BIN
GUI/Images/64x64/alert.png
Normal file
BIN
GUI/Images/64x64/alert.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -1,6 +1,6 @@
|
|||||||
// Game Resource Browser
|
// Game Resource Browser
|
||||||
//
|
//
|
||||||
// Copyright (C) 2014-2015 by morkt
|
// Copyright (C) 2014-2017 by morkt
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
@ -35,6 +35,7 @@ using System.Windows;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Interop;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Microsoft.VisualBasic.FileIO;
|
using Microsoft.VisualBasic.FileIO;
|
||||||
using GARbro.GUI.Properties;
|
using GARbro.GUI.Properties;
|
||||||
@ -195,6 +196,40 @@ namespace GARbro.GUI
|
|||||||
Dispatcher.Invoke (() => MessageBox.Show (this, message, title, MessageBoxButton.OK, MessageBoxImage.Error));
|
Dispatcher.Invoke (() => MessageBox.Show (this, message, title, MessageBoxButton.OK, MessageBoxImage.Error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal FileErrorDialogResult ShowErrorDialog (string error_title, string error_text, IntPtr parent_hwnd)
|
||||||
|
{
|
||||||
|
var dialog = new FileErrorDialog (error_title, error_text);
|
||||||
|
SetModalWindowParent (dialog, parent_hwnd);
|
||||||
|
return dialog.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FileExistsDialogResult ShowFileExistsDialog (string title, string text, IntPtr parent_hwnd)
|
||||||
|
{
|
||||||
|
var dialog = new FileExistsDialog (title, text);
|
||||||
|
SetModalWindowParent (dialog, parent_hwnd);
|
||||||
|
return dialog.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetModalWindowParent (Window dialog, IntPtr parent_hwnd)
|
||||||
|
{
|
||||||
|
if (parent_hwnd != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var native_dialog = new WindowInteropHelper (dialog);
|
||||||
|
native_dialog.Owner = parent_hwnd;
|
||||||
|
NativeMethods.EnableWindow (parent_hwnd, false);
|
||||||
|
EventHandler on_closed = null;
|
||||||
|
on_closed = (s, e) => {
|
||||||
|
NativeMethods.EnableWindow (parent_hwnd, true);
|
||||||
|
dialog.Closed -= on_closed;
|
||||||
|
};
|
||||||
|
dialog.Closed += on_closed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dialog.Owner = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const int MaxRecentFiles = 9;
|
const int MaxRecentFiles = 9;
|
||||||
LinkedList<string> m_recent_files;
|
LinkedList<string> m_recent_files;
|
||||||
|
|
||||||
|
116
GUI/ProgressDialog/IProgressDialog.cs
Normal file
116
GUI/ProgressDialog/IProgressDialog.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace GARbro.GUI.Interop
|
||||||
|
{
|
||||||
|
[ComImport, Guid ("F8383852-FCD3-11d1-A6B9-006097DF5BD4")]
|
||||||
|
internal class ProgressDialogRCW
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport, Guid ("EBBC7C04-315E-11d2-B62F-006097DF5BD4"), CoClass (typeof(ProgressDialogRCW))]
|
||||||
|
internal interface ProgressDialog : IProgressDialog
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum ProgressDialogFlags : uint
|
||||||
|
{
|
||||||
|
Normal = 0x00000000,
|
||||||
|
Modal = 0x00000001,
|
||||||
|
AutoTime = 0x00000002,
|
||||||
|
NoTime = 0x00000004,
|
||||||
|
NoMinimize = 0x00000008,
|
||||||
|
NoProgressBar = 0x00000010,
|
||||||
|
MarqueeProgress = 0x00000020,
|
||||||
|
NoCancel = 0x00000040
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum ProgressTimerAction : uint
|
||||||
|
{
|
||||||
|
Reset = 0x00000001,
|
||||||
|
Pause = 0x00000002,
|
||||||
|
Resume = 0x00000003
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport, Guid ("EBBC7C04-315E-11d2-B62F-006097DF5BD4"), InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
internal interface IProgressDialog
|
||||||
|
{
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void StartProgressDialog(
|
||||||
|
IntPtr hwndParent,
|
||||||
|
[MarshalAs(UnmanagedType.IUnknown)]
|
||||||
|
object punkEnableModless,
|
||||||
|
ProgressDialogFlags dwFlags,
|
||||||
|
IntPtr pvResevered
|
||||||
|
);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void StopProgressDialog();
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void SetTitle(
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
string pwzTitle
|
||||||
|
);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void SetAnimation(
|
||||||
|
IntPtr hInstAnimation,
|
||||||
|
ushort idAnimation
|
||||||
|
);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
bool HasUserCancelled();
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void SetProgress(
|
||||||
|
uint dwCompleted,
|
||||||
|
uint dwTotal
|
||||||
|
);
|
||||||
|
[PreserveSig]
|
||||||
|
void SetProgress64(
|
||||||
|
ulong ullCompleted,
|
||||||
|
ulong ullTotal
|
||||||
|
);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void SetLine(
|
||||||
|
uint dwLineNum,
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
string pwzString,
|
||||||
|
[MarshalAs(UnmanagedType.VariantBool)]
|
||||||
|
bool fCompactPath,
|
||||||
|
IntPtr pvResevered
|
||||||
|
);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void SetCancelMsg(
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
string pwzCancelMsg,
|
||||||
|
object pvResevered
|
||||||
|
);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void Timer(
|
||||||
|
ProgressTimerAction dwTimerAction,
|
||||||
|
object pvResevered
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport, Guid ("00000114-0000-0000-C000-000000000046"), InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
internal interface IOleWindow
|
||||||
|
{
|
||||||
|
[PreserveSig]
|
||||||
|
void GetWindow (out IntPtr phwnd);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
void ContextSensitiveHelp ([MarshalAs(UnmanagedType.Bool)] bool fEnterMode);
|
||||||
|
}
|
||||||
|
}
|
713
GUI/ProgressDialog/ProgressDialog.cs
Normal file
713
GUI/ProgressDialog/ProgressDialog.cs
Normal file
@ -0,0 +1,713 @@
|
|||||||
|
// Modified ProgressDialog from Ookii.Dialogs
|
||||||
|
//
|
||||||
|
// Copyright © Sven Groot (Ookii.org) 2009
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1) Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// 2) Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// 3) Neither the name of the ORGANIZATION nor the names of its contributors
|
||||||
|
// may be used to endorse or promote products derived from this software
|
||||||
|
// without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
// THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
|
||||||
|
namespace GARbro.GUI
|
||||||
|
{
|
||||||
|
public class ProgressDialog : Component
|
||||||
|
{
|
||||||
|
private class ProgressChangedData
|
||||||
|
{
|
||||||
|
public string Text { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public object UserState { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _windowTitle;
|
||||||
|
private string _text;
|
||||||
|
private string _description;
|
||||||
|
private Interop.IProgressDialog _dialog;
|
||||||
|
private string _cancellationText;
|
||||||
|
private bool _useCompactPathsForText;
|
||||||
|
private bool _useCompactPathsForDescription;
|
||||||
|
private bool _cancellationPending;
|
||||||
|
private BackgroundWorker _backgroundWorker;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the dialog is displayed.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Use this event to perform the operation that the dialog is showing the progress for.
|
||||||
|
/// This event will be raised on a different thread than the UI thread.
|
||||||
|
/// </remarks>
|
||||||
|
public event DoWorkEventHandler DoWork;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the operation completes.
|
||||||
|
/// </summary>
|
||||||
|
public event RunWorkerCompletedEventHandler RunWorkerCompleted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when <see cref="ReportProgress(int,string,string,object)"/> is called.
|
||||||
|
/// </summary>
|
||||||
|
public event ProgressChangedEventHandler ProgressChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProgressDialog"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ProgressDialog ()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
ProgressBarStyle = ProgressBarStyle.ProgressBar;
|
||||||
|
ShowCancelButton = true;
|
||||||
|
MinimizeBox = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the text in the progress dialog's title bar.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The text in the progress dialog's title bar. The default value is an empty string.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This property must be set before <see cref="ShowDialog()"/> or <see cref="Show()"/> is called. Changing property has
|
||||||
|
/// no effect while the dialog is being displayed.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Localizable(true), Category("Appearance"), Description("The text in the progress dialog's title bar."), DefaultValue("")]
|
||||||
|
public string WindowTitle
|
||||||
|
{
|
||||||
|
get { return _windowTitle ?? string.Empty; }
|
||||||
|
set { _windowTitle = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a short description of the operation being carried out.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// A short description of the operation being carried. The default value is an empty string.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This is the primary message to the user.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This property can be changed while the dialog is running, but may only be changed from the thread which
|
||||||
|
/// created the progress dialog. The recommended method to change this value while the dialog is running
|
||||||
|
/// is to use the <see cref="ReportProgress(int,string,string)"/> method.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Localizable(true), Category("Appearance"), Description("A short description of the operation being carried out.")]
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return _text ?? string.Empty; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_text = value;
|
||||||
|
if (_dialog != null)
|
||||||
|
_dialog.SetLine (1, Text, UseCompactPathsForText, IntPtr.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether path strings in the <see cref="Text"/> property should be compacted if
|
||||||
|
/// they are too large to fit on one line.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <see langword="true"/> to compact path strings if they are too large to fit on one line; otherwise,
|
||||||
|
/// <see langword="false"/>. The default value is <see langword="false"/>.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <note>
|
||||||
|
/// This property requires Windows Vista or later. On older versions of Windows, it has no effect.
|
||||||
|
/// </note>
|
||||||
|
/// <para>
|
||||||
|
/// This property can be changed while the dialog is running, but may only be changed from the thread which
|
||||||
|
/// created the progress dialog.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Category("Behavior"), Description("Indicates whether path strings in the Text property should be compacted if they are too large to fit on one line."), DefaultValue(false)]
|
||||||
|
public bool UseCompactPathsForText
|
||||||
|
{
|
||||||
|
get { return _useCompactPathsForText; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_useCompactPathsForText = value;
|
||||||
|
if (_dialog != null)
|
||||||
|
_dialog.SetLine (1, Text, _useCompactPathsForText, IntPtr.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets additional details about the operation being carried out.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// Additional details about the operation being carried out. The default value is an empty string.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// This text is used to provide additional details beyond the <see cref="Text"/> property.
|
||||||
|
/// </remarks>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This property can be changed while the dialog is running, but may only be changed from the thread which
|
||||||
|
/// created the progress dialog. The recommended method to change this value while the dialog is running
|
||||||
|
/// is to use the <see cref="ReportProgress(int,string,string)"/> method.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Localizable(true), Category("Appearance"), Description("Additional details about the operation being carried out."), DefaultValue("")]
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get { return _description ?? string.Empty; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_description = value;
|
||||||
|
if (_dialog != null)
|
||||||
|
_dialog.SetLine (2, Description, UseCompactPathsForDescription, IntPtr.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether path strings in the <see cref="Description"/> property should be compacted if
|
||||||
|
/// they are too large to fit on one line.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <see langword="true"/> to compact path strings if they are too large to fit on one line; otherwise,
|
||||||
|
/// <see langword="false"/>. The default value is <see langword="false"/>.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <note>
|
||||||
|
/// This property requires Windows Vista or later. On older versions of Windows, it has no effect.
|
||||||
|
/// </note>
|
||||||
|
/// <para>
|
||||||
|
/// This property can be changed while the dialog is running, but may only be changed from the thread which
|
||||||
|
/// created the progress dialog.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Category("Behavior"), Description("Indicates whether path strings in the Description property should be compacted if they are too large to fit on one line."), DefaultValue(false)]
|
||||||
|
public bool UseCompactPathsForDescription
|
||||||
|
{
|
||||||
|
get { return _useCompactPathsForDescription; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_useCompactPathsForDescription = value;
|
||||||
|
if( _dialog != null )
|
||||||
|
_dialog.SetLine(2, Description, UseCompactPathsForDescription, IntPtr.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the text that will be shown after the Cancel button is pressed.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The text that will be shown after the Cancel button is pressed.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This property must be set before <see cref="ShowDialog()"/> or <see cref="Show()"/> is called. Changing property has
|
||||||
|
/// no effect while the dialog is being displayed.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Localizable(true), Category("Appearance"), Description("The text that will be shown after the Cancel button is pressed."), DefaultValue("")]
|
||||||
|
public string CancellationText
|
||||||
|
{
|
||||||
|
get { return _cancellationText ?? string.Empty; }
|
||||||
|
set { _cancellationText = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether an estimate of the remaining time will be shown.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <see langword="true"/> if an estimate of remaining time will be shown; otherwise, <see langword="false"/>. The
|
||||||
|
/// default value is <see langword="false"/>.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This property must be set before <see cref="ShowDialog()"/> or <see cref="Show()"/> is called. Changing property has
|
||||||
|
/// no effect while the dialog is being displayed.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Category("Appearance"), Description("Indicates whether an estimate of the remaining time will be shown."), DefaultValue(false)]
|
||||||
|
public bool ShowTimeRemaining { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether the dialog has a cancel button.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <see langword="true"/> if the dialog has a cancel button; otherwise, <see langword="false"/>. The default
|
||||||
|
/// value is <see langword="true"/>.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <note>
|
||||||
|
/// This property requires Windows Vista or later; on older versions of Windows, the cancel button will always
|
||||||
|
/// be displayed.
|
||||||
|
/// </note>
|
||||||
|
/// <para>
|
||||||
|
/// The event handler for the <see cref="DoWork"/> event must periodically check the value of the
|
||||||
|
/// <see cref="CancellationPending"/> property to see if the operation has been cancelled if this
|
||||||
|
/// property is <see langword="true"/>.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Setting this property to <see langword="false"/> is not recommended unless absolutely necessary.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Category("Appearance"), Description("Indicates whether the dialog has a cancel button. Do not set to false unless absolutely necessary."), DefaultValue(true)]
|
||||||
|
public bool ShowCancelButton { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether the progress dialog has a minimize button.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <see langword="true"/> if the dialog has a minimize button; otherwise, <see langword="false"/>. The default
|
||||||
|
/// value is <see langword="true"/>.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <note>
|
||||||
|
/// This property has no effect on modal dialogs (which do not have a minimize button). It only applies
|
||||||
|
/// to modeless dialogs shown by using the <see cref="Show()"/> method.
|
||||||
|
/// </note>
|
||||||
|
/// <para>
|
||||||
|
/// This property must be set before <see cref="Show()"/> is called. Changing property has
|
||||||
|
/// no effect while the dialog is being displayed.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Category("Window Style"), Description("Indicates whether the progress dialog has a minimize button."), DefaultValue(true)]
|
||||||
|
public bool MinimizeBox { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the user has requested cancellation of the operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <see langword="true" /> if the user has cancelled the progress dialog; otherwise, <see langword="false" />. The default is <see langword="false" />.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// The event handler for the <see cref="DoWork"/> event must periodically check this property and abort the operation
|
||||||
|
/// if it returns <see langword="true"/>.
|
||||||
|
/// </remarks>
|
||||||
|
[Browsable(false)]
|
||||||
|
public bool CancellationPending
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_backgroundWorker.ReportProgress (-1); // Call with an out-of-range percentage will update the value of
|
||||||
|
// _cancellationPending but do nothing else.
|
||||||
|
return _cancellationPending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that indicates whether a regular or marquee style progress bar should be used.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// One of the values of <see cref="Ookii.Dialogs.Wpf.ProgressBarStyle"/>.
|
||||||
|
/// The default value is <see cref="Ookii.Dialogs.Wpf.ProgressBarStyle.ProgressBar"/>.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// <note>
|
||||||
|
/// Operating systems older than Windows Vista do not support marquee progress bars on the progress dialog. On those operating systems, the
|
||||||
|
/// progress bar will be hidden completely if this property is <see cref="Ookii.Dialogs.Wpf.ProgressBarStyle.MarqueeProgressBar"/>.
|
||||||
|
/// </note>
|
||||||
|
/// <para>
|
||||||
|
/// When this property is set to <see cref="Ookii.Dialogs.Wpf.ProgressBarStyle.ProgressBar" />, use the <see cref="ReportProgress(int)"/> method to set
|
||||||
|
/// the value of the progress bar. When this property is set to <see cref="Ookii.Dialogs.Wpf.ProgressBarStyle.MarqueeProgressBar"/>
|
||||||
|
/// you can still use the <see cref="ReportProgress(int,string,string)"/> method to update the text of the dialog,
|
||||||
|
/// but the percentage will be ignored.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This property must be set before <see cref="ShowDialog()"/> or <see cref="Show()"/> is called. Changing property has
|
||||||
|
/// no effect while the dialog is being displayed.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Category("Appearance"), Description("Indicates the style of the progress bar."), DefaultValue(ProgressBarStyle.ProgressBar)]
|
||||||
|
public ProgressBarStyle ProgressBarStyle { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value that indicates whether the <see cref="ProgressDialog"/> is running an asynchronous operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <see langword="true"/> if the <see cref="ProgressDialog"/> is running an asynchronous operation;
|
||||||
|
/// otherwise, <see langword="false"/>.
|
||||||
|
/// </value>
|
||||||
|
[Browsable(false)]
|
||||||
|
public bool IsBusy
|
||||||
|
{
|
||||||
|
get { return _backgroundWorker.IsBusy; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays the progress dialog as a modeless dialog.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This function will not block the parent window and will return immediately.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Although this function returns immediately, you cannot use the UI thread to do any processing. The dialog
|
||||||
|
/// will not function correctly unless the UI thread continues to handle window messages, so that thread may
|
||||||
|
/// not be blocked by some other activity. All processing related to the progress dialog must be done in
|
||||||
|
/// the <see cref="DoWork"/> event handler.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public void Show ()
|
||||||
|
{
|
||||||
|
Show (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays the progress dialog as a modeless dialog.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="argument">A parameter for use by the background operation to be executed in the <see cref="DoWork"/> event handler.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This function will not block the parent window and return immediately.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Although this function returns immediately, you cannot use the UI thread to do any processing. The dialog
|
||||||
|
/// will not function correctly unless the UI thread continues to handle window messages, so that thread may
|
||||||
|
/// not be blocked by some other activity. All processing related to the progress dialog must be done in
|
||||||
|
/// the <see cref="DoWork"/> event handler.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public void Show (object argument)
|
||||||
|
{
|
||||||
|
RunProgressDialog (IntPtr.Zero, argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays the progress dialog as a modal dialog.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The ShowDialog function for most .Net dialogs will not return until the dialog is closed. However,
|
||||||
|
/// the <see cref="ShowDialog()"/> function for the <see cref="ProgressDialog"/> class will return immediately.
|
||||||
|
/// The parent window will be disabled as with all modal dialogs.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Although this function returns immediately, you cannot use the UI thread to do any processing. The dialog
|
||||||
|
/// will not function correctly unless the UI thread continues to handle window messages, so that thread may
|
||||||
|
/// not be blocked by some other activity. All processing related to the progress dialog must be done in
|
||||||
|
/// the <see cref="DoWork"/> event handler.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The progress dialog's window will appear in the taskbar. This behaviour is also contrary to most .Net dialogs,
|
||||||
|
/// but is part of the underlying native progress dialog API so cannot be avoided.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// When possible, it is recommended that you use a modeless dialog using the <see cref="Show()"/> function.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public void ShowDialog()
|
||||||
|
{
|
||||||
|
ShowDialog (null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays the progress dialog as a modal dialog.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">The window that owns the dialog.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The ShowDialog function for most .Net dialogs will not return until the dialog is closed. However,
|
||||||
|
/// the <see cref="ShowDialog()"/> function for the <see cref="ProgressDialog"/> class will return immediately.
|
||||||
|
/// The parent window will be disabled as with all modal dialogs.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Although this function returns immediately, you cannot use the UI thread to do any processing. The dialog
|
||||||
|
/// will not function correctly unless the UI thread continues to handle window messages, so that thread may
|
||||||
|
/// not be blocked by some other activity. All processing related to the progress dialog must be done in
|
||||||
|
/// the <see cref="DoWork"/> event handler.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The progress dialog's window will appear in the taskbar. This behaviour is also contrary to most .Net dialogs,
|
||||||
|
/// but is part of the underlying native progress dialog API so cannot be avoided.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// When possible, it is recommended that you use a modeless dialog using the <see cref="Show()"/> function.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public void ShowDialog (Window owner)
|
||||||
|
{
|
||||||
|
ShowDialog (owner, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays the progress dialog as a modal dialog.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">The window that owns the dialog.</param>
|
||||||
|
/// <param name="argument">A parameter for use by the background operation to be executed in the <see cref="DoWork"/> event handler.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The ShowDialog function for most .Net dialogs will not return until the dialog is closed. However,
|
||||||
|
/// the <see cref="ShowDialog()"/> function for the <see cref="ProgressDialog"/> class will return immediately.
|
||||||
|
/// The parent window will be disabled as with all modal dialogs.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Although this function returns immediately, you cannot use the UI thread to do any processing. The dialog
|
||||||
|
/// will not function correctly unless the UI thread continues to handle window messages, so that thread may
|
||||||
|
/// not be blocked by some other activity. All processing related to the progress dialog must be done in
|
||||||
|
/// the <see cref="DoWork"/> event handler.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The progress dialog's window will appear in the taskbar. This behaviour is also contrary to most .Net dialogs,
|
||||||
|
/// but is part of the underlying native progress dialog API so cannot be avoided.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// When possible, it is recommended that you use a modeless dialog using the <see cref="Show()"/> function.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public void ShowDialog (Window owner, object argument)
|
||||||
|
{
|
||||||
|
RunProgressDialog (owner == null ? NativeMethods.GetActiveWindow() : new WindowInteropHelper(owner).Handle, argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int SW_HIDE = 0;
|
||||||
|
const int SW_SHOW = 5;
|
||||||
|
|
||||||
|
public void Hide ()
|
||||||
|
{
|
||||||
|
if (null == _dialog)
|
||||||
|
return;
|
||||||
|
var hwnd = GetWindowHandle();
|
||||||
|
if (hwnd != IntPtr.Zero)
|
||||||
|
NativeMethods.ShowWindow (hwnd, SW_HIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Restore ()
|
||||||
|
{
|
||||||
|
if (null == _dialog)
|
||||||
|
return;
|
||||||
|
var hwnd = GetWindowHandle();
|
||||||
|
if (hwnd != IntPtr.Zero)
|
||||||
|
NativeMethods.ShowWindow (hwnd, SW_SHOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get win32 handle of the progress dialog window.
|
||||||
|
/// </summary>
|
||||||
|
public IntPtr GetWindowHandle ()
|
||||||
|
{
|
||||||
|
var ole = _dialog as Interop.IOleWindow;
|
||||||
|
if (null == ole)
|
||||||
|
return IntPtr.Zero;
|
||||||
|
IntPtr hwnd;
|
||||||
|
ole.GetWindow (out hwnd);
|
||||||
|
return hwnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the dialog's progress bar.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="percentProgress">The percentage, from 0 to 100, of the operation that is complete.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Call this method from the <see cref="DoWork"/> event handler if you want to report progress.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This method has no effect is <see cref="ProgressBarStyle"/> is <see cref="Ookii.Dialogs.Wpf.ProgressBarStyle.MarqueeProgressBar"/>
|
||||||
|
/// or <see cref="Ookii.Dialogs.Wpf.ProgressBarStyle.None"/>.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="percentProgress"/> is out of range.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">The progress dialog is not currently being displayed.</exception>
|
||||||
|
public void ReportProgress (int percentProgress)
|
||||||
|
{
|
||||||
|
ReportProgress (percentProgress, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the dialog's progress bar.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="percentProgress">The percentage, from 0 to 100, of the operation that is complete.</param>
|
||||||
|
/// <param name="text">The new value of the progress dialog's primary text message, or <see langword="null"/> to leave the value unchanged.</param>
|
||||||
|
/// <param name="description">The new value of the progress dialog's additional description message, or <see langword="null"/> to leave the value unchanged.</param>
|
||||||
|
/// <remarks>Call this method from the <see cref="DoWork"/> event handler if you want to report progress.</remarks>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="percentProgress"/> is out of range.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">The progress dialog is not currently being displayed.</exception>
|
||||||
|
public void ReportProgress (int percentProgress, string text, string description)
|
||||||
|
{
|
||||||
|
ReportProgress (percentProgress, text, description, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the dialog's progress bar.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="percentProgress">The percentage, from 0 to 100, of the operation that is complete.</param>
|
||||||
|
/// <param name="text">The new value of the progress dialog's primary text message, or <see langword="null"/> to leave the value unchanged.</param>
|
||||||
|
/// <param name="description">The new value of the progress dialog's additional description message, or <see langword="null"/> to leave the value unchanged.</param>
|
||||||
|
/// <param name="userState">A state object that will be passed to the <see cref="ProgressChanged"/> event handler.</param>
|
||||||
|
/// <remarks>Call this method from the <see cref="DoWork"/> event handler if you want to report progress.</remarks>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="percentProgress"/> is out of range.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">The progress dialog is not currently being displayed.</exception>
|
||||||
|
public void ReportProgress (int percentProgress, string text, string description, object userState)
|
||||||
|
{
|
||||||
|
if (percentProgress < 0 || percentProgress > 100)
|
||||||
|
throw new ArgumentOutOfRangeException ("percentProgress");
|
||||||
|
if (_dialog == null)
|
||||||
|
throw new InvalidOperationException ("The progress dialog is not shown.");
|
||||||
|
_backgroundWorker.ReportProgress (percentProgress, new ProgressChangedData { Text = text, Description = description, UserState = userState });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="DoWork"/> event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The <see cref="DoWorkEventArgs"/> containing data for the event.</param>
|
||||||
|
protected virtual void OnDoWork (DoWorkEventArgs e)
|
||||||
|
{
|
||||||
|
var handler = DoWork;
|
||||||
|
if (handler != null)
|
||||||
|
handler (this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="RunWorkerCompleted"/> event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The <see cref="EventArgs"/> containing data for the event.</param>
|
||||||
|
protected virtual void OnRunWorkerCompleted (RunWorkerCompletedEventArgs e)
|
||||||
|
{
|
||||||
|
var handler = RunWorkerCompleted;
|
||||||
|
if (handler != null)
|
||||||
|
handler (this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="ProgressChanged"/> event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The <see cref="ProgressChangedEventArgs"/> containing data for the event.</param>
|
||||||
|
protected virtual void OnProgressChanged (ProgressChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var handler = ProgressChanged;
|
||||||
|
if (handler != null)
|
||||||
|
handler (this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunProgressDialog (IntPtr owner, object argument)
|
||||||
|
{
|
||||||
|
if (_backgroundWorker.IsBusy)
|
||||||
|
throw new InvalidOperationException ("The progress dialog is already running.");
|
||||||
|
|
||||||
|
_cancellationPending = false;
|
||||||
|
_dialog = new Interop.ProgressDialog();
|
||||||
|
_dialog.SetTitle (WindowTitle);
|
||||||
|
|
||||||
|
if (CancellationText.Length > 0)
|
||||||
|
_dialog.SetCancelMsg (CancellationText, null);
|
||||||
|
_dialog.SetLine (1, Text, UseCompactPathsForText, IntPtr.Zero);
|
||||||
|
_dialog.SetLine (2, Description, UseCompactPathsForDescription, IntPtr.Zero);
|
||||||
|
|
||||||
|
var flags = Interop.ProgressDialogFlags.Normal;
|
||||||
|
if (owner != IntPtr.Zero)
|
||||||
|
flags |= Interop.ProgressDialogFlags.Modal;
|
||||||
|
switch (ProgressBarStyle)
|
||||||
|
{
|
||||||
|
case ProgressBarStyle.None:
|
||||||
|
flags |= Interop.ProgressDialogFlags.NoProgressBar;
|
||||||
|
break;
|
||||||
|
case ProgressBarStyle.MarqueeProgressBar:
|
||||||
|
if (NativeMethods.IsWindowsVistaOrLater)
|
||||||
|
flags |= Interop.ProgressDialogFlags.MarqueeProgress;
|
||||||
|
else
|
||||||
|
flags |= Interop.ProgressDialogFlags.NoProgressBar; // Older than Vista doesn't support marquee.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( ShowTimeRemaining )
|
||||||
|
flags |= Interop.ProgressDialogFlags.AutoTime;
|
||||||
|
if( !ShowCancelButton )
|
||||||
|
flags |= Interop.ProgressDialogFlags.NoCancel;
|
||||||
|
if( !MinimizeBox )
|
||||||
|
flags |= Interop.ProgressDialogFlags.NoMinimize;
|
||||||
|
|
||||||
|
_dialog.StartProgressDialog (owner, null, flags, IntPtr.Zero);
|
||||||
|
_backgroundWorker.RunWorkerAsync (argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent ()
|
||||||
|
{
|
||||||
|
_backgroundWorker = new BackgroundWorker();
|
||||||
|
_backgroundWorker.WorkerReportsProgress = true;
|
||||||
|
_backgroundWorker.WorkerSupportsCancellation = true;
|
||||||
|
_backgroundWorker.DoWork += new DoWorkEventHandler (_backgroundWorker_DoWork);
|
||||||
|
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler (_backgroundWorker_RunWorkerCompleted);
|
||||||
|
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler (_backgroundWorker_ProgressChanged);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _backgroundWorker_DoWork (object sender, DoWorkEventArgs e)
|
||||||
|
{
|
||||||
|
OnDoWork (e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _backgroundWorker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
|
||||||
|
{
|
||||||
|
_dialog.StopProgressDialog();
|
||||||
|
Marshal.ReleaseComObject (_dialog);
|
||||||
|
_dialog = null;
|
||||||
|
|
||||||
|
OnRunWorkerCompleted (new RunWorkerCompletedEventArgs((!e.Cancelled && e.Error == null) ? e.Result : null, e.Error, e.Cancelled));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _backgroundWorker_ProgressChanged (object sender, ProgressChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_cancellationPending = _dialog.HasUserCancelled();
|
||||||
|
// ReportProgress doesn't allow values outside this range. However, CancellationPending will call
|
||||||
|
// BackgroundWorker.ReportProgress directly with a value that is outside this range to update the value of the property.
|
||||||
|
if (e.ProgressPercentage >= 0 && e.ProgressPercentage <= 100)
|
||||||
|
{
|
||||||
|
_dialog.SetProgress ((uint)e.ProgressPercentage, 100);
|
||||||
|
var data = e.UserState as ProgressChangedData;
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
if (data.Text != null)
|
||||||
|
Text = data.Text;
|
||||||
|
if (data.Description != null)
|
||||||
|
Description = data.Description;
|
||||||
|
OnProgressChanged (new ProgressChangedEventArgs (e.ProgressPercentage, data.UserState));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the type of progress on a task dialog.
|
||||||
|
/// </summary>
|
||||||
|
public enum ProgressBarStyle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No progress bar is displayed on the dialog.
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
/// <summary>
|
||||||
|
/// A regular progress bar is displayed on the dialog.
|
||||||
|
/// </summary>
|
||||||
|
ProgressBar,
|
||||||
|
/// <summary>
|
||||||
|
/// A marquee progress bar is displayed on the dialog. Use this value for operations
|
||||||
|
/// that cannot report concrete progress information.
|
||||||
|
/// </summary>
|
||||||
|
MarqueeProgressBar
|
||||||
|
}
|
||||||
|
}
|
101
GUI/Strings/guiStrings.Designer.cs
generated
101
GUI/Strings/guiStrings.Designer.cs
generated
@ -60,6 +60,15 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Abort.
|
||||||
|
/// </summary>
|
||||||
|
public static string ButtonAbort {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ButtonAbort", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Cancel.
|
/// Looks up a localized string similar to Cancel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -69,6 +78,15 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Continue.
|
||||||
|
/// </summary>
|
||||||
|
public static string ButtonContinue {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ButtonContinue", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Convert.
|
/// Looks up a localized string similar to Convert.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -96,6 +114,33 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Overwrite.
|
||||||
|
/// </summary>
|
||||||
|
public static string ButtonOverwrite {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ButtonOverwrite", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Rename.
|
||||||
|
/// </summary>
|
||||||
|
public static string ButtonRename {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ButtonRename", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Skip.
|
||||||
|
/// </summary>
|
||||||
|
public static string ButtonSkip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ButtonSkip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to _Close.
|
/// Looks up a localized string similar to _Close.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -294,6 +339,15 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to A_pply to all duplicate files.
|
||||||
|
/// </summary>
|
||||||
|
public static string LabelApplyToAll {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LabelApplyToAll", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Archive format.
|
/// Looks up a localized string similar to Archive format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -348,6 +402,15 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to What should be done?.
|
||||||
|
/// </summary>
|
||||||
|
public static string LabelDuplicateFileQuestion {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LabelDuplicateFileQuestion", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Encoding.
|
/// Looks up a localized string similar to Encoding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -384,6 +447,15 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Ignore further errors.
|
||||||
|
/// </summary>
|
||||||
|
public static string LabelIgnoreErrors {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LabelIgnoreErrors", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Skip incovertible files..
|
/// Looks up a localized string similar to Skip incovertible files..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -936,6 +1008,17 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Error occured while converting file
|
||||||
|
///{0}
|
||||||
|
///{1}.
|
||||||
|
/// </summary>
|
||||||
|
public static string TextErrorConverting {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TextErrorConverting", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Error occured while extracting file
|
/// Looks up a localized string similar to Error occured while extracting file
|
||||||
///{0}
|
///{0}
|
||||||
@ -965,6 +1048,15 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to File extraction error.
|
||||||
|
/// </summary>
|
||||||
|
public static string TextExtractionError {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TextExtractionError", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Extract text.
|
/// Looks up a localized string similar to Extract text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -983,6 +1075,15 @@ namespace GARbro.GUI.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to File {0} already exists in the destination folder..
|
||||||
|
/// </summary>
|
||||||
|
public static string TextFileAlreadyExists {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TextFileAlreadyExists", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Multimedia conversion error.
|
/// Looks up a localized string similar to Multimedia conversion error.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -458,4 +458,46 @@
|
|||||||
<data name="CtxMenuSelectByMask" xml:space="preserve">
|
<data name="CtxMenuSelectByMask" xml:space="preserve">
|
||||||
<value>마스크로 파일 선택...</value>
|
<value>마스크로 파일 선택...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ButtonAbort" xml:space="preserve">
|
||||||
|
<value>중단</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonContinue" xml:space="preserve">
|
||||||
|
<value>계속</value>
|
||||||
|
</data>
|
||||||
|
<data name="LabelIgnoreErrors" xml:space="preserve">
|
||||||
|
<value>추가 오류 무시</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextExtractionError" xml:space="preserve">
|
||||||
|
<value>파일 추출 오류</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonOverwrite" xml:space="preserve">
|
||||||
|
<value>Overwrite</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonRename" xml:space="preserve">
|
||||||
|
<value>Rename</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonSkip" xml:space="preserve">
|
||||||
|
<value>Skip</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="LabelApplyToAll" xml:space="preserve">
|
||||||
|
<value>Apply to all duplicate files</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="LabelDuplicateFileQuestion" xml:space="preserve">
|
||||||
|
<value>What should be done?</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="TextErrorConverting" xml:space="preserve">
|
||||||
|
<value>Error occured while converting file
|
||||||
|
{0}
|
||||||
|
{1}</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="TextFileAlreadyExists" xml:space="preserve">
|
||||||
|
<value>File {0} already exists in the destination folder.</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -462,4 +462,39 @@ Overwrite?</value>
|
|||||||
<data name="CtxMenuSelectByMask" xml:space="preserve">
|
<data name="CtxMenuSelectByMask" xml:space="preserve">
|
||||||
<value>Select files by mask...</value>
|
<value>Select files by mask...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ButtonAbort" xml:space="preserve">
|
||||||
|
<value>_Abort</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonContinue" xml:space="preserve">
|
||||||
|
<value>_Continue</value>
|
||||||
|
</data>
|
||||||
|
<data name="LabelIgnoreErrors" xml:space="preserve">
|
||||||
|
<value>_Ignore further errors</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextExtractionError" xml:space="preserve">
|
||||||
|
<value>File extraction error</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonOverwrite" xml:space="preserve">
|
||||||
|
<value>_Overwrite</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonRename" xml:space="preserve">
|
||||||
|
<value>_Rename</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonSkip" xml:space="preserve">
|
||||||
|
<value>_Skip</value>
|
||||||
|
</data>
|
||||||
|
<data name="LabelApplyToAll" xml:space="preserve">
|
||||||
|
<value>A_pply to all duplicate files</value>
|
||||||
|
</data>
|
||||||
|
<data name="LabelDuplicateFileQuestion" xml:space="preserve">
|
||||||
|
<value>What should be done?</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextErrorConverting" xml:space="preserve">
|
||||||
|
<value>Error occured while converting file
|
||||||
|
{0}
|
||||||
|
{1}</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextFileAlreadyExists" xml:space="preserve">
|
||||||
|
<value>File {0} already exists in the destination folder.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -460,7 +460,7 @@
|
|||||||
<value>Выбрать файлы</value>
|
<value>Выбрать файлы</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TextErrorExtracting" xml:space="preserve">
|
<data name="TextErrorExtracting" xml:space="preserve">
|
||||||
<value>Произошёл сбой во время извлечения файла
|
<value>Не удалось извлечь файл
|
||||||
{0}
|
{0}
|
||||||
{1}</value>
|
{1}</value>
|
||||||
</data>
|
</data>
|
||||||
@ -483,4 +483,39 @@
|
|||||||
<data name="CtxMenuSelectByMask" xml:space="preserve">
|
<data name="CtxMenuSelectByMask" xml:space="preserve">
|
||||||
<value>Выбрать файлы по маске...</value>
|
<value>Выбрать файлы по маске...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ButtonAbort" xml:space="preserve">
|
||||||
|
<value>Прервать</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonContinue" xml:space="preserve">
|
||||||
|
<value>Продолжить</value>
|
||||||
|
</data>
|
||||||
|
<data name="LabelIgnoreErrors" xml:space="preserve">
|
||||||
|
<value>Игнорировать дальнейшие ошибки</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextExtractionError" xml:space="preserve">
|
||||||
|
<value>Ошибка извлечения файла</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonOverwrite" xml:space="preserve">
|
||||||
|
<value>Заменить</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonRename" xml:space="preserve">
|
||||||
|
<value>Переименовать</value>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonSkip" xml:space="preserve">
|
||||||
|
<value>Пропустить</value>
|
||||||
|
</data>
|
||||||
|
<data name="LabelApplyToAll" xml:space="preserve">
|
||||||
|
<value>Применить ко всем совпадающим файлам</value>
|
||||||
|
</data>
|
||||||
|
<data name="LabelDuplicateFileQuestion" xml:space="preserve">
|
||||||
|
<value>Что делать?</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextErrorConverting" xml:space="preserve">
|
||||||
|
<value>Не удадось конвертировать файл
|
||||||
|
{0}
|
||||||
|
{1}</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextFileAlreadyExists" xml:space="preserve">
|
||||||
|
<value>Файл с именем {0} уже существует.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -460,4 +460,49 @@
|
|||||||
<value>Select files by mask...</value>
|
<value>Select files by mask...</value>
|
||||||
<comment>translation pending</comment>
|
<comment>translation pending</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ButtonAbort" xml:space="preserve">
|
||||||
|
<value>Abort</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonContinue" xml:space="preserve">
|
||||||
|
<value>Continue</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="LabelIgnoreErrors" xml:space="preserve">
|
||||||
|
<value>Ignore further errors</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="TextExtractionError" xml:space="preserve">
|
||||||
|
<value>File extraction error</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonOverwrite" xml:space="preserve">
|
||||||
|
<value>Overwrite</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonRename" xml:space="preserve">
|
||||||
|
<value>Rename</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ButtonSkip" xml:space="preserve">
|
||||||
|
<value>Skip</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="LabelApplyToAll" xml:space="preserve">
|
||||||
|
<value>Apply to all duplicate files</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="LabelDuplicateFileQuestion" xml:space="preserve">
|
||||||
|
<value>What should be done?</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="TextErrorConverting" xml:space="preserve">
|
||||||
|
<value>Error occured while converting file
|
||||||
|
{0}
|
||||||
|
{1}</value>
|
||||||
|
<comment>translation pending</comment>
|
||||||
|
</data>
|
||||||
|
<data name="TextFileAlreadyExists" xml:space="preserve">
|
||||||
|
<value>文件{0}已经存在。</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -35,6 +35,14 @@ namespace GARbro.GUI
|
|||||||
{
|
{
|
||||||
internal class NativeMethods
|
internal class NativeMethods
|
||||||
{
|
{
|
||||||
|
public static bool IsWindowsVistaOrLater
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= new Version (6, 0, 6000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[DllImport ("shlwapi.dll", CharSet = CharSet.Unicode)]
|
[DllImport ("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||||
internal static extern int StrCmpLogicalW (string psz1, string psz2);
|
internal static extern int StrCmpLogicalW (string psz1, string psz2);
|
||||||
|
|
||||||
@ -46,6 +54,15 @@ namespace GARbro.GUI
|
|||||||
|
|
||||||
[DllImport ("user32.dll")]
|
[DllImport ("user32.dll")]
|
||||||
internal static extern int ReleaseDC (IntPtr hWnd, IntPtr hDc);
|
internal static extern int ReleaseDC (IntPtr hWnd, IntPtr hDc);
|
||||||
|
|
||||||
|
[DllImport ("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
|
||||||
|
internal static extern IntPtr GetActiveWindow();
|
||||||
|
|
||||||
|
[DllImport ("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool ShowWindow (IntPtr hWnd, int nCmdShow);
|
||||||
|
|
||||||
|
[DllImport ("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool EnableWindow (IntPtr hWnd, bool bEnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Desktop
|
public static class Desktop
|
||||||
|
Loading…
Reference in New Issue
Block a user