From bf9605a7c39717f42961d2566428d676c6dc269f Mon Sep 17 00:00:00 2001 From: Takayoshi Matsuyama Date: Thu, 2 Apr 2015 05:14:50 +0900 Subject: [PATCH] Ver.1.0.0.185 Task187 Interface based design --- Main/App.config | 15 +- Main/App.xaml | 9 +- Main/App.xaml.cs | 43 +- Main/Bootstrapper.cs | 97 ++ Main/Documents/Screenshot.png | Bin 0 -> 42523 bytes Main/Properties/AssemblyInfo.cs | 12 +- Main/Properties/Settings.Designer.cs | 24 - Main/Properties/Settings.settings | 11 +- .../AppInfrastructure/IAppComponent.cs | 34 + Main/SimpleBackup.Core/Models/BackupSourceType.cs | 39 + Main/SimpleBackup.Core/Models/BackupState.cs | 59 + Main/SimpleBackup.Core/Models/IBackupInfo.cs | 101 ++ Main/SimpleBackup.Core/Models/IBackupSetting.cs | 96 ++ .../Models/IDestinationPathInfo.cs | 39 + Main/SimpleBackup.Core/Models/IModelFactory.cs | 130 +++ Main/SimpleBackup.Core/Models/IResultInfo.cs | 39 + .../Models/ItemMovingDirection.cs | 39 + Main/SimpleBackup.Core/ObjectContainer.cs | 92 ++ .../Services/FileBackupProgressEventArgs.cs | 53 + Main/SimpleBackup.Core/Services/IBackupService.cs | 62 + .../Services/IBackupSettingService.cs | 134 +++ .../Services/IClipboardService.cs | 63 + .../SimpleBackup.Core/Services/ISettingsService.cs | 39 + .../SimpleBackup.Core/Services/IUndoRedoService.cs | 68 ++ .../Services/SettingFileEventArgs.cs | 49 + Main/SimpleBackup.Core/SimpleBackup.Core.csproj | 115 ++ Main/SimpleBackup.Core/SimpleBackupKey.snk | Bin 0 -> 596 bytes Main/SimpleBackup.Core/Utilities/Constants.cs | 56 + .../Utilities/HelperExtensions.cs | 214 ++++ Main/SimpleBackup.Core/Utilities/Helpers.cs | 167 +++ Main/SimpleBackup.Core/Utilities/IdIndexPair.cs | 64 + .../Utilities/PropertyChangeNotificationBase.cs | 48 + .../ViewModels/BackupInfoPathType.cs | 39 + .../ViewModels/FocusOnGridRowEventArgs.cs | 51 + .../ViewModels/IBackupInfoViewModel.cs | 123 ++ .../IDestinationColumnHeaderViewModel.cs | 30 + .../ViewModels/ILabelColumnHeaderViewModel.cs | 30 + .../ViewModels/IMainWindowViewModel.cs | 52 + .../ViewModels/ISourceColumnHeaderViewModel.cs | 30 + .../ViewModels/IViewModelFactory.cs | 35 + Main/SimpleBackup.Core/ViewModels/PasteType.cs | 39 + ...ataGridSelectedFirstCellItemChangedEventArgs.cs | 54 + Main/SimpleBackup.Core/Views/IFileFolderDialog.cs | 42 + Main/SimpleBackup.Core/Views/IMainWindow.cs | 39 + .../Views/IVersionInformationWindow.cs | 35 + Main/SimpleBackup.Core/Views/IViewFactory.cs | 47 + Main/SimpleBackup.Core/Views/RelayCommand.cs | 105 ++ Main/SimpleBackup.Models/BackupInfo.cs | 464 ++++++++ Main/SimpleBackup.Models/BackupSetting.cs | 246 ++++ Main/SimpleBackup.Models/DestinationPathInfo.cs | 52 + Main/SimpleBackup.Models/ModelComponent.cs | 41 + Main/SimpleBackup.Models/ModelFactory.cs | 278 +++++ Main/SimpleBackup.Models/ResultInfo.cs | 52 + .../SimpleBackup.Models/SimpleBackup.Models.csproj | 90 ++ Main/SimpleBackup.Models/SimpleBackupKey.snk | Bin 0 -> 596 bytes .../Images/Activity_16xLG.png | Bin 0 -> 543 bytes .../Images/AddVariable_5541.png | Bin 0 -> 331 bytes .../Images/ApplicationIcon.ico | Bin 0 -> 22486 bytes .../Images/Arrow_RedoRetry_16xLG.png | Bin 0 -> 416 bytes .../Images/Arrow_UndoRevertRestore_16xLG.png | Bin 0 -> 464 bytes Main/SimpleBackup.Resources/Images/Copy_6524.png | Bin 0 -> 150 bytes Main/SimpleBackup.Resources/Images/Cut_6523.png | Bin 0 -> 379 bytes .../Images/Delete_black_32x32.png | Bin 0 -> 4229 bytes .../Images/FileGroup_10135_32x.png | Bin 0 -> 448 bytes .../SimpleBackup.Resources/Images/NewFile_6276.png | Bin 0 -> 270 bytes Main/SimpleBackup.Resources/Images/Open_6529.png | Bin 0 -> 343 bytes Main/SimpleBackup.Resources/Images/Paste_6520.png | Bin 0 -> 275 bytes Main/SimpleBackup.Resources/Images/Print_11009.png | Bin 0 -> 210 bytes ...atusAnnotations_Complete_and_ok_32xLG_color.png | Bin 0 -> 677 bytes .../StatusAnnotations_Critical_32xLG_color.png | Bin 0 -> 745 bytes .../Images/Symbols_Complete_and_ok_32xLG.png | Bin 0 -> 332 bytes .../Images/Synchronize_16xLG.png | Bin 0 -> 436 bytes Main/SimpleBackup.Resources/Images/Warning.png | Bin 0 -> 3520 bytes .../Images/action_Cancel_16xLG.png | Bin 0 -> 637 bytes .../Images/arrow_Down_16xLG.png | Bin 0 -> 238 bytes .../Images/arrow_Up_16xLG.png | Bin 0 -> 230 bytes .../Images/arrow_all_run_16xLG.png | Bin 0 -> 3232 bytes .../Images/arrow_run_16xLG.png | Bin 0 -> 347 bytes .../Images/document_32xLG.png | Bin 0 -> 379 bytes Main/SimpleBackup.Resources/Images/flag_16xLG.png | Bin 0 -> 256 bytes .../Images/refresh_16xLG.png | Bin 0 -> 492 bytes Main/SimpleBackup.Resources/Images/save_16xLG.png | Bin 0 -> 206 bytes Main/SimpleBackup.Resources/ResourceHelper.cs | 156 +++ Main/SimpleBackup.Resources/Resources.Designer.cs | 778 +++++++++++++ Main/SimpleBackup.Resources/Resources.ja.resx | 348 ++++++ Main/SimpleBackup.Resources/Resources.resx | 361 ++++++ .../SimpleBackup.Resources.csproj | 165 +++ Main/SimpleBackup.Resources/SimpleBackupKey.snk | Bin 0 -> 596 bytes Main/SimpleBackup.Services/BackupService.cs | 643 ++++++++++ Main/SimpleBackup.Services/BackupSettingService.cs | 591 ++++++++++ Main/SimpleBackup.Services/ClipboardService.cs | 139 +++ .../Properties/Settings.Designer.cs | 50 + .../Properties/Settings.settings | 12 + Main/SimpleBackup.Services/ServiceComponent.cs | 45 + Main/SimpleBackup.Services/SettingsService.cs | 110 ++ .../SimpleBackup.Services.csproj | 108 ++ Main/SimpleBackup.Services/SimpleBackupKey.snk | Bin 0 -> 596 bytes Main/SimpleBackup.Services/UndoRedoActionSet.cs | 71 ++ Main/SimpleBackup.Services/UndoRedoService.cs | 144 +++ Main/SimpleBackup.Services/app.config | 18 + .../SimpleBackup.ViewModels/BackupInfoPasteInfo.cs | 67 ++ .../SimpleBackup.ViewModels/BackupInfoViewModel.cs | 794 +++++++++++++ .../DataGridColumnHeaderBaseViewModel.cs | 56 + .../DestinationColumnHeaderViewModel.cs | 32 + .../EncodingInfoItemViewModel.cs | 55 + .../IndexBackupInfoViewModelPair.cs | 63 + .../IsZipArchiveColumnHeaderViewModel.cs | 30 + .../LabelColumnHeaderViewModel.cs | 32 + .../SimpleBackup.ViewModels/MainWindowViewModel.cs | 1223 ++++++++++++++++++++ Main/SimpleBackup.ViewModels/ProgressViewModel.cs | 56 + .../SimpleBackup.ViewModels.csproj | 100 ++ Main/SimpleBackup.ViewModels/SimpleBackupKey.snk | Bin 0 -> 596 bytes .../SourceColumnHeaderViewModel.cs | 32 + Main/SimpleBackup.ViewModels/ViewModelComponent.cs | 41 + Main/SimpleBackup.ViewModels/ViewModelFactory.cs | 40 + .../BackupSourceTypeToImageConverter.cs | 87 ++ .../BackupStateToImageConverter.cs | 99 ++ Main/SimpleBackup.Views/ExDataGrid.cs | 148 +++ .../ExDataGridSelectedFirstCellItemBehavior.cs | 102 ++ Main/SimpleBackup.Views/FileFolderDialog.cs | 157 +++ Main/SimpleBackup.Views/MainWindow.xaml | 553 +++++++++ Main/SimpleBackup.Views/MainWindow.xaml.cs | 356 ++++++ Main/SimpleBackup.Views/SimpleBackup.Views.csproj | 118 ++ Main/SimpleBackup.Views/SimpleBackupKey.snk | Bin 0 -> 596 bytes .../VersionInformationWindow.xaml | 66 ++ .../VersionInformationWindow.xaml.cs | 59 + Main/SimpleBackup.Views/ViewComponent.cs | 41 + Main/SimpleBackup.Views/ViewFactory.cs | 69 ++ Main/SimpleBackup.csproj | 156 +-- Main/SimpleBackup.psess | 80 ++ Main/SimpleBackup.sln | 61 +- 131 files changed, 12279 insertions(+), 218 deletions(-) create mode 100644 Main/Bootstrapper.cs create mode 100644 Main/Documents/Screenshot.png create mode 100644 Main/SimpleBackup.Core/AppInfrastructure/IAppComponent.cs create mode 100644 Main/SimpleBackup.Core/Models/BackupSourceType.cs create mode 100644 Main/SimpleBackup.Core/Models/BackupState.cs create mode 100644 Main/SimpleBackup.Core/Models/IBackupInfo.cs create mode 100644 Main/SimpleBackup.Core/Models/IBackupSetting.cs create mode 100644 Main/SimpleBackup.Core/Models/IDestinationPathInfo.cs create mode 100644 Main/SimpleBackup.Core/Models/IModelFactory.cs create mode 100644 Main/SimpleBackup.Core/Models/IResultInfo.cs create mode 100644 Main/SimpleBackup.Core/Models/ItemMovingDirection.cs create mode 100644 Main/SimpleBackup.Core/ObjectContainer.cs create mode 100644 Main/SimpleBackup.Core/Services/FileBackupProgressEventArgs.cs create mode 100644 Main/SimpleBackup.Core/Services/IBackupService.cs create mode 100644 Main/SimpleBackup.Core/Services/IBackupSettingService.cs create mode 100644 Main/SimpleBackup.Core/Services/IClipboardService.cs create mode 100644 Main/SimpleBackup.Core/Services/ISettingsService.cs create mode 100644 Main/SimpleBackup.Core/Services/IUndoRedoService.cs create mode 100644 Main/SimpleBackup.Core/Services/SettingFileEventArgs.cs create mode 100644 Main/SimpleBackup.Core/SimpleBackup.Core.csproj create mode 100644 Main/SimpleBackup.Core/SimpleBackupKey.snk create mode 100644 Main/SimpleBackup.Core/Utilities/Constants.cs create mode 100644 Main/SimpleBackup.Core/Utilities/HelperExtensions.cs create mode 100644 Main/SimpleBackup.Core/Utilities/Helpers.cs create mode 100644 Main/SimpleBackup.Core/Utilities/IdIndexPair.cs create mode 100644 Main/SimpleBackup.Core/Utilities/PropertyChangeNotificationBase.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/BackupInfoPathType.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/FocusOnGridRowEventArgs.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/IBackupInfoViewModel.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/IDestinationColumnHeaderViewModel.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/ILabelColumnHeaderViewModel.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/IMainWindowViewModel.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/ISourceColumnHeaderViewModel.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/IViewModelFactory.cs create mode 100644 Main/SimpleBackup.Core/ViewModels/PasteType.cs create mode 100644 Main/SimpleBackup.Core/Views/ExDataGridSelectedFirstCellItemChangedEventArgs.cs create mode 100644 Main/SimpleBackup.Core/Views/IFileFolderDialog.cs create mode 100644 Main/SimpleBackup.Core/Views/IMainWindow.cs create mode 100644 Main/SimpleBackup.Core/Views/IVersionInformationWindow.cs create mode 100644 Main/SimpleBackup.Core/Views/IViewFactory.cs create mode 100644 Main/SimpleBackup.Core/Views/RelayCommand.cs create mode 100644 Main/SimpleBackup.Models/BackupInfo.cs create mode 100644 Main/SimpleBackup.Models/BackupSetting.cs create mode 100644 Main/SimpleBackup.Models/DestinationPathInfo.cs create mode 100644 Main/SimpleBackup.Models/ModelComponent.cs create mode 100644 Main/SimpleBackup.Models/ModelFactory.cs create mode 100644 Main/SimpleBackup.Models/ResultInfo.cs create mode 100644 Main/SimpleBackup.Models/SimpleBackup.Models.csproj create mode 100644 Main/SimpleBackup.Models/SimpleBackupKey.snk create mode 100644 Main/SimpleBackup.Resources/Images/Activity_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/AddVariable_5541.png create mode 100644 Main/SimpleBackup.Resources/Images/ApplicationIcon.ico create mode 100644 Main/SimpleBackup.Resources/Images/Arrow_RedoRetry_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/Arrow_UndoRevertRestore_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/Copy_6524.png create mode 100644 Main/SimpleBackup.Resources/Images/Cut_6523.png create mode 100644 Main/SimpleBackup.Resources/Images/Delete_black_32x32.png create mode 100644 Main/SimpleBackup.Resources/Images/FileGroup_10135_32x.png create mode 100644 Main/SimpleBackup.Resources/Images/NewFile_6276.png create mode 100644 Main/SimpleBackup.Resources/Images/Open_6529.png create mode 100644 Main/SimpleBackup.Resources/Images/Paste_6520.png create mode 100644 Main/SimpleBackup.Resources/Images/Print_11009.png create mode 100644 Main/SimpleBackup.Resources/Images/StatusAnnotations_Complete_and_ok_32xLG_color.png create mode 100644 Main/SimpleBackup.Resources/Images/StatusAnnotations_Critical_32xLG_color.png create mode 100644 Main/SimpleBackup.Resources/Images/Symbols_Complete_and_ok_32xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/Synchronize_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/Warning.png create mode 100644 Main/SimpleBackup.Resources/Images/action_Cancel_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/arrow_Down_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/arrow_Up_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/arrow_all_run_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/arrow_run_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/document_32xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/flag_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/refresh_16xLG.png create mode 100644 Main/SimpleBackup.Resources/Images/save_16xLG.png create mode 100644 Main/SimpleBackup.Resources/ResourceHelper.cs create mode 100644 Main/SimpleBackup.Resources/Resources.Designer.cs create mode 100644 Main/SimpleBackup.Resources/Resources.ja.resx create mode 100644 Main/SimpleBackup.Resources/Resources.resx create mode 100644 Main/SimpleBackup.Resources/SimpleBackup.Resources.csproj create mode 100644 Main/SimpleBackup.Resources/SimpleBackupKey.snk create mode 100644 Main/SimpleBackup.Services/BackupService.cs create mode 100644 Main/SimpleBackup.Services/BackupSettingService.cs create mode 100644 Main/SimpleBackup.Services/ClipboardService.cs create mode 100644 Main/SimpleBackup.Services/Properties/Settings.Designer.cs create mode 100644 Main/SimpleBackup.Services/Properties/Settings.settings create mode 100644 Main/SimpleBackup.Services/ServiceComponent.cs create mode 100644 Main/SimpleBackup.Services/SettingsService.cs create mode 100644 Main/SimpleBackup.Services/SimpleBackup.Services.csproj create mode 100644 Main/SimpleBackup.Services/SimpleBackupKey.snk create mode 100644 Main/SimpleBackup.Services/UndoRedoActionSet.cs create mode 100644 Main/SimpleBackup.Services/UndoRedoService.cs create mode 100644 Main/SimpleBackup.Services/app.config create mode 100644 Main/SimpleBackup.ViewModels/BackupInfoPasteInfo.cs create mode 100644 Main/SimpleBackup.ViewModels/BackupInfoViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/DataGridColumnHeaderBaseViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/DestinationColumnHeaderViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/EncodingInfoItemViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/IndexBackupInfoViewModelPair.cs create mode 100644 Main/SimpleBackup.ViewModels/IsZipArchiveColumnHeaderViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/LabelColumnHeaderViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/MainWindowViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/ProgressViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/SimpleBackup.ViewModels.csproj create mode 100644 Main/SimpleBackup.ViewModels/SimpleBackupKey.snk create mode 100644 Main/SimpleBackup.ViewModels/SourceColumnHeaderViewModel.cs create mode 100644 Main/SimpleBackup.ViewModels/ViewModelComponent.cs create mode 100644 Main/SimpleBackup.ViewModels/ViewModelFactory.cs create mode 100644 Main/SimpleBackup.Views/BackupSourceTypeToImageConverter.cs create mode 100644 Main/SimpleBackup.Views/BackupStateToImageConverter.cs create mode 100644 Main/SimpleBackup.Views/ExDataGrid.cs create mode 100644 Main/SimpleBackup.Views/ExDataGridSelectedFirstCellItemBehavior.cs create mode 100644 Main/SimpleBackup.Views/FileFolderDialog.cs create mode 100644 Main/SimpleBackup.Views/MainWindow.xaml create mode 100644 Main/SimpleBackup.Views/MainWindow.xaml.cs create mode 100644 Main/SimpleBackup.Views/SimpleBackup.Views.csproj create mode 100644 Main/SimpleBackup.Views/SimpleBackupKey.snk create mode 100644 Main/SimpleBackup.Views/VersionInformationWindow.xaml create mode 100644 Main/SimpleBackup.Views/VersionInformationWindow.xaml.cs create mode 100644 Main/SimpleBackup.Views/ViewComponent.cs create mode 100644 Main/SimpleBackup.Views/ViewFactory.cs create mode 100644 Main/SimpleBackup.psess diff --git a/Main/App.config b/Main/App.config index 4d0f454..89a67b9 100644 --- a/Main/App.config +++ b/Main/App.config @@ -13,25 +13,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Foobar. If not, see . +along with Simple Backup. If not, see . --> - -
- - - - - - - - - - - \ No newline at end of file diff --git a/Main/App.xaml b/Main/App.xaml index 89f7c69..55ca79c 100644 --- a/Main/App.xaml +++ b/Main/App.xaml @@ -12,12 +12,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Foobar. If not, see . +along with Simple Backup. If not, see . --> + - - - - + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"/> diff --git a/Main/App.xaml.cs b/Main/App.xaml.cs index b3a2597..4fac83b 100644 --- a/Main/App.xaml.cs +++ b/Main/App.xaml.cs @@ -17,27 +17,37 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with Foobar. If not, see . - -using System; -using System.Windows; -using SimpleBackup.Services; -using SimpleBackup.ViewModels; -using SimpleBackup.Views; +// along with Simple Backup. If not, see . namespace SimpleBackup { + using System; + using System.Windows; + using SimpleBackup.Core; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.ViewModels; + using SimpleBackup.Core.Views; + /// - /// App.xaml の相互作用ロジック + /// The Code-Behind of App.xaml. /// public partial class App : Application { + /// + /// Raises the event. + /// + /// A that contains the event data. protected override void OnStartup(StartupEventArgs e) { try { - var mainWindow = new MainWindow(); - var mainWindowViewModel = new MainWindowViewModel(); + var bootStrapper = new Bootstrapper(); + bootStrapper.Execute(); + + var viewFactory = ObjectContainer.Resolve(); + var viewModelFactory = ObjectContainer.Resolve(); + IMainWindow mainWindow = viewFactory.CreateMainWindow(); + IMainWindowViewModel mainWindowViewModel = viewModelFactory.CreateMainWindowViewModel(); mainWindow.DataContext = mainWindowViewModel; mainWindow.Show(); } @@ -47,15 +57,20 @@ namespace SimpleBackup } } + /// + /// Raises the event. + /// + /// An that contains the event data. protected override void OnExit(ExitEventArgs e) { base.OnExit(e); - if (BackupSettingService.Instance.CurrentSetting != null) + var backupSettingService = ObjectContainer.Resolve(); + if (backupSettingService.CurrentSetting != null) { - SimpleBackup.Properties.Settings.Default.DefaultSettingFileName = - BackupSettingService.Instance.CurrentSetting.SettingFileName; - SimpleBackup.Properties.Settings.Default.Save(); + var settingsService = ObjectContainer.Resolve(); + settingsService.DefaultSettingFileName = + backupSettingService.CurrentSetting.SettingFileName; } } } diff --git a/Main/Bootstrapper.cs b/Main/Bootstrapper.cs new file mode 100644 index 0000000..5e3b8aa --- /dev/null +++ b/Main/Bootstrapper.cs @@ -0,0 +1,97 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Reflection; + using SimpleBackup.Core.AppInfrastructure; + + /// + /// Executes application starting procedure. + /// + public class Bootstrapper + { + /// + /// Executes application starting procedure. + /// + public void Execute() + { + IAppComponent[] appComponents = SearchApplicationComponents(); + InitializeAppComponents(appComponents); + } + + /// + /// Searches the application components. + /// + /// The collection of application component. + private static IAppComponent[] SearchApplicationComponents() + { + Type appComponenType = typeof(IAppComponent); + var appComponents = new HashSet(); + + Assembly executingAssembly = Assembly.GetExecutingAssembly(); + string executingAssemblyFolder = Path.GetDirectoryName(executingAssembly.Location); + string[] files = Directory.GetFiles(executingAssemblyFolder, "*.dll"); + foreach (string file in files) + { + Assembly assembly = Assembly.LoadFrom(file); + Type[] types = assembly.GetTypes(); + foreach (Type type in types) + { + Type[] interfaceTypes = type.GetInterfaces(); + foreach (Type interfaceType in interfaceTypes) + { + if ((interfaceType.FullName == appComponenType.FullName) && + (interfaceType.Assembly.FullName == appComponenType.Assembly.FullName)) + { + appComponents.Add((IAppComponent)Activator.CreateInstance(type)); + } + } + } + } + + return appComponents.ToArray(); + } + + /// + /// Initializes the application components. + /// + /// The application components. + private static void InitializeAppComponents(IEnumerable appComponents) + { + foreach (IAppComponent appComponent in appComponents) + { + try + { + appComponent.Initialize(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + } + } +} diff --git a/Main/Documents/Screenshot.png b/Main/Documents/Screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..4528a2a81efa67856fa2c339bad6de408bfa8e25 GIT binary patch literal 42523 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

uEQi33NO1W6Z}h{bcoJM?cf{BlL* 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 literal 0 HcmV?d00001 diff --git a/Main/Properties/AssemblyInfo.cs b/Main/Properties/AssemblyInfo.cs index 4188813..ea5202c 100644 --- a/Main/Properties/AssemblyInfo.cs +++ b/Main/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with Foobar. If not, see . +// along with Simple Backup. If not, see . using System.Reflection; using System.Resources; @@ -34,10 +34,10 @@ using System.Windows; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, - ResourceDictionaryLocation.SourceAssembly)] +//[assembly: ThemeInfo( +// ResourceDictionaryLocation.None, +// ResourceDictionaryLocation.SourceAssembly)] -[assembly: AssemblyVersion("1.0.0.182")] -[assembly: AssemblyFileVersion("1.0.0.182")] +[assembly: AssemblyVersion("1.0.0.185")] +[assembly: AssemblyFileVersion("1.0.0.185")] [assembly: NeutralResourcesLanguageAttribute("en")] diff --git a/Main/Properties/Settings.Designer.cs b/Main/Properties/Settings.Designer.cs index 1735088..99259b0 100644 --- a/Main/Properties/Settings.Designer.cs +++ b/Main/Properties/Settings.Designer.cs @@ -22,29 +22,5 @@ namespace SimpleBackup.Properties { return defaultInstance; } } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string DefaultSettingFileName { - get { - return ((string)(this["DefaultSettingFileName"])); - } - set { - this["DefaultSettingFileName"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string DefaultZipEncodingKeyText { - get { - return ((string)(this["DefaultZipEncodingKeyText"])); - } - set { - this["DefaultZipEncodingKeyText"] = value; - } - } } } diff --git a/Main/Properties/Settings.settings b/Main/Properties/Settings.settings index cec136e..8e615f2 100644 --- a/Main/Properties/Settings.settings +++ b/Main/Properties/Settings.settings @@ -1,12 +1,5 @@  - + - - - - - - - - + \ No newline at end of file diff --git a/Main/SimpleBackup.Core/AppInfrastructure/IAppComponent.cs b/Main/SimpleBackup.Core/AppInfrastructure/IAppComponent.cs new file mode 100644 index 0000000..9fed912 --- /dev/null +++ b/Main/SimpleBackup.Core/AppInfrastructure/IAppComponent.cs @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.AppInfrastructure +{ + ///

+ /// Interface of an application component. + /// + public interface IAppComponent + { + /// + /// Initializes this application component. + /// + void Initialize(); + } +} diff --git a/Main/SimpleBackup.Core/Models/BackupSourceType.cs b/Main/SimpleBackup.Core/Models/BackupSourceType.cs new file mode 100644 index 0000000..1befdbf --- /dev/null +++ b/Main/SimpleBackup.Core/Models/BackupSourceType.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + /// + /// Represents backup source type. + /// + public enum BackupSourceType + { + /// + /// The file + /// + File, + + /// + /// The folder + /// + Folder + } +} diff --git a/Main/SimpleBackup.Core/Models/BackupState.cs b/Main/SimpleBackup.Core/Models/BackupState.cs new file mode 100644 index 0000000..57c755c --- /dev/null +++ b/Main/SimpleBackup.Core/Models/BackupState.cs @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + /// + /// Represents backup state. + /// + public enum BackupState + { + /// + /// The to do + /// + Todo, + + /// + /// The in progress + /// + InProgress, + + /// + /// The success + /// + Success, + + /// + /// The failed + /// + Failed, + + /// + /// The cancelled + /// + Cancelled, + + /// + /// The skipped + /// + Skipped, + } +} diff --git a/Main/SimpleBackup.Core/Models/IBackupInfo.cs b/Main/SimpleBackup.Core/Models/IBackupInfo.cs new file mode 100644 index 0000000..c5ac655 --- /dev/null +++ b/Main/SimpleBackup.Core/Models/IBackupInfo.cs @@ -0,0 +1,101 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + using System; + using System.ComponentModel; + using System.Xml.Linq; + + /// + /// A interface of single backup information. + /// + public interface IBackupInfo : INotifyPropertyChanged + { + /// + /// Occurs when a property which has to be saved in setting file is changed. + /// + event EventHandler SettingFilePropertyChanged; + + /// + /// Gets or sets the identifier. + /// + Guid Id { get; set; } + + /// + /// Gets or sets the label. + /// + string Label { get; set; } + + /// + /// Gets or sets the type of the backup source. + /// + BackupSourceType BackupSourceType { get; set; } + + /// + /// Gets or sets a value indicating whether the backup is enabled. + /// + bool IsEnabled { get; set; } + + /// + /// Gets or sets a value indicating whether the backup is zip archive. + /// + bool IsZipArchive { get; set; } + + /// + /// Gets or sets the source path. + /// + string SourcePath { get; set; } + + /// + /// Gets or sets the destination folder path. + /// + string DestinationFolderPath { get; set; } + + /// + /// Gets or sets the state of the backup. + /// + BackupState BackupState { get; set; } + + /// + /// Gets or sets the name of the latest successful backup target. + /// + string LatestSuccessfulBackupTargetName { get; set; } + + /// + /// Saves this instance to a XElement. + /// + /// The generated XElement. + XElement ToXml(); + + /// + /// Gets the binary representation of this instance. + /// + /// The binary representation of this instance. + byte[] ToBinary(); + + /// + /// Gets the formatted text representation of this instance. + /// + /// The text representation of this instance. + string ToFormattedText(); + } +} diff --git a/Main/SimpleBackup.Core/Models/IBackupSetting.cs b/Main/SimpleBackup.Core/Models/IBackupSetting.cs new file mode 100644 index 0000000..ef11a85 --- /dev/null +++ b/Main/SimpleBackup.Core/Models/IBackupSetting.cs @@ -0,0 +1,96 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + using System; + using System.Collections.Generic; + using System.Xml.Linq; + + /// + /// Interface of a backup setting. + /// + public interface IBackupSetting + { + /// + /// Occurs when backup setting is modified. + /// + event EventHandler SettingModified; + + /// + /// Gets the name of the setting. + /// + string SettingName { get; } + + /// + /// Gets or sets the name of the setting file. + /// + string SettingFileName { get; set; } + + /// + /// Gets or sets a value indicating whether this is modified. + /// + bool Modified { get; set; } + + /// + /// Gets the backup infos. + /// + IReadOnlyCollection BackupInfos { get; } + + /// + /// Gets the count of backup Information item. + /// + int Count { get; } + + /// + /// Firsts the or default. + /// + /// The identifier. + /// The IBackupInfo which is firstly found or null. + IBackupInfo FirstOrDefault(Guid id); + + /// + /// Inserts the specified index. + /// + /// The index. + /// The backup information. + void Insert(int index, IBackupInfo backupInfo); + + /// + /// Removes the specified removing backup information. + /// + /// The removing backup information. + void Remove(IBackupInfo removingBackupInfo); + + /// + /// Moves the item. + /// + /// The backup information identifier. + /// The moving direction. + void MoveItem(Guid backupInfoId, ItemMovingDirection movingDirection); + + /// + /// To the XML. + /// + /// The xml data. + XElement ToXml(); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Models/IDestinationPathInfo.cs b/Main/SimpleBackup.Core/Models/IDestinationPathInfo.cs new file mode 100644 index 0000000..9a72c73 --- /dev/null +++ b/Main/SimpleBackup.Core/Models/IDestinationPathInfo.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + /// + /// Interface of a destination path information. + /// + public interface IDestinationPathInfo + { + /// + /// Gets the type of the backup source. + /// + BackupSourceType BackupSourceType { get; } + + /// + /// Gets the path. + /// + string Path { get; } + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Models/IModelFactory.cs b/Main/SimpleBackup.Core/Models/IModelFactory.cs new file mode 100644 index 0000000..542bea0 --- /dev/null +++ b/Main/SimpleBackup.Core/Models/IModelFactory.cs @@ -0,0 +1,130 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + using System; + using System.Collections.Generic; + using System.Xml.Linq; + + /// + /// Interface of a model factory. + /// + public interface IModelFactory + { + /// + /// Creates the backup setting. + /// + /// The backup setting. + IBackupSetting CreateBackupSetting(); + + /// + /// Creates the backup setting. + /// + /// Name of the setting file. + /// The backup information collection. + /// The backup setting. + IBackupSetting CreateBackupSetting(string settingFileName, IEnumerable backupInfoCollection); + + /// + /// Creates the backup information. + /// + /// The backup inforamtion. + IBackupInfo CreateBackupInfo(); + + /// + /// Creates the backup information. + /// + /// The source backup information. + /// The backup inforamtion. + IBackupInfo CreateBackupInfo(IBackupInfo sourceBackupInfo); + + /// + /// Creates the backup information. + /// + /// The label. + /// Type of the backup source. + /// if set to true [is enabled]. + /// if set to true [is zip archive]. + /// The source path. + /// The destination folder path. + /// The backup inforamtion. + IBackupInfo CreateBackupInfo( + string label, + BackupSourceType backupSourceType, + bool isEnabled, + bool isZipArchive, + string sourcePath, + string destinationFolderPath); + + /// + /// Creates the backup information. + /// + /// The identifier. + /// The label. + /// Type of the backup source. + /// if set to true [is enabled]. + /// if set to true [is zip archive]. + /// The source path. + /// The destination folder path. + /// The backup inforamtion. + IBackupInfo CreateBackupInfo( + Guid id, + string label, + BackupSourceType backupSourceType, + bool isEnabled, + bool isZipArchive, + string sourcePath, + string destinationFolderPath); + + /// + /// Creates the backup information from binary. + /// + /// The binary data. + /// if set to true copy suffix is needed. + /// The backup inforamtion. + IBackupInfo CreateBackupInfoFromBinary(byte[] binaryData, bool copySuffixNeeded); + + /// + /// Creates the result information. + /// + /// The category. + /// The description. + /// The result inforamtion. + IResultInfo CreateResultInfo(BackupState category, string description); + + /// + /// Creates the destination path information. + /// + /// Type of the backup source. + /// The path. + /// The destination path information. + IDestinationPathInfo CreateDestinationPathInfo(BackupSourceType backupSourceType, string path); + + /// + /// Restores the backup setting from XML. + /// + /// The XML. + /// Name of the file. + /// The restored backup setting. + IBackupSetting RestoreBackupSettingFromXml(XElement xml, string fileName); + } +} diff --git a/Main/SimpleBackup.Core/Models/IResultInfo.cs b/Main/SimpleBackup.Core/Models/IResultInfo.cs new file mode 100644 index 0000000..5a8f163 --- /dev/null +++ b/Main/SimpleBackup.Core/Models/IResultInfo.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + /// + /// Interface of a result information. + /// + public interface IResultInfo + { + /// + /// Gets the state of the backup. + /// + BackupState BackupState { get; } + + /// + /// Gets the description. + /// + string Description { get; } + } +} diff --git a/Main/SimpleBackup.Core/Models/ItemMovingDirection.cs b/Main/SimpleBackup.Core/Models/ItemMovingDirection.cs new file mode 100644 index 0000000..6d38734 --- /dev/null +++ b/Main/SimpleBackup.Core/Models/ItemMovingDirection.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Models +{ + /// + /// Represents item moving direction. + /// + public enum ItemMovingDirection + { + /// + /// The move up + /// + MoveUp, + + /// + /// The move down + /// + MoveDown + } +} diff --git a/Main/SimpleBackup.Core/ObjectContainer.cs b/Main/SimpleBackup.Core/ObjectContainer.cs new file mode 100644 index 0000000..3b95341 --- /dev/null +++ b/Main/SimpleBackup.Core/ObjectContainer.cs @@ -0,0 +1,92 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core +{ + using System; + using System.Collections.Generic; + using SimpleBackup.Core.Utilities; + + /// + /// The container class which contains objects with corresponding interface type. + /// + public static class ObjectContainer + { + /// + /// The object dictionary. + /// + private static readonly Dictionary ObjectDictionary = new Dictionary(); + + /// + /// The lock object. + /// + private static readonly object LockObj = new object(); + + /// + /// Registers the specified object instance. + /// + /// The type of the interface. + /// The object instance. + /// The provided object instance is null. + /// The specified type is not an interface. + public static void Register(TInterface objectInstance) + { + objectInstance.ThrowsArgumentNullException("objectInstance"); + + Type type = typeof(TInterface); + if (type.IsInterface == false) + { + throw new ArgumentException(string.Format("The specified type {0} is not an interface.", type)); + } + + lock (LockObj) + { + ObjectDictionary.Add(type, objectInstance); + } + } + + /// + /// Resolves this instance. + /// + /// The type of the interface. + /// The object instance or null. + /// The specified type is not an interface. + public static TInterface Resolve() + { + Type type = typeof(TInterface); + if (type.IsInterface == false) + { + throw new ArgumentException(string.Format("The specified type {0} is not an interface.", type)); + } + + lock (LockObj) + { + object instance; + if (ObjectDictionary.TryGetValue(type, out instance)) + { + return (TInterface)instance; + } + + return default(TInterface); + } + } + } +} diff --git a/Main/SimpleBackup.Core/Services/FileBackupProgressEventArgs.cs b/Main/SimpleBackup.Core/Services/FileBackupProgressEventArgs.cs new file mode 100644 index 0000000..92643df --- /dev/null +++ b/Main/SimpleBackup.Core/Services/FileBackupProgressEventArgs.cs @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Services +{ + using System; + using SimpleBackup.Core.Models; + + /// + /// Event argument which represents file backup progress. + /// + public class FileBackupProgressEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The progress value. + /// The latest result information. + public FileBackupProgressEventArgs(double progressValue, IResultInfo latestResultInfo) + { + this.ProgressValue = progressValue; + this.LatestResultInfo = latestResultInfo; + } + + /// + /// Gets the progress value. + /// + public double ProgressValue { get; private set; } + + /// + /// Gets the latest result information. + /// + public IResultInfo LatestResultInfo { get; private set; } + } +} diff --git a/Main/SimpleBackup.Core/Services/IBackupService.cs b/Main/SimpleBackup.Core/Services/IBackupService.cs new file mode 100644 index 0000000..8479e5a --- /dev/null +++ b/Main/SimpleBackup.Core/Services/IBackupService.cs @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Services +{ + using System; + using System.Threading; + using SimpleBackup.Core.Models; + + /// + /// Provides backup function. + /// + public interface IBackupService + { + /// + /// Occurs when file backup progress is updated. + /// + event EventHandler NofityFileBackupProgress; + + /// + /// Gets a value indicating whether this service is ready for backup. + /// + bool IsReadyForBackup { get; } + + /// + /// Gets a value indicating whether this service is executing backup. + /// + bool IsExecutingBackup { get; } + + /// + /// Backups multipul files. + /// + /// The cancellation token. + /// The array of result information. + void BackupMultipulFiles(CancellationToken cancellationToken, out IResultInfo[] resultInfos); + + /// + /// Backups single file. + /// + /// The backup information identifier. + /// The result information. + IResultInfo BackupSingleFile(Guid backupInfoId); + } +} diff --git a/Main/SimpleBackup.Core/Services/IBackupSettingService.cs b/Main/SimpleBackup.Core/Services/IBackupSettingService.cs new file mode 100644 index 0000000..a017bdc --- /dev/null +++ b/Main/SimpleBackup.Core/Services/IBackupSettingService.cs @@ -0,0 +1,134 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Services +{ + using System; + using SimpleBackup.Core.Models; + + /// + /// Provides backup setting management function. + /// + public interface IBackupSettingService + { + /// + /// Occurs when backup setting is created. + /// + event EventHandler BackupSettingCreated; + + /// + /// Occurs when backup setting is opened. + /// + event EventHandler BackupSettingOpened; + + /// + /// Occurs when backup setting is modified. + /// + event EventHandler BackupSettingModified; + + /// + /// Occurs when backup setting is saved. + /// + event EventHandler BackupSettingSaved; + + /// + /// Occurs when backup setting is closed. + /// + event EventHandler BackupSettingClosed; + + /// + /// Gets the current setting. + /// + IBackupSetting CurrentSetting { get; } + + /// + /// Creates the backup setting. + /// + /// true if the new backup setting is created; otherwise, false. + bool CreateBackupSetting(); + + /// + /// Opens the backup setting. + /// + /// The result message. + /// + /// true if backup setting is successfully loaded; otherwise, false. + /// + bool OpenBackupSetting(out string resultMessage); + + /// + /// Opens the default backup setting. + /// + /// The result message. + /// + /// true if succeeded, otherwise; false. + /// + bool OpenDefaultBackupSetting(out string resultMessage); + + /// + /// Closes the backup setting. + /// + void CloseBackupSetting(); + + /// + /// Overwrites the currnt backup setting. + /// + /// true if the backup setting is saved; otherwise, false. + bool OverWriteCurrntBackupSetting(); + + /// + /// Saves the current backup setting as a new file. + /// + /// true if the backup setting is saved; otherwise, false. + bool SaveCurrentBackupSettingAsNewFile(); + + /// + /// Creates the backup information. + /// + /// The index. + /// The created backup information. + /// + IBackupInfo CreateBackupInfo(int index); + + /// + /// Copies the backup information. + /// + /// The source backup information. + /// The copied backup information. + /// + IBackupInfo CopyBackupInfo(IBackupInfo sourceBackupInfo); + + /// + /// Inserts the backup information. + /// + /// The index. + /// The backup information. + /// + /// + void InsertBackupInfo(int index, IBackupInfo backupInfo); + + /// + /// Removes the backup information. + /// + /// The backup information identifier. + void RemoveBackupInfo(Guid backupInfoId); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Services/IClipboardService.cs b/Main/SimpleBackup.Core/Services/IClipboardService.cs new file mode 100644 index 0000000..4a0959d --- /dev/null +++ b/Main/SimpleBackup.Core/Services/IClipboardService.cs @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Services +{ + using System; + using System.Windows; + + /// + /// Provides clip board access. + /// + public interface IClipboardService + { + /// + /// Sets the data object. + /// + /// The data object. + /// The data object is null. + void SetDataObject(IDataObject dataObject); + + /// + /// Gets the data. + /// + /// The type. + /// The format. + /// + /// The data. + /// + /// The format string is null or empty. + T GetData(string format); + + /// + /// Gets a boolean value indicating whether the clipboard data contains data in specified format. + /// + /// The format. + /// The format string is null or empty. + /// True if the specified format is contained in the Clipboard. + bool DoesClipboardDataContain(string format); + + /// + /// Clears the clipbord. + /// + void ClearClipbord(); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Services/ISettingsService.cs b/Main/SimpleBackup.Core/Services/ISettingsService.cs new file mode 100644 index 0000000..317eb02 --- /dev/null +++ b/Main/SimpleBackup.Core/Services/ISettingsService.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Services +{ + /// + /// Interface of a seting service. + /// + public interface ISettingsService + { + /// + /// Gets or sets the default name of the setting file. + /// + string DefaultSettingFileName { get; set; } + + /// + /// Gets or sets the default zip encoding key text. + /// + string DefaultZipEncodingKeyText { get; set; } + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Services/IUndoRedoService.cs b/Main/SimpleBackup.Core/Services/IUndoRedoService.cs new file mode 100644 index 0000000..d8982d0 --- /dev/null +++ b/Main/SimpleBackup.Core/Services/IUndoRedoService.cs @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Services +{ + using System; + + /// + /// Provides undo/redo function. + /// + public interface IUndoRedoService + { + /// + /// Commits the specified redo action with related undo action and the context information. + /// + /// The redo action. + /// The undo action. + /// The context. + /// The redoAction is null. + /// The undoAction is null. + void Commit(Action redoAction, Action undoAction, object context); + + /// + /// Executes undo action. + /// + void Undo(); + + /// + /// Determines whether the undo action is executable. + /// + /// true if the undo action can be executable; otherwise, false. + bool CanExecuteUndo(); + + /// + /// Executes redo action. + /// + void Redo(); + + /// + /// Determines whether the redo action is executable. + /// + /// true if the redo action can be executable; otherwise, false. + bool CanExecuteRedo(); + + /// + /// Clears the undo redo buffer. + /// + void ClearUndoRedoBuffer(); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Services/SettingFileEventArgs.cs b/Main/SimpleBackup.Core/Services/SettingFileEventArgs.cs new file mode 100644 index 0000000..5fe6f7d --- /dev/null +++ b/Main/SimpleBackup.Core/Services/SettingFileEventArgs.cs @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Services +{ + using System; + using SimpleBackup.Core.Utilities; + + /// + /// Setting file event argument + /// + public class SettingFileEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// Name of the setting. + /// The provided setting name is null. + public SettingFileEventArgs(string settingName) + { + settingName.ThrowsArgumentNullException("settingName"); + + this.SettingName = settingName; + } + + /// + /// Gets the name of the setting. + /// + public string SettingName { get; private set; } + } +} diff --git a/Main/SimpleBackup.Core/SimpleBackup.Core.csproj b/Main/SimpleBackup.Core/SimpleBackup.Core.csproj new file mode 100644 index 0000000..6c0cc5f --- /dev/null +++ b/Main/SimpleBackup.Core/SimpleBackup.Core.csproj @@ -0,0 +1,115 @@ + + + + + Debug + AnyCPU + {33F1D454-9962-4EB6-AAD3-8D11D9A78D1F} + Library + Properties + SimpleBackup.Core + SimpleBackup.Core + v4.5 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + SimpleBackupKey.snk + + + + + + + + + + + + + + + + + + Properties\AssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {a655131e-d439-4de1-bc39-5c955306183f} + SimpleBackup.Resources + + + + + \ No newline at end of file diff --git a/Main/SimpleBackup.Core/SimpleBackupKey.snk b/Main/SimpleBackup.Core/SimpleBackupKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..def2e6df6a67d7e5802b3319c2b385c61304db29 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=*mMuj7Bow@Ep}p%TfOae=&U%vR9qh+ z@B2Y7h5t%KB~GowmVCnTwn!=ol7j~SRw};|aqMe69$!Xr!@Kl)p?8Xg2;G;~Cd60S zyuxBRv<}vHJsUi)3u6Y?7~u<-nIO&1Fj-O8+VD)*I{}r1s+^@Kmf2Y}gp`|NRs+em z$u>8Tw)yg`4_#X9od;DS_`m7gjCw7)_oIM$fq-7kckw~B<7M;zI>N{SPq*6$huq7Z zgYNgU;sUWRbAi&O+L_hd!U0Li?IE-i`qYl6ItfNG&LGLWV{U{YZh>Ax4*J$khFNYOR0lC!sQ=xnj0#!GfwNKNLWeC6+{0F(k120wr_Sb zIyF(GL;3}qT}4Ed2plZ&Isj`rlkfJc)Ea1aKb3p_jTAd0vy@;AzzF|BpZp|m^l#y& zbx94OX%V&s<FnfGWY1Nh zxKnroP3(eKfbr85Y^JZ_CW>v48ZxICTuX?#TOI&z>)DFD-NiB2i|wPJnn~;|{CGZv i!2z3|Al4b1%II9A@B0rIjj|^@+oAX!*AylRLZAX-U?o=o literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Core/Utilities/Constants.cs b/Main/SimpleBackup.Core/Utilities/Constants.cs new file mode 100644 index 0000000..0010eb8 --- /dev/null +++ b/Main/SimpleBackup.Core/Utilities/Constants.cs @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Utilities +{ + using System.Text.RegularExpressions; + + /// + /// Defines constants + /// + public static class Constants + { + /// + /// The backup information clipboard format: "BackupInfoClipboardFormat" + /// + public const string BackupInfoClipboardFormat = "BackupInfoClipboardFormat"; + + /// + /// The end path segment regex: "[^\\]*$" + /// + public static readonly Regex EndPathSegmentRegex = new Regex(@"[^\\]*$", RegexOptions.Compiled); + + /// + /// The end path separator regex: "\\$" + /// + public static readonly Regex EndPathSeparatorRegex = new Regex(@"\\$", RegexOptions.Compiled); + + /// + /// The file name regex: "^.*(?=\.)" + /// + public static readonly Regex FileNameRegex = new Regex(@"^.*(?=\.)", RegexOptions.Compiled); + + /// + /// The extension regex: "[^\.]*$" + /// + public static readonly Regex ExtensionRegex = new Regex(@"[^\.]*$", RegexOptions.Compiled); + } +} diff --git a/Main/SimpleBackup.Core/Utilities/HelperExtensions.cs b/Main/SimpleBackup.Core/Utilities/HelperExtensions.cs new file mode 100644 index 0000000..52b3f21 --- /dev/null +++ b/Main/SimpleBackup.Core/Utilities/HelperExtensions.cs @@ -0,0 +1,214 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Utilities +{ + using System; + using System.IO; + using System.Windows; + using System.Windows.Media; + using SimpleBackup.Core.Models; + using SimpleBackup.Resources; + + /// + /// Defines helper extension methods. + /// + public static class HelperExtensions + { + /// + /// Throwses the argument null exception. + /// + /// The source. + /// Name of the parameter. + /// The argument is null. + public static void ThrowsArgumentNullException(this object source, string parameterName) + { + if (source == null) + { + throw new ArgumentNullException(parameterName); + } + } + + public static void ThrowsArgumentExceptionIfNullOrEmpty(this string source, string parameterName) + { + if (string.IsNullOrEmpty(source)) + { + throw new ArgumentException("provided text is null or empty.", parameterName); + } + } + + public static T SearchUpParentWithSelf(this DependencyObject source) + where T : DependencyObject + { + if (source == null) + { + return null; + } + + if (source is T) + { + return (T)source; + } + + DependencyObject parent = VisualTreeHelper.GetParent(source); + while (true) + { + parent = VisualTreeHelper.GetParent(parent); + if ((parent == null) || (parent is Window)) + { + return null; + } + + if (parent is T) + { + return (T)parent; + } + } + } + + public static T GetVisualChild(this Visual source) where T : Visual + { + T targetChild = default(T); + int childrenCount = VisualTreeHelper.GetChildrenCount(source); + for (int i = 0; i < childrenCount; i++) + { + var childVisual = (Visual)VisualTreeHelper.GetChild(source, i); + targetChild = childVisual as T ?? GetVisualChild(childVisual); + if (targetChild != null) + { + break; + } + } + + return targetChild; + } + + public static object GetVisualChild(this Visual source, Type targeType) + { + object targetChild = null; + int childrenCount = VisualTreeHelper.GetChildrenCount(source); + for (int i = 0; i < childrenCount; i++) + { + var childVisual = (Visual)VisualTreeHelper.GetChild(source, i); + if (childVisual.GetType() == targeType) + { + targetChild = childVisual; + break; + } + + targetChild = GetVisualChild(childVisual, targeType); + } + + return targetChild; + } + + public static bool IsValidFileOrDirectoryPath(this string pathText) + { + if (string.IsNullOrWhiteSpace(pathText)) + { + return false; + } + + return File.Exists(pathText) || Directory.Exists(pathText); + } + + public static bool IsValidFilePath(this string pathText) + { + if (string.IsNullOrWhiteSpace(pathText)) + { + return false; + } + + return File.Exists(pathText); + } + + public static bool IsValidDirectoryPath(this string pathText) + { + if (string.IsNullOrWhiteSpace(pathText)) + { + return false; + } + + return Directory.Exists(pathText); + } + + public static bool IsExistingFileOrDirectoryPath(this string pathText) + { + if (string.IsNullOrWhiteSpace(pathText)) + { + return false; + } + + if (File.Exists(pathText)) + { + return true; + } + + if (Directory.Exists(pathText)) + { + return true; + } + + return false; + } + + public static string AddTailPathSeparatorIfNotExist(this string text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return text; + } + + if (text.EndsWith("\\") == false) + { + return text + "\\"; + } + + return text; + } + + /// + /// Translates the specified backup state. + /// + /// State of the backup. + /// The translated text. + public static string Translate(this BackupState backupState) + { + switch (backupState) + { + case BackupState.Todo: + return Resources.BackupState_Todo; + case BackupState.InProgress: + return Resources.BackupState_InProgress; + case BackupState.Success: + return Resources.BackupState_Success; + case BackupState.Failed: + return Resources.BackupState_Failed; + case BackupState.Cancelled: + return Resources.BackupState_Cancelled; + case BackupState.Skipped: + return Resources.BackupState_Skipped; + default: + return string.Empty; + } + } + } +} diff --git a/Main/SimpleBackup.Core/Utilities/Helpers.cs b/Main/SimpleBackup.Core/Utilities/Helpers.cs new file mode 100644 index 0000000..6113b0b --- /dev/null +++ b/Main/SimpleBackup.Core/Utilities/Helpers.cs @@ -0,0 +1,167 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Utilities +{ + using System.Diagnostics; + using System.Globalization; + using System.IO; + using System.Windows; + using System.Windows.Threading; + + /// + /// Defines helper methods. + /// + public static class Helpers + { + #region WPF + + public static void UpdateWpfGui() + { + var frame = new DispatcherFrame(); + var callback = new DispatcherOperationCallback(obj => + { + ((DispatcherFrame)obj).Continue = false; + return null; + }); + Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, callback, frame); + Dispatcher.PushFrame(frame); + } + + #endregion + + #region Files and directories + + public static bool TryExtractValidFolderPath(string sourcePath, out string extractedPath) + { + extractedPath = string.Empty; + + if (string.IsNullOrEmpty(sourcePath)) + { + return false; + } + + string testPath = sourcePath; + while (true) + { + if (Directory.Exists(testPath)) + { + extractedPath = testPath; + return true; + } + + testPath = Path.GetDirectoryName(testPath); + if (string.IsNullOrEmpty(testPath)) + { + break; + } + } + + return false; + } + + /// + /// Creates the display path text. + /// + /// The full path. + /// The display path text. + public static string CreateDisplayPathText(string fullPath) + { + if (string.IsNullOrWhiteSpace(fullPath)) + { + return string.Empty; + } + + string fileName = Path.GetFileName(fullPath); + string directoryName = Path.GetDirectoryName(fullPath); + + return string.Format(CultureInfo.CurrentCulture, "{0} ({1})", fileName, directoryName); + } + + public static void OpenFolder(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + MessageBox.Show( + string.Format(SimpleBackup.Resources.Resources.FileAccess_InvalidPathFormat, path)); + return; + } + + if (Directory.Exists(path)) + { + Process.Start("explorer.exe", string.Format("/n, /e, {0}", path)); + } + else + { + MessageBox.Show( + string.Format(Resources.Resources.FileAccess_FolderPathNotExistFormat, path)); + } + } + + /// + /// Opens the parent folder and select the specified file or folder. + /// + /// The path. + public static void OpenParentFolderAndSelect(string path) + { + if (path.IsExistingFileOrDirectoryPath() == false) + { + MessageBox.Show( + string.Format(Resources.Resources.FileAccess_InvalidPathFormat, path)); + return; + } + + Process.Start("explorer.exe", string.Format("/n, /e, /select,{0}", path)); + } + + /// + /// Opens the file. + /// + /// Name of the file. + public static void OpenFile(string fileName) + { + if (fileName.IsExistingFileOrDirectoryPath() == false) + { + MessageBox.Show( + string.Format(Resources.Resources.FileAccess_InvalidPathFormat, fileName)); + return; + } + + var processStartInfo = new ProcessStartInfo + { + FileName = fileName, + UseShellExecute = true + }; + + try + { + Process.Start(processStartInfo); + } + catch + { + MessageBox.Show( + string.Format(Resources.Resources.FileAccess_FailedToOpenFormat, fileName)); + } + } + + #endregion + } +} diff --git a/Main/SimpleBackup.Core/Utilities/IdIndexPair.cs b/Main/SimpleBackup.Core/Utilities/IdIndexPair.cs new file mode 100644 index 0000000..f8c41d8 --- /dev/null +++ b/Main/SimpleBackup.Core/Utilities/IdIndexPair.cs @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Utilities +{ + using System; + + /// + /// A pair of Guid and index. + /// + public class IdIndexPair + { + /// + /// Initializes a new instance of the class. + /// + /// The identifier. + /// The index. + /// The provided GUID is zero. + /// The provided index is a minus value. + public IdIndexPair(Guid id, int index) + { + if (id == default(Guid)) + { + throw new ArgumentException("The provided GUID is zero.", "id"); + } + + if (index < 0) + { + throw new ArgumentException("The provided index is a minus value.", "index"); + } + + this.Id = id; + this.Index = index; + } + + /// + /// Gets the identifier. + /// + public Guid Id { get; private set; } + + /// + /// Gets the index. + /// + public int Index { get; private set; } + } +} diff --git a/Main/SimpleBackup.Core/Utilities/PropertyChangeNotificationBase.cs b/Main/SimpleBackup.Core/Utilities/PropertyChangeNotificationBase.cs new file mode 100644 index 0000000..e52dba1 --- /dev/null +++ b/Main/SimpleBackup.Core/Utilities/PropertyChangeNotificationBase.cs @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Utilities +{ + using System.ComponentModel; + + /// + /// Base class of classes which implement INotifyPropertyChanged. + /// + public abstract class PropertyChangeNotificationBase : INotifyPropertyChanged + { + /// + /// Occurs when a property value changes. + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Notifies the property changed. + /// + /// Name of the property. + protected void NotifyPropertyChanged(string propertyName) + { + if (this.PropertyChanged != null) + { + this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + } +} diff --git a/Main/SimpleBackup.Core/ViewModels/BackupInfoPathType.cs b/Main/SimpleBackup.Core/ViewModels/BackupInfoPathType.cs new file mode 100644 index 0000000..6a0c229 --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/BackupInfoPathType.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + /// + /// Represents backup information path type. + /// + public enum BackupInfoPathType + { + /// + /// The source + /// + Source, + + /// + /// The destination + /// + Destination + } +} diff --git a/Main/SimpleBackup.Core/ViewModels/FocusOnGridRowEventArgs.cs b/Main/SimpleBackup.Core/ViewModels/FocusOnGridRowEventArgs.cs new file mode 100644 index 0000000..da66a8b --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/FocusOnGridRowEventArgs.cs @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + using System; + + /// + /// Event argument of FocusOnGridRow event. + /// + public class FocusOnGridRowEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The index. + /// The provided index is out of the range. + public FocusOnGridRowEventArgs(int index) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException("index"); + } + + this.Index = index; + } + + /// + /// Gets the index. + /// + public int Index { get; private set; } + } +} diff --git a/Main/SimpleBackup.Core/ViewModels/IBackupInfoViewModel.cs b/Main/SimpleBackup.Core/ViewModels/IBackupInfoViewModel.cs new file mode 100644 index 0000000..bc72ce8 --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/IBackupInfoViewModel.cs @@ -0,0 +1,123 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + using System; + using SimpleBackup.Core.Models; + using SimpleBackup.Core.Views; + + /// + /// The interface of backup information view model. + /// + public interface IBackupInfoViewModel + { + /// + /// Gets the open source file relay command. + /// + RelayCommand OpenSourceFileRelayCommand { get; } + + /// + /// Gets the open source folder relay command. + /// + RelayCommand OpenSourceFolderRelayCommand { get; } + + /// + /// Gets the select source relay command. + /// + RelayCommand SelectSourceRelayCommand { get; } + + /// + /// Gets the open destination folder relay command. + /// + RelayCommand OpenDestinationFolderRelayCommand { get; } + + /// + /// Gets the select destination relay command. + /// + RelayCommand SelectDestinationRelayCommand { get; } + + /// + /// Gets the edit source relay command. + /// + RelayCommand EditSourceRelayCommand { get; } + + /// + /// Gets the edit destination relay command. + /// + RelayCommand EditDestinationRelayCommand { get; } + + /// + /// Gets the single backup with context menu relay command. + /// + RelayCommand SingleBackupRelayCommand { get; } + + Guid BackupInfoId { get; } + + BackupSourceType SourceType { get; } + + BackupState BackupState { get; } + + bool IsEnabled { get; set; } + + bool IsZipArchive { get; set; } + + string Label { get; set; } + + string SourcePath { get; set; } + + string DisplaySourcePath { get; } + + string EditingSourcePath { get; set; } + + string SourceToolTipText { get; } + + bool IsSourceEditing { get; set; } + + bool HasSourcePathError { get; } + + string DestinationFolderPath { get; set; } + + string DisplayDestinationFolderPath { get; } + + string EditingDestinationPath { get; set; } + + string DestinationToolTipText { get; } + + bool IsDestinationEditing { get; set; } + + bool HasDestinationFolderPathError { get; } + + bool IsEditing { get; } + + bool IsCutReserved { get; set; } + + IBackupInfo GetBackupInfo(); + + void ExecuteDoubleClickAction(BackupInfoPathType pathType); + + void SingleBackup(); + + void CommitEditingContents(); + + void ResetBackupState(); + } +} diff --git a/Main/SimpleBackup.Core/ViewModels/IDestinationColumnHeaderViewModel.cs b/Main/SimpleBackup.Core/ViewModels/IDestinationColumnHeaderViewModel.cs new file mode 100644 index 0000000..20b4562 --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/IDestinationColumnHeaderViewModel.cs @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + /// + /// Interface of a destination column header view model. + /// + public interface IDestinationColumnHeaderViewModel + { + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/ViewModels/ILabelColumnHeaderViewModel.cs b/Main/SimpleBackup.Core/ViewModels/ILabelColumnHeaderViewModel.cs new file mode 100644 index 0000000..bba6949 --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/ILabelColumnHeaderViewModel.cs @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + /// + /// Interface of a label column header view model. + /// + public interface ILabelColumnHeaderViewModel + { + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/ViewModels/IMainWindowViewModel.cs b/Main/SimpleBackup.Core/ViewModels/IMainWindowViewModel.cs new file mode 100644 index 0000000..2582e60 --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/IMainWindowViewModel.cs @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + using System; + using SimpleBackup.Core.Views; + + /// + /// Interface of a main window view model. + /// + public interface IMainWindowViewModel : IDisposable + { + /// + /// Occurs when the focus is set on the Grid. + /// + event EventHandler FocusOnGrid; + + /// + /// Occurs when the focus is set on a Grid row. + /// + event EventHandler FocusOnGridRow; + + /// + /// Gets the save backup setting relay command. + /// + RelayCommand SaveBackupSettingRelayCommand { get; } + + /// + /// Called when Escape key is pressed. + /// + void OnEscKeyPressed(); + } +} diff --git a/Main/SimpleBackup.Core/ViewModels/ISourceColumnHeaderViewModel.cs b/Main/SimpleBackup.Core/ViewModels/ISourceColumnHeaderViewModel.cs new file mode 100644 index 0000000..c1315ce --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/ISourceColumnHeaderViewModel.cs @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + /// + /// Interface of a source column header view model. + /// + public interface ISourceColumnHeaderViewModel + { + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/ViewModels/IViewModelFactory.cs b/Main/SimpleBackup.Core/ViewModels/IViewModelFactory.cs new file mode 100644 index 0000000..0b2d8dd --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/IViewModelFactory.cs @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + /// + /// Interface of a view model factory. + /// + public interface IViewModelFactory + { + /// + /// Creates the main window view model. + /// + /// The main window view model. + IMainWindowViewModel CreateMainWindowViewModel(); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/ViewModels/PasteType.cs b/Main/SimpleBackup.Core/ViewModels/PasteType.cs new file mode 100644 index 0000000..c3c8ec3 --- /dev/null +++ b/Main/SimpleBackup.Core/ViewModels/PasteType.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.ViewModels +{ + /// + /// Paste operation type. + /// + public enum PasteType + { + /// + /// The copy + /// + Copy, + + /// + /// The cut + /// + Cut + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Views/ExDataGridSelectedFirstCellItemChangedEventArgs.cs b/Main/SimpleBackup.Core/Views/ExDataGridSelectedFirstCellItemChangedEventArgs.cs new file mode 100644 index 0000000..3dc8ad6 --- /dev/null +++ b/Main/SimpleBackup.Core/Views/ExDataGridSelectedFirstCellItemChangedEventArgs.cs @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Views +{ + using System; + + /// + /// Event argument of ExDataGrid's SelectedFirstCellItemChangedEvent event. + /// + public class ExDataGridSelectedFirstCellItemChangedEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// Index of the selected first cell item. + /// The selected first cell item. + public ExDataGridSelectedFirstCellItemChangedEventArgs( + int selectedFirstCellItemIndex, + object selectedFirstCellItem) + { + this.SelectedFirstCellItemIndex = selectedFirstCellItemIndex; + this.SelectedFirstCellItem = selectedFirstCellItem; + } + + /// + /// Gets the index of the selected first cell item. + /// + public int SelectedFirstCellItemIndex { get; private set; } + + /// + /// Gets the selected first cell item. + /// + public object SelectedFirstCellItem { get; private set; } + } +} diff --git a/Main/SimpleBackup.Core/Views/IFileFolderDialog.cs b/Main/SimpleBackup.Core/Views/IFileFolderDialog.cs new file mode 100644 index 0000000..3709604 --- /dev/null +++ b/Main/SimpleBackup.Core/Views/IFileFolderDialog.cs @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Views +{ + using System.Windows.Forms; + + /// + /// Interface of a file folder dialog. + /// + public interface IFileFolderDialog + { + /// + /// Gets or sets the selected path. + /// + string SelectedPath { get; set; } + + /// + /// Shows the dialog. + /// + /// The dialog result. + DialogResult ShowDialog(); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Views/IMainWindow.cs b/Main/SimpleBackup.Core/Views/IMainWindow.cs new file mode 100644 index 0000000..70568e1 --- /dev/null +++ b/Main/SimpleBackup.Core/Views/IMainWindow.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Views +{ + /// + /// Interface of a main window. + /// + public interface IMainWindow + { + /// + /// Gets or sets the data context. + /// + object DataContext { get; set; } + + /// + /// Shows the window. + /// + void Show(); + } +} diff --git a/Main/SimpleBackup.Core/Views/IVersionInformationWindow.cs b/Main/SimpleBackup.Core/Views/IVersionInformationWindow.cs new file mode 100644 index 0000000..ffc9bc1 --- /dev/null +++ b/Main/SimpleBackup.Core/Views/IVersionInformationWindow.cs @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Views +{ + /// + /// Interface of a version information window. + /// + public interface IVersionInformationWindow + { + /// + /// Shows the dialog window. + /// + /// The result. + bool? ShowDialogWindow(); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Views/IViewFactory.cs b/Main/SimpleBackup.Core/Views/IViewFactory.cs new file mode 100644 index 0000000..d050f1d --- /dev/null +++ b/Main/SimpleBackup.Core/Views/IViewFactory.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Views +{ + /// + /// Interface of a view factory. + /// + public interface IViewFactory + { + /// + /// Creates the main window. + /// + /// The main window. + IMainWindow CreateMainWindow(); + + /// + /// Creates the version information window. + /// + /// The version information window. + IVersionInformationWindow CreateVersionInformationWindow(); + + /// + /// Creates the file folder dialog. + /// + /// The file folder dialog. + IFileFolderDialog CreateFileFolderDialog(); + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Core/Views/RelayCommand.cs b/Main/SimpleBackup.Core/Views/RelayCommand.cs new file mode 100644 index 0000000..ad29dc2 --- /dev/null +++ b/Main/SimpleBackup.Core/Views/RelayCommand.cs @@ -0,0 +1,105 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Core.Views +{ + using System; + using System.Diagnostics; + using System.Windows.Input; + using SimpleBackup.Core.Utilities; + + /// + /// A relay command for WPF MVVM pattern. + /// See WPF Apps With The Model-View-ViewModel Design Pattern http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030 + /// in MSDN Magazine > Issues and Downloads > 2009 > February. + /// + public class RelayCommand : ICommand + { + /// + /// The execute action + /// + private readonly Action executeAction; + + /// + /// The can execute predicate + /// + private readonly Predicate canExecutePredicate; + + /// + /// Initializes a new instance of the class. + /// + /// The execute action. + public RelayCommand(Action executeAction) + : this(executeAction, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The execute action. + /// The can execute predicate. + /// executeAction is null. + public RelayCommand(Action executeAction, Predicate canExecutePredicate) + { + executeAction.ThrowsArgumentNullException("executeAction"); + + this.executeAction = executeAction; + this.canExecutePredicate = canExecutePredicate; + } + + /// + /// Occurs when changes occur that affect whether or not the command should execute. + /// + public event EventHandler CanExecuteChanged + { + add + { + CommandManager.RequerySuggested += value; + } + + remove + { + CommandManager.RequerySuggested -= value; + } + } + + /// + /// Defines the method to be called when the command is invoked. + /// + /// Data used by the command. If the command does not require data to be passed, this object can be set to null. + public void Execute(object parameter) + { + this.executeAction(parameter); + } + + /// + /// Defines the method that determines whether the command can execute in its current state. + /// + /// Data used by the command. If the command does not require data to be passed, this object can be set to null. + /// true if this command can be executed; otherwise, false. + [DebuggerStepThrough] + public bool CanExecute(object parameter) + { + return this.canExecutePredicate == null || this.canExecutePredicate(parameter); + } + } +} \ No newline at end of file diff --git a/Main/SimpleBackup.Models/BackupInfo.cs b/Main/SimpleBackup.Models/BackupInfo.cs new file mode 100644 index 0000000..6b85734 --- /dev/null +++ b/Main/SimpleBackup.Models/BackupInfo.cs @@ -0,0 +1,464 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Models +{ + using System; + using System.IO; + using System.Xml.Linq; + using SimpleBackup.Core.Models; + using SimpleBackup.Core.Utilities; + using Resources = SimpleBackup.Resources.Resources; + + /// + /// A model of single backup information. + /// + internal class BackupInfo : PropertyChangeNotificationBase, IBackupInfo + { + private Guid innerId = Guid.NewGuid(); + private string innerLabel = string.Empty; + private BackupSourceType innerBackupSourceType = BackupSourceType.File; + private bool innerIsEnabled = true; + private bool innerIsZipArchive; + private string innerSourcePath = string.Empty; + private string innerDestinationFolderPath = string.Empty; + private BackupState innerBackupState = BackupState.Todo; + + /// + /// Initializes a new instance of the class. + /// + internal BackupInfo() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The source backup information. + /// The index is out of range. + internal BackupInfo(IBackupInfo sourceBackupInfo) + { + sourceBackupInfo.ThrowsArgumentNullException("sourceBackupInfo"); + + this.Id = Guid.NewGuid(); + this.BackupState = BackupState.Todo; + + this.Label = sourceBackupInfo.Label; + this.BackupSourceType = sourceBackupInfo.BackupSourceType; + this.IsEnabled = sourceBackupInfo.IsEnabled; + this.IsZipArchive = sourceBackupInfo.IsZipArchive; + this.SourcePath = sourceBackupInfo.SourcePath; + this.DestinationFolderPath = sourceBackupInfo.DestinationFolderPath; + } + + /// + /// Initializes a new instance of the class. + /// + /// The label. + /// Type of the backup source. + /// if set to true the backup is enabled. + /// if set to true zip archive switch is on. + /// The source path. + /// The destination folder path. + /// The label is null. + /// The source path is null. + /// The destination folder path is null. + internal BackupInfo( + string label, + BackupSourceType backupSourceType, + bool isEnabled, + bool isZipArchive, + string sourcePath, + string destinationFolderPath) + { + label.ThrowsArgumentNullException("label"); + sourcePath.ThrowsArgumentNullException("sourcePath"); + destinationFolderPath.ThrowsArgumentNullException("destinationFolderPath"); + + this.Id = Guid.NewGuid(); + this.BackupState = BackupState.Todo; + + this.Label = label; + this.BackupSourceType = backupSourceType; + this.IsEnabled = isEnabled; + this.IsZipArchive = isZipArchive; + this.SourcePath = sourcePath; + this.DestinationFolderPath = destinationFolderPath; + } + + /// + /// Initializes a new instance of the class. + /// + /// The identifier. + /// The label. + /// Type of the backup source. + /// if set to true the backup is enabled. + /// if set to true zip archive switch is on. + /// The source path. + /// The destination folder path. + /// The label is null. + /// The label is null. + /// The label is null. + internal BackupInfo( + Guid id, + string label, + BackupSourceType backupSourceType, + bool isEnabled, + bool isZipArchive, + string sourcePath, + string destinationFolderPath) + { + label.ThrowsArgumentNullException("label"); + sourcePath.ThrowsArgumentNullException("sourcePath"); + destinationFolderPath.ThrowsArgumentNullException("destinationFolderPath"); + + this.Id = id; + this.BackupState = BackupState.Todo; + + this.Label = label; + this.BackupSourceType = backupSourceType; + this.IsEnabled = isEnabled; + this.IsZipArchive = isZipArchive; + this.SourcePath = sourcePath; + this.DestinationFolderPath = destinationFolderPath; + } + + /// + /// Occurs when a property which has to be saved in setting file is changed. + /// + public event EventHandler SettingFilePropertyChanged; + + /// + /// Gets or sets the identifier. + /// + public Guid Id + { + get + { + return this.innerId; + } + + set + { + if (this.innerId != value) + { + this.innerId = value; + this.NotifyPropertyChanged("Id"); + this.NotifySettingFilePropertyChanged(); + } + } + } + + /// + /// Gets or sets the label. + /// + public string Label + { + get + { + return this.innerLabel; + } + + set + { + if (this.innerLabel != value) + { + this.innerLabel = value; + this.NotifyPropertyChanged("Label"); + this.NotifySettingFilePropertyChanged(); + } + } + } + + /// + /// Gets or sets the type of the backup source. + /// + public BackupSourceType BackupSourceType + { + get + { + return this.innerBackupSourceType; + } + + set + { + if (this.innerBackupSourceType != value) + { + this.innerBackupSourceType = value; + this.NotifyPropertyChanged("BackupSourceType"); + this.NotifySettingFilePropertyChanged(); + } + } + } + + /// + /// Gets or sets a value indicating whether the backup is enabled. + /// + public bool IsEnabled + { + get + { + return this.innerIsEnabled; + } + + set + { + if (this.innerIsEnabled != value) + { + this.innerIsEnabled = value; + this.NotifyPropertyChanged("IsEnabled"); + this.NotifySettingFilePropertyChanged(); + } + } + } + + /// + /// Gets or sets a value indicating whether the backup is zip archive. + /// + public bool IsZipArchive + { + get + { + return this.innerIsZipArchive; + } + + set + { + if (this.innerIsZipArchive != value) + { + this.innerIsZipArchive = value; + this.NotifyPropertyChanged("IsZipArchive"); + this.NotifySettingFilePropertyChanged(); + } + } + } + + /// + /// Gets or sets the source path. + /// + public string SourcePath + { + get + { + return this.innerSourcePath; + } + + set + { + if (this.innerSourcePath != value) + { + this.innerSourcePath = value; + this.NotifyPropertyChanged("SourcePath"); + this.NotifySettingFilePropertyChanged(); + } + } + } + + /// + /// Gets or sets the destination folder path. + /// + public string DestinationFolderPath + { + get + { + return this.innerDestinationFolderPath; + } + + set + { + if (this.innerDestinationFolderPath != value) + { + this.innerDestinationFolderPath = value; + this.NotifyPropertyChanged("DestinationFolderPath"); + this.NotifySettingFilePropertyChanged(); + } + } + } + + /// + /// Gets or sets the state of the backup. + /// + public BackupState BackupState + { + get + { + return this.innerBackupState; + } + + set + { + if (this.innerBackupState != value) + { + this.innerBackupState = value; + this.NotifyPropertyChanged("BackupState"); + } + } + } + + /// + /// Gets or sets the name of the latest successful backup target. + /// + public string LatestSuccessfulBackupTargetName { get; set; } + + /// + /// Creates the backup information. + /// + /// The backup information. + public static IBackupInfo CreateBackupInfo() + { + return new BackupInfo(); + } + + /// + /// Creates the backup information. + /// + /// The source backup information. + /// The backup information. + public static IBackupInfo CreateBackupInfo(IBackupInfo sourceBackupInfo) + { + return new BackupInfo(sourceBackupInfo); + } + + /// + /// Creates the backup information. + /// + /// The identifier. + /// The label. + /// Type of the backup source. + /// if set to true [is enabled]. + /// if set to true [is zip archive]. + /// The source path. + /// The destination folder path. + /// The backup information. + public static IBackupInfo CreateBackupInfo( + Guid id, + string label, + BackupSourceType backupSourceType, + bool isEnabled, + bool isZipArchive, + string sourcePath, + string destinationFolderPath) + { + return new BackupInfo( + id, + label, + backupSourceType, + isEnabled, + isZipArchive, + sourcePath, + destinationFolderPath); + } + + /// + /// Restores from binary. + /// + /// The binary data. + /// if set to true [copy suffix needed]. + /// The restored backup information. + public static IBackupInfo FromBinary(byte[] binaryData, bool copySuffixNeeded) + { + var memoryStream = new MemoryStream(binaryData); + using (var binaryReader = new BinaryReader(memoryStream)) + { + string label = binaryReader.ReadString(); + var backupSourceType = (BackupSourceType)Enum.ToObject(typeof(BackupSourceType), binaryReader.ReadInt32()); + bool isEnabled = binaryReader.ReadBoolean(); + bool isZipArchive = binaryReader.ReadBoolean(); + string sourcePath = binaryReader.ReadString(); + string destinationFolderPath = binaryReader.ReadString(); + + return new BackupInfo( + copySuffixNeeded ? string.Format("{0} - {1}", label, Resources.Edit_CopySuffix) : label, + backupSourceType, + isEnabled, + isZipArchive, + sourcePath, + destinationFolderPath); + } + } + + /// + /// Saves this instance to a XElement. + /// + /// The generated XElement. + public XElement ToXml() + { + var element = new XElement("BackupInfo"); + element.Add(new XElement("Id", this.Id)); + element.Add(new XElement("Label", this.Label)); + element.Add(new XElement("BackupSourceType", this.BackupSourceType)); + element.Add(new XElement("IsEnabled", this.IsEnabled)); + element.Add(new XElement("IsZipArchive", this.IsZipArchive)); + element.Add(new XElement("SourcePath", this.SourcePath)); + element.Add(new XElement("DestinationFolderPath", this.DestinationFolderPath)); + + return element; + } + + /// + /// Gets the binary representation of this instance. + /// + /// The binary representation of this instance. + public byte[] ToBinary() + { + var memoryStream = new MemoryStream(); + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(this.Label); + binaryWriter.Write((int)this.BackupSourceType); + binaryWriter.Write(this.IsEnabled); + binaryWriter.Write(this.IsZipArchive); + binaryWriter.Write(this.SourcePath); + binaryWriter.Write(this.DestinationFolderPath); + + memoryStream.Flush(); + return memoryStream.GetBuffer(); + } + } + + /// + /// Gets the text representation of this instance. + /// + /// The text representation of this instance. + public string ToFormattedText() + { + return string.Format( + "{0}\t{1}\t{2}\t{3}\t{4}\t{5}", + this.Label, + this.BackupSourceType, + this.IsEnabled, + this.IsZipArchive, + this.SourcePath, + this.DestinationFolderPath); + } + + /// + /// Notifies the setting file property is changed. + /// + private void NotifySettingFilePropertyChanged() + { + if (this.SettingFilePropertyChanged != null) + { + this.SettingFilePropertyChanged(this, new EventArgs()); + } + } + } +} diff --git a/Main/SimpleBackup.Models/BackupSetting.cs b/Main/SimpleBackup.Models/BackupSetting.cs new file mode 100644 index 0000000..93c7fa8 --- /dev/null +++ b/Main/SimpleBackup.Models/BackupSetting.cs @@ -0,0 +1,246 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Models +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Xml.Linq; + using SimpleBackup.Core.Models; + + /// + /// Represents a backup setting. + /// + internal class BackupSetting : IBackupSetting + { + private readonly List backupInfoList = new List(); + + /// + /// Initializes a new instance of the class. + /// + internal BackupSetting() + { + this.SettingFileName = string.Empty; + this.Modified = true; + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the setting file. + /// The backup information collection. + internal BackupSetting( + string settingFileName, + IEnumerable backupInfoCollection) + { + this.SettingFileName = settingFileName; + this.backupInfoList.AddRange(backupInfoCollection); + foreach (IBackupInfo backupInfo in this.backupInfoList) + { + backupInfo.SettingFilePropertyChanged += this.OnBackupInfoSettingFilePropertyChanged; + } + } + + /// + /// Occurs when backup setting is modified. + /// + public event EventHandler SettingModified; + + /// + /// Gets the name of the setting. + /// + public string SettingName + { + get + { + if (string.IsNullOrEmpty(this.SettingFileName)) + { + return Resources.Resources.Views_NewBackupSettingName; + } + + return this.SettingFileName; + } + } + + /// + /// Gets or sets the name of the setting file. + /// + public string SettingFileName { get; set; } + + /// + /// Gets or sets a value indicating whether this is modified. + /// + public bool Modified { get; set; } + + /// + /// Gets the backup infos. + /// + public IReadOnlyCollection BackupInfos + { + get + { + return this.backupInfoList.AsReadOnly(); + } + } + + /// + /// Gets the count. + /// + public int Count + { + get + { + return this.backupInfoList.Count; + } + } + + /// + /// Creates the backup setting. + /// + /// The backup setting. + public static IBackupSetting CreateBackupSetting() + { + return new BackupSetting(); + } + + /// + /// Creates the backup setting. + /// + /// Name of the setting file. + /// The backup information collection. + /// The backup setting. +// public static IBackupSetting CreateBackupSetting( +// string settingFileName, +// IEnumerable backupInfoCollection) +// { +// return new BackupSetting(settingFileName, backupInfoCollection); +// } + + /// + /// Inserts the specified index. + /// + /// The index. + /// The backup information. + public void Insert(int index, IBackupInfo backupInfo) + { + backupInfo.SettingFilePropertyChanged += this.OnBackupInfoSettingFilePropertyChanged; + this.backupInfoList.Insert(index, backupInfo); + + this.MarkAsModifiedAndPublishNotification(); + } + + /// + /// Removes the specified removing backup information. + /// + /// The removing backup information. + public void Remove(IBackupInfo removingBackupInfo) + { + removingBackupInfo.SettingFilePropertyChanged -= this.OnBackupInfoSettingFilePropertyChanged; + this.backupInfoList.Remove(removingBackupInfo); + + this.MarkAsModifiedAndPublishNotification(); + } + + public IBackupInfo FirstOrDefault(Guid id) + { + return this.backupInfoList.FirstOrDefault(p => p.Id == id); + } + + public void MoveItem(Guid backupInfoId, ItemMovingDirection movingDirection) + { + IBackupInfo movingBackupInfo = null; + int currentIndex = 0; + for (int i = 0; i < this.backupInfoList.Count; i++) + { + if (this.backupInfoList[i].Id == backupInfoId) + { + currentIndex = i; + movingBackupInfo = this.backupInfoList[i]; + break; + } + } + + if (movingBackupInfo != null) + { + int newIndex = -1; + switch (movingDirection) + { + case ItemMovingDirection.MoveUp: + if (currentIndex > 0) + { + newIndex = currentIndex - 1; + } + + break; + case ItemMovingDirection.MoveDown: + if (currentIndex < this.backupInfoList.Count - 1) + { + newIndex = currentIndex + 1; + } + + break; + default: + throw new InvalidOperationException("Not supported direction."); + } + + if (newIndex != -1) + { + IBackupInfo temp = this.backupInfoList[newIndex]; + this.backupInfoList[newIndex] = this.backupInfoList[currentIndex]; + this.backupInfoList[currentIndex] = temp; + } + + this.MarkAsModifiedAndPublishNotification(); + } + } + + public XElement ToXml() + { + var backupSettingElement = new XElement("BackupSetting"); + backupSettingElement.SetAttributeValue("Version", "1.0"); + backupSettingElement.SetAttributeValue("RequiredToolVersion", "1.0.0.181"); + + var items = new XElement("Items"); + foreach (IBackupInfo backupInfo in this.BackupInfos) + { + items.Add(backupInfo.ToXml()); + } + + backupSettingElement.Add(items); + return backupSettingElement; + } + + private void OnBackupInfoSettingFilePropertyChanged(object sender, EventArgs e) + { + this.MarkAsModifiedAndPublishNotification(); + } + + private void MarkAsModifiedAndPublishNotification() + { + this.Modified = true; + if (this.SettingModified != null) + { + this.SettingModified(this, new EventArgs()); + } + } + } +} diff --git a/Main/SimpleBackup.Models/DestinationPathInfo.cs b/Main/SimpleBackup.Models/DestinationPathInfo.cs new file mode 100644 index 0000000..d54f65a --- /dev/null +++ b/Main/SimpleBackup.Models/DestinationPathInfo.cs @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Models +{ + using SimpleBackup.Core.Models; + + /// + /// The destination path information. + /// + internal class DestinationPathInfo : IDestinationPathInfo + { + /// + /// Initializes a new instance of the class. + /// + /// Type of the backup source. + /// The path. + public DestinationPathInfo(BackupSourceType backupSourceType, string path) + { + this.BackupSourceType = backupSourceType; + this.Path = path; + } + + /// + /// Gets the type of the backup source. + /// + public BackupSourceType BackupSourceType { get; private set; } + + /// + /// Gets the path. + /// + public string Path { get; private set; } + } +} diff --git a/Main/SimpleBackup.Models/ModelComponent.cs b/Main/SimpleBackup.Models/ModelComponent.cs new file mode 100644 index 0000000..df9d461 --- /dev/null +++ b/Main/SimpleBackup.Models/ModelComponent.cs @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Models +{ + using SimpleBackup.Core; + using SimpleBackup.Core.AppInfrastructure; + using SimpleBackup.Core.Models; + + /// + /// The model component. + /// + internal class ModelComponent : IAppComponent + { + /// + /// Initializes this application component. + /// + public void Initialize() + { + ObjectContainer.Register(new ModelFactory()); + } + } +} diff --git a/Main/SimpleBackup.Models/ModelFactory.cs b/Main/SimpleBackup.Models/ModelFactory.cs new file mode 100644 index 0000000..0a9e1e6 --- /dev/null +++ b/Main/SimpleBackup.Models/ModelFactory.cs @@ -0,0 +1,278 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Models +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Xml.Linq; + using SimpleBackup.Core.Models; + + /// + /// Creates model objectrs. + /// + internal class ModelFactory : IModelFactory + { + /// + /// Creates the backup setting. + /// + /// + /// The backup setting. + /// + public IBackupSetting CreateBackupSetting() + { + return new BackupSetting(); + } + + /// + /// Creates the backup setting. + /// + /// Name of the setting file. + /// The backup information collection. + /// + /// The backup setting. + /// + public IBackupSetting CreateBackupSetting( + string settingFileName, + IEnumerable backupInfoCollection) + { + return new BackupSetting(settingFileName, backupInfoCollection); + } + + /// + /// Creates the backup information. + /// + /// + /// The backup inforamtion. + /// + public IBackupInfo CreateBackupInfo() + { + return new BackupInfo(); + } + + /// + /// Creates the backup information. + /// + /// The source backup information. + /// + /// The backup inforamtion. + /// + public IBackupInfo CreateBackupInfo(IBackupInfo sourceBackupInfo) + { + return new BackupInfo(sourceBackupInfo); + } + + /// + /// Creates the backup information. + /// + /// The label. + /// Type of the backup source. + /// if set to true [is enabled]. + /// if set to true [is zip archive]. + /// The source path. + /// The destination folder path. + /// + /// The backup inforamtion. + /// + public IBackupInfo CreateBackupInfo( + string label, + BackupSourceType backupSourceType, + bool isEnabled, + bool isZipArchive, + string sourcePath, + string destinationFolderPath) + { + return new BackupInfo( + label, + backupSourceType, + isEnabled, + isZipArchive, + sourcePath, + destinationFolderPath); + } + + /// + /// Creates the backup information. + /// + /// The identifier. + /// The label. + /// Type of the backup source. + /// if set to true [is enabled]. + /// if set to true [is zip archive]. + /// The source path. + /// The destination folder path. + /// + /// The backup inforamtion. + /// + public IBackupInfo CreateBackupInfo( + Guid id, + string label, + BackupSourceType backupSourceType, + bool isEnabled, + bool isZipArchive, + string sourcePath, + string destinationFolderPath) + { + return new BackupInfo( + id, + label, + backupSourceType, + isEnabled, + isZipArchive, + sourcePath, + destinationFolderPath); + } + + /// + /// Creates the backup information from binary. + /// + /// The binary data. + /// if set to true copy suffix is needed. + /// + /// The backup inforamtion. + /// + public IBackupInfo CreateBackupInfoFromBinary(byte[] binaryData, bool copySuffixNeeded) + { + return BackupInfo.FromBinary(binaryData, copySuffixNeeded); + } + + /// + /// Creates the result information. + /// + /// The category. + /// The description. + /// + /// The result inforamtion. + /// + public IResultInfo CreateResultInfo(BackupState category, string description) + { + return new ResultInfo(category, description); + } + + /// + /// Creates the destination path information. + /// + /// Type of the backup source. + /// The path. + /// + /// The destination path information. + /// + public IDestinationPathInfo CreateDestinationPathInfo(BackupSourceType backupSourceType, string path) + { + return new DestinationPathInfo(backupSourceType, path); + } + + /// + /// Restores the backup setting from XML. + /// + /// The XML. + /// Name of the file. + /// The restored backup setting. + public IBackupSetting RestoreBackupSettingFromXml(XElement xml, string fileName) + { + if (xml.Name != "BackupSetting") + { + return null; + } + + XElement itemsElement = xml.Elements("Items").FirstOrDefault(); + if (itemsElement == null) + { + return null; + } + + var backupInfoList = new List(); + foreach (XElement element in itemsElement.Elements()) + { + IBackupInfo backupInfo = RestoreBackupInfoFromXml(element); + backupInfoList.Add(backupInfo); + } + + return new BackupSetting(fileName, backupInfoList); + } + + /// + /// Restores the backup information from XML. + /// + /// The XML. + /// The restored backup information. + private static IBackupInfo RestoreBackupInfoFromXml(XElement xml) + { + if (xml.Name != "BackupInfo") + { + return null; + } + + XElement idElement = xml.Elements("Id").FirstOrDefault(); + XElement labelElement = xml.Elements("Label").FirstOrDefault(); + XElement backupSourceTypeElement = xml.Elements("BackupSourceType").FirstOrDefault(); + XElement enabledElement = xml.Elements("IsEnabled").FirstOrDefault(); + XElement zipArchiveElement = xml.Elements("IsZipArchive").FirstOrDefault(); + XElement sourcePathElement = xml.Elements("SourcePath").FirstOrDefault(); + XElement destinationFolderPathElement = xml.Elements("DestinationFolderPath").FirstOrDefault(); + + if ((idElement == null) || + (labelElement == null) || + (backupSourceTypeElement == null) || + (enabledElement == null) || + (zipArchiveElement == null) || + (sourcePathElement == null) || + (destinationFolderPathElement == null)) + { + return null; + } + + Guid id; + if (Guid.TryParse(idElement.Value, out id) == false) + { + return null; + } + + BackupSourceType backupSourceType; + if (Enum.TryParse(backupSourceTypeElement.Value, out backupSourceType) == false) + { + return null; + } + + bool isEnabled; + if (bool.TryParse(enabledElement.Value, out isEnabled) == false) + { + return null; + } + + bool isZipArchive; + if (bool.TryParse(zipArchiveElement.Value, out isZipArchive) == false) + { + return null; + } + + return BackupInfo.CreateBackupInfo( + id, + labelElement.Value, + backupSourceType, + isEnabled, + isZipArchive, + sourcePathElement.Value, + destinationFolderPathElement.Value); + } + } +} diff --git a/Main/SimpleBackup.Models/ResultInfo.cs b/Main/SimpleBackup.Models/ResultInfo.cs new file mode 100644 index 0000000..49642b9 --- /dev/null +++ b/Main/SimpleBackup.Models/ResultInfo.cs @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Models +{ + using SimpleBackup.Core.Models; + + /// + /// Represents a backup result. + /// + internal class ResultInfo : IResultInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The category. + /// The description. + public ResultInfo(BackupState category, string description) + { + this.BackupState = category; + this.Description = description ?? string.Empty; + } + + /// + /// Gets the state of the backup. + /// + public BackupState BackupState { get; private set; } + + /// + /// Gets the description. + /// + public string Description { get; private set; } + } +} diff --git a/Main/SimpleBackup.Models/SimpleBackup.Models.csproj b/Main/SimpleBackup.Models/SimpleBackup.Models.csproj new file mode 100644 index 0000000..1c59dad --- /dev/null +++ b/Main/SimpleBackup.Models/SimpleBackup.Models.csproj @@ -0,0 +1,90 @@ + + + + + Debug + AnyCPU + {7B8C68F1-8A5C-470F-9356-F0EC1268617F} + Library + Properties + SimpleBackup.Models + SimpleBackup.Models + v4.5 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + SimpleBackupKey.snk + + + + + + + + + + + + + + + Properties\AssemblyInfo.cs + + + + + + + + + + + + + + {33f1d454-9962-4eb6-aad3-8d11d9a78d1f} + SimpleBackup.Core + + + {a655131e-d439-4de1-bc39-5c955306183f} + SimpleBackup.Resources + + + + + set EXE_BIN_DIR=$(ProjectDir)..\bin\$(ConfigurationName)\ +xcopy "$(TargetDir)$(TargetName).dll" "%25EXE_BIN_DIR%25" /Y +if exist "$(TargetDir)$(TargetName).pdb" xcopy "$(TargetDir)$(TargetName).pdb" "%25EXE_BIN_DIR%25" /Y + + + \ No newline at end of file diff --git a/Main/SimpleBackup.Models/SimpleBackupKey.snk b/Main/SimpleBackup.Models/SimpleBackupKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..def2e6df6a67d7e5802b3319c2b385c61304db29 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=*mMuj7Bow@Ep}p%TfOae=&U%vR9qh+ z@B2Y7h5t%KB~GowmVCnTwn!=ol7j~SRw};|aqMe69$!Xr!@Kl)p?8Xg2;G;~Cd60S zyuxBRv<}vHJsUi)3u6Y?7~u<-nIO&1Fj-O8+VD)*I{}r1s+^@Kmf2Y}gp`|NRs+em z$u>8Tw)yg`4_#X9od;DS_`m7gjCw7)_oIM$fq-7kckw~B<7M;zI>N{SPq*6$huq7Z zgYNgU;sUWRbAi&O+L_hd!U0Li?IE-i`qYl6ItfNG&LGLWV{U{YZh>Ax4*J$khFNYOR0lC!sQ=xnj0#!GfwNKNLWeC6+{0F(k120wr_Sb zIyF(GL;3}qT}4Ed2plZ&Isj`rlkfJc)Ea1aKb3p_jTAd0vy@;AzzF|BpZp|m^l#y& zbx94OX%V&s<FnfGWY1Nh zxKnroP3(eKfbr85Y^JZ_CW>v48ZxICTuX?#TOI&z>)DFD-NiB2i|wPJnn~;|{CGZv i!2z3|Al4b1%II9A@B0rIjj|^@+oAX!*AylRLZAX-U?o=o literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Activity_16xLG.png b/Main/SimpleBackup.Resources/Images/Activity_16xLG.png new file mode 100644 index 0000000000000000000000000000000000000000..9fe818e9715e7ef8296b2436ab7b2d49d9f1ca5f GIT binary patch literal 543 zcmV+)0^t3LP)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ-rAb6VRCwB?k}ZtlP!xr~H^H!)dsqgOs7*8iv>xN;5ZIdRZ*5Dz|pqt zkEVzN;1I`gCyFA9q993YZvYVt30Iy&YD@qC002ovPDHLkV1ftn=e_^{ literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/AddVariable_5541.png b/Main/SimpleBackup.Resources/Images/AddVariable_5541.png new file mode 100644 index 0000000000000000000000000000000000000000..78888630e3441ed5285a11261a146601cf31e091 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!3Ul$jv*HQTPGO`H5mxFS~j(B+^}pp|6KP% zHtqa|$(?z&Y%PtAzrF2lAA?6yan`@dhbA0Rkb9ey$Ro1VO6CoN YnAcS~r2^)kK)*70y85}Sb4q9e0D>lehyVZp literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/ApplicationIcon.ico b/Main/SimpleBackup.Resources/Images/ApplicationIcon.ico new file mode 100644 index 0000000000000000000000000000000000000000..393d054a94fd7c9f35ca61b10dde459598cbffc6 GIT binary patch literal 22486 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

884!hSou*$_IPWKx~>;<&eyK% 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 literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Arrow_RedoRetry_16xLG.png b/Main/SimpleBackup.Resources/Images/Arrow_RedoRetry_16xLG.png new file mode 100644 index 0000000000000000000000000000000000000000..75b508d6cd130ff91fab492e15394952d0224fdf GIT binary patch literal 416 zcmV;R0bl-!P)Bfvc&G7w`ZmNCU0UgRtdXd|{=L*IssZy<-&7rfK@1$S4L1vS3)wPQqSC0wLrn zS?{`TNYj*wc$*$`nNeaZOs)El+K(JXF_`2WkYTLH+ z#xM*eiXve4VTi?XJo`maU{NVJ!6DCco*V>0qiNcM0>0w={u~>}QTb~dv`+&n3m%V0 zEH{czipS-0VU?xWh|HqD-EJF@(EC1iyPfjZAPt-R^?HR=KNKocN0e2Bs6qy*m;$0y z?+S}5+$_sNt9;5ylAwd{6_VG7gzBR9ecz*-(?1=&l2ELW$gl7;dC&8j^ZCplkmER5 zGt5dVqm0D1?M8e+Wm&>KFm+ae4^a_65Tuo<0u@#bB#Z94OvYa^L2GX&(PNJQ0000< KMNUMnLSTYAm9aAb literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Arrow_UndoRevertRestore_16xLG.png b/Main/SimpleBackup.Resources/Images/Arrow_UndoRevertRestore_16xLG.png new file mode 100644 index 0000000000000000000000000000000000000000..d75956896708a9891d552e2d0b7081adfba8f6ef GIT binary patch literal 464 zcmV;>0WbcEP)hbAR3-Ypi3Ubovd+wHa@QA}sZ?dbXc|7@Ml=d0_w&}=s0a=C!S zIij4nvBZIOJRZ%%;lKsag_5|@Xs9p@NgU(i96BMVUnnf_v`(iJ@1xO3`M$5}^*ZT> z@m`87mrL3@xdlW~6sg&4M&S+hiJIEB&ABYgXfsO-v|26Yc^<=tVeE^ZdquI$IF6rl z4;Tl=J!|W#TCGZ6y<+tr++T{E=quY`J7$t3oY1X&m$e}9hrp}Vis4$VrX0s1cT+A< z0{3uO^l~vQa|wb#TKnY|3SbZ6XgnU%y_XKPk^|2Xiu(Qj10DanMprD7R zi(^Pd+}+8JTnq{vEY-9B|L-onnf*}rMpsLKhr~A}X6~pk<^}f?c1JgM%;69T$u(B_ uP@>kjym(53b-mh#Gok{P+yDQmWuF(JzkUCb(`G<389ZJ6T-G@yGywn{CNUKN literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Cut_6523.png b/Main/SimpleBackup.Resources/Images/Cut_6523.png new file mode 100644 index 0000000000000000000000000000000000000000..6683ee7467af50c3ec183dcef0750ef4d1b27b0a GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4FaAnjv*HQQzzN-H8}{hS~j_V;F#AquVq?r z0c-w)#1}7DZdfqgDOcmdhwybZ((Pxo)=W$}Wc2>*Z1clxja9$)+4nrYA@q5(aL48+ z4_`<<=h5^Ho}4;UvhAUULV8g`K@F1{kMm@ePSs11yCyTw{(S7UL&qbhUD*$P8BbKs zv(_t6TI3pNv3M<4X>567nAM}E2R?i`n|DV=#Drc2s+&Ap_Lx1ZLWX#K>GBzC&3%() z@2o4Aw%_jmaL*dy{T(-i1Z3VlXSFg+7IED+TmQjsxzGduCO4tcHQa(xxLJ`%lUstExEO+IQ6T1Rq?d_ADC8r W`{vlzekl$ZU<{tFelF{r5}E)9qL~!{ literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Delete_black_32x32.png b/Main/SimpleBackup.Resources/Images/Delete_black_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..906d053b304b40b9c1c7349ef7f6d9f736235ea5 GIT binary patch literal 4229 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 bfWHR-sgL+=MgfeO00000NkvXXu0mjf$w2L$ literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/FileGroup_10135_32x.png b/Main/SimpleBackup.Resources/Images/FileGroup_10135_32x.png new file mode 100644 index 0000000000000000000000000000000000000000..166c1aecc97c4ec90b3095b83b37e61211d4727c GIT binary patch literal 448 zcmV;x0YCnUP)xLJxMk~1T*S|YJpqg_$)Nh1o1dGp?mc7yBniXaHkN7FQq0M=9w7)~mL z*uwz#WkM=b^Cf^vHy_N723W&F1T$|S%Cf}ye8v!xBte#CATkm$Cnr)E2o2NEd2%V` z;N}bqX5lSM60w5;bq1U==RAMDf1!AOdHUx>%buMuoB_AYd4Rk7h`)oKhCw(5!~U7dpF}2LX5~HU=lD1m;_7$ z7K;U1F8VGQiPPzX4x8~E(35`%A>OSH@NMP;DJ8#-KurVN7JR9kJZ8?#)#TRqz$;a? qTCKq4nT>4=*rFqVR5{^2a|3_>x3>STNKAeJ0000zr?|{uKfu|b?JB@I6L?O{zL0>YrGUL9J%6&PCf|X z1>VaeL_q*+Eqan=nSulm5e8o9#kc(g#Oy6PgHR}W(!g(-ZVoJ>PMnZRp~xWIHs3x# z@&K)?g}cw4Z{S5#99_(cqUfrss*$4?w{!;b`q$kU`+D0vx$->6vMg!dkO?PRx~@TMt$YH0p6G$ne-Pup42FWsV|{NxSN;SF5#blS09loe UG8Nz?4*&oF07*qoM6N<$f{3ehNB{r; literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Open_6529.png b/Main/SimpleBackup.Resources/Images/Open_6529.png new file mode 100644 index 0000000000000000000000000000000000000000..74822865eba0c2a93d566b9ea5f45f6bb910dc26 GIT binary patch literal 343 zcmV-d0jU0oP)pG2}wjjRCr#UlCf&TFc60Q2JMrSK0@&;bg?0U4&DuUf=(Wt&ZSUj z1D^T-$)Md+7C}g|m<~xHfpZes9i3zl$V z907&f)mGmJX9wnDI7HZjrfD8XK$8c;gm?#hKpY+x@Z`=JP|X3EfQl%JP$`8)Q6Tqv z=oKvEIHrb(#e884s;YX*U)2S_>*Qd1>3xXi%y#)xvP%PQ3x0Zl@<2^|dv0(N& pvjp^*o|ID5lwu12;FgO2@C$IpkvFKnImrM3002ovPDHLkV1f*Uk(U4f literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Paste_6520.png b/Main/SimpleBackup.Resources/Images/Paste_6520.png new file mode 100644 index 0000000000000000000000000000000000000000..656678c73dd8bf4a0851389b3196fbf0567bbc5c GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!4;k^jv*HQcPAV29ai9REpCy~OnTmSM|FDU zW`he}hCLzjCr{|MP1rh7MEw zlAyM~P9Y7~l=yR`7N{;-Y|qg1EV$*!qnBqBq%H`1zc&w8?Gp;w*~R{WQ8X~{$DSDv RHUQns;OXk;vd$@?2>?&{V%-1$ literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/Print_11009.png b/Main/SimpleBackup.Resources/Images/Print_11009.png new file mode 100644 index 0000000000000000000000000000000000000000..fd56bdf805f258343039b462762dbcd7efaa1559 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!E{d-#}Etu;A>V9B)KtFupJ`Wb8^}FqHbRE1^KLL0hb# zs`18(BVuPYG$+l_I68|fahZVEF@wsi)PxO|426=4)~m|>On_E0c)I$ztaD0e0syZp BL?ZwI literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/StatusAnnotations_Complete_and_ok_32xLG_color.png b/Main/SimpleBackup.Resources/Images/StatusAnnotations_Complete_and_ok_32xLG_color.png new file mode 100644 index 0000000000000000000000000000000000000000..31d44e1ffaa4be3c593e90ac0dae97f12746a3a2 GIT binary patch literal 677 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 ZS=xjxVQ29F#~}AJc)I$ztaD0e0ssf^Ri6L= literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/arrow_all_run_16xLG.png b/Main/SimpleBackup.Resources/Images/arrow_all_run_16xLG.png new file mode 100644 index 0000000000000000000000000000000000000000..c2cf001b2d985d5d3628959368ffe6ce0f59efac GIT binary patch literal 3232 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 SN)fdH0000#8~t$;3dQS$r=znI02- z`fZU+<=937g**dKBv0>;&HP_%1A%7vJmB(e>;Q9-I0gdELvYXVWnkx>G_{}{k+I-t zw?prs{{igFkj;z)y+&UNd|+pFLaVHywpru6HKM*%zX3c6M*xKc65_ORrs{0fhdEP)@935{rWK0VEdB{&|BxF$EaG7Fp#1ObL&xC2lC zSiz00h?MvRCVnmfHs1iKO>;*Ip5u}Ld1fig5>3tp;Oq+DnOV3llWmXw}6ot*#b)(Hinz=zrO`uzzcW*FW?2d zz{295H`(PxDP@(wfh9>2Oa#v|%{!X}wgBohO~Gek-bND;kxu|mCW(pY0KAIG3r_HV Z$KRNhYzU1%w`BkT002ovPDHLkV1iDblKlVx literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/Images/flag_16xLG.png b/Main/SimpleBackup.Resources/Images/flag_16xLG.png new file mode 100644 index 0000000000000000000000000000000000000000..25c3b866bd5f8a083e878f25f030493e8facb389 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5M?jcysy3fAP;ir{ zi(^Pd+|o%Kd7Tsm9R90^h3rq}YBMlkoyy64f@4=>UcynaHxJmZm4sZ^nl9m7WT~%l zQubA8NcH8M5+i^8&xx@RvlY+8VF<%!rw$|!^#tuk4qUE-mY#~ec*nim!kzI z)5b>~qLUofOC88wmTFnu?-77`m3Zdkb z8mFPWOVrp7mH)tLiG&8_-1lwvC6kTwk}vbU-}By#(psx~Li_c4)dAf9;v)AFO{rF^ zs?lh46N$t#)XKe1CYR1#U<2rEHmeJTf}YRkI^9U5;_Pq%b}etW+aVGesK8ZNR;v|{IA9j=lWlYv*6Ve(-|rPAm&>VA zspNCf`~ChIG!uS;dHU@+hqO;o477x-O_*o4m<(=$gH$&+yx zoN+drHKCpea@u51LF_2}eZQyEDWB~j7{l1`|Cb_*^?I!x#|bC;Hu@N2<_HnUC;8p& ic1-X=P8)q@Q_3IQ*l)VyN2l8W00007Ed}V-p`MCHp9!yQueItDy^j&uQx4SBDHtxHP(iUmf=cD9|W>>Jv~0S32A1q zmw&n2V9g>C<9A_;sow_mAFT4Viw)WG6Xt*BV@@-?dQ41S9_SVZPgg&ebxsLQ0QP}L AfB*mh literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Resources/ResourceHelper.cs b/Main/SimpleBackup.Resources/ResourceHelper.cs new file mode 100644 index 0000000..d4362b6 --- /dev/null +++ b/Main/SimpleBackup.Resources/ResourceHelper.cs @@ -0,0 +1,156 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Resources +{ + using System; + using System.Resources; + using System.Windows; + + ///

+ /// Provides localized resources. + /// + public class ResourceHelper + { + /// + /// The resource identifier property + /// + public static readonly DependencyProperty ResourceIdProperty = DependencyProperty.RegisterAttached( + "ResourceId", + typeof(string), + typeof(ResourceHelper), + new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None, OnResourceIdChanged)); + + /// + /// The resource text property + /// + public static readonly DependencyProperty ResourceTextProperty = DependencyProperty.RegisterAttached( + "ResourceText", + typeof(string), + typeof(ResourceHelper), + new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None)); + + /// + /// The inner resource manager + /// + private static readonly ResourceManager InnerResourceManager = + new ResourceManager("SimpleBackup.Resources.Resources", typeof(ResourceHelper).Assembly); + + /// + /// The synchronize root + /// + private static readonly object SyncRoot = new object(); + + /// + /// The instance of ResourceService. + /// + private static volatile ResourceHelper instance; + + /// + /// Prevents a default instance of the class from being created. + /// + private ResourceHelper() + { + } + + /// + /// Sets the resource identifier. + /// + /// The dependency object. + /// The value. + public static void SetResourceId(DependencyObject obj, string value) + { + obj.SetValue(ResourceIdProperty, value); + } + + /// + /// Gets the resource identifier. + /// + /// The dependency object. + /// The resource ID. + public static string GetResourceId(DependencyObject obj) + { + return (string)obj.GetValue(ResourceIdProperty); + } + + /// + /// Gets the resource text. + /// + /// The object. + /// The resource text. + public static string GetResourceText(DependencyObject obj) + { + return (string)obj.GetValue(ResourceTextProperty); + } + + /// + /// Called when [resource identifier changed]. + /// + /// The dependency object. + /// The instance containing the event data. + private static void OnResourceIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var newResourceId = (string)e.NewValue; + string resourceText; + if (TryGetResourceText(newResourceId, out resourceText)) + { + d.SetValue(ResourceTextProperty, resourceText); + } + } + + /// + /// Tries the get resource text. + /// + /// The resource identifier. + /// The resource text. + /// True if succeeded to get resource text. + private static bool TryGetResourceText(string resourceId, out string resourceText) + { + resourceText = string.Empty; + + try + { + resourceText = InnerResourceManager.GetString(resourceId); + } + catch (ArgumentNullException) + { + //// Ignore exception. + } + catch (InvalidOperationException) + { + //// Ignore exception. + } + catch (MissingManifestResourceException) + { + //// Ignore exception. + } + catch (MissingSatelliteAssemblyException) + { + //// Ignore exception. + } + + var succeeded = resourceText != null; + resourceText = resourceText ?? string.Empty; + + return succeeded; + } + } +} diff --git a/Main/SimpleBackup.Resources/Resources.Designer.cs b/Main/SimpleBackup.Resources/Resources.Designer.cs new file mode 100644 index 0000000..09d4ef4 --- /dev/null +++ b/Main/SimpleBackup.Resources/Resources.Designer.cs @@ -0,0 +1,778 @@ +//------------------------------------------------------------------------------ +// +// このコードはツールによって生成されました。 +// ランタイム バージョン:4.0.30319.34014 +// +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 +// コードが再生成されるときに損失したりします。 +// +//------------------------------------------------------------------------------ + +namespace SimpleBackup.Resources { + using System; + + + /// + /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 + /// + // このクラスは StronglyTypedResourceBuilder クラスが ResGen + // または Visual Studio のようなツールを使用して自動生成されました。 + // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に + // ResGen を実行し直すか、または VS プロジェクトをビルドし直します。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// このクラスで使用されているキャッシュされた ResourceManager インスタンスを返します。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SimpleBackup.Resources.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 厳密に型指定されたこのリソース クラスを使用して、すべての検索リソースに対し、 + /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Backup... に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_ExecutingBackup { + get { + return ResourceManager.GetString("Backup_ExecutingBackup", resourceCulture); + } + } + + /// + /// The backup information has not been prepared. に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_Failed_BackupInfomationNotPrepared { + get { + return ResourceManager.GetString("Backup_Failed_BackupInfomationNotPrepared", resourceCulture); + } + } + + /// + /// The destination Folder does not exist. に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_Failed_DestinationNotExist { + get { + return ResourceManager.GetString("Backup_Failed_DestinationNotExist", resourceCulture); + } + } + + /// + /// Failed to copy the file. に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_Failed_FailedToCopy { + get { + return ResourceManager.GetString("Backup_Failed_FailedToCopy", resourceCulture); + } + } + + /// + /// The source does not exist. に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_Failed_SourceNotExist { + get { + return ResourceManager.GetString("Backup_Failed_SourceNotExist", resourceCulture); + } + } + + /// + /// From に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_From { + get { + return ResourceManager.GetString("Backup_From", resourceCulture); + } + } + + /// + /// The backup has been skipped. に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_Skipped { + get { + return ResourceManager.GetString("Backup_Skipped", resourceCulture); + } + } + + /// + /// Done! に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_Succeeded { + get { + return ResourceManager.GetString("Backup_Succeeded", resourceCulture); + } + } + + /// + /// To に類似しているローカライズされた文字列を検索します。 + /// + public static string Backup_To { + get { + return ResourceManager.GetString("Backup_To", resourceCulture); + } + } + + /// + /// Failed to open the backup setting. The file name is empty: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_FailedToOpenSetting_EmptyFileNameFormat { + get { + return ResourceManager.GetString("BackupSetting_FailedToOpenSetting_EmptyFileNameFormat", resourceCulture); + } + } + + /// + /// Failed to open the backup setting. Invalid major version value: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_FailedToOpenSetting_InvalidMajorVersionFormat { + get { + return ResourceManager.GetString("BackupSetting_FailedToOpenSetting_InvalidMajorVersionFormat", resourceCulture); + } + } + + /// + /// Failed to open the backup setting. Invalid minor version value: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_FailedToOpenSetting_InvalidMinorVersionFormat { + get { + return ResourceManager.GetString("BackupSetting_FailedToOpenSetting_InvalidMinorVersionFormat", resourceCulture); + } + } + + /// + /// Failed to open the backup setting. Invalid "RequiredToolVersion" value: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_FailedToOpenSetting_InvalidRequiredToolVersionFormat { + get { + return ResourceManager.GetString("BackupSetting_FailedToOpenSetting_InvalidRequiredToolVersionFormat", resourceCulture); + } + } + + /// + /// Failed to open the backup setting. Invalid "Version" value: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_FailedToOpenSetting_InvalidVersionFormat { + get { + return ResourceManager.GetString("BackupSetting_FailedToOpenSetting_InvalidVersionFormat", resourceCulture); + } + } + + /// + /// Failed to open the backup setting. There is no "BackupSetting" tag: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_FailedToOpenSetting_NoBackupSettingElementFormat { + get { + return ResourceManager.GetString("BackupSetting_FailedToOpenSetting_NoBackupSettingElementFormat", resourceCulture); + } + } + + /// + /// Failed to open the backup setting. There is no "Version" tag: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_FailedToOpenSetting_NoVersionElementFormat { + get { + return ResourceManager.GetString("BackupSetting_FailedToOpenSetting_NoVersionElementFormat", resourceCulture); + } + } + + /// + /// Failed to read the backup setting data because it is incomatible. To read the backup setting data, please use Simple Backup Ver.{0} or later. に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_IncompatibleMajorVersionFormat { + get { + return ResourceManager.GetString("BackupSetting_IncompatibleMajorVersionFormat", resourceCulture); + } + } + + /// + /// Failed to read some part of the backup setting data because they are incompatible. To read all the backup setting data, please use Simple Backup Ver.{0} or later. に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_IncompatibleMinorVersionFormat { + get { + return ResourceManager.GetString("BackupSetting_IncompatibleMinorVersionFormat", resourceCulture); + } + } + + /// + /// The backup setting is opened: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupSetting_SettingOpenedFormat { + get { + return ResourceManager.GetString("BackupSetting_SettingOpenedFormat", resourceCulture); + } + } + + /// + /// Cancelled に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupState_Cancelled { + get { + return ResourceManager.GetString("BackupState_Cancelled", resourceCulture); + } + } + + /// + /// Fail に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupState_Failed { + get { + return ResourceManager.GetString("BackupState_Failed", resourceCulture); + } + } + + /// + /// In Progress に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupState_InProgress { + get { + return ResourceManager.GetString("BackupState_InProgress", resourceCulture); + } + } + + /// + /// Skipped に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupState_Skipped { + get { + return ResourceManager.GetString("BackupState_Skipped", resourceCulture); + } + } + + /// + /// Success に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupState_Success { + get { + return ResourceManager.GetString("BackupState_Success", resourceCulture); + } + } + + /// + /// TODO に類似しているローカライズされた文字列を検索します。 + /// + public static string BackupState_Todo { + get { + return ResourceManager.GetString("BackupState_Todo", resourceCulture); + } + } + + /// + /// Copy に類似しているローカライズされた文字列を検索します。 + /// + public static string Edit_CopySuffix { + get { + return ResourceManager.GetString("Edit_CopySuffix", resourceCulture); + } + } + + /// + /// Failed to open the file: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string FileAccess_FailedToOpenFormat { + get { + return ResourceManager.GetString("FileAccess_FailedToOpenFormat", resourceCulture); + } + } + + /// + /// The folder path does not exist: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string FileAccess_FolderPathNotExistFormat { + get { + return ResourceManager.GetString("FileAccess_FolderPathNotExistFormat", resourceCulture); + } + } + + /// + /// The path is not valid: {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string FileAccess_InvalidPathFormat { + get { + return ResourceManager.GetString("FileAccess_InvalidPathFormat", resourceCulture); + } + } + + /// + /// Copyright© 2015 Takayoshi Matsuyama に類似しているローカライズされた文字列を検索します。 + /// + public static string Version_Copyright { + get { + return ResourceManager.GetString("Version_Copyright", resourceCulture); + } + } + + /// + /// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + /// + ///This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + /// + ///You should have received a copy [残りの文字列は切り詰められました]"; に類似しているローカライズされた文字列を検索します。 + /// + public static string Version_CopyrightDescription { + get { + return ResourceManager.GetString("Version_CopyrightDescription", resourceCulture); + } + } + + /// + /// Add に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_AddButtonToolTipText { + get { + return ResourceManager.GetString("Views_AddButtonToolTipText", resourceCulture); + } + } + + /// + /// Destination に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_BackupDestinationColumnHeaderText { + get { + return ResourceManager.GetString("Views_BackupDestinationColumnHeaderText", resourceCulture); + } + } + + /// + /// Source に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_BackupSourceColumnHeaderText { + get { + return ResourceManager.GetString("Views_BackupSourceColumnHeaderText", resourceCulture); + } + } + + /// + /// Cancel Multi Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_CancelMultiBackupButtonToolTipText { + get { + return ResourceManager.GetString("Views_CancelMultiBackupButtonToolTipText", resourceCulture); + } + } + + /// + /// Confirmation に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ConfirmationDialogTitle { + get { + return ResourceManager.GetString("Views_ConfirmationDialogTitle", resourceCulture); + } + } + + /// + /// Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ContextMenu_Backup { + get { + return ResourceManager.GetString("Views_ContextMenu_Backup", resourceCulture); + } + } + + /// + /// Edit に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ContextMenu_Edit { + get { + return ResourceManager.GetString("Views_ContextMenu_Edit", resourceCulture); + } + } + + /// + /// Open Destination に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ContextMenu_OpenDestination { + get { + return ResourceManager.GetString("Views_ContextMenu_OpenDestination", resourceCulture); + } + } + + /// + /// Open File に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ContextMenu_OpenFile { + get { + return ResourceManager.GetString("Views_ContextMenu_OpenFile", resourceCulture); + } + } + + /// + /// Open Source Folder に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ContextMenu_OpenSourceFolder { + get { + return ResourceManager.GetString("Views_ContextMenu_OpenSourceFolder", resourceCulture); + } + } + + /// + /// Select Destination に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ContextMenu_SelectDestination { + get { + return ResourceManager.GetString("Views_ContextMenu_SelectDestination", resourceCulture); + } + } + + /// + /// Select Source に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ContextMenu_SelectSource { + get { + return ResourceManager.GetString("Views_ContextMenu_SelectSource", resourceCulture); + } + } + + /// + /// Copy に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_CopyButtonToolTipText { + get { + return ResourceManager.GetString("Views_CopyButtonToolTipText", resourceCulture); + } + } + + /// + /// Simple Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_CopyrightApplicationName { + get { + return ResourceManager.GetString("Views_CopyrightApplicationName", resourceCulture); + } + } + + /// + /// Cut に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_CutButtonToolTipText { + get { + return ResourceManager.GetString("Views_CutButtonToolTipText", resourceCulture); + } + } + + /// + /// Simple Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_DefaultWindowTitle { + get { + return ResourceManager.GetString("Views_DefaultWindowTitle", resourceCulture); + } + } + + /// + /// Label に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_LabelColumnHeaderText { + get { + return ResourceManager.GetString("Views_LabelColumnHeaderText", resourceCulture); + } + } + + /// + /// _Close に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_Close { + get { + return ResourceManager.GetString("Views_MainMenu_Close", resourceCulture); + } + } + + /// + /// E_xit に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_Exit { + get { + return ResourceManager.GetString("Views_MainMenu_Exit", resourceCulture); + } + } + + /// + /// _File に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_File { + get { + return ResourceManager.GetString("Views_MainMenu_File", resourceCulture); + } + } + + /// + /// _Help に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_Help { + get { + return ResourceManager.GetString("Views_MainMenu_Help", resourceCulture); + } + } + + /// + /// _New に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_New { + get { + return ResourceManager.GetString("Views_MainMenu_New", resourceCulture); + } + } + + /// + /// _Open に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_Open { + get { + return ResourceManager.GetString("Views_MainMenu_Open", resourceCulture); + } + } + + /// + /// Open Current Setting File Location に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_OpenCurrentSettingFileLocation { + get { + return ResourceManager.GetString("Views_MainMenu_OpenCurrentSettingFileLocation", resourceCulture); + } + } + + /// + /// _Save に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_Save { + get { + return ResourceManager.GetString("Views_MainMenu_Save", resourceCulture); + } + } + + /// + /// Save _As に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_SaveAs { + get { + return ResourceManager.GetString("Views_MainMenu_SaveAs", resourceCulture); + } + } + + /// + /// Show Help (_V) に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_ShowHelp { + get { + return ResourceManager.GetString("Views_MainMenu_ShowHelp", resourceCulture); + } + } + + /// + /// Show Version Information (_A) に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MainMenu_ShowVersionInformation { + get { + return ResourceManager.GetString("Views_MainMenu_ShowVersionInformation", resourceCulture); + } + } + + /// + /// Move down に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MoveDownButtonToolTipText { + get { + return ResourceManager.GetString("Views_MoveDownButtonToolTipText", resourceCulture); + } + } + + /// + /// Move up に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MoveUpButtonToolTipText { + get { + return ResourceManager.GetString("Views_MoveUpButtonToolTipText", resourceCulture); + } + } + + /// + /// Multiple Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_MultipleBackupButtonToolTipText { + get { + return ResourceManager.GetString("Views_MultipleBackupButtonToolTipText", resourceCulture); + } + } + + /// + /// New Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_NewBackupSettingName { + get { + return ResourceManager.GetString("Views_NewBackupSettingName", resourceCulture); + } + } + + /// + /// New に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_NewFileButtonToolTipText { + get { + return ResourceManager.GetString("Views_NewFileButtonToolTipText", resourceCulture); + } + } + + /// + /// Open Backup Setting に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_OpenBackupSettingButtonToolTipText { + get { + return ResourceManager.GetString("Views_OpenBackupSettingButtonToolTipText", resourceCulture); + } + } + + /// + /// Open Backup Setting に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_OpenFileDialogTitle { + get { + return ResourceManager.GetString("Views_OpenFileDialogTitle", resourceCulture); + } + } + + /// + /// Clear に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_OutputWindowContextMenu_Clear { + get { + return ResourceManager.GetString("Views_OutputWindowContextMenu_Clear", resourceCulture); + } + } + + /// + /// Paste に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_PasteButtonToolTipText { + get { + return ResourceManager.GetString("Views_PasteButtonToolTipText", resourceCulture); + } + } + + /// + /// Redo に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_RedoButtonToolTipText { + get { + return ResourceManager.GetString("Views_RedoButtonToolTipText", resourceCulture); + } + } + + /// + /// Refresh に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_RefreshButtonToolTipText { + get { + return ResourceManager.GetString("Views_RefreshButtonToolTipText", resourceCulture); + } + } + + /// + /// Remove に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_RemoveButtonToolTipText { + get { + return ResourceManager.GetString("Views_RemoveButtonToolTipText", resourceCulture); + } + } + + /// + /// Save Backup Setting に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_SaveBackupSettingButtonToolTipText { + get { + return ResourceManager.GetString("Views_SaveBackupSettingButtonToolTipText", resourceCulture); + } + } + + /// + /// Save the changes? に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_SaveConfirmationMessage { + get { + return ResourceManager.GetString("Views_SaveConfirmationMessage", resourceCulture); + } + } + + /// + /// Save Backup Setting に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_SaveFileDialogTitle { + get { + return ResourceManager.GetString("Views_SaveFileDialogTitle", resourceCulture); + } + } + + /// + /// Single Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_SingleBackupButtonToolTipText { + get { + return ResourceManager.GetString("Views_SingleBackupButtonToolTipText", resourceCulture); + } + } + + /// + /// Undo に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_UndoButtonToolTipText { + get { + return ResourceManager.GetString("Views_UndoButtonToolTipText", resourceCulture); + } + } + + /// + /// Version Information of Simple Backup に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_VersionWindowTitle { + get { + return ResourceManager.GetString("Views_VersionWindowTitle", resourceCulture); + } + } + + /// + /// Simple Backup - {0} に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_WindowTitleFormat { + get { + return ResourceManager.GetString("Views_WindowTitleFormat", resourceCulture); + } + } + + /// + /// Zip Encoding に類似しているローカライズされた文字列を検索します。 + /// + public static string Views_ZipEncodingTitleText { + get { + return ResourceManager.GetString("Views_ZipEncodingTitleText", resourceCulture); + } + } + } +} diff --git a/Main/SimpleBackup.Resources/Resources.ja.resx b/Main/SimpleBackup.Resources/Resources.ja.resx new file mode 100644 index 0000000..b16a2a4 --- /dev/null +++ b/Main/SimpleBackup.Resources/Resources.ja.resx @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + キャンセル + + + 失敗 + + + 進行中 + + + スキップ + + + 成功 + + + 実行待ち + + + バックアップ実行中... + + + バックアップ対象がありません。 + + + バックアップ情報が準備できていません。 + + + バックアップはスキップされました。 + + + バックアップ対象 + + + バックアップ先 + + + コピー + + + 追加 + + + バックアップ先 + + + バックアップ対象 + + + マルチバックアップをキャンセル + + + バックアップ + + + 編集 + + + バックアップ先の場所を開く + + + ファイルを開く + + + バックアップ対象の場所を開く + + + バックアップ先を選ぶ + + + バックアップ対象を選ぶ + + + コピー + + + 切り取り + + + バックアップツール + + + ラベル + + + 閉じる(_C) + + + 終了(_X) + + + ファイル(_F) + + + ヘルプ(_H) + + + 新規作成(_N) + + + 開く(_O) + + + 現在の設定ファイルの場所を開く + + + ヘルプの表示(_V) + + + バージョン情報(_A) + + + 下へ移動 + + + 上へ移動 + + + マルチバックアップ + + + 新しいバックアップ + + + 新規作成 + + + バックアップ設定を開く + + + クリア + + + 貼り付け + + + やり直し + + + リフレッシュ + + + 削除 + + + バックアップ設定を保存する + + + シングルバックアップ + + + 元に戻す + + + バックアップツールのバージョン情報 + + + バックアップツール - {0} + + + バックアップ先のフォルダががありません。 + + + ファイルのコピーに失敗しました。 + + + バックアップを完了しました。 + + + 保存(_S) + + + 名前を付けて保存(_A) + + + Zipエンコード + + + バックアップ設定を開く + + + バックアップ設定の保存 + + + 互換性がないため、バックアップ設定データの読み込みに失敗しました。このバックアップ設定データを読み込むには、Ver.{0}以降のバックアップツールを入手してください。 + + + 互換性がないため、一部のバックアップ設定データの読み込みに失敗しました。全てのバックアップ設定データを読み込むには、Ver.{0}以降のバックアップツールを入手してください。 + + + バックアップ設定を開きました。{0} + + + バックアップ設定の読み込みに失敗しました。ファイル名が空です。{0} + + + バックアップ設定の読み込みに失敗しました。メジャーバージョン値が不正です。{0} + + + バックアップ設定の読み込みに失敗しました。マイナーバージョン値が不正です。{0} + + + バックアップ設定の読み込みに失敗しました。"RequiredToolVersion"値が不正です。{0} + + + バックアップ設定の読み込みに失敗しました。"Version"値が不正です。{0} + + + バックアップ設定の読み込みに失敗しました。"BackupSetting"タグが見つかりません。{0} + + + バックアップ設定の読み込みに失敗しました。"Version"タグが見つかりません。{0} + + + ファイルオープンに失敗しました。 {0} + + + 存在しないフォルダです。 {0} + + + 不正なパスです。 {0} + + + 確認 + + + 変更を保存しますか? + + \ No newline at end of file diff --git a/Main/SimpleBackup.Resources/Resources.resx b/Main/SimpleBackup.Resources/Resources.resx new file mode 100644 index 0000000..a8eb5b9 --- /dev/null +++ b/Main/SimpleBackup.Resources/Resources.resx @@ -0,0 +1,361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cancelled + + + Fail + + + In Progress + + + Skipped + + + Success + + + TODO + + + Backup... + + + The source does not exist. + + + The backup information has not been prepared. + + + The backup has been skipped. + + + From + + + To + + + Copy + + + Copyright© 2015 Takayoshi Matsuyama + + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. + + + Add + + + Destination + + + Source + + + Cancel Multi Backup + + + Backup + + + Edit + + + Open Destination + + + Open File + + + Open Source Folder + + + Select Destination + + + Select Source + + + Copy + + + Simple Backup + + + Cut + + + Simple Backup + + + Label + + + _Close + + + E_xit + + + _File + + + _Help + + + _New + + + _Open + + + Open Current Setting File Location + + + Show Help (_V) + + + Show Version Information (_A) + + + Move down + + + Move up + + + Multiple Backup + + + New Backup + + + New + + + Open Backup Setting + + + Clear + + + Paste + + + Redo + + + Refresh + + + Remove + + + Save Backup Setting + + + Single Backup + + + Undo + + + Version Information of Simple Backup + + + Simple Backup - {0} + + + The destination Folder does not exist. + + + Failed to copy the file. + + + Done! + + + _Save + + + Save _As + + + Zip Encoding + + + Open Backup Setting + + + Save Backup Setting + + + Failed to read the backup setting data because it is incomatible. To read the backup setting data, please use Simple Backup Ver.{0} or later. + + + Failed to read some part of the backup setting data because they are incompatible. To read all the backup setting data, please use Simple Backup Ver.{0} or later. + + + The backup setting is opened: {0} + + + Failed to open the backup setting. The file name is empty: {0} + + + Failed to open the backup setting. Invalid major version value: {0} + + + Failed to open the backup setting. Invalid minor version value: {0} + + + Failed to open the backup setting. Invalid "RequiredToolVersion" value: {0} + + + Failed to open the backup setting. Invalid "Version" value: {0} + + + Failed to open the backup setting. There is no "BackupSetting" tag: {0} + + + Failed to open the backup setting. There is no "Version" tag: {0} + + + Failed to open the file: {0} + + + The folder path does not exist: {0} + + + The path is not valid: {0} + + + Confirmation + + + Save the changes? + + \ No newline at end of file diff --git a/Main/SimpleBackup.Resources/SimpleBackup.Resources.csproj b/Main/SimpleBackup.Resources/SimpleBackup.Resources.csproj new file mode 100644 index 0000000..5bdec14 --- /dev/null +++ b/Main/SimpleBackup.Resources/SimpleBackup.Resources.csproj @@ -0,0 +1,165 @@ + + + + + Debug + AnyCPU + {A655131E-D439-4DE1-BC39-5C955306183F} + Library + Properties + SimpleBackup.Resources + SimpleBackup.Resources + v4.5 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + SimpleBackupKey.snk + + + + + + + + + + + + + + + + + Properties\AssemblyInfo.cs + + + Resources.resx + True + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + \ No newline at end of file diff --git a/Main/SimpleBackup.Resources/SimpleBackupKey.snk b/Main/SimpleBackup.Resources/SimpleBackupKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..def2e6df6a67d7e5802b3319c2b385c61304db29 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=*mMuj7Bow@Ep}p%TfOae=&U%vR9qh+ z@B2Y7h5t%KB~GowmVCnTwn!=ol7j~SRw};|aqMe69$!Xr!@Kl)p?8Xg2;G;~Cd60S zyuxBRv<}vHJsUi)3u6Y?7~u<-nIO&1Fj-O8+VD)*I{}r1s+^@Kmf2Y}gp`|NRs+em z$u>8Tw)yg`4_#X9od;DS_`m7gjCw7)_oIM$fq-7kckw~B<7M;zI>N{SPq*6$huq7Z zgYNgU;sUWRbAi&O+L_hd!U0Li?IE-i`qYl6ItfNG&LGLWV{U{YZh>Ax4*J$khFNYOR0lC!sQ=xnj0#!GfwNKNLWeC6+{0F(k120wr_Sb zIyF(GL;3}qT}4Ed2plZ&Isj`rlkfJc)Ea1aKb3p_jTAd0vy@;AzzF|BpZp|m^l#y& zbx94OX%V&s<FnfGWY1Nh zxKnroP3(eKfbr85Y^JZ_CW>v48ZxICTuX?#TOI&z>)DFD-NiB2i|wPJnn~;|{CGZv i!2z3|Al4b1%II9A@B0rIjj|^@+oAX!*AylRLZAX-U?o=o literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Services/BackupService.cs b/Main/SimpleBackup.Services/BackupService.cs new file mode 100644 index 0000000..a77dc58 --- /dev/null +++ b/Main/SimpleBackup.Services/BackupService.cs @@ -0,0 +1,643 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Services +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.IO.Compression; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using System.Threading; + using SimpleBackup.Core; + using SimpleBackup.Core.Models; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.Utilities; + using SimpleBackup.Resources; + + /// + /// Backup service. + /// + internal class BackupService : IBackupService + { + /// + /// The synchronize root + /// + private static readonly object SyncRoot = new object(); + + /// + /// The instance of BackupService. + /// + private static volatile BackupService instance; + + /// + /// Prevents a default instance of the class from being created. + /// + private BackupService() + { + BackupSettingService.Instance.BackupSettingCreated += this.OnBackupSettingCreated; + BackupSettingService.Instance.BackupSettingOpened += this.OnBackupSettingOpened; + BackupSettingService.Instance.BackupSettingClosed += this.OnBackupSettingClosed; + } + + /// + /// Occurs when file backup progress is updated. + /// + public event EventHandler NofityFileBackupProgress; + + /// + /// Gets the instance. + /// + public static IBackupService Instance + { + get + { + if (instance == null) + { + lock (SyncRoot) + { + if (instance == null) + { + instance = new BackupService(); + } + } + } + + return instance; + } + } + + /// + /// Gets a value indicating whether this service is ready for backup. + /// + public bool IsReadyForBackup { get; private set; } + + /// + /// Gets a value indicating whether this service is executing backup. + /// + public bool IsExecutingBackup { get; private set; } + + /// + /// Backups multipul files. + /// + /// The cancellation token. + /// The array of result information. + public void BackupMultipulFiles(CancellationToken cancellationToken, out IResultInfo[] resultInfos) + { + var modelFactory = ObjectContainer.Resolve(); + + this.IsExecutingBackup = true; + var resultList = new List(); + if (this.IsReadyForBackup == false) + { + resultList.Add(modelFactory.CreateResultInfo(BackupState.Failed, Resources.Backup_Failed_BackupInfomationNotPrepared)); + resultInfos = resultList.ToArray(); + return; + } + + try + { + this.NotifyBackupProgress(0, null); + + int processedCount = 0; + + foreach (IBackupInfo backupInfo in BackupSettingService.Instance.CurrentSetting.BackupInfos) + { + cancellationToken.ThrowIfCancellationRequested(); + backupInfo.BackupState = BackupState.InProgress; + + Thread.Sleep(100); + + IResultInfo resultInfo = null; + double progressValue = 0; + + if (backupInfo.IsEnabled == false) + { + string description = string.Format( + "{0}\r\n\t{1}: {2}", + Resources.Backup_Skipped, + Resources.Backup_From, + backupInfo.SourcePath); + resultInfo = modelFactory.CreateResultInfo(BackupState.Skipped, description); + processedCount++; + progressValue = processedCount * 100.0 / BackupSettingService.Instance.CurrentSetting.Count; + this.NotifyBackupProgress(progressValue, resultInfo); + backupInfo.BackupState = BackupState.Skipped; + continue; + } + + // Check the source. + if (((backupInfo.BackupSourceType == BackupSourceType.File) && (File.Exists(backupInfo.SourcePath) == false)) || + ((backupInfo.BackupSourceType == BackupSourceType.Folder) && (Directory.Exists(backupInfo.SourcePath) == false))) + { + string description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}", + Resources.Backup_Failed_SourceNotExist, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + backupInfo.DestinationFolderPath); + resultInfo = modelFactory.CreateResultInfo(BackupState.Failed, description); + resultList.Add(resultInfo); + processedCount++; + progressValue = processedCount * 100.0 / BackupSettingService.Instance.CurrentSetting.Count; + this.NotifyBackupProgress(progressValue, resultInfo); + backupInfo.BackupState = BackupState.Failed; + continue; + } + + // Check the destination. + if ((backupInfo.DestinationFolderPath == "\\") || + (Directory.Exists(backupInfo.DestinationFolderPath) == false)) + { + string description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}", + Resources.Backup_Failed_DestinationNotExist, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + backupInfo.DestinationFolderPath); + resultInfo = modelFactory.CreateResultInfo(BackupState.Failed, description); + resultList.Add(resultInfo); + processedCount++; + progressValue = processedCount * 100.0 / BackupSettingService.Instance.CurrentSetting.Count; + this.NotifyBackupProgress(progressValue, resultInfo); + backupInfo.BackupState = BackupState.Failed; + continue; + } + + var destinationFileNames = new IDestinationPathInfo[0]; + try + { + if (backupInfo.IsZipArchive) + { + if (backupInfo.BackupSourceType == BackupSourceType.File) + { + BackupFileToZip(backupInfo, out destinationFileNames); + } + else if (backupInfo.BackupSourceType == BackupSourceType.Folder) + { + BackupFolerToZip(backupInfo, out destinationFileNames); + } + } + else + { + if (backupInfo.BackupSourceType == BackupSourceType.File) + { + BackupFile(backupInfo, out destinationFileNames); + } + else if (backupInfo.BackupSourceType == BackupSourceType.Folder) + { + BackupFolder(backupInfo, out destinationFileNames); + } + } + } + catch (Exception e) + { + string description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}\r\n{5}", + Resources.Backup_Failed_FailedToCopy, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + destinationFileNames.FirstOrDefault(), + e.Message); + resultInfo = modelFactory.CreateResultInfo(BackupState.Failed, description); + resultList.Add(resultInfo); + processedCount++; + progressValue = processedCount * 100.0 / BackupSettingService.Instance.CurrentSetting.Count; + this.NotifyBackupProgress(progressValue, resultInfo); + backupInfo.BackupState = BackupState.Failed; + continue; + } + + if (CheckExistence(destinationFileNames)) + { + string description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}", + Resources.Backup_Succeeded, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + destinationFileNames.First().Path); + resultInfo = modelFactory.CreateResultInfo(BackupState.Success, description); + resultList.Add(resultInfo); + backupInfo.BackupState = BackupState.Success; + backupInfo.LatestSuccessfulBackupTargetName = destinationFileNames.First().Path; + } + + processedCount++; + progressValue = processedCount * 100.0 / BackupSettingService.Instance.CurrentSetting.Count; + this.NotifyBackupProgress(progressValue, resultInfo); + } + + this.NotifyBackupProgress(100.0, null); + } + catch (OperationCanceledException) + { + var resultInfo = modelFactory.CreateResultInfo(BackupState.Cancelled, Resources.BackupState_Cancelled); + resultList.Add(resultInfo); + this.NotifyBackupProgress(100.0, resultInfo); + } + finally + { + resultInfos = resultList.ToArray(); + this.IsExecutingBackup = false; + } + } + + /// + /// Backups single file. + /// + /// The backup information identifier. + /// The result information. + public IResultInfo BackupSingleFile(Guid backupInfoId) + { + var modelFactory = ObjectContainer.Resolve(); + + IBackupInfo backupInfo = BackupSettingService.Instance.CurrentSetting.FirstOrDefault(backupInfoId); + if (backupInfo == null) + { + return modelFactory.CreateResultInfo( + BackupState.Failed, + Resources.Backup_Failed_BackupInfomationNotPrepared); + } + + backupInfo.BackupState = BackupState.InProgress; + Helpers.UpdateWpfGui(); + + IResultInfo resultInfo = null; + string description = string.Empty; + + // Check the source. + if (((backupInfo.BackupSourceType == BackupSourceType.File) && (File.Exists(backupInfo.SourcePath) == false)) || + ((backupInfo.BackupSourceType == BackupSourceType.Folder) && (Directory.Exists(backupInfo.SourcePath) == false))) + { + description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}", + Resources.Backup_Failed_SourceNotExist, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + backupInfo.DestinationFolderPath); + resultInfo = modelFactory.CreateResultInfo(BackupState.Failed, description); + backupInfo.BackupState = BackupState.Failed; + return resultInfo; + } + + // Check the destination. + if (Directory.Exists(backupInfo.DestinationFolderPath) == false) + { + description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}", + Resources.Backup_Failed_DestinationNotExist, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + backupInfo.DestinationFolderPath); + resultInfo = modelFactory.CreateResultInfo(BackupState.Failed, description); + backupInfo.BackupState = BackupState.Failed; + return resultInfo; + } + + var destinationFileNames = new IDestinationPathInfo[0]; + try + { + if (backupInfo.IsZipArchive) + { + if (backupInfo.BackupSourceType == BackupSourceType.File) + { + BackupFileToZip(backupInfo, out destinationFileNames); + } + else if (backupInfo.BackupSourceType == BackupSourceType.Folder) + { + BackupFolerToZip(backupInfo, out destinationFileNames); + } + } + else + { + if (backupInfo.BackupSourceType == BackupSourceType.File) + { + BackupFile(backupInfo, out destinationFileNames); + } + else if (backupInfo.BackupSourceType == BackupSourceType.Folder) + { + BackupFolder(backupInfo, out destinationFileNames); + } + } + } + catch (Exception e) + { + description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}\r\n{5}", + Resources.Backup_Failed_FailedToCopy, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + destinationFileNames.FirstOrDefault(), + e.Message); + resultInfo = modelFactory.CreateResultInfo(BackupState.Failed, description); + backupInfo.BackupState = BackupState.Failed; + return resultInfo; + } + + if (CheckExistence(destinationFileNames)) + { + description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}", + Resources.Backup_Succeeded, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + destinationFileNames.First().Path); + resultInfo = modelFactory.CreateResultInfo(BackupState.Success, description); + backupInfo.BackupState = BackupState.Success; + backupInfo.LatestSuccessfulBackupTargetName = destinationFileNames.First().Path; + return resultInfo; + } + + description = string.Format( + "{0}\r\n\t{1}: {2}\r\n\t{3}: {4}", + Resources.Backup_Failed_FailedToCopy, + Resources.Backup_From, + backupInfo.SourcePath, + Resources.Backup_To, + destinationFileNames.FirstOrDefault()); + return modelFactory.CreateResultInfo(BackupState.Failed, description); + } + + private static void BackupFileToZip(IBackupInfo backupInfo, out IDestinationPathInfo[] destinationPathInfoArray) + { + var innerDestinationPathInfoList = new List(); + + var modelFactory = ObjectContainer.Resolve(); + + Match lastPathSegmentMatch = Constants.EndPathSegmentRegex.Match(backupInfo.SourcePath); + Match fileNameMatch = Constants.FileNameRegex.Match(lastPathSegmentMatch.Value); + Match extensionMatch = Constants.ExtensionRegex.Match(lastPathSegmentMatch.Value); + + string destinationFolderPath = backupInfo.DestinationFolderPath.AddTailPathSeparatorIfNotExist(); + string destinationTempFolderPath = destinationFolderPath + fileNameMatch.Value + + " - " + DateTime.Now.ToString("yyyyMMdd-HHmmss") + "-tmp"; + string destinationTempFileName = destinationTempFolderPath + "\\" + fileNameMatch.Value + + " - " + DateTime.Now.ToString("yyyyMMdd-HHmmss") + "." + extensionMatch.Value; + try + { + try + { + Directory.CreateDirectory(destinationTempFolderPath); + } + catch (Exception e) + { + throw new InvalidOperationException( + string.Format( + "Failed to create the folder: {0}\r\n{1}", + destinationTempFolderPath, + e.Message), + e); + } + + try + { + File.Copy(backupInfo.SourcePath, destinationTempFileName); + } + catch (Exception e) + { + throw new InvalidOperationException( + string.Format( + "Failed to copy the file.\r\n\tFrom: {0}\r\n\tTo: {1}\r\n{2}", + backupInfo.SourcePath, + destinationTempFolderPath, + e.Message), + e); + } + + var destinationFileName = destinationFolderPath + fileNameMatch.Value + + " - " + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".zip"; + innerDestinationPathInfoList.Add(modelFactory.CreateDestinationPathInfo(BackupSourceType.File, destinationFileName)); + + try + { + ZipFile.CreateFromDirectory( + destinationTempFolderPath, + destinationFileName, + CompressionLevel.Optimal, + false, + Encoding.GetEncoding(Properties.Settings.Default.DefaultZipEncodingKeyText)); + } + catch (Exception e) + { + backupInfo.BackupState = BackupState.Failed; + throw new InvalidOperationException( + string.Format( + "Failed to create the zip archive.\r\n\tFrom: {0}\r\n\tTo: {1}\r\n{2}", + destinationTempFolderPath, + destinationFileName, + e.Message), + e); + } + } + finally + { + destinationPathInfoArray = innerDestinationPathInfoList.ToArray(); + + if (File.Exists(destinationTempFileName)) + { + File.Delete(destinationTempFileName); + } + + if (Directory.Exists(destinationTempFolderPath)) + { + Directory.Delete(destinationTempFolderPath); + } + } + } + + private static void BackupFolerToZip(IBackupInfo backupInfo, out IDestinationPathInfo[] destinationPathInfoArray) + { + var innerDestinationPathInfoList = new List(); + + var modelFactory = ObjectContainer.Resolve(); + + Match lastPathSegmentMatch = Constants.EndPathSegmentRegex.Match(backupInfo.SourcePath); + + string destinationFolderPath = backupInfo.DestinationFolderPath.AddTailPathSeparatorIfNotExist(); + var destinationFileName = destinationFolderPath + + lastPathSegmentMatch.Value + " - " + + DateTime.Now.ToString("yyyyMMdd-HHmmss") + + ".zip"; + innerDestinationPathInfoList.Add(modelFactory.CreateDestinationPathInfo(BackupSourceType.File, destinationFileName)); + + try + { + ZipFile.CreateFromDirectory( + backupInfo.SourcePath, + destinationFileName, + CompressionLevel.Optimal, + false, + Encoding.GetEncoding(Properties.Settings.Default.DefaultZipEncodingKeyText)); + } + catch (Exception e) + { + backupInfo.BackupState = BackupState.Failed; + throw new InvalidOperationException( + string.Format( + "Failed to create the zip archive.\r\n\tFrom: {0}\r\n\tTo: {1}\r\n{2}", + backupInfo.SourcePath, + destinationFileName, + e.Message), + e); + } + finally + { + destinationPathInfoArray = innerDestinationPathInfoList.ToArray(); + } + } + + private static void BackupFile(IBackupInfo backupInfo, out IDestinationPathInfo[] destinationPathInfoArray) + { + var innerDestinationPathInfoList = new List(); + + var modelFactory = ObjectContainer.Resolve(); + + Match lastPathSegmentMatch = Constants.EndPathSegmentRegex.Match(backupInfo.SourcePath); + Match fileNameMatch = Constants.FileNameRegex.Match(lastPathSegmentMatch.Value); + Match extensionMatch = Constants.ExtensionRegex.Match(lastPathSegmentMatch.Value); + + string destinationFolderPath = backupInfo.DestinationFolderPath.AddTailPathSeparatorIfNotExist(); + var destinationFileName = destinationFolderPath + fileNameMatch.Value + + " - " + DateTime.Now.ToString("yyyyMMdd-HHmmss") + "." + extensionMatch.Value; + innerDestinationPathInfoList.Add(modelFactory.CreateDestinationPathInfo(BackupSourceType.File, destinationFileName)); + + try + { + File.Copy(backupInfo.SourcePath, destinationFileName); + } + finally + { + destinationPathInfoArray = innerDestinationPathInfoList.ToArray(); + } + } + + private static void BackupFolder(IBackupInfo backupInfo, out IDestinationPathInfo[] destinationPathInfoArray) + { + var innerDestinationPathInfoList = new List(); + + var modelFactory = ObjectContainer.Resolve(); + + Match lastPathSegmentMatch = Constants.EndPathSegmentRegex.Match(backupInfo.SourcePath); + + //// 方法 : ディレクトリをコピーする + //// http://msdn.microsoft.com/ja-jp/library/bb762914(v=vs.110).aspx + string destinationFolderPath = backupInfo.DestinationFolderPath.AddTailPathSeparatorIfNotExist(); + var destinationFolderName = destinationFolderPath + + lastPathSegmentMatch.Value + " - " + DateTime.Now.ToString("yyyyMMdd-HHmmss"); + innerDestinationPathInfoList.Add(modelFactory.CreateDestinationPathInfo(BackupSourceType.Folder, destinationFolderName)); + + try + { + FolderCopy(backupInfo.SourcePath, destinationFolderName, true); + } + finally + { + destinationPathInfoArray = innerDestinationPathInfoList.ToArray(); + } + } + + private static void FolderCopy(string sourceFolderPath, string destinationFolderPath, bool copySubFolders) + { + var sourceDirectoryInfo = new DirectoryInfo(sourceFolderPath); + DirectoryInfo[] subDirectoryInfos = sourceDirectoryInfo.GetDirectories(); + + if (sourceDirectoryInfo.Exists == false) + { + throw new DirectoryNotFoundException( + "Source directory does not exist or could not be found: " + + sourceFolderPath); + } + + // If the destination directory doesn't exist, create it. + if (Directory.Exists(destinationFolderPath) == false) + { + Directory.CreateDirectory(destinationFolderPath); + } + + // Get the files in the directory and copy them to the new location. + FileInfo[] files = sourceDirectoryInfo.GetFiles(); + foreach (FileInfo file in files) + { + string temppath = Path.Combine(destinationFolderPath, file.Name); + file.CopyTo(temppath, false); + } + + // If copying subdirectories, copy them and their contents to new location. + if (copySubFolders) + { + foreach (DirectoryInfo subDirectoryInfo in subDirectoryInfos) + { + string temppath = Path.Combine(destinationFolderPath, subDirectoryInfo.Name); + FolderCopy(subDirectoryInfo.FullName, temppath, copySubFolders); + } + } + } + + private static bool CheckExistence(IDestinationPathInfo[] destinationPathInfoArray) + { + return (destinationPathInfoArray != null) && + (destinationPathInfoArray.Length != 0) && + destinationPathInfoArray.All( + destinationPathInfo => + { + if (destinationPathInfo.BackupSourceType == BackupSourceType.File) + { + return File.Exists(destinationPathInfo.Path); + } + + return Directory.Exists(destinationPathInfo.Path); + }); + } + + private void OnBackupSettingCreated(object sender, SettingFileEventArgs settingFileEventArgs) + { + this.IsReadyForBackup = true; + } + + private void OnBackupSettingOpened(object sender, SettingFileEventArgs settingFileEventArgs) + { + this.IsReadyForBackup = true; + } + + private void OnBackupSettingClosed(object sender, SettingFileEventArgs settingFileEventArgs) + { + this.IsReadyForBackup = false; + } + + private void NotifyBackupProgress(double progressValue, IResultInfo latestResultInfo) + { + if (this.NofityFileBackupProgress != null) + { + this.NofityFileBackupProgress(this, new FileBackupProgressEventArgs(progressValue, latestResultInfo)); + } + } + } +} diff --git a/Main/SimpleBackup.Services/BackupSettingService.cs b/Main/SimpleBackup.Services/BackupSettingService.cs new file mode 100644 index 0000000..2827371 --- /dev/null +++ b/Main/SimpleBackup.Services/BackupSettingService.cs @@ -0,0 +1,591 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Services +{ + using System; + using System.IO; + using System.Linq; + using System.Windows; + using System.Windows.Input; + using System.Xml.Linq; + using SimpleBackup.Core; + using SimpleBackup.Core.Models; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.Utilities; + using SimpleBackup.Resources; + using Application = System.Windows.Application; + using Cursors = System.Windows.Input.Cursors; + using MessageBox = System.Windows.MessageBox; + using OpenFileDialog = Microsoft.Win32.OpenFileDialog; + using SaveFileDialog = Microsoft.Win32.SaveFileDialog; + + /// + /// Backup Setting service. + /// + internal class BackupSettingService : IBackupSettingService + { + /// + /// The supported major version + /// + private const int SupportedMajorVersion = 1; + + /// + /// The supported minor version + /// + private const int SupportedMinorVersion = 0; + + /// + /// The synchronize root + /// + private static readonly object SyncRoot = new object(); + + /// + /// The instance of SettingFileService. + /// + private static volatile BackupSettingService instance; + + /// + /// Prevents a default instance of the class from being created. + /// + private BackupSettingService() + { + } + + /// + /// Occurs when backup setting is created. + /// + public event EventHandler BackupSettingCreated; + + /// + /// Occurs when backup setting is opened. + /// + public event EventHandler BackupSettingOpened; + + /// + /// Occurs when backup setting is modified. + /// + public event EventHandler BackupSettingModified; + + /// + /// Occurs when backup setting is saved. + /// + public event EventHandler BackupSettingSaved; + + /// + /// Occurs when backup setting is closed. + /// + public event EventHandler BackupSettingClosed; + + /// + /// Gets the instance. + /// + public static IBackupSettingService Instance + { + get + { + if (instance == null) + { + lock (SyncRoot) + { + if (instance == null) + { + instance = new BackupSettingService(); + } + } + } + + return instance; + } + } + + /// + /// Gets the current setting. + /// + public IBackupSetting CurrentSetting { get; private set; } + + /// + /// Creates the backup setting. + /// + /// true if the new backup setting is created; otherwise, false. + public bool CreateBackupSetting() + { + if ((this.CurrentSetting != null) && this.CurrentSetting.Modified) + { + MessageBoxResult confirmationResult = MessageBox.Show( + Application.Current.MainWindow, + Resources.Views_SaveConfirmationMessage, + Resources.Views_ConfirmationDialogTitle, + MessageBoxButton.YesNoCancel); + if (confirmationResult == MessageBoxResult.Yes) + { + this.SaveCurrentBackupSetting(); + } + else if (confirmationResult == MessageBoxResult.Cancel) + { + return false; + } + } + + if (this.CurrentSetting != null) + { + this.CloseCurrentBackupSetting(); + } + + var modelFactory = ObjectContainer.Resolve(); + + IBackupSetting backupSetting = modelFactory.CreateBackupSetting(); + this.CurrentSetting = backupSetting; + this.CurrentSetting.SettingModified += this.OnCurrentSettingModified; + + if (this.BackupSettingCreated != null) + { + this.BackupSettingCreated(this, new SettingFileEventArgs(this.CurrentSetting.SettingName)); + } + + return true; + } + + /// + /// Opens the backup setting. + /// + /// The result message. + /// + /// true if backup setting is successfully loaded; otherwise, false. + /// + public bool OpenBackupSetting(out string resultMessage) + { + if ((this.CurrentSetting != null) && this.CurrentSetting.Modified) + { + MessageBoxResult confirmationResult = MessageBox.Show( + Application.Current.MainWindow, + Resources.Views_SaveConfirmationMessage, + Resources.Views_ConfirmationDialogTitle, + MessageBoxButton.YesNoCancel); + if (confirmationResult == MessageBoxResult.Yes) + { + this.SaveCurrentBackupSetting(); + } + else if (confirmationResult == MessageBoxResult.Cancel) + { + resultMessage = string.Empty; + return false; + } + } + + string initialDirectory = AppDomain.CurrentDomain.BaseDirectory; + if ((this.CurrentSetting != null) && + this.CurrentSetting.SettingFileName.IsValidFilePath()) + { + initialDirectory = Path.GetDirectoryName(this.CurrentSetting.SettingFileName); + this.CloseBackupSetting(); + } + + var openFileDialog = new OpenFileDialog + { + Title = Resources.Views_OpenFileDialogTitle, + DefaultExt = ".xml", + Filter = "Backup Setting File|*.xml", + InitialDirectory = initialDirectory, + Multiselect = false + }; + + if (openFileDialog.ShowDialog(Application.Current.MainWindow) != true) + { + resultMessage = string.Empty; + return false; + } + + var fileName = openFileDialog.FileName; + try + { + Mouse.OverrideCursor = Cursors.Wait; + return this.OpenBackupSetting(fileName, out resultMessage); + } + finally + { + Mouse.OverrideCursor = null; + } + } + + /// + /// Closes the backup setting. + /// + public void CloseBackupSetting() + { + if (this.CurrentSetting == null) + { + return; + } + + if (this.CurrentSetting.Modified) + { + MessageBoxResult confirmationResult = MessageBox.Show( + Application.Current.MainWindow, + Resources.Views_SaveConfirmationMessage, + Resources.Views_ConfirmationDialogTitle, + MessageBoxButton.YesNoCancel); + if (confirmationResult == MessageBoxResult.Yes) + { + this.SaveCurrentBackupSetting(); + } + else if (confirmationResult == MessageBoxResult.Cancel) + { + return; + } + } + + this.CloseCurrentBackupSetting(); + } + + /// + /// Overwrites the currnt backup setting. + /// + /// true if the backup setting is saved; otherwise, false. + public bool OverWriteCurrntBackupSetting() + { + if (this.CurrentSetting == null) + { + return false; + } + + if (string.IsNullOrEmpty(this.CurrentSetting.SettingFileName) || + (File.Exists(this.CurrentSetting.SettingFileName) == false)) + { + var saveFileDialog = new SaveFileDialog + { + Title = Resources.Views_SaveFileDialogTitle, + DefaultExt = ".xml", + Filter = "Backup Setting File|*.xml" + }; + + if (saveFileDialog.ShowDialog(Application.Current.MainWindow) != true) + { + return false; + } + + this.CurrentSetting.SettingFileName = saveFileDialog.FileName; + } + + this.SaveCurrentBackupSetting(); + return true; + } + + /// + /// Saves the current backup setting as a new file. + /// + /// true if the backup setting is saved; otherwise, false. + public bool SaveCurrentBackupSettingAsNewFile() + { + if (this.CurrentSetting == null) + { + return false; + } + + var saveFileDialog = new SaveFileDialog + { + Title = Resources.Views_SaveFileDialogTitle, + DefaultExt = ".xml", + Filter = "Backup Setting File|*.xml" + }; + + if (saveFileDialog.ShowDialog(Application.Current.MainWindow) != true) + { + return false; + } + + this.CurrentSetting.SettingFileName = saveFileDialog.FileName; + + this.SaveCurrentBackupSetting(); + return true; + } + + /// + /// Opens the default backup setting. + /// + /// The result message. + /// + /// true if succeeded, otherwise; false. + /// + public bool OpenDefaultBackupSetting(out string resultMessage) + { + return this.OpenBackupSetting( + Properties.Settings.Default.DefaultSettingFileName, + out resultMessage); + } + + /// + /// Creates the backup information. + /// + /// The index. + /// The created backup information. + /// + public IBackupInfo CreateBackupInfo(int index) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException("index"); + } + + var modelFactory = ObjectContainer.Resolve(); + + IBackupInfo backupInfo = modelFactory.CreateBackupInfo(); + this.CurrentSetting.Insert(index, backupInfo); + return backupInfo; + } + + /// + /// Copies the backup information. + /// + /// The source backup information. + /// A copied BackupInfo. + /// + public IBackupInfo CopyBackupInfo(IBackupInfo sourceBackupInfo) + { + sourceBackupInfo.ThrowsArgumentNullException("sourceBackupInfo"); + + var modelFactory = ObjectContainer.Resolve(); + return modelFactory.CreateBackupInfo(sourceBackupInfo); + } + + /// + /// Inserts the backup information. + /// + /// The index. + /// The backup information. + /// + /// + public void InsertBackupInfo(int index, IBackupInfo backupInfo) + { + if (index > this.CurrentSetting.Count) + { + throw new ArgumentOutOfRangeException("index"); + } + + backupInfo.ThrowsArgumentNullException("backupInfo"); + + this.CurrentSetting.Insert(index, backupInfo); + } + + /// + /// Removes the backup information. + /// + /// The backup information identifier. + public void RemoveBackupInfo(Guid backupInfoId) + { + IBackupInfo removingBackupInfo = + this.CurrentSetting.FirstOrDefault(backupInfoId); + if (removingBackupInfo == null) + { + return; + } + + this.CurrentSetting.Remove(removingBackupInfo); + } + + /// + /// Saves the backup setting. + /// + /// The backup setting. + private static void SaveBackupSetting(IBackupSetting backupSetting) + { + var xdoc = new XDocument { Declaration = new XDeclaration("1.0", "utf-8", "yes") }; + xdoc.Add(backupSetting.ToXml()); + + xdoc.Save(backupSetting.SettingFileName, SaveOptions.None); + } + + /// + /// Opens the backup setting. + /// + /// Name of the file. + /// The result message. + /// + /// true if succeeded; otherwise, false. + /// + private bool OpenBackupSetting(string fileName, out string resultMessage) + { + resultMessage = string.Empty; + + if (string.IsNullOrEmpty(fileName)) + { + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_EmptyFileNameFormat, + fileName); + return false; + } + + XDocument xml = XDocument.Load(fileName, LoadOptions.None); + XElement backupSettingElement = xml.Elements("BackupSetting").FirstOrDefault(); + if (backupSettingElement == null) + { + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_NoBackupSettingElementFormat, + fileName); + return false; + } + + XAttribute versionAttribute = backupSettingElement.Attributes().FirstOrDefault(p => p.Name == "Version"); + if (versionAttribute == null) + { + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_NoVersionElementFormat, + fileName); + return false; + } + + string[] versionTextFlagments = versionAttribute.Value.Split('.'); + if (versionTextFlagments.Length != 2) + { + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_InvalidVersionFormat, + fileName); + return false; + } + + int majorVersion; + if (int.TryParse(versionTextFlagments[0], out majorVersion) == false) + { + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_InvalidMajorVersionFormat, + fileName); + return false; + } + + int minorVersion; + if (int.TryParse(versionTextFlagments[1], out minorVersion) == false) + { + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_InvalidMinorVersionFormat, + fileName); + return false; + } + + XAttribute requiredToolVersionAttribute = backupSettingElement.Attributes().FirstOrDefault(p => p.Name == "RequiredToolVersion"); + if (requiredToolVersionAttribute == null) + { + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_InvalidRequiredToolVersionFormat, + fileName); + return false; + } + + if (majorVersion > SupportedMajorVersion) + { + string message = string.Format( + Resources.BackupSetting_IncompatibleMajorVersionFormat, + requiredToolVersionAttribute.Value); + MessageBox.Show( + Application.Current.MainWindow, + message, + Resources.Views_DefaultWindowTitle, + MessageBoxButton.OK, + MessageBoxImage.Error); + resultMessage = message; + return false; + } + + if (minorVersion > SupportedMinorVersion) + { + string message = string.Format( + Resources.BackupSetting_IncompatibleMinorVersionFormat, + requiredToolVersionAttribute.Value); + MessageBox.Show( + Application.Current.MainWindow, + message, + Resources.Views_DefaultWindowTitle, + MessageBoxButton.OK, + MessageBoxImage.Warning); + resultMessage = message + "\r\n"; + } + + var modelFactory = ObjectContainer.Resolve(); + if (modelFactory != null) + { + IBackupSetting backupSetting = modelFactory.RestoreBackupSettingFromXml(backupSettingElement, fileName); + this.CurrentSetting = backupSetting; + this.CurrentSetting.SettingModified += this.OnCurrentSettingModified; + if (this.BackupSettingOpened != null) + { + this.BackupSettingOpened(this, new SettingFileEventArgs(backupSetting.SettingFileName)); + } + + resultMessage += string.Format(Resources.BackupSetting_SettingOpenedFormat, fileName); + return true; + } + + resultMessage = string.Format( + Resources.BackupSetting_FailedToOpenSetting_EmptyFileNameFormat, + fileName); + return false; + } + + /// + /// Saves the current backup setting. + /// + private void SaveCurrentBackupSetting() + { + try + { + Mouse.OverrideCursor = Cursors.Wait; + + SaveBackupSetting(this.CurrentSetting); + + this.CurrentSetting.Modified = false; + } + finally + { + Mouse.OverrideCursor = null; + } + + if (this.BackupSettingSaved != null) + { + this.BackupSettingSaved(this, new SettingFileEventArgs(this.CurrentSetting.SettingFileName)); + } + } + + private void CloseCurrentBackupSetting() + { + UndoRedoService.Instance.ClearUndoRedoBuffer(); + string settingName = this.CurrentSetting.SettingFileName; + this.CurrentSetting.SettingModified -= this.OnCurrentSettingModified; + this.CurrentSetting = null; + + if (this.BackupSettingClosed != null) + { + this.BackupSettingClosed(this, new SettingFileEventArgs(settingName)); + } + } + + /// + /// Called when current setting is modified. + /// + /// The sender. + /// The instance containing the event data. + private void OnCurrentSettingModified(object sender, EventArgs eventArgs) + { + if (this.BackupSettingModified != null) + { + this.BackupSettingModified(this, new SettingFileEventArgs(this.CurrentSetting.SettingName)); + } + } + } +} diff --git a/Main/SimpleBackup.Services/ClipboardService.cs b/Main/SimpleBackup.Services/ClipboardService.cs new file mode 100644 index 0000000..2efd783 --- /dev/null +++ b/Main/SimpleBackup.Services/ClipboardService.cs @@ -0,0 +1,139 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Services +{ + using System; + using System.Linq; + using System.Windows; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.Utilities; + + /// + /// Provides clip board access. + /// + internal class ClipboardService : IClipboardService + { + private static readonly object SyncRoot = new object(); + private static volatile ClipboardService instance; + + /// + /// Prevents a default instance of the class from being created. + /// + private ClipboardService() + { + } + + /// + /// Gets the instance. + /// + public static IClipboardService Instance + { + get + { + if (instance == null) + { + lock (SyncRoot) + { + if (instance == null) + { + instance = new ClipboardService(); + } + } + } + + return instance; + } + } + + /// + /// Sets the data object. + /// + /// The data object. + /// The data object is null. + public void SetDataObject(IDataObject dataObject) + { + dataObject.ThrowsArgumentNullException("dataObject"); + + Clipboard.SetDataObject(dataObject); + } + + /// + /// Gets the data. + /// + /// The type. + /// The format. + /// + /// The data. + /// + /// The format string is null or empty. + public T GetData(string format) + { + format.ThrowsArgumentExceptionIfNullOrEmpty("format"); + + IDataObject dataObject = Clipboard.GetDataObject(); + if (dataObject != null) + { + if (dataObject.GetDataPresent(format)) + { + try + { + return (T)dataObject.GetData(format); + } + catch + { + return default(T); + } + } + } + + return default(T); + } + + /// + /// Gets a boolean value indicating whether the clipboard data contains data in specified format. + /// + /// The format. + /// The format string is null or empty. + /// True if the specified format is contained in the Clipboard. + public bool DoesClipboardDataContain(string format) + { + format.ThrowsArgumentExceptionIfNullOrEmpty("format"); + + IDataObject dataObject = Clipboard.GetDataObject(); + if (dataObject != null) + { + string[] formats = dataObject.GetFormats(); + return formats.Contains(format); + } + + return false; + } + + /// + /// Clears the clipbord. + /// + public void ClearClipbord() + { + Clipboard.Clear(); + } + } +} diff --git a/Main/SimpleBackup.Services/Properties/Settings.Designer.cs b/Main/SimpleBackup.Services/Properties/Settings.Designer.cs new file mode 100644 index 0000000..fdf4566 --- /dev/null +++ b/Main/SimpleBackup.Services/Properties/Settings.Designer.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// このコードはツールによって生成されました。 +// ランタイム バージョン:4.0.30319.34014 +// +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 +// コードが再生成されるときに損失したりします。 +// +//------------------------------------------------------------------------------ + +namespace SimpleBackup.Services.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string DefaultSettingFileName { + get { + return ((string)(this["DefaultSettingFileName"])); + } + set { + this["DefaultSettingFileName"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string DefaultZipEncodingKeyText { + get { + return ((string)(this["DefaultZipEncodingKeyText"])); + } + set { + this["DefaultZipEncodingKeyText"] = value; + } + } + } +} diff --git a/Main/SimpleBackup.Services/Properties/Settings.settings b/Main/SimpleBackup.Services/Properties/Settings.settings new file mode 100644 index 0000000..4973a97 --- /dev/null +++ b/Main/SimpleBackup.Services/Properties/Settings.settings @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Main/SimpleBackup.Services/ServiceComponent.cs b/Main/SimpleBackup.Services/ServiceComponent.cs new file mode 100644 index 0000000..46a15e4 --- /dev/null +++ b/Main/SimpleBackup.Services/ServiceComponent.cs @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Services +{ + using SimpleBackup.Core; + using SimpleBackup.Core.AppInfrastructure; + using SimpleBackup.Core.Services; + + /// + /// The service component. + /// + internal class ServiceComponent : IAppComponent + { + /// + /// Initializes this application component. + /// + public void Initialize() + { + ObjectContainer.Register(BackupService.Instance); + ObjectContainer.Register(BackupSettingService.Instance); + ObjectContainer.Register(ClipboardService.Instance); + ObjectContainer.Register(SettingsService.Instance); + ObjectContainer.Register(UndoRedoService.Instance); + } + } +} diff --git a/Main/SimpleBackup.Services/SettingsService.cs b/Main/SimpleBackup.Services/SettingsService.cs new file mode 100644 index 0000000..98aa9b0 --- /dev/null +++ b/Main/SimpleBackup.Services/SettingsService.cs @@ -0,0 +1,110 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Services +{ + using SimpleBackup.Core.Services; + + /// + /// Provides application setting. + /// + internal class SettingsService : ISettingsService + { + /// + /// The synchronize root. + /// + private static readonly object SyncRoot = new object(); + + /// + /// The instance of SettingsService. + /// + private static volatile SettingsService instance; + + /// + /// Prevents a default instance of the class from being created. + /// + private SettingsService() + { + } + + /// + /// Gets the instance. + /// + public static ISettingsService Instance + { + get + { + if (instance == null) + { + lock (SyncRoot) + { + if (instance == null) + { + instance = new SettingsService(); + } + } + } + + return instance; + } + } + + /// + /// Gets or sets the default name of the setting file. + /// + public string DefaultSettingFileName + { + get + { + return Properties.Settings.Default.DefaultSettingFileName; + } + + set + { + if (Properties.Settings.Default.DefaultSettingFileName != value) + { + Properties.Settings.Default.DefaultSettingFileName = value; + Properties.Settings.Default.Save(); + } + } + } + + /// + /// Gets or sets the default zip encoding key text. + /// + public string DefaultZipEncodingKeyText + { + get + { + return Properties.Settings.Default.DefaultZipEncodingKeyText; + } + + set + { + if (Properties.Settings.Default.DefaultZipEncodingKeyText != value) + { + Properties.Settings.Default.DefaultZipEncodingKeyText = value; + Properties.Settings.Default.Save(); + } + } + } + } +} diff --git a/Main/SimpleBackup.Services/SimpleBackup.Services.csproj b/Main/SimpleBackup.Services/SimpleBackup.Services.csproj new file mode 100644 index 0000000..c36f0ae --- /dev/null +++ b/Main/SimpleBackup.Services/SimpleBackup.Services.csproj @@ -0,0 +1,108 @@ + + + + + Debug + AnyCPU + {950EE3DF-1731-49B7-94C2-F33154855782} + Library + Properties + SimpleBackup.Services + SimpleBackup.Services + v4.5 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + SimpleBackupKey.snk + + + + + + + + + False + ..\Lib\Expression\Blend\.NETFramework\v4.5\Libraries\System.Windows.Interactivity.dll + + + + + + + + + + + + Properties\AssemblyInfo.cs + + + + + + True + True + Settings.settings + + + + + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + {33f1d454-9962-4eb6-aad3-8d11d9a78d1f} + SimpleBackup.Core + + + {a655131e-d439-4de1-bc39-5c955306183f} + SimpleBackup.Resources + + + + + set EXE_BIN_DIR=$(ProjectDir)..\bin\$(ConfigurationName)\ +xcopy "$(TargetDir)$(TargetName).dll" "%25EXE_BIN_DIR%25" /Y +if exist "$(TargetDir)$(TargetName).pdb" xcopy "$(TargetDir)$(TargetName).pdb" "%25EXE_BIN_DIR%25" /Y + + + \ No newline at end of file diff --git a/Main/SimpleBackup.Services/SimpleBackupKey.snk b/Main/SimpleBackup.Services/SimpleBackupKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..def2e6df6a67d7e5802b3319c2b385c61304db29 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=*mMuj7Bow@Ep}p%TfOae=&U%vR9qh+ z@B2Y7h5t%KB~GowmVCnTwn!=ol7j~SRw};|aqMe69$!Xr!@Kl)p?8Xg2;G;~Cd60S zyuxBRv<}vHJsUi)3u6Y?7~u<-nIO&1Fj-O8+VD)*I{}r1s+^@Kmf2Y}gp`|NRs+em z$u>8Tw)yg`4_#X9od;DS_`m7gjCw7)_oIM$fq-7kckw~B<7M;zI>N{SPq*6$huq7Z zgYNgU;sUWRbAi&O+L_hd!U0Li?IE-i`qYl6ItfNG&LGLWV{U{YZh>Ax4*J$khFNYOR0lC!sQ=xnj0#!GfwNKNLWeC6+{0F(k120wr_Sb zIyF(GL;3}qT}4Ed2plZ&Isj`rlkfJc)Ea1aKb3p_jTAd0vy@;AzzF|BpZp|m^l#y& zbx94OX%V&s<FnfGWY1Nh zxKnroP3(eKfbr85Y^JZ_CW>v48ZxICTuX?#TOI&z>)DFD-NiB2i|wPJnn~;|{CGZv i!2z3|Al4b1%II9A@B0rIjj|^@+oAX!*AylRLZAX-U?o=o literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Services/UndoRedoActionSet.cs b/Main/SimpleBackup.Services/UndoRedoActionSet.cs new file mode 100644 index 0000000..db4bb14 --- /dev/null +++ b/Main/SimpleBackup.Services/UndoRedoActionSet.cs @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Services +{ + using System; + using SimpleBackup.Core.Utilities; + + /// + /// Provides undo/redo function. + /// + internal partial class UndoRedoService + { + /// + /// Represents a pair of undo/redo actions and its context information. + /// + private class UndoRedoActionSet + { + /// + /// Initializes a new instance of the class. + /// + /// The redo action. + /// The undo action. + /// The context. + /// The redoAction is null. + /// The undoAction is null. + public UndoRedoActionSet(Action redoAction, Action undoAction, object context) + { + redoAction.ThrowsArgumentNullException("redoAction"); + undoAction.ThrowsArgumentNullException("undoAction"); + + this.RedoAction = redoAction; + this.UndoAction = undoAction; + this.Context = context; + } + + /// + /// Gets the redo action. + /// + public Action RedoAction { get; private set; } + + /// + /// Gets the undo action. + /// + public Action UndoAction { get; private set; } + + /// + /// Gets the context. + /// + public object Context { get; private set; } + } + } +} diff --git a/Main/SimpleBackup.Services/UndoRedoService.cs b/Main/SimpleBackup.Services/UndoRedoService.cs new file mode 100644 index 0000000..5e221b3 --- /dev/null +++ b/Main/SimpleBackup.Services/UndoRedoService.cs @@ -0,0 +1,144 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Services +{ + using System; + using System.Collections.Generic; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.Utilities; + + /// + /// Provides undo/redo function. + /// + internal partial class UndoRedoService : IUndoRedoService + { + private static readonly object SyncRoot = new object(); + private static volatile UndoRedoService instance; + + private readonly Stack actionSetsForUndo = new Stack(); + private readonly Stack actionSetsForRedo = new Stack(); + + /// + /// Prevents a default instance of the class from being created. + /// + private UndoRedoService() + { + } + + /// + /// Gets the instance. + /// + public static IUndoRedoService Instance + { + get + { + if (instance == null) + { + lock (SyncRoot) + { + if (instance == null) + { + instance = new UndoRedoService(); + } + } + } + + return instance; + } + } + + /// + /// Commits the specified redo action with related undo action and the context information. + /// + /// The redo action. + /// The undo action. + /// The context. + /// The redoAction is null. + /// The undoAction is null. + public void Commit(Action redoAction, Action undoAction, object context) + { + redoAction.ThrowsArgumentNullException("redoAction"); + undoAction.ThrowsArgumentNullException("undoAction"); + + var undoRedoActionSet = new UndoRedoActionSet(redoAction, undoAction, context); + this.actionSetsForUndo.Push(undoRedoActionSet); + redoAction.Invoke(undoRedoActionSet.Context); + } + + /// + /// Executes undo action. + /// + public void Undo() + { + if (this.CanExecuteUndo() == false) + { + return; + } + + UndoRedoActionSet undoRedoActionSet = this.actionSetsForUndo.Pop(); + undoRedoActionSet.UndoAction.Invoke(undoRedoActionSet.Context); + this.actionSetsForRedo.Push(undoRedoActionSet); + } + + /// + /// Determines whether the undo action is executable. + /// + /// true if the undo action can be executable; otherwise, false. + public bool CanExecuteUndo() + { + return this.actionSetsForUndo.Count != 0; + } + + /// + /// Executes redo action. + /// + public void Redo() + { + if (this.CanExecuteRedo() == false) + { + return; + } + + UndoRedoActionSet undoRedoActionSet = this.actionSetsForRedo.Pop(); + undoRedoActionSet.RedoAction.Invoke(undoRedoActionSet.Context); + this.actionSetsForUndo.Push(undoRedoActionSet); + } + + /// + /// Determines whether the redo action is executable. + /// + /// true if the redo action can be executable; otherwise, false. + public bool CanExecuteRedo() + { + return this.actionSetsForRedo.Count != 0; + } + + /// + /// Clears the undo redo buffer. + /// + public void ClearUndoRedoBuffer() + { + this.actionSetsForUndo.Clear(); + this.actionSetsForRedo.Clear(); + } + } +} diff --git a/Main/SimpleBackup.Services/app.config b/Main/SimpleBackup.Services/app.config new file mode 100644 index 0000000..632bc35 --- /dev/null +++ b/Main/SimpleBackup.Services/app.config @@ -0,0 +1,18 @@ + + + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/Main/SimpleBackup.ViewModels/BackupInfoPasteInfo.cs b/Main/SimpleBackup.ViewModels/BackupInfoPasteInfo.cs new file mode 100644 index 0000000..d169528 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/BackupInfoPasteInfo.cs @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using System; + using SimpleBackup.Core.Utilities; + using SimpleBackup.Core.ViewModels; + + /// + /// Paste information of BackupInfo. + /// + [Serializable] + internal class BackupInfoPasteInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The backup information bytes. + /// Type of the paste. + /// Index of the source backup information view model. + public BackupInfoPasteInfo( + byte[] backupInfoBytes, + PasteType pasteType, + int sourceIndex) + { + backupInfoBytes.ThrowsArgumentNullException("backupInfoBytes"); + + this.BackupInfoBytes = backupInfoBytes; + this.PasteType = pasteType; + this.SourceIndex = sourceIndex; + } + + /// + /// Gets the backup information bytes. + /// + public byte[] BackupInfoBytes { get; private set; } + + /// + /// Gets the type of the paste. + /// + public PasteType PasteType { get; private set; } + + /// + /// Gets the index of the source backup information view model. + /// + public int SourceIndex { get; private set; } + } +} diff --git a/Main/SimpleBackup.ViewModels/BackupInfoViewModel.cs b/Main/SimpleBackup.ViewModels/BackupInfoViewModel.cs new file mode 100644 index 0000000..c4ac97f --- /dev/null +++ b/Main/SimpleBackup.ViewModels/BackupInfoViewModel.cs @@ -0,0 +1,794 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using System; + using System.ComponentModel; + using System.IO; + using System.Text.RegularExpressions; + using System.Windows.Forms; + using System.Windows.Input; + using SimpleBackup.Core; + using SimpleBackup.Core.Models; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.Utilities; + using SimpleBackup.Core.ViewModels; + using SimpleBackup.Core.Views; + using SimpleBackup.Resources; + + /// + /// Backup information view model. + /// + internal class BackupInfoViewModel : PropertyChangeNotificationBase, IBackupInfoViewModel + { + private readonly IBackupService backupService; + private readonly IBackupSettingService backupSettingService; + private readonly IViewFactory viewFactory; + + private readonly IBackupInfo backupInfoModel; + + private readonly Action clearOutputMessageAction; + + private readonly Action addOutputMessageAction; + + private bool innerHasSourcePathError; + + private bool innerHasDestinationFolderPathError; + + private bool innerIsSourceEditing; + + private string innerEditingSourcePath = string.Empty; + + private bool innerIsDestinationEditing; + + private string innerEditingDestinationPath = string.Empty; + + private bool innerIsCutReserved; + + /// + /// Initializes a new instance of the class. + /// + /// The backup information model. + /// The clear output message action. + /// The add output message action. + private BackupInfoViewModel( + IBackupInfo backupInfoModel, + Action clearOutputMessageAction, + Action addOutputMessageAction) + { + backupInfoModel.ThrowsArgumentNullException("backupInfoModel"); + clearOutputMessageAction.ThrowsArgumentNullException("clearOutputMessageAction"); + addOutputMessageAction.ThrowsArgumentNullException("addOutputMessageAction"); + + this.backupInfoModel = backupInfoModel; + this.backupInfoModel.PropertyChanged += this.OnBackupInfoModelPropertyChanged; + this.clearOutputMessageAction = clearOutputMessageAction; + this.addOutputMessageAction = addOutputMessageAction; + + this.backupService = ObjectContainer.Resolve(); + this.backupSettingService = ObjectContainer.Resolve(); + this.viewFactory = ObjectContainer.Resolve(); + + this.OpenSourceFileRelayCommand = new RelayCommand(this.ExecuteOpenSourceFile, this.CanExecuteOpenSourceFile); + this.OpenSourceFolderRelayCommand = new RelayCommand(this.ExecuteOpenSourceFolder, this.CanExecuteOpenSourceFolder); + this.SelectSourceRelayCommand = new RelayCommand(this.ExecuteSelectSource, this.CanExecuteSelectSource); + this.OpenDestinationFolderRelayCommand = new RelayCommand(this.ExecuteOpenDestinationFolder, this.CanExecuteOpenDestinationFolder); + this.SelectDestinationRelayCommand = new RelayCommand(this.ExecuteSelectDestination, this.CanExecuteSelectDestination); + this.EditSourceRelayCommand = new RelayCommand(this.ExecuteEditSource, this.CanExecuteEditSource); + this.EditDestinationRelayCommand = new RelayCommand(this.ExecuteEditDestination, this.CanExecuteEditDestination); + this.SingleBackupRelayCommand = new RelayCommand(this.ExecuteSingleBackup, this.CanExecuteSingleBackup); + + this.UpdateErrorStatus(); + } + + /// + /// Gets the open source file relay command. + /// + public RelayCommand OpenSourceFileRelayCommand { get; private set; } + + /// + /// Gets the open source folder relay command. + /// + public RelayCommand OpenSourceFolderRelayCommand { get; private set; } + + /// + /// Gets the select source relay command. + /// + public RelayCommand SelectSourceRelayCommand { get; private set; } + + /// + /// Gets the open destination folder relay command. + /// + public RelayCommand OpenDestinationFolderRelayCommand { get; private set; } + + /// + /// Gets the select destination relay command. + /// + public RelayCommand SelectDestinationRelayCommand { get; private set; } + + /// + /// Gets the edit source relay command. + /// + public RelayCommand EditSourceRelayCommand { get; private set; } + + /// + /// Gets the edit destination relay command. + /// + public RelayCommand EditDestinationRelayCommand { get; private set; } + + /// + /// Gets the single backup with context menu relay command. + /// + public RelayCommand SingleBackupRelayCommand { get; private set; } + + /// + /// Gets the backup information identifier. + /// + public Guid BackupInfoId + { + get + { + return this.backupInfoModel.Id; + } + } + + /// + /// Gets the type of the source. + /// + public BackupSourceType SourceType + { + get + { + return this.backupInfoModel.BackupSourceType; + } + } + + /// + /// Gets the state of the backup. + /// + public BackupState BackupState + { + get + { + return this.backupInfoModel.BackupState; + } + } + + /// + /// Gets or sets a value indicating whether the backup is enabled. + /// + public bool IsEnabled + { + get + { + return this.backupInfoModel.IsEnabled; + } + + set + { + if (this.backupInfoModel.IsEnabled != value) + { + this.backupInfoModel.IsEnabled = value; + this.NotifyPropertyChanged("IsEnabled"); + } + } + } + + /// + /// Gets or sets a value indicating whether the backup is zip archive. + /// + public bool IsZipArchive + { + get + { + return this.backupInfoModel.IsZipArchive; + } + + set + { + if (this.backupInfoModel.IsZipArchive != value) + { + this.backupInfoModel.IsZipArchive = value; + this.NotifyPropertyChanged("IsZipArchive"); + } + } + } + + /// + /// Gets or sets the label. + /// + public string Label + { + get + { + return this.backupInfoModel.Label; + } + + set + { + if (this.backupInfoModel.Label != value) + { + this.backupInfoModel.Label = value; + this.NotifyPropertyChanged("Label"); + } + } + } + + /// + /// Gets or sets the source path. + /// + public string SourcePath + { + get + { + return this.backupInfoModel.SourcePath; + } + + set + { + if ((this.backupInfoModel.SourcePath != value) && + value.IsValidFileOrDirectoryPath()) + { + this.backupInfoModel.SourcePath = value; + this.UpdateErrorStatus(); + this.NotifyPropertyChanged("SourcePath"); + this.NotifyPropertyChanged("DisplaySourcePath"); + } + } + } + + /// + /// Gets the display source path. + /// + public string DisplaySourcePath + { + get + { + return Helpers.CreateDisplayPathText(this.backupInfoModel.SourcePath); + } + } + + /// + /// Gets or sets the editing source path. + /// + public string EditingSourcePath + { + get + { + return this.innerEditingSourcePath; + } + + set + { + if (this.innerEditingSourcePath != value) + { + this.innerEditingSourcePath = value; + this.NotifyPropertyChanged("EditingSourcePath"); + } + } + } + + /// + /// Gets the source tool tip text. + /// + public string SourceToolTipText + { + get + { + Match match = Constants.EndPathSegmentRegex.Match(this.backupInfoModel.SourcePath); + return match.Success ? match.Value : string.Empty; + } + } + + /// + /// Gets or sets a value indicating whether this instance is source editing. + /// + public bool IsSourceEditing + { + get + { + return this.innerIsSourceEditing; + } + + set + { + if (this.innerIsSourceEditing != value) + { + this.innerIsSourceEditing = value; + this.NotifyPropertyChanged("IsSourceEditing"); + } + } + } + + /// + /// Gets a value indicating whether this instance has source path error. + /// + public bool HasSourcePathError + { + get + { + return this.innerHasSourcePathError; + } + + private set + { + if (this.innerHasSourcePathError != value) + { + this.innerHasSourcePathError = value; + this.NotifyPropertyChanged("HasSourcePathError"); + } + } + } + + /// + /// Gets or sets the destination folder path. + /// + public string DestinationFolderPath + { + get + { + return this.backupInfoModel.DestinationFolderPath; + } + + set + { + if ((this.backupInfoModel.DestinationFolderPath != value) && + value.IsValidFileOrDirectoryPath()) + { + this.backupInfoModel.DestinationFolderPath = value; + this.UpdateErrorStatus(); + this.NotifyPropertyChanged("DestinationFolderPath"); + this.NotifyPropertyChanged("DisplayDestinationFolderPath"); + } + } + } + + /// + /// Gets the display destination folder path. + /// + public string DisplayDestinationFolderPath + { + get + { + return Helpers.CreateDisplayPathText( + Regex.Replace(this.backupInfoModel.DestinationFolderPath, @"\\$", string.Empty)); + } + } + + /// + /// Gets or sets the editing destination path. + /// + public string EditingDestinationPath + { + get + { + return this.innerEditingDestinationPath; + } + + set + { + if (this.innerEditingDestinationPath != value) + { + this.innerEditingDestinationPath = value; + this.NotifyPropertyChanged("EditingDestinationPath"); + } + } + } + + /// + /// Gets the destination tool tip text. + /// + public string DestinationToolTipText + { + get + { + string endSeparatorRemovedPath = Constants.EndPathSeparatorRegex.Replace(this.backupInfoModel.DestinationFolderPath, string.Empty); + Match match = Constants.EndPathSegmentRegex.Match(endSeparatorRemovedPath); + return match.Success ? match.Value : string.Empty; + } + } + + /// + /// Gets or sets a value indicating whether this instance is destination editing. + /// + public bool IsDestinationEditing + { + get + { + return this.innerIsDestinationEditing; + } + + set + { + if (this.innerIsDestinationEditing != value) + { + this.innerIsDestinationEditing = value; + this.NotifyPropertyChanged("IsDestinationEditing"); + } + } + } + + /// + /// Gets a value indicating whether this instance has destination folder path error. + /// + public bool HasDestinationFolderPathError + { + get + { + return this.innerHasDestinationFolderPathError; + } + + private set + { + if (this.innerHasDestinationFolderPathError != value) + { + this.innerHasDestinationFolderPathError = value; + this.NotifyPropertyChanged("HasDestinationFolderPathError"); + } + } + } + + /// + /// Gets a value indicating whether this instance is editing. + /// + public bool IsEditing + { + get + { + return this.IsSourceEditing || this.IsDestinationEditing; + } + } + + /// + /// Gets or sets a value indicating whether this instance is cut reserved. + /// + public bool IsCutReserved + { + get + { + return this.innerIsCutReserved; + } + + set + { + if (this.innerIsCutReserved != value) + { + this.innerIsCutReserved = value; + this.NotifyPropertyChanged("IsCutReserved"); + } + } + } + + /// + /// Creates the backup information view mode. + /// + /// The backup information model. + /// The clear output message action. + /// The add output message action. + /// The backup information view model. + public static IBackupInfoViewModel CreateBackupInfoViewMode( + IBackupInfo backupInfoModel, + Action clearOutputMessageAction, + Action addOutputMessageAction) + { + return new BackupInfoViewModel( + backupInfoModel, + clearOutputMessageAction, + addOutputMessageAction); + } + + /// + /// Gets the backup information. + /// + /// The backup information. + public IBackupInfo GetBackupInfo() + { + return this.backupInfoModel; + } + + /// + /// Executes the double click action. + /// + /// Type of the path. + public void ExecuteDoubleClickAction(BackupInfoPathType pathType) + { + switch (pathType) + { + case BackupInfoPathType.Source: + if (this.SourcePath.IsValidFileOrDirectoryPath()) + { + this.SingleBackup(); + } + else + { + string extractedPath; + this.SelectSource( + Helpers.TryExtractValidFolderPath(this.SourcePath, out extractedPath) + ? extractedPath + : string.Empty); + } + + break; + case BackupInfoPathType.Destination: + if (this.DestinationFolderPath.IsValidFileOrDirectoryPath()) + { + this.ExecuteOpenDestinationFolder(null); + } + else + { + string extractedPath; + this.SelectDestination( + Helpers.TryExtractValidFolderPath(this.DestinationFolderPath, out extractedPath) + ? extractedPath + : string.Empty); + } + + break; + } + } + + /// + /// Executes single backup. + /// + public void SingleBackup() + { + try + { + Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait; + + this.clearOutputMessageAction(); + Helpers.UpdateWpfGui(); + this.addOutputMessageAction(Resources.Backup_ExecutingBackup); + Helpers.UpdateWpfGui(); + + IResultInfo resultInfo = this.backupService.BackupSingleFile(this.BackupInfoId); + this.addOutputMessageAction(string.Format("{0}: {1}", resultInfo.BackupState.Translate(), resultInfo.Description)); + } + finally + { + Mouse.OverrideCursor = null; + } + } + + /// + /// Commits the editing contents. + /// + public void CommitEditingContents() + { + if (this.IsSourceEditing) + { + // Path validation is executed in SourcePath setter. + this.SourcePath = this.EditingSourcePath; + this.EditingSourcePath = string.Empty; + this.IsSourceEditing = false; + } + + if (this.IsDestinationEditing) + { + // Path validation is executed in DestinationFolderPath setter. + this.DestinationFolderPath = this.EditingDestinationPath; + this.EditingDestinationPath = string.Empty; + this.IsDestinationEditing = false; + } + } + + /// + /// Resets the state of the backup. + /// + public void ResetBackupState() + { + this.backupInfoModel.BackupState = BackupState.Todo; + this.UpdateErrorStatus(); + } + + private void OnBackupInfoModelPropertyChanged( + object sender, + PropertyChangedEventArgs propertyChangedEventArgs) + { + if (propertyChangedEventArgs.PropertyName == "BackupState") + { + this.NotifyPropertyChanged("BackupState"); + } + } + + private void ExecuteOpenSourceFile(object obj) + { + if (this.CanExecuteOpenSourceFile(obj) == false) + { + return; + } + + Helpers.OpenFile(this.SourcePath); + } + + private bool CanExecuteOpenSourceFile(object obj) + { + return (this.backupService.IsExecutingBackup == false) && + (this.backupInfoModel.BackupSourceType == BackupSourceType.File); + } + + private void ExecuteOpenSourceFolder(object obj) + { + Helpers.OpenParentFolderAndSelect(this.SourcePath); + } + + private bool CanExecuteOpenSourceFolder(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteSelectSource(object obj) + { + this.SelectSource(string.Empty); + } + + private void SelectSource(string initialDirectoryPath) + { + string newSourcePath = string.Empty; + + IFileFolderDialog fileFolderDialog = this.viewFactory.CreateFileFolderDialog(); + if ((string.IsNullOrEmpty(initialDirectoryPath) == false) && Directory.Exists(initialDirectoryPath)) + { + fileFolderDialog.SelectedPath = initialDirectoryPath; + } + else + { + fileFolderDialog.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + } + + if (fileFolderDialog.ShowDialog() == DialogResult.OK) + { + if (File.Exists(fileFolderDialog.SelectedPath)) + { + this.backupInfoModel.BackupSourceType = BackupSourceType.File; + newSourcePath = fileFolderDialog.SelectedPath; + } + else if (Directory.Exists(fileFolderDialog.SelectedPath)) + { + this.backupInfoModel.BackupSourceType = BackupSourceType.Folder; + newSourcePath = fileFolderDialog.SelectedPath; + } + } + + if (string.IsNullOrEmpty(newSourcePath) == false) + { + this.backupInfoModel.SourcePath = newSourcePath; + this.NotifyPropertyChanged("SourceType"); + this.NotifyPropertyChanged("SourcePath"); + this.NotifyPropertyChanged("DisplaySourcePath"); + } + + this.UpdateErrorStatus(); + } + + private bool CanExecuteSelectSource(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteOpenDestinationFolder(object obj) + { + IBackupInfo backupInfo = this.GetBackupInfo(); + if (((backupInfo.BackupSourceType == BackupSourceType.File) && + File.Exists(backupInfo.LatestSuccessfulBackupTargetName)) || + ((backupInfo.BackupSourceType == BackupSourceType.Folder) && + Directory.Exists(backupInfo.LatestSuccessfulBackupTargetName))) + { + Helpers.OpenParentFolderAndSelect(backupInfo.LatestSuccessfulBackupTargetName); + } + else + { + Helpers.OpenFolder(this.DestinationFolderPath); + } + } + + private bool CanExecuteOpenDestinationFolder(object obj) + { + return this.backupSettingService.CurrentSetting != null; + } + + private void ExecuteSelectDestination(object obj) + { + this.SelectDestination(string.Empty); + } + + private void SelectDestination(string initialDirectoryPath) + { + IFileFolderDialog fileFolderDialog = this.viewFactory.CreateFileFolderDialog(); + if ((string.IsNullOrEmpty(initialDirectoryPath) == false) && Directory.Exists(initialDirectoryPath)) + { + fileFolderDialog.SelectedPath = initialDirectoryPath; + } + else + { + fileFolderDialog.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + } + + if (fileFolderDialog.ShowDialog() == DialogResult.OK) + { + string destinationPath = + Directory.Exists(fileFolderDialog.SelectedPath) + ? fileFolderDialog.SelectedPath + : Path.GetDirectoryName(fileFolderDialog.SelectedPath); + this.backupInfoModel.DestinationFolderPath = destinationPath; + this.NotifyPropertyChanged("DestinationFolderPath"); + this.NotifyPropertyChanged("DisplayDestinationFolderPath"); + } + + this.UpdateErrorStatus(); + } + + private bool CanExecuteSelectDestination(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteEditSource(object obj) + { + this.EditingSourcePath = this.SourcePath; + this.IsSourceEditing = true; + } + + private bool CanExecuteEditSource(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteEditDestination(object obj) + { + this.EditingDestinationPath = this.DestinationFolderPath; + this.IsDestinationEditing = true; + } + + private bool CanExecuteEditDestination(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteSingleBackup(object obj) + { + this.SingleBackup(); + } + + private bool CanExecuteSingleBackup(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void UpdateErrorStatus() + { + switch (this.backupInfoModel.BackupSourceType) + { + case BackupSourceType.File: + this.HasSourcePathError = File.Exists(this.backupInfoModel.SourcePath) == false; + break; + case BackupSourceType.Folder: + this.HasSourcePathError = Directory.Exists(this.backupInfoModel.SourcePath) == false; + break; + default: + throw new InvalidOperationException("Unexpected backup source type."); + } + + this.HasDestinationFolderPathError = Directory.Exists(this.backupInfoModel.DestinationFolderPath) == false; + } + } +} diff --git a/Main/SimpleBackup.ViewModels/DataGridColumnHeaderBaseViewModel.cs b/Main/SimpleBackup.ViewModels/DataGridColumnHeaderBaseViewModel.cs new file mode 100644 index 0000000..8fd7cee --- /dev/null +++ b/Main/SimpleBackup.ViewModels/DataGridColumnHeaderBaseViewModel.cs @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core.Utilities; + + /// + /// A base class of a DataGridColumn view models. + /// + internal abstract class DataGridColumnHeaderBaseViewModel : PropertyChangeNotificationBase + { + /// + /// The inner header + /// + private object innerHeader = new object(); + + /// + /// Gets or sets the header. + /// + public object Header + { + get + { + return this.innerHeader; + } + + set + { + if (this.innerHeader != value) + { + this.innerHeader = value; + this.NotifyPropertyChanged("Header"); + } + } + } + } +} diff --git a/Main/SimpleBackup.ViewModels/DestinationColumnHeaderViewModel.cs b/Main/SimpleBackup.ViewModels/DestinationColumnHeaderViewModel.cs new file mode 100644 index 0000000..7c7df46 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/DestinationColumnHeaderViewModel.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core.ViewModels; + + /// + /// The view model of destination column header. + /// + internal class DestinationColumnHeaderViewModel : DataGridColumnHeaderBaseViewModel, IDestinationColumnHeaderViewModel + { + } +} diff --git a/Main/SimpleBackup.ViewModels/EncodingInfoItemViewModel.cs b/Main/SimpleBackup.ViewModels/EncodingInfoItemViewModel.cs new file mode 100644 index 0000000..3fda81d --- /dev/null +++ b/Main/SimpleBackup.ViewModels/EncodingInfoItemViewModel.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core.Utilities; + + /// + /// A view model for single encoding information item. + /// + internal class EncodingInfoItemViewModel + { + /// + /// Initializes a new instance of the class. + /// + /// Name of the encoding key. + /// Display name of the encoding. + public EncodingInfoItemViewModel(string encodingKeyName, string encodingDisplayName) + { + encodingKeyName.ThrowsArgumentExceptionIfNullOrEmpty("encodingKeyName"); + encodingDisplayName.ThrowsArgumentExceptionIfNullOrEmpty("encodingDisplayName"); + + this.EncodingKeyName = encodingKeyName; + this.EncodingDisplayName = encodingDisplayName; + } + + /// + /// Gets the name of the encoding key. + /// + public string EncodingKeyName { get; private set; } + + /// + /// Gets the display name of the encoding. + /// + public string EncodingDisplayName { get; private set; } + } +} diff --git a/Main/SimpleBackup.ViewModels/IndexBackupInfoViewModelPair.cs b/Main/SimpleBackup.ViewModels/IndexBackupInfoViewModelPair.cs new file mode 100644 index 0000000..471fc83 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/IndexBackupInfoViewModelPair.cs @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using System; + using SimpleBackup.Core.Utilities; + using SimpleBackup.Core.ViewModels; + + /// + /// A pair of index and backup information view model. + /// + internal class IndexBackupInfoViewModelPair + { + /// + /// Initializes a new instance of the class. + /// + /// The index. + /// The backup information view model. + /// The provided index is out of the range. + /// The provided backupInfoViewModel is null. + public IndexBackupInfoViewModelPair(int index, IBackupInfoViewModel backupInfoViewModel) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException("index"); + } + + backupInfoViewModel.ThrowsArgumentNullException("backupInfoViewModel"); + + this.Index = index; + this.BackupInfoViewModel = backupInfoViewModel; + } + + /// + /// Gets the index. + /// + public int Index { get; private set; } + + /// + /// Gets the backup information view model. + /// + public IBackupInfoViewModel BackupInfoViewModel { get; private set; } + } +} diff --git a/Main/SimpleBackup.ViewModels/IsZipArchiveColumnHeaderViewModel.cs b/Main/SimpleBackup.ViewModels/IsZipArchiveColumnHeaderViewModel.cs new file mode 100644 index 0000000..262f9a4 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/IsZipArchiveColumnHeaderViewModel.cs @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + /// + /// The view model of IsZipArchive column header. + /// + internal class IsZipArchiveColumnHeaderViewModel : DataGridColumnHeaderBaseViewModel + { + } +} diff --git a/Main/SimpleBackup.ViewModels/LabelColumnHeaderViewModel.cs b/Main/SimpleBackup.ViewModels/LabelColumnHeaderViewModel.cs new file mode 100644 index 0000000..cc19cfa --- /dev/null +++ b/Main/SimpleBackup.ViewModels/LabelColumnHeaderViewModel.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core.ViewModels; + + /// + /// The view model of label column header. + /// + internal class LabelColumnHeaderViewModel : DataGridColumnHeaderBaseViewModel, ILabelColumnHeaderViewModel + { + } +} diff --git a/Main/SimpleBackup.ViewModels/MainWindowViewModel.cs b/Main/SimpleBackup.ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..ad617f5 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/MainWindowViewModel.cs @@ -0,0 +1,1223 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Threading; + using System.Threading.Tasks; + using System.Windows; + using System.Windows.Input; + using SimpleBackup.Core; + using SimpleBackup.Core.Models; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.Utilities; + using SimpleBackup.Core.ViewModels; + using SimpleBackup.Core.Views; + + /// + /// The view model of the main window. + /// + internal class MainWindowViewModel : PropertyChangeNotificationBase, IMainWindowViewModel + { + private readonly string defaultWindowTitleFormat = Resources.Resources.Views_DefaultWindowTitle; + private readonly string windowTitleFormat = Resources.Resources.Views_WindowTitleFormat; + private readonly List innerZipEncodings = new List(); + private readonly IBackupService backupService; + private readonly IBackupSettingService backupSettingService; + private readonly IClipboardService clipboardService; + private readonly IUndoRedoService undoRedoService; + private readonly IModelFactory modelFactory; + private readonly IViewFactory viewFactory; + private string innerWindowTitle; + private string innerOutputMessage; + private EncodingInfoItemViewModel innerSelectedEncodingInfoItem; + private CancellationTokenSource cancellationTokenSource; + private IBackupInfoViewModel innerSelectedBackupInfoViewModel; + private int innerSelectedFirstCellItemIndex; + + /// + /// Prevents a default instance of the class from being created. + /// + private MainWindowViewModel() + { + this.CreateNewBackupSettingRelayCommand = new RelayCommand(this.ExecuteCreateNewBackupSetting, this.CanExecuteCreateNewBackupSetting); + this.OpenBackupSettingRelayCommand = new RelayCommand(this.ExecuteOpenBackupSetting, this.CanExecuteOpenBackupSetting); + this.SaveBackupSettingRelayCommand = new RelayCommand(this.ExecuteSaveBackupSetting, this.CanExecuteSaveBackupSetting); + this.SaveAsBackupSettingRelayCommand = new RelayCommand(this.ExecuteSaveAsBackupSetting, this.CanExecuteSaveAsBackupSetting); + this.CloseBackupSettingRelayCommand = new RelayCommand(this.ExecuteCloseBackupSetting, this.CanExecuteCloseBackupSetting); + this.OpenCurrentSettingFileLocationRelayCommand = new RelayCommand(this.ExecuteOpenCurrentSettingFileLocation, this.CanExecuteOpenCurrentSettingFileLocation); + this.ExitRelayCommand = new RelayCommand(this.ExecuteExit, this.CanExecuteExit); + + this.ShowHelpRelayCommand = new RelayCommand(this.ExecuteShowHelp); + this.ShowVersionInformationRelayCommand = new RelayCommand(this.ExecuteShowVersionInformation); + + this.BackUpRelayCommand = new RelayCommand(this.ExecuteBackup, this.CanExecuteBackup); + this.BackupCancelRelayCommand = new RelayCommand(this.ExecuteBackupCancel, this.CanExecuteBackupCancel); + this.SingleBackupRelayCommand = new RelayCommand(this.ExecuteSingleBackup, this.CanExecuteSingleBackup); + this.AddItemRelayCommand = new RelayCommand(this.ExecuteAddItem, this.CanExecuteAddItem); + this.RemoveItemRelayCommand = new RelayCommand(this.ExecuteRemoveItem, this.CanExecuteRemoveItem); + this.MoveUpItemRelayCommand = new RelayCommand(this.ExecuteMoveUpItem, this.CanExecuteMoveUpItem); + this.MoveDownItemRelayCommand = new RelayCommand(this.ExecuteMoveDownItem, this.CanExecuteMoveDownItem); + this.CopyRelayCommand = new RelayCommand(this.ExecuteCopy, this.CanExecuteCopy); + this.CutRelayCommand = new RelayCommand(this.ExecuteCut, this.CanExecuteCut); + this.PasteRelayCommand = new RelayCommand(this.ExecutePaste, this.CanExecutePaste); + this.UndoRelayCommand = new RelayCommand(this.ExecuteUndo, this.CanExecuteUndo); + this.RedoRelayCommand = new RelayCommand(this.ExecuteRedo, this.CanExecuteRedo); + this.RefreshRelayCommand = new RelayCommand(this.ExecuteRefresh, this.CanExecuteRefresh); + this.ClearOutputWindowRelayCommand = new RelayCommand(this.ExecuteClearOutputWindow, this.CanExecuteClearOutputWindow); + + this.WindowTitle = this.defaultWindowTitleFormat; + this.BackupInfoViewModels = new ObservableCollection(); + + this.IsZipArchiveColumnHeaderViewModel = new IsZipArchiveColumnHeaderViewModel { Header = "Zip" }; + this.LabelColumnHeaderViewModel = new LabelColumnHeaderViewModel { Header = Resources.Resources.Views_LabelColumnHeaderText }; + this.SourceColumnHeaderViewModel = new SourceColumnHeaderViewModel { Header = Resources.Resources.Views_BackupSourceColumnHeaderText }; + this.DestinationColumnHeaderViewModel = new DestinationColumnHeaderViewModel { Header = Resources.Resources.Views_BackupDestinationColumnHeaderText }; + this.ProgressViewModel = new ProgressViewModel(); + + this.innerOutputMessage = string.Empty; + this.SetupZipEncodingItems(); + + this.backupService = ObjectContainer.Resolve(); + this.backupSettingService = ObjectContainer.Resolve(); + this.clipboardService = ObjectContainer.Resolve(); + this.undoRedoService = ObjectContainer.Resolve(); + this.modelFactory = ObjectContainer.Resolve(); + this.viewFactory = ObjectContainer.Resolve(); + + this.backupSettingService.BackupSettingOpened += this.OnBackupSettingOpened; + this.backupSettingService.BackupSettingModified += this.OnBackupSettingModified; + this.backupSettingService.BackupSettingSaved += this.OnBackupSettingSaved; + this.backupSettingService.BackupSettingClosed += this.OnBackupSettingClosed; + this.backupService.NofityFileBackupProgress += this.OnBackupServiceNofityFileBackupProgress; + + string resultMessage; + if (this.backupSettingService.OpenDefaultBackupSetting(out resultMessage)) + { + foreach (IBackupInfo backupInfo in this.backupSettingService.CurrentSetting.BackupInfos) + { + IBackupInfoViewModel backupInfoViewModel = BackupInfoViewModel.CreateBackupInfoViewMode( + backupInfo, + this.ClearOutputMessage, + this.AddOutputMessage); + this.BackupInfoViewModels.Add(backupInfoViewModel); + } + } + + if (string.IsNullOrEmpty(resultMessage) == false) + { + this.OutputMessage = resultMessage; + } + } + + /// + /// Occurs when focusing on grid is required. + /// + public event EventHandler FocusOnGrid; + + /// + /// Occurs when focusing on grid row is required. + /// + public event EventHandler FocusOnGridRow; + + /// + /// Gets the create new backup settings relay command. + /// + public RelayCommand CreateNewBackupSettingRelayCommand { get; private set; } + + /// + /// Gets the open backup settings relay command. + /// + public RelayCommand OpenBackupSettingRelayCommand { get; private set; } + + /// + /// Gets the save backup settings relay command. + /// + public RelayCommand SaveBackupSettingRelayCommand { get; private set; } + + /// + /// Gets the save as backup settings relay command. + /// + public RelayCommand SaveAsBackupSettingRelayCommand { get; private set; } + + /// + /// Gets the close backup settings relay command. + /// + public RelayCommand CloseBackupSettingRelayCommand { get; private set; } + + /// + /// Gets the open current setting file location relay command. + /// + public RelayCommand OpenCurrentSettingFileLocationRelayCommand { get; private set; } + + /// + /// Gets the exit relay command. + /// + public RelayCommand ExitRelayCommand { get; private set; } + + /// + /// Gets the show help relay command. + /// + public RelayCommand ShowHelpRelayCommand { get; private set; } + + /// + /// Gets the show version information relay command. + /// + public RelayCommand ShowVersionInformationRelayCommand { get; private set; } + + /// + /// Gets the back up relay command. + /// + public RelayCommand BackUpRelayCommand { get; private set; } + + /// + /// Gets the backup cancel relay command. + /// + public RelayCommand BackupCancelRelayCommand { get; private set; } + + /// + /// Gets the single backup relay command. + /// + public RelayCommand SingleBackupRelayCommand { get; private set; } + + /// + /// Gets the add item relay command. + /// + public RelayCommand AddItemRelayCommand { get; private set; } + + /// + /// Gets the remove item relay command. + /// + public RelayCommand RemoveItemRelayCommand { get; private set; } + + /// + /// Gets the move up item relay command. + /// + public RelayCommand MoveUpItemRelayCommand { get; private set; } + + /// + /// Gets the move down item relay command. + /// + public RelayCommand MoveDownItemRelayCommand { get; private set; } + + /// + /// Gets the copy relay command. + /// + public RelayCommand CopyRelayCommand { get; private set; } + + /// + /// Gets the cut relay command. + /// + public RelayCommand CutRelayCommand { get; private set; } + + /// + /// Gets the paste relay command. + /// + public RelayCommand PasteRelayCommand { get; private set; } + + /// + /// Gets the undo relay command. + /// + public RelayCommand UndoRelayCommand { get; private set; } + + /// + /// Gets the redo relay command. + /// + public RelayCommand RedoRelayCommand { get; private set; } + + /// + /// Gets the refresh relay command. + /// + public RelayCommand RefreshRelayCommand { get; private set; } + + /// + /// Gets the clear output window relay command. + /// + public RelayCommand ClearOutputWindowRelayCommand { get; private set; } + + /// + /// Gets the backup information view models. + /// + public ObservableCollection BackupInfoViewModels { get; private set; } + + /// + /// Gets the progress view model. + /// + public ProgressViewModel ProgressViewModel { get; private set; } + + /// + /// Gets the is zip archive column header view model. + /// + public IsZipArchiveColumnHeaderViewModel IsZipArchiveColumnHeaderViewModel { get; private set; } + + /// + /// Gets the label column header view model. + /// + public LabelColumnHeaderViewModel LabelColumnHeaderViewModel { get; private set; } + + /// + /// Gets the source column header view model. + /// + public SourceColumnHeaderViewModel SourceColumnHeaderViewModel { get; private set; } + + /// + /// Gets the destination column header view model. + /// + public DestinationColumnHeaderViewModel DestinationColumnHeaderViewModel { get; private set; } + + /// + /// Gets or sets the window title. + /// + public string WindowTitle + { + get + { + return this.innerWindowTitle; + } + + set + { + if (this.innerWindowTitle != value) + { + this.innerWindowTitle = value; + this.NotifyPropertyChanged("WindowTitle"); + } + } + } + + /// + /// Gets the zip encodings. + /// + public IEnumerable ZipEncodings + { + get + { + return this.innerZipEncodings; + } + } + + /// + /// Gets or sets the selected encoding information item. + /// + public EncodingInfoItemViewModel SelectedEncodingInfoItem + { + get + { + return this.innerSelectedEncodingInfoItem; + } + + set + { + if (this.innerSelectedEncodingInfoItem != value) + { + this.innerSelectedEncodingInfoItem = value; + var settingsService = ObjectContainer.Resolve(); + settingsService.DefaultZipEncodingKeyText = value.EncodingKeyName; + } + } + } + + /// + /// Gets or sets the selected backup information view model. + /// + public IBackupInfoViewModel SelectedBackupInfoViewModel + { + get + { + return this.innerSelectedBackupInfoViewModel; + } + + set + { + if (this.innerSelectedBackupInfoViewModel != value) + { + this.innerSelectedBackupInfoViewModel = value; + this.NotifyPropertyChanged("SelectedBackupInfoViewModel"); + } + } + } + + /// + /// Gets or sets the output message. + /// + public string OutputMessage + { + get + { + return this.innerOutputMessage; + } + + set + { + if (this.innerOutputMessage != value) + { + this.innerOutputMessage = value; + this.NotifyPropertyChanged("OutputMessage"); + } + } + } + + /// + /// Gets or sets the index of the selected first cell item. + /// + public int SelectedFirstCellItemIndex + { + get + { + return this.innerSelectedFirstCellItemIndex; + } + + set + { + this.innerSelectedFirstCellItemIndex = value; + this.CommitEditingContents(); + } + } + + /// + /// Gets or sets the selected first cell item. + /// + public BackupInfoViewModel SelectedFirstCellItem { get; set; } + + /// + /// Creates the main window view model. + /// + /// The main window view model. + public static IMainWindowViewModel CreateMainWindowViewModel() + { + return new MainWindowViewModel(); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Called when ESC key is pressed. + /// + public void OnEscKeyPressed() + { + this.CancelCutOperation(); + this.CancelCellEditOperation(); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // dispose managed resources + this.cancellationTokenSource.Dispose(); + } + + //// free native resources - Nothing to dispose. + } + + /// + /// Cancels the cut operation. + /// + private void CancelCutOperation() + { + var cutReservedBackupInfoViewModels = this.BackupInfoViewModels.Where(p => p.IsCutReserved).ToArray(); + foreach (IBackupInfoViewModel infoViewModel in cutReservedBackupInfoViewModels) + { + infoViewModel.IsCutReserved = false; + this.clipboardService.ClearClipbord(); + } + } + + /// + /// Cancels the cell edit operation. + /// + private void CancelCellEditOperation() + { + var editingInfoViewModels = this.BackupInfoViewModels.Where(p => p.IsEditing).ToArray(); + foreach (IBackupInfoViewModel infoViewModel in editingInfoViewModels) + { + infoViewModel.IsSourceEditing = false; + infoViewModel.IsDestinationEditing = false; + } + } + + private void OnBackupSettingOpened(object sender, SettingFileEventArgs args) + { + this.WindowTitle = string.Format(CultureInfo.InvariantCulture, this.windowTitleFormat, args.SettingName); + } + + private void OnBackupSettingModified(object sender, SettingFileEventArgs args) + { + this.UpdateWindowTitleAsModified(args.SettingName); + } + + private void OnBackupSettingSaved(object sender, SettingFileEventArgs args) + { + this.WindowTitle = string.Format(CultureInfo.InvariantCulture, this.windowTitleFormat, args.SettingName); + } + + private void OnBackupSettingClosed(object sender, SettingFileEventArgs args) + { + this.WindowTitle = this.defaultWindowTitleFormat; + this.BackupInfoViewModels.Clear(); + } + + private void ExecuteCreateNewBackupSetting(object obj) + { + this.backupSettingService.CreateBackupSetting(); + this.ExecuteAddItem(null); + this.UpdateWindowTitleAsModified(this.backupSettingService.CurrentSetting.SettingName); + } + + private bool CanExecuteCreateNewBackupSetting(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteBackup(object obj) + { + if (this.cancellationTokenSource != null) + { + this.cancellationTokenSource.Dispose(); + } + + this.cancellationTokenSource = new CancellationTokenSource(); + Action backupAction = () => + { + try + { + Application.Current.Dispatcher.Invoke( + () => + { + this.OutputMessage = Resources.Resources.Backup_ExecutingBackup; + Mouse.OverrideCursor = Cursors.Wait; + }); + + IResultInfo[] resultInfos; + this.backupService.BackupMultipulFiles(this.cancellationTokenSource.Token, out resultInfos); + } + finally + { + Application.Current.Dispatcher.Invoke( + () => + { + Mouse.OverrideCursor = null; + }); + } + }; + Action postBackupAction = previousTask => + { + if (previousTask.Exception != null) + { + this.OutputMessage = this.OutputMessage + "\r\n" + previousTask.Exception.ToString(); + } + + if (this.FocusOnGrid != null) + { + Application.Current.Dispatcher.Invoke( + () => this.FocusOnGrid(this, new EventArgs())); + } + }; + + Task.Factory.StartNew(backupAction, this.cancellationTokenSource.Token) + .ContinueWith(postBackupAction); + } + + private bool CanExecuteBackup(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + this.backupService.IsReadyForBackup && (this.backupService.IsExecutingBackup == false); + } + + private void ExecuteBackupCancel(object obj) + { + if (this.cancellationTokenSource != null) + { + this.cancellationTokenSource.Cancel(); + } + } + + private bool CanExecuteBackupCancel(object obj) + { + return this.backupService.IsReadyForBackup && this.backupService.IsExecutingBackup; + } + + private void ExecuteOpenBackupSetting(object obj) + { + if (this.CanExecuteOpenBackupSetting(obj) == false) + { + return; + } + + string resultMessage; + if (this.backupSettingService.OpenBackupSetting(out resultMessage)) + { + foreach (IBackupInfo backupInfo in this.backupSettingService.CurrentSetting.BackupInfos) + { + IBackupInfoViewModel backupInfoViewModel = BackupInfoViewModel.CreateBackupInfoViewMode( + backupInfo, + this.ClearOutputMessage, + this.AddOutputMessage); + this.BackupInfoViewModels.Add(backupInfoViewModel); + } + } + + if (string.IsNullOrEmpty(resultMessage) == false) + { + this.OutputMessage = resultMessage; + } + } + + private bool CanExecuteOpenBackupSetting(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteSaveBackupSetting(object obj) + { + this.backupSettingService.OverWriteCurrntBackupSetting(); + } + + private bool CanExecuteSaveBackupSetting(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false); + } + + private void ExecuteSaveAsBackupSetting(object obj) + { + this.backupSettingService.SaveCurrentBackupSettingAsNewFile(); + } + + private bool CanExecuteSaveAsBackupSetting(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false); + } + + private void ExecuteCloseBackupSetting(object obj) + { + this.backupSettingService.CloseBackupSetting(); + } + + private bool CanExecuteCloseBackupSetting(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false); + } + + private void ExecuteOpenCurrentSettingFileLocation(object obj) + { + Helpers.OpenParentFolderAndSelect(this.backupSettingService.CurrentSetting.SettingFileName); + } + + private bool CanExecuteOpenCurrentSettingFileLocation(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false); + } + + private void ExecuteExit(object obj) + { + Application.Current.Shutdown(0); + } + + private bool CanExecuteExit(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteShowHelp(object obj) + { + string helpFilePath = string.Format( + @"{0}\Documents\HelpDocument.pdf", + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); + Helpers.OpenFile(helpFilePath); + } + + private void ExecuteShowVersionInformation(object obj) + { + IVersionInformationWindow versionInformationWindow = this.viewFactory.CreateVersionInformationWindow(); + + versionInformationWindow.ShowDialogWindow(); + } + + private void ExecuteSingleBackup(object obj) + { + if (this.SelectedFirstCellItem != null) + { + this.SelectedFirstCellItem.SingleBackup(); + } + } + + private bool CanExecuteSingleBackup(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteAddItem(object obj) + { + if (this.CanExecuteAddItem(obj) == false) + { + return; + } + + int currentIndex = -1; + if (this.SelectedBackupInfoViewModel != null) + { + currentIndex = this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel); + } + + int targetIndex = (currentIndex != -1) ? currentIndex + 1 : this.BackupInfoViewModels.Count; + + var action = new Action( + context => + { + var index = (int)context; + IBackupInfo backupInfo = this.backupSettingService.CreateBackupInfo(index); + IBackupInfoViewModel backupInfoViewModel = BackupInfoViewModel.CreateBackupInfoViewMode( + backupInfo, + this.ClearOutputMessage, + this.AddOutputMessage); + this.BackupInfoViewModels.Insert(index, backupInfoViewModel); + + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(index)); + } + + this.SelectedBackupInfoViewModel = backupInfoViewModel; + }); + + var undoAction = new Action( + context => + { + var index = (int)context; + if (index < this.BackupInfoViewModels.Count) + { + var removingBackupInfoViewModel = this.BackupInfoViewModels[index]; + this.backupSettingService.RemoveBackupInfo(removingBackupInfoViewModel.BackupInfoId); + this.BackupInfoViewModels.Remove(removingBackupInfoViewModel); + + if (index < this.BackupInfoViewModels.Count) + { + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(index)); + } + + this.SelectedBackupInfoViewModel = this.BackupInfoViewModels[index]; + } + else if (this.BackupInfoViewModels.Count != 0) + { + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(index - 1)); + } + + this.SelectedBackupInfoViewModel = this.BackupInfoViewModels[index - 1]; + } + } + }); + + this.undoRedoService.Commit(action, undoAction, targetIndex); + } + + private bool CanExecuteAddItem(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false); + } + + private void ExecuteRemoveItem(object obj) + { + if (this.CanExecuteRemoveItem(obj) == false) + { + return; + } + + var targetIndexViewModelPair = new IndexBackupInfoViewModelPair( + this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel), + this.SelectedBackupInfoViewModel); + + this.RemoveItem(targetIndexViewModelPair); + } + + private void RemoveItem(IndexBackupInfoViewModelPair targetIndexViewModelPair) + { + var action = new Action( + context => + { + var indexViewModelPair = (IndexBackupInfoViewModelPair)context; + if (indexViewModelPair.Index < this.BackupInfoViewModels.Count) + { + var removingBackupInfoViewModel = this.BackupInfoViewModels[indexViewModelPair.Index]; + this.backupSettingService.RemoveBackupInfo(removingBackupInfoViewModel.BackupInfoId); + this.BackupInfoViewModels.Remove(removingBackupInfoViewModel); + + if (indexViewModelPair.Index < this.BackupInfoViewModels.Count) + { + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(indexViewModelPair.Index)); + } + + this.SelectedBackupInfoViewModel = this.BackupInfoViewModels[indexViewModelPair.Index]; + } + else if (this.BackupInfoViewModels.Count != 0) + { + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(indexViewModelPair.Index - 1)); + } + + this.SelectedBackupInfoViewModel = this.BackupInfoViewModels[indexViewModelPair.Index - 1]; + } + } + }); + + var undoAction = new Action( + context => + { + var indexViewModelPair = (IndexBackupInfoViewModelPair)context; + + this.backupSettingService.InsertBackupInfo( + indexViewModelPair.Index, + indexViewModelPair.BackupInfoViewModel.GetBackupInfo()); + this.BackupInfoViewModels.Insert( + indexViewModelPair.Index, + indexViewModelPair.BackupInfoViewModel); + + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(indexViewModelPair.Index)); + } + + this.SelectedBackupInfoViewModel = indexViewModelPair.BackupInfoViewModel; + }); + + this.undoRedoService.Commit(action, undoAction, targetIndexViewModelPair); + } + + private bool CanExecuteRemoveItem(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false) && + (this.SelectedBackupInfoViewModel != null); + } + + private void ExecuteMoveUpItem(object obj) + { + if (this.CanExecuteMoveUpItem(obj) == false) + { + return; + } + + var selectedIdIndexPair = new IdIndexPair( + this.SelectedBackupInfoViewModel.BackupInfoId, + this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel)); + var action = new Action(context => + { + var idIndexPair = (IdIndexPair)context; + if (idIndexPair.Index > 0) + { + this.backupSettingService.CurrentSetting.MoveItem(idIndexPair.Id, ItemMovingDirection.MoveUp); + this.BackupInfoViewModels.Move(idIndexPair.Index, idIndexPair.Index - 1); + } + }); + + var undoAction = new Action(context => + { + var idIndexPair = (IdIndexPair)context; + var index = idIndexPair.Index - 1; + if (index < this.BackupInfoViewModels.Count - 1) + { + this.backupSettingService.CurrentSetting.MoveItem(idIndexPair.Id, ItemMovingDirection.MoveDown); + this.BackupInfoViewModels.Move(index, index + 1); + } + }); + + this.undoRedoService.Commit(action, undoAction, selectedIdIndexPair); + } + + private bool CanExecuteMoveUpItem(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false) && + (this.SelectedBackupInfoViewModel != null) && + this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel) > 0; + } + + private void ExecuteMoveDownItem(object obj) + { + if (this.CanExecuteMoveDownItem(obj) == false) + { + return; + } + + var selectedIdIndexPair = new IdIndexPair( + this.SelectedBackupInfoViewModel.BackupInfoId, + this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel)); + var action = new Action(context => + { + var idIndexPair = (IdIndexPair)context; + if (idIndexPair.Index < this.BackupInfoViewModels.Count - 1) + { + this.backupSettingService.CurrentSetting.MoveItem(idIndexPair.Id, ItemMovingDirection.MoveDown); + this.BackupInfoViewModels.Move(idIndexPair.Index, idIndexPair.Index + 1); + } + }); + + var undoAction = new Action(context => + { + var idIndexPair = (IdIndexPair)context; + var index = idIndexPair.Index + 1; + if (index > 0) + { + this.backupSettingService.CurrentSetting.MoveItem(idIndexPair.Id, ItemMovingDirection.MoveUp); + this.BackupInfoViewModels.Move(index, index - 1); + } + }); + + this.undoRedoService.Commit(action, undoAction, selectedIdIndexPair); + } + + private bool CanExecuteMoveDownItem(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + (this.backupService.IsExecutingBackup == false) && + (this.SelectedBackupInfoViewModel != null) && + this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel) < this.BackupInfoViewModels.Count - 1; + } + + private void ExecuteCopy(object obj) + { + if (this.CanExecuteCopy(obj)) + { + IBackupInfo copiedBackupInfo = this.backupSettingService.CopyBackupInfo( + this.SelectedBackupInfoViewModel.GetBackupInfo()); + byte[] backupInfoBytes = copiedBackupInfo.ToBinary(); + var info = new BackupInfoPasteInfo( + backupInfoBytes, + PasteType.Copy, + this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel)); + IDataObject dataObject = new DataObject(); + dataObject.SetData(Constants.BackupInfoClipboardFormat, info); + dataObject.SetData(DataFormats.Text, copiedBackupInfo.ToFormattedText()); + this.clipboardService.SetDataObject(dataObject); + } + } + + private bool CanExecuteCopy(object obj) + { + return this.SelectedBackupInfoViewModel != null; + } + + private void ExecuteCut(object obj) + { + if (this.CanExecuteCut(obj)) + { + IBackupInfo copiedBackupInfo = this.backupSettingService.CopyBackupInfo( + this.SelectedBackupInfoViewModel.GetBackupInfo()); + byte[] backupInfoBytes = copiedBackupInfo.ToBinary(); + var info = new BackupInfoPasteInfo( + backupInfoBytes, + PasteType.Cut, + this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel)); + IDataObject dataObject = new DataObject(); + dataObject.SetData(Constants.BackupInfoClipboardFormat, info); + this.clipboardService.SetDataObject(dataObject); + dataObject.SetData(DataFormats.Text, copiedBackupInfo.ToFormattedText()); + this.SelectedBackupInfoViewModel.IsCutReserved = true; + } + } + + private bool CanExecuteCut(object obj) + { + return this.SelectedBackupInfoViewModel != null; + } + + private void ExecutePaste(object obj) + { + if (this.CanExecutePaste(obj)) + { + if (this.clipboardService.DoesClipboardDataContain(Constants.BackupInfoClipboardFormat)) + { + var pasteInfo = + this.clipboardService.GetData(Constants.BackupInfoClipboardFormat); + if (pasteInfo != null) + { + IBackupInfo backupInfo = this.modelFactory.CreateBackupInfoFromBinary( + pasteInfo.BackupInfoBytes, + pasteInfo.PasteType == PasteType.Copy); + + if ((pasteInfo.PasteType == PasteType.Cut) && + (pasteInfo.SourceIndex < this.BackupInfoViewModels.Count)) + { + IBackupInfoViewModel source = this.BackupInfoViewModels[pasteInfo.SourceIndex]; + if (source.IsCutReserved) + { + var targetIndexViewModelPair = new IndexBackupInfoViewModelPair( + pasteInfo.SourceIndex, + source); + this.RemoveItem(targetIndexViewModelPair); + } + } + + int targetIndex = this.GetTargetItemIndex(); + this.InsertBackupInfo(backupInfo, targetIndex); + } + } + } + } + + private bool CanExecutePaste(object obj) + { + var supportedClipboardFormats = new string[] { Constants.BackupInfoClipboardFormat }; + + return supportedClipboardFormats.Any(p => this.clipboardService.DoesClipboardDataContain(p)); + } + + private void InsertBackupInfo(IBackupInfo backupInfo, int targetIndex) + { + if ((backupInfo == null) || (targetIndex < 0) || (targetIndex > this.BackupInfoViewModels.Count)) + { + return; + } + + IBackupInfoViewModel backupInfoViewModel = BackupInfoViewModel.CreateBackupInfoViewMode( + backupInfo, + this.ClearOutputMessage, + this.AddOutputMessage); + var targetIndexViewModelPair = new IndexBackupInfoViewModelPair( + targetIndex, + backupInfoViewModel); + + var action = new Action(context => this.InsertBackupInfo(context)); + var undoAction = new Action(context => this.RemoveInsertedBackupInfo(context)); + this.undoRedoService.Commit(action, undoAction, targetIndexViewModelPair); + } + + private void InsertBackupInfo(object context) + { + var indexViewModelPair = (IndexBackupInfoViewModelPair)context; + this.backupSettingService.InsertBackupInfo( + indexViewModelPair.Index, + indexViewModelPair.BackupInfoViewModel.GetBackupInfo()); + this.BackupInfoViewModels.Insert(indexViewModelPair.Index, indexViewModelPair.BackupInfoViewModel); + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(indexViewModelPair.Index)); + } + + this.SelectedBackupInfoViewModel = indexViewModelPair.BackupInfoViewModel; + } + + private void RemoveInsertedBackupInfo(object context) + { + var indexViewModelPair = (IndexBackupInfoViewModelPair)context; + if (indexViewModelPair.Index < this.BackupInfoViewModels.Count) + { + var removingBackupInfoViewModel = this.BackupInfoViewModels[indexViewModelPair.Index]; + this.backupSettingService.RemoveBackupInfo(removingBackupInfoViewModel.BackupInfoId); + this.BackupInfoViewModels.Remove(removingBackupInfoViewModel); + + if (indexViewModelPair.Index < this.BackupInfoViewModels.Count) + { + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(indexViewModelPair.Index)); + } + + this.SelectedBackupInfoViewModel = this.BackupInfoViewModels[indexViewModelPair.Index]; + } + else if (this.BackupInfoViewModels.Count != 0) + { + if (this.FocusOnGridRow != null) + { + this.FocusOnGridRow(this, new FocusOnGridRowEventArgs(indexViewModelPair.Index - 1)); + } + + this.SelectedBackupInfoViewModel = this.BackupInfoViewModels[indexViewModelPair.Index - 1]; + } + } + } + + private void ExecuteUndo(object obj) + { + if (this.undoRedoService.CanExecuteUndo()) + { + this.undoRedoService.Undo(); + } + } + + private bool CanExecuteUndo(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + this.undoRedoService.CanExecuteUndo(); + } + + private void ExecuteRedo(object obj) + { + if (this.undoRedoService.CanExecuteRedo()) + { + this.undoRedoService.Redo(); + } + } + + private bool CanExecuteRedo(object obj) + { + return (this.backupSettingService.CurrentSetting != null) && + this.undoRedoService.CanExecuteRedo(); + } + + private void ExecuteRefresh(object obj) + { + this.ResetAllBackItemStates(); + this.RestProgressBar(); + } + + private bool CanExecuteRefresh(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void ExecuteClearOutputWindow(object obj) + { + this.OutputMessage = string.Empty; + } + + private bool CanExecuteClearOutputWindow(object obj) + { + return this.backupService.IsExecutingBackup == false; + } + + private void OnBackupServiceNofityFileBackupProgress(object sender, FileBackupProgressEventArgs args) + { + this.ProgressViewModel.ProgressValue = args.ProgressValue; + if (args.LatestResultInfo != null) + { + this.OutputMessage = this.OutputMessage + "\r\n" + + string.Format( + "{0}: {1}", + args.LatestResultInfo.BackupState.Translate(), + args.LatestResultInfo.Description); + } + } + + private void CommitEditingContents() + { + IBackupInfoViewModel[] editingViewModels = + this.BackupInfoViewModels.Where(p => p.IsEditing).ToArray(); + + foreach (IBackupInfoViewModel backupInfoViewModel in editingViewModels) + { + backupInfoViewModel.CommitEditingContents(); + } + } + + private void UpdateWindowTitleAsModified(string backupSettingName) + { + this.WindowTitle = string.Format( + CultureInfo.InvariantCulture, + this.windowTitleFormat, + backupSettingName + "*"); + } + + private void ResetAllBackItemStates() + { + foreach (IBackupInfoViewModel backupInfoViewModel in this.BackupInfoViewModels) + { + backupInfoViewModel.ResetBackupState(); + } + } + + private void RestProgressBar() + { + this.ProgressViewModel.ProgressValue = 0; + } + + private void ClearOutputMessage() + { + this.OutputMessage = string.Empty; + } + + private void AddOutputMessage(string additionalMessage) + { + this.OutputMessage = this.OutputMessage + (additionalMessage ?? string.Empty) + "\r\n"; + } + + private int GetTargetItemIndex() + { + int currentIndex = -1; + if (this.SelectedBackupInfoViewModel != null) + { + currentIndex = this.BackupInfoViewModels.IndexOf(this.SelectedBackupInfoViewModel); + } + else + { + currentIndex = this.SelectedFirstCellItemIndex; + } + + int targetIndex = (currentIndex != -1) ? currentIndex + 1 : this.BackupInfoViewModels.Count; + + return targetIndex; + } + + private void SetupZipEncodingItems() + { + var settingsService = ObjectContainer.Resolve(); + if (string.IsNullOrEmpty(settingsService.DefaultZipEncodingKeyText)) + { + settingsService.DefaultZipEncodingKeyText = "utf-8"; + } + + this.innerZipEncodings.Add(new EncodingInfoItemViewModel("shift_jis", "Japanese (Shift-JIS)")); + this.innerZipEncodings.Add(new EncodingInfoItemViewModel("utf-16", "Unicode")); + this.innerZipEncodings.Add(new EncodingInfoItemViewModel("utf-8", "Unicode (UTF-8)")); + + EncodingInfoItemViewModel defaultEncodingItem = + this.innerZipEncodings.FirstOrDefault( + p => + string.Equals( + p.EncodingKeyName, + settingsService.DefaultZipEncodingKeyText, + StringComparison.OrdinalIgnoreCase)); + if (defaultEncodingItem != null) + { + this.SelectedEncodingInfoItem = defaultEncodingItem; + } + } + } +} diff --git a/Main/SimpleBackup.ViewModels/ProgressViewModel.cs b/Main/SimpleBackup.ViewModels/ProgressViewModel.cs new file mode 100644 index 0000000..8313e26 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/ProgressViewModel.cs @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core.Utilities; + + /// + /// The view model for reporting progress. + /// + internal class ProgressViewModel : PropertyChangeNotificationBase + { + /// + /// The progress value + /// + private double progressValue; + + /// + /// Gets or sets the progress value. + /// + public double ProgressValue + { + get + { + return this.progressValue; + } + + set + { + if (this.progressValue.Equals(value) == false) + { + this.progressValue = value; + this.NotifyPropertyChanged("ProgressValue"); + } + } + } + } +} diff --git a/Main/SimpleBackup.ViewModels/SimpleBackup.ViewModels.csproj b/Main/SimpleBackup.ViewModels/SimpleBackup.ViewModels.csproj new file mode 100644 index 0000000..8ffd7ca --- /dev/null +++ b/Main/SimpleBackup.ViewModels/SimpleBackup.ViewModels.csproj @@ -0,0 +1,100 @@ + + + + + Debug + AnyCPU + {70BC6544-A4C9-4325-9CE1-CC3F79787693} + Library + Properties + SimpleBackup.ViewModels + SimpleBackup.ViewModels + v4.5 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + SimpleBackupKey.snk + + + + + + + + + + + + + + + + + + Properties\AssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + {33f1d454-9962-4eb6-aad3-8d11d9a78d1f} + SimpleBackup.Core + + + {a655131e-d439-4de1-bc39-5c955306183f} + SimpleBackup.Resources + + + + + set EXE_BIN_DIR=$(ProjectDir)..\bin\$(ConfigurationName)\ +xcopy "$(TargetDir)$(TargetName).dll" "%25EXE_BIN_DIR%25" /Y +if exist "$(TargetDir)$(TargetName).pdb" xcopy "$(TargetDir)$(TargetName).pdb" "%25EXE_BIN_DIR%25" /Y + + + \ No newline at end of file diff --git a/Main/SimpleBackup.ViewModels/SimpleBackupKey.snk b/Main/SimpleBackup.ViewModels/SimpleBackupKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..def2e6df6a67d7e5802b3319c2b385c61304db29 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=*mMuj7Bow@Ep}p%TfOae=&U%vR9qh+ z@B2Y7h5t%KB~GowmVCnTwn!=ol7j~SRw};|aqMe69$!Xr!@Kl)p?8Xg2;G;~Cd60S zyuxBRv<}vHJsUi)3u6Y?7~u<-nIO&1Fj-O8+VD)*I{}r1s+^@Kmf2Y}gp`|NRs+em z$u>8Tw)yg`4_#X9od;DS_`m7gjCw7)_oIM$fq-7kckw~B<7M;zI>N{SPq*6$huq7Z zgYNgU;sUWRbAi&O+L_hd!U0Li?IE-i`qYl6ItfNG&LGLWV{U{YZh>Ax4*J$khFNYOR0lC!sQ=xnj0#!GfwNKNLWeC6+{0F(k120wr_Sb zIyF(GL;3}qT}4Ed2plZ&Isj`rlkfJc)Ea1aKb3p_jTAd0vy@;AzzF|BpZp|m^l#y& zbx94OX%V&s<FnfGWY1Nh zxKnroP3(eKfbr85Y^JZ_CW>v48ZxICTuX?#TOI&z>)DFD-NiB2i|wPJnn~;|{CGZv i!2z3|Al4b1%II9A@B0rIjj|^@+oAX!*AylRLZAX-U?o=o literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.ViewModels/SourceColumnHeaderViewModel.cs b/Main/SimpleBackup.ViewModels/SourceColumnHeaderViewModel.cs new file mode 100644 index 0000000..cca8b35 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/SourceColumnHeaderViewModel.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core.ViewModels; + + /// + /// The view model of source column header. + /// + internal class SourceColumnHeaderViewModel : DataGridColumnHeaderBaseViewModel, ISourceColumnHeaderViewModel + { + } +} diff --git a/Main/SimpleBackup.ViewModels/ViewModelComponent.cs b/Main/SimpleBackup.ViewModels/ViewModelComponent.cs new file mode 100644 index 0000000..f2547b1 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/ViewModelComponent.cs @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core; + using SimpleBackup.Core.AppInfrastructure; + using SimpleBackup.Core.ViewModels; + + /// + /// The view model component. + /// + internal class ViewModelComponent : IAppComponent + { + /// + /// Initializes this application component. + /// + public void Initialize() + { + ObjectContainer.Register(new ViewModelFactory()); + } + } +} diff --git a/Main/SimpleBackup.ViewModels/ViewModelFactory.cs b/Main/SimpleBackup.ViewModels/ViewModelFactory.cs new file mode 100644 index 0000000..a54e0b3 --- /dev/null +++ b/Main/SimpleBackup.ViewModels/ViewModelFactory.cs @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.ViewModels +{ + using SimpleBackup.Core.ViewModels; + + /// + /// The view model factory. + /// + internal class ViewModelFactory : IViewModelFactory + { + /// + /// Creates the main window view model. + /// + /// The main window view model. + public IMainWindowViewModel CreateMainWindowViewModel() + { + return MainWindowViewModel.CreateMainWindowViewModel(); + } + } +} diff --git a/Main/SimpleBackup.Views/BackupSourceTypeToImageConverter.cs b/Main/SimpleBackup.Views/BackupSourceTypeToImageConverter.cs new file mode 100644 index 0000000..25bed54 --- /dev/null +++ b/Main/SimpleBackup.Views/BackupSourceTypeToImageConverter.cs @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System; + using System.Diagnostics; + using System.Windows.Controls; + using System.Windows.Data; + using System.Windows.Media.Imaging; + using SimpleBackup.Core.Models; + + /// + /// A converter which converts BackupSourceType to Image. + /// + internal class BackupSourceTypeToImageConverter : IValueConverter + { + /// + /// Converts a value. + /// + /// The value produced by the binding source. + /// The type of the binding target property. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + Uri imageSourceUri; + var backupState = (BackupSourceType)value; + switch (backupState) + { + case BackupSourceType.File: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/document_32xLG.png", UriKind.Absolute); + break; + case BackupSourceType.Folder: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/FileGroup_10135_32x.png", UriKind.Absolute); + break; + default: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/document_32xLG.png", UriKind.Absolute); + break; + } + + var bitmapImage = new BitmapImage(); + bitmapImage.BeginInit(); + bitmapImage.UriSource = imageSourceUri; + bitmapImage.EndInit(); + + return new Image { Source = bitmapImage }; + } + + /// + /// Converts a value. + /// + /// The value that is produced by the binding target. + /// The type to convert to. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + Debug.Assert(true, "ConvertBack is called."); + return new object(); + } + } +} diff --git a/Main/SimpleBackup.Views/BackupStateToImageConverter.cs b/Main/SimpleBackup.Views/BackupStateToImageConverter.cs new file mode 100644 index 0000000..63c1f48 --- /dev/null +++ b/Main/SimpleBackup.Views/BackupStateToImageConverter.cs @@ -0,0 +1,99 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System; + using System.Diagnostics; + using System.Windows.Controls; + using System.Windows.Data; + using System.Windows.Media.Imaging; + using SimpleBackup.Core.Models; + + /// + /// A converter which converts BackupState to Image. + /// + internal class BackupStateToImageConverter : IValueConverter + { + /// + /// Converts a value. + /// + /// The value produced by the binding source. + /// The type of the binding target property. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + Uri imageSourceUri; + var backupState = (BackupState)value; + switch (backupState) + { + case BackupState.Todo: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/flag_16xLG.png", UriKind.Absolute); + break; + case BackupState.InProgress: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/Activity_16xLG.png", UriKind.Absolute); + break; + case BackupState.Success: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/StatusAnnotations_Complete_and_ok_32xLG_color.png", UriKind.Absolute); + break; + case BackupState.Failed: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/StatusAnnotations_Critical_32xLG_color.png", UriKind.Absolute); + break; + case BackupState.Cancelled: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/Warning.png", UriKind.Absolute); + break; + case BackupState.Skipped: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/Warning.png", UriKind.Absolute); + break; + default: + imageSourceUri = new Uri("pack://application:,,,/SimpleBackup.Resources;component/Images/Remove_16xLG.png", UriKind.Absolute); + break; + } + + var bitmapImage = new BitmapImage(); + bitmapImage.BeginInit(); + bitmapImage.UriSource = imageSourceUri; + bitmapImage.EndInit(); + + return new Image { Source = bitmapImage }; + } + + /// + /// Converts a value. + /// + /// The value that is produced by the binding target. + /// The type to convert to. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + Debug.Assert(true, "ConvertBack is called."); + return new object(); + } + } +} diff --git a/Main/SimpleBackup.Views/ExDataGrid.cs b/Main/SimpleBackup.Views/ExDataGrid.cs new file mode 100644 index 0000000..f998a76 --- /dev/null +++ b/Main/SimpleBackup.Views/ExDataGrid.cs @@ -0,0 +1,148 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System; + using System.Linq; + using System.Windows; + using System.Windows.Controls; + using SimpleBackup.Core.Views; + + /// + /// An extended data grid control. + /// + internal class ExDataGrid : DataGrid + { + /// + /// The selected first cell item index property key + /// Read-Only Dependency Properties + /// http://msdn.microsoft.com/en-us/library/ms754044(v=vs.110).aspx + /// + public static readonly DependencyPropertyKey SelectedFirstCellItemIndexPropertyKey = + DependencyProperty.RegisterReadOnly( + "SelectedFirstCellItemIndex", + typeof(int), + typeof(ExDataGrid), + new PropertyMetadata(default(int))); + + /// + /// The selected first cell item index property + /// + public static readonly DependencyProperty SelectedFirstCellItemIndexProperty = + SelectedFirstCellItemIndexPropertyKey.DependencyProperty; + + /// + /// The selected first cell item property key + /// + public static readonly DependencyPropertyKey SelectedFirstCellItemPropertyKey = + DependencyProperty.RegisterReadOnly( + "SelectedFirstCellItem", + typeof(object), + typeof(ExDataGrid), + new PropertyMetadata(default(object))); + + /// + /// The selected first cell item property + /// + public static readonly DependencyProperty SelectedFirstCellItemProperty = + SelectedFirstCellItemPropertyKey.DependencyProperty; + + /// + /// Initializes a new instance of the class. + /// + public ExDataGrid() + { + this.Loaded += (sender, args) => + { + if (this.SelectedFirstCellItemChanged != null) + { + if (this.Items.Count != 0) + { + this.SelectedFirstCellItemChanged( + this, + new ExDataGridSelectedFirstCellItemChangedEventArgs( + 0, + this.Items[0])); + } + } + }; + } + + public event EventHandler SelectedFirstCellItemChanged; + + /// + /// Gets the index of the selected first cell item. + /// + public int SelectedFirstCellItemIndex + { + get + { + return (int)this.GetValue(SelectedFirstCellItemIndexProperty); + } + } + + /// + /// Gets the selected first cell item. + /// + public object SelectedFirstCellItem + { + get + { + return (object)this.GetValue(SelectedFirstCellItemProperty); + } + } + + protected override void OnSelectedCellsChanged(SelectedCellsChangedEventArgs e) + { + base.OnSelectedCellsChanged(e); + + int firstIndex = int.MaxValue; + object firstIndexItem = null; + + DataGridCellInfo[] validCellInfos = this.SelectedCells.Where(p => p.IsValid).ToArray(); + foreach (DataGridCellInfo cellInfo in validCellInfos) + { + int index = this.Items.IndexOf(cellInfo.Item); + if (index < firstIndex) + { + firstIndex = index; + firstIndexItem = cellInfo.Item; + } + } + + if (this.SelectedFirstCellItemIndex != firstIndex) + { + this.SetValue(SelectedFirstCellItemIndexPropertyKey, firstIndex); + this.SetValue(SelectedFirstCellItemPropertyKey, firstIndexItem); + + if (this.SelectedFirstCellItemChanged != null) + { + this.SelectedFirstCellItemChanged( + this, + new ExDataGridSelectedFirstCellItemChangedEventArgs( + firstIndex, + firstIndexItem)); + } + } + } + } +} diff --git a/Main/SimpleBackup.Views/ExDataGridSelectedFirstCellItemBehavior.cs b/Main/SimpleBackup.Views/ExDataGridSelectedFirstCellItemBehavior.cs new file mode 100644 index 0000000..b1a6b79 --- /dev/null +++ b/Main/SimpleBackup.Views/ExDataGridSelectedFirstCellItemBehavior.cs @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System.Windows; + using System.Windows.Interactivity; + using SimpleBackup.Core.Views; + + /// + /// Behavior for ExDataGrid's SelectedFirstCellItemIndex and SelectedFirstCellItem read-only dependency properties. + /// + internal class ExDataGridSelectedFirstCellItemBehavior : Behavior + { + /// + /// The selected first cell item index property. + /// This wraps ExDataGrid's SelectedFirstCellItemIndex read-only dependency property. + /// + public static readonly DependencyProperty SelectedFirstCellItemIndexProperty = + DependencyProperty.Register( + "SelectedFirstCellItemIndex", + typeof(int), + typeof(ExDataGridSelectedFirstCellItemBehavior), + new PropertyMetadata(default(int))); + + /// + /// The selected first cell item property. + /// This wraps ExDataGrid's SelectedFirstCellItem read-only dependency property. + /// + public static readonly DependencyProperty SelectedFirstCellItemProperty = + DependencyProperty.Register( + "SelectedFirstCellItem", + typeof(object), + typeof(ExDataGridSelectedFirstCellItemBehavior), + new PropertyMetadata(default(object))); + + /// + /// Gets or sets the index of the selected first cell item. + /// + public int SelectedFirstCellItemIndex + { + get { return (int)this.GetValue(SelectedFirstCellItemIndexProperty); } + set { this.SetValue(SelectedFirstCellItemIndexProperty, value); } + } + + /// + /// Gets or sets the selected first cell item. + /// + public object SelectedFirstCellItem + { + get { return (object)this.GetValue(SelectedFirstCellItemProperty); } + set { this.SetValue(SelectedFirstCellItemProperty, value); } + } + + /// + /// Called after the behavior is attached to an AssociatedObject. + /// + protected override void OnAttached() + { + base.OnAttached(); + this.AssociatedObject.SelectedFirstCellItemChanged += this.OnExDataGridSelectedFirstCellItemChanged; + } + + /// + /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred. + /// + protected override void OnDetaching() + { + base.OnDetaching(); + this.AssociatedObject.SelectedFirstCellItemChanged -= this.OnExDataGridSelectedFirstCellItemChanged; + } + + /// + /// Called when ExDataGrid's SelectedFirstCellItemChanged event is published. + /// + /// The sender. + /// The instance containing the event data. + private void OnExDataGridSelectedFirstCellItemChanged(object sender, ExDataGridSelectedFirstCellItemChangedEventArgs e) + { + this.SelectedFirstCellItemIndex = e.SelectedFirstCellItemIndex; + this.SelectedFirstCellItem = e.SelectedFirstCellItem; + } + } +} diff --git a/Main/SimpleBackup.Views/FileFolderDialog.cs b/Main/SimpleBackup.Views/FileFolderDialog.cs new file mode 100644 index 0000000..c605a9b --- /dev/null +++ b/Main/SimpleBackup.Views/FileFolderDialog.cs @@ -0,0 +1,157 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System; + using System.IO; + using System.Text; + using System.Windows.Forms; + using SimpleBackup.Core.Views; + + /// + /// File folder dialog. + /// + internal class FileFolderDialog : CommonDialog, IFileFolderDialog + { + /// + /// The inner open file dialog + /// + private readonly OpenFileDialog innerOpenFileDialog = new OpenFileDialog(); + + /// + /// Gets or sets the selected path. + /// + public string SelectedPath + { + get + { + if ((string.IsNullOrEmpty(this.innerOpenFileDialog.FileName) == false) && + (this.innerOpenFileDialog.FileName.EndsWith("Folder Selection.") || (File.Exists(this.innerOpenFileDialog.FileName) == false)) && + (Directory.Exists(this.innerOpenFileDialog.FileName) == false)) + { + return Path.GetDirectoryName(this.innerOpenFileDialog.FileName); + } + + return this.innerOpenFileDialog.FileName; + } + + set + { + if (string.IsNullOrEmpty(value) == false) + { + this.innerOpenFileDialog.FileName = value; + } + } + } + + /// + /// Gets the selected paths as semi-colon seprated string. + /// + public string SelectedPaths + { + get + { + if ((this.innerOpenFileDialog.FileNames != null) && (this.innerOpenFileDialog.FileNames.Length > 1)) + { + var sb = new StringBuilder(); + foreach (string fileName in this.innerOpenFileDialog.FileNames) + { + if (File.Exists(fileName)) + { + sb.Append(fileName + ";"); + } + } + + return sb.ToString(); + } + + return null; + } + } + + /// + /// Runs a common dialog box with a default owner. + /// + /// + /// if the user clicks OK in the dialog box; otherwise, . + /// + /// + /// + /// + /// + /// + /// + public new DialogResult ShowDialog() + { + return this.ShowDialog(null); + } + + /// + /// Runs a common dialog box with the specified owner. + /// + /// Any object that implements that represents the top-level window that will own the modal dialog box. + /// + /// if the user clicks OK in the dialog box; otherwise, . + /// + public new DialogResult ShowDialog(IWin32Window owner) + { + this.innerOpenFileDialog.ValidateNames = false; + this.innerOpenFileDialog.CheckFileExists = false; + this.innerOpenFileDialog.CheckPathExists = true; + + // Set initial directory (used when dialog.FileName is set from outside) + if (string.IsNullOrEmpty(this.innerOpenFileDialog.FileName) == false) + { + this.innerOpenFileDialog.InitialDirectory = Directory.Exists(this.innerOpenFileDialog.FileName) + ? this.innerOpenFileDialog.FileName + : Path.GetDirectoryName(this.innerOpenFileDialog.FileName); + } + + // Always default to Folder Selection. + this.innerOpenFileDialog.FileName = "Folder Selection."; + + return (owner == null) + ? this.innerOpenFileDialog.ShowDialog() + : this.innerOpenFileDialog.ShowDialog(owner); + } + + /// + /// When overridden in a derived class, resets the properties of a common dialog box to their default values. + /// + public override void Reset() + { + this.innerOpenFileDialog.Reset(); + } + + /// + /// When overridden in a derived class, specifies a common dialog box. + /// + /// A value that represents the window handle of the owner window for the common dialog box. + /// + /// true if the dialog box was successfully run; otherwise, false. + /// + protected override bool RunDialog(IntPtr hwndOwner) + { + return true; + } + } +} diff --git a/Main/SimpleBackup.Views/MainWindow.xaml b/Main/SimpleBackup.Views/MainWindow.xaml new file mode 100644 index 0000000..2f4922c --- /dev/null +++ b/Main/SimpleBackup.Views/MainWindow.xaml @@ -0,0 +1,553 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Main/SimpleBackup.Views/MainWindow.xaml.cs b/Main/SimpleBackup.Views/MainWindow.xaml.cs new file mode 100644 index 0000000..8519569 --- /dev/null +++ b/Main/SimpleBackup.Views/MainWindow.xaml.cs @@ -0,0 +1,356 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System; + using System.ComponentModel; + using System.Linq; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Input; + using SimpleBackup.Core; + using SimpleBackup.Core.Services; + using SimpleBackup.Core.Utilities; + using SimpleBackup.Core.ViewModels; + using SimpleBackup.Core.Views; + using Application = System.Windows.Application; + using DataGrid = System.Windows.Controls.DataGrid; + using DataGridCell = System.Windows.Controls.DataGridCell; + using KeyEventArgs = System.Windows.Input.KeyEventArgs; + using MessageBox = System.Windows.MessageBox; + using TextBox = System.Windows.Controls.TextBox; + + /// + /// The Code-Behind of MainWindow.xaml. + /// + internal partial class MainWindow : Window, IMainWindow + { + private IBackupSettingService backupSettingService; + + /// + /// Prevents a default instance of the class from being created. + /// + private MainWindow() + { + this.InitializeComponent(); + + this.backupSettingService = ObjectContainer.Resolve(); + + this.DataContextChanged += (sender, args) => + { + var viewModel = this.DataContext as IMainWindowViewModel; + if (viewModel != null) + { + viewModel.FocusOnGrid += this.OnFocusOnGridRequired; + viewModel.FocusOnGridRow += this.OnFocusOnGridRowRequired; + } + else + { + throw new InvalidOperationException("The data context is not an IMainWindowViewModel object."); + } + }; + + this.BackupInfoDataGrid.Loaded += (sender, args) => + { + if (this.BackupInfoDataGrid.Items.Count != 0) + { + this.FocusOnGridRow(0); + } + }; + } + + /// + /// Creates the main window. + /// + /// The main window. + public static IMainWindow CreateMainWindow() + { + return new MainWindow(); + } + + /// + /// Raises the Closing event. + /// + /// A that contains the event data. + protected override void OnClosing(CancelEventArgs e) + { + if ((this.backupSettingService.CurrentSetting != null) && + this.backupSettingService.CurrentSetting.Modified) + { + MessageBoxResult confirmationResult = MessageBox.Show( + Application.Current.MainWindow, + SimpleBackup.Resources.Resources.Views_SaveConfirmationMessage, + SimpleBackup.Resources.Resources.Views_ConfirmationDialogTitle, + MessageBoxButton.YesNoCancel); + if (confirmationResult == MessageBoxResult.Yes) + { + if (this.backupSettingService.OverWriteCurrntBackupSetting() == false) + { + e.Cancel = true; + } + } + else if (confirmationResult == MessageBoxResult.Cancel) + { + e.Cancel = true; + } + } + } + + private void OnFocusOnGridRequired(object sender, EventArgs eventArgs) + { + this.BackupInfoDataGrid.Focus(); + } + + private void OnFocusOnGridRowRequired(object sender, FocusOnGridRowEventArgs args) + { + this.FocusOnGridRow(args.Index); + } + + private void FocusOnGridRow(int index) + { + this.BackupInfoDataGrid.Focus(); + var dataGridRow = this.BackupInfoDataGrid.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow; + if (dataGridRow != null) + { + dataGridRow.Focus(); + this.SelectBackupInfoDataGridItem(index); + + var dataGridCellsPanel = dataGridRow.GetVisualChild(); + if (dataGridCellsPanel != null) + { + if (dataGridCellsPanel.Children.Count != 0) + { + var dataGridCell = dataGridCellsPanel.Children[0] as DataGridCell; + if (dataGridCell != null) + { + dataGridCell.Focus(); + } + } + } + } + } + + private void SelectBackupInfoDataGridItem(int index) + { + this.BackupInfoDataGrid.SelectedIndex = index; + } + + private void OnDataGridMouseDoubleClick(object sender, MouseButtonEventArgs e) + { + var dataGrid = (DataGrid)sender; + var currentItemviewModel = dataGrid.CurrentItem as IBackupInfoViewModel; + if (currentItemviewModel == null) + { + return; + } + + DataGridCellInfo currentCellInfo = dataGrid.CurrentCell; + var currentColumnHeaderContentPresenter = currentCellInfo.Column.Header as ContentPresenter; + if (currentColumnHeaderContentPresenter != null) + { + var sourceColumnHeaderViewModel = + currentColumnHeaderContentPresenter.Content as ISourceColumnHeaderViewModel; + if (sourceColumnHeaderViewModel != null) + { + currentItemviewModel.ExecuteDoubleClickAction(BackupInfoPathType.Source); + } + else + { + var destinationColumnHeaderViewModel = + currentColumnHeaderContentPresenter.Content as IDestinationColumnHeaderViewModel; + if (destinationColumnHeaderViewModel != null) + { + currentItemviewModel.ExecuteDoubleClickAction(BackupInfoPathType.Destination); + } + } + } + } + + private void OnCellContentPreviewKeyDown(object sender, KeyEventArgs e) + { + Type sourceType = sender.GetType(); + + var sourceDataGridCell = ((DependencyObject)sender).SearchUpParentWithSelf(); + if (sourceDataGridCell == null) + { + return; + } + + var sourceDataGridRow = sourceDataGridCell.SearchUpParentWithSelf(); + if (sourceDataGridRow == null) + { + return; + } + + var dataGrid = sourceDataGridRow.SearchUpParentWithSelf(); + if (dataGrid == null) + { + return; + } + + int sourceRowIndex = dataGrid.Items.IndexOf(sourceDataGridRow.Item); + int targetRowIndex = -1; + switch (e.Key) + { + case Key.Up: + if (sourceRowIndex != 0) + { + targetRowIndex = sourceRowIndex - 1; + } + + break; + case Key.Down: + if (sourceRowIndex < dataGrid.Items.Count - 1) + { + targetRowIndex = sourceRowIndex + 1; + } + + break; + case Key.PageUp: + break; + case Key.PageDown: + break; + } + + if (targetRowIndex < 0) + { + return; + } + + var targetDataGridRow = dataGrid.ItemContainerGenerator.ContainerFromIndex(targetRowIndex) as DataGridRow; + if (targetDataGridRow == null) + { + return; + } + + var targetCellsPresenter = targetDataGridRow.GetVisualChild(); + if (targetCellsPresenter == null) + { + return; + } + + var targetDataGridCell = + (DataGridCell)targetCellsPresenter.ItemContainerGenerator.ContainerFromIndex(sourceDataGridCell.Column.DisplayIndex); + if (targetDataGridCell == null) + { + return; + } + + var targetElement = targetDataGridCell.GetVisualChild(sourceType) as UIElement; + if (targetElement == null) + { + return; + } + + sourceDataGridRow.IsSelected = false; + targetDataGridRow.IsSelected = true; + targetElement.Focus(); + + e.Handled = true; + } + + private void OnMainWindowPreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.F2) + { + this.StartEditCurrentCell(); + e.Handled = true; + } + else if (e.Key == Key.Escape) + { + var viewModel = this.DataContext as IMainWindowViewModel; + if (viewModel != null) + { + viewModel.OnEscKeyPressed(); + } + + e.Handled = true; + } + else if ((Keyboard.Modifiers & ModifierKeys.Control) > 0) + { + if (e.Key == Key.S) + { + var viewModel = this.DataContext as IMainWindowViewModel; + if (viewModel != null) + { + if (viewModel.SaveBackupSettingRelayCommand.CanExecute(this)) + { + viewModel.SaveBackupSettingRelayCommand.Execute(this); + e.Handled = true; + } + } + } + } + } + + private void StartEditCurrentCell() + { + var currentItemviewModel = this.BackupInfoDataGrid.CurrentItem as IBackupInfoViewModel; + if (currentItemviewModel == null) + { + return; + } + + DataGridCellInfo currentCellInfo = this.BackupInfoDataGrid.CurrentCell; + var currentColumnHeaderContentPresenter = currentCellInfo.Column.Header as ContentPresenter; + if (currentColumnHeaderContentPresenter != null) + { + if (currentColumnHeaderContentPresenter.Content is ISourceColumnHeaderViewModel) + { + currentItemviewModel.EditSourceRelayCommand.Execute(null); + this.FocusOnTextBoxInSelectedDataGridCell(); + } + else if (currentColumnHeaderContentPresenter.Content is IDestinationColumnHeaderViewModel) + { + currentItemviewModel.EditDestinationRelayCommand.Execute(null); + this.FocusOnTextBoxInSelectedDataGridCell(); + } + else if (currentColumnHeaderContentPresenter.Content is ILabelColumnHeaderViewModel) + { + this.FocusOnTextBoxInSelectedDataGridCell(); + } + } + } + + private void FocusOnTextBoxInSelectedDataGridCell() + { + DataGridCellInfo cellInfo = this.BackupInfoDataGrid.SelectedCells.FirstOrDefault(); + var cellContentPresenter = cellInfo.Column.GetCellContent(cellInfo.Item) as ContentPresenter; + if (cellContentPresenter != null) + { + var textBox = cellContentPresenter.GetVisualChild(); + if (textBox != null) + { + textBox.Focus(); + textBox.Select(textBox.Text.Length, 0); + } + } + } + + private void OnZipEncodingSelectionChanged(object sender, SelectionChangedEventArgs e) + { + // Move focus setting from the ComboBox by setting focus to the main window. + this.Focus(); + } + } +} diff --git a/Main/SimpleBackup.Views/SimpleBackup.Views.csproj b/Main/SimpleBackup.Views/SimpleBackup.Views.csproj new file mode 100644 index 0000000..7fce336 --- /dev/null +++ b/Main/SimpleBackup.Views/SimpleBackup.Views.csproj @@ -0,0 +1,118 @@ + + + + + Debug + AnyCPU + {C42B720C-323E-4E0C-ACBF-7FA9CFE228BE} + Library + Properties + SimpleBackup.Views + SimpleBackup.Views + v4.5 + 512 + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + SimpleBackupKey.snk + + + + + + + + + False + ..\Lib\Expression\Blend\.NETFramework\v4.5\Libraries\System.Windows.Interactivity.dll + + + + + + + + + + + + Properties\AssemblyInfo.cs + + + + + + + Component + + + MainWindow.xaml + + + VersionInformationWindow.xaml + + + + + + + + + + {33f1d454-9962-4eb6-aad3-8d11d9a78d1f} + SimpleBackup.Core + + + {a655131e-d439-4de1-bc39-5c955306183f} + SimpleBackup.Resources + + + + + MSBuild:Compile + Designer + + + + + MSBuild:Compile + Designer + + + + + set EXE_BIN_DIR=$(ProjectDir)..\bin\$(ConfigurationName)\ +xcopy "$(TargetDir)$(TargetName).dll" "%25EXE_BIN_DIR%25" /Y +if exist "$(TargetDir)$(TargetName).pdb" xcopy "$(TargetDir)$(TargetName).pdb" "%25EXE_BIN_DIR%25" /Y + + + \ No newline at end of file diff --git a/Main/SimpleBackup.Views/SimpleBackupKey.snk b/Main/SimpleBackup.Views/SimpleBackupKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..def2e6df6a67d7e5802b3319c2b385c61304db29 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=*mMuj7Bow@Ep}p%TfOae=&U%vR9qh+ z@B2Y7h5t%KB~GowmVCnTwn!=ol7j~SRw};|aqMe69$!Xr!@Kl)p?8Xg2;G;~Cd60S zyuxBRv<}vHJsUi)3u6Y?7~u<-nIO&1Fj-O8+VD)*I{}r1s+^@Kmf2Y}gp`|NRs+em z$u>8Tw)yg`4_#X9od;DS_`m7gjCw7)_oIM$fq-7kckw~B<7M;zI>N{SPq*6$huq7Z zgYNgU;sUWRbAi&O+L_hd!U0Li?IE-i`qYl6ItfNG&LGLWV{U{YZh>Ax4*J$khFNYOR0lC!sQ=xnj0#!GfwNKNLWeC6+{0F(k120wr_Sb zIyF(GL;3}qT}4Ed2plZ&Isj`rlkfJc)Ea1aKb3p_jTAd0vy@;AzzF|BpZp|m^l#y& zbx94OX%V&s<FnfGWY1Nh zxKnroP3(eKfbr85Y^JZ_CW>v48ZxICTuX?#TOI&z>)DFD-NiB2i|wPJnn~;|{CGZv i!2z3|Al4b1%II9A@B0rIjj|^@+oAX!*AylRLZAX-U?o=o literal 0 HcmV?d00001 diff --git a/Main/SimpleBackup.Views/VersionInformationWindow.xaml b/Main/SimpleBackup.Views/VersionInformationWindow.xaml new file mode 100644 index 0000000..0e0d9aa --- /dev/null +++ b/Main/SimpleBackup.Views/VersionInformationWindow.xaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + diff --git a/Main/SimpleBackup.Views/VersionInformationWindow.xaml.cs b/Main/SimpleBackup.Views/VersionInformationWindow.xaml.cs new file mode 100644 index 0000000..2fe79f0 --- /dev/null +++ b/Main/SimpleBackup.Views/VersionInformationWindow.xaml.cs @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System.Reflection; + using System.Windows; + using SimpleBackup.Core.Views; + + /// + /// The Code-Behind of VersionInformationWindow.xaml. + /// + internal partial class VersionInformationWindow : Window, IVersionInformationWindow + { + /// + /// Initializes a new instance of the class. + /// + public VersionInformationWindow() + { + this.InitializeComponent(); + + this.VersionInfoTextBox.Text = string.Format( + "{0} Ver.{1}\r\n{2}", + SimpleBackup.Resources.Resources.Views_CopyrightApplicationName, + Assembly.GetExecutingAssembly().GetName().Version, + SimpleBackup.Resources.Resources.Version_Copyright); + this.CopyrightTextBox.Text = SimpleBackup.Resources.Resources.Version_CopyrightDescription; + } + + /// + /// Shows the dialog window. + /// + /// + /// The result. + /// + public bool? ShowDialogWindow() + { + return this.ShowDialog(); + } + } +} diff --git a/Main/SimpleBackup.Views/ViewComponent.cs b/Main/SimpleBackup.Views/ViewComponent.cs new file mode 100644 index 0000000..6c881ea --- /dev/null +++ b/Main/SimpleBackup.Views/ViewComponent.cs @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using SimpleBackup.Core; + using SimpleBackup.Core.AppInfrastructure; + using SimpleBackup.Core.Views; + + /// + /// The view component. + /// + internal class ViewComponent : IAppComponent + { + /// + /// Initializes this application component. + /// + public void Initialize() + { + ObjectContainer.Register(new ViewFactory()); + } + } +} diff --git a/Main/SimpleBackup.Views/ViewFactory.cs b/Main/SimpleBackup.Views/ViewFactory.cs new file mode 100644 index 0000000..ea89c16 --- /dev/null +++ b/Main/SimpleBackup.Views/ViewFactory.cs @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Takayoshi Matsuyama. All rights reserved. +// +//----------------------------------------------------------------------- + +// This file is part of Simple Backup. +// +// Simple Backup is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Simple Backup is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Simple Backup. If not, see . + +namespace SimpleBackup.Views +{ + using System.Windows; + using SimpleBackup.Core.Views; + + /// + /// Creates view objects. + /// + internal class ViewFactory : IViewFactory + { + /// + /// Creates the main window. + /// + /// + /// The main window. + /// + public IMainWindow CreateMainWindow() + { + return MainWindow.CreateMainWindow(); + } + + /// + /// Creates the version information window. + /// + /// + /// The version information window. + /// + public IVersionInformationWindow CreateVersionInformationWindow() + { + return new VersionInformationWindow + { + Owner = Application.Current.MainWindow, + WindowStartupLocation = WindowStartupLocation.CenterOwner + }; + } + + /// + /// Creates the file folder dialog. + /// + /// + /// The file folder dialog. + /// + public IFileFolderDialog CreateFileFolderDialog() + { + return new FileFolderDialog(); + } + } +} diff --git a/Main/SimpleBackup.csproj b/Main/SimpleBackup.csproj index 2aaad22..05dd942 100644 --- a/Main/SimpleBackup.csproj +++ b/Main/SimpleBackup.csproj @@ -59,25 +59,22 @@ SimpleBackupKey.snk - Resources\Images\ApplicationIcon.ico + + - - False Lib\Expression\Blend\.NETFramework\v4.5\Libraries\System.Windows.Interactivity.dll + - - 4.0 - @@ -87,83 +84,11 @@ MSBuild:Compile Designer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VersionInformationWindow.xaml - - - MSBuild:Compile - Designer - + App.xaml Code - - - True - True - Resources.resx - - - - - - - - - - - - - - - - - - - - - Component - - - MainWindow.xaml - Code - - - Designer - MSBuild:Compile - @@ -183,11 +108,6 @@ ResXFileCodeGenerator Resources.Designer.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - PreserveNewest @@ -206,9 +126,6 @@ - - - False Microsoft .NET Framework 4.5 %28x86 および x64%29 @@ -226,63 +143,16 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + {33f1d454-9962-4eb6-aad3-8d11d9a78d1f} + SimpleBackup.Core + + + {a655131e-d439-4de1-bc39-5c955306183f} + SimpleBackup.Resources + +