diff --git a/RomRepoMgr.Core/EventArgs/ImportedRomEventArgs.cs b/RomRepoMgr.Core/EventArgs/ImportedRomEventArgs.cs new file mode 100644 index 0000000..1c8be3b --- /dev/null +++ b/RomRepoMgr.Core/EventArgs/ImportedRomEventArgs.cs @@ -0,0 +1,34 @@ +/****************************************************************************** +// RomRepoMgr - ROM repository manager +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// 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 . +// +// ---------------------------------------------------------------------------- +// Copyright © 2020 Natalia Portillo +*******************************************************************************/ + +using RomRepoMgr.Core.Models; + +namespace RomRepoMgr.Core.EventArgs +{ + public sealed class ImportedRomItemEventArgs : System.EventArgs + { + public ImportRomItem Item { get; set; } + } +} \ No newline at end of file diff --git a/RomRepoMgr.Core/Models/ImportRomItem.cs b/RomRepoMgr.Core/Models/ImportRomItem.cs new file mode 100644 index 0000000..af7e01b --- /dev/null +++ b/RomRepoMgr.Core/Models/ImportRomItem.cs @@ -0,0 +1,33 @@ +/****************************************************************************** +// RomRepoMgr - ROM repository manager +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// 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 . +// +// ---------------------------------------------------------------------------- +// Copyright © 2020 Natalia Portillo +*******************************************************************************/ + +namespace RomRepoMgr.Core.Models +{ + public sealed class ImportRomItem + { + public string Filename { get; set; } + public string Status { get; set; } + } +} \ No newline at end of file diff --git a/RomRepoMgr.Core/Workers/FileImporter.cs b/RomRepoMgr.Core/Workers/FileImporter.cs index 1183442..0536cd5 100644 --- a/RomRepoMgr.Core/Workers/FileImporter.cs +++ b/RomRepoMgr.Core/Workers/FileImporter.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using RomRepoMgr.Core.EventArgs; +using RomRepoMgr.Core.Models; using RomRepoMgr.Database; using RomRepoMgr.Database.Models; using SharpCompress.Compressors; @@ -18,21 +19,114 @@ namespace RomRepoMgr.Core.Workers readonly Dictionary _pendingFiles; + string _lastMessage; + long _position; + long _totalFiles; + public FileImporter(bool onlyKnown, bool deleteAfterImport) { _pendingFiles = new Dictionary(); _onlyKnown = onlyKnown; _deleteAfterImport = deleteAfterImport; + _position = 0; } - public string LastMessage { get; private set; } + public event EventHandler SetIndeterminateProgress2; + public event EventHandler SetProgressBounds2; + public event EventHandler SetProgress2; + public event EventHandler SetMessage2; + public event EventHandler SetIndeterminateProgress; + public event EventHandler SetProgressBounds; + public event EventHandler SetProgress; + public event EventHandler SetMessage; + public event EventHandler Finished; + public event EventHandler ImportedRom; - public event EventHandler SetIndeterminateProgress; - public event EventHandler SetProgressBounds; - public event EventHandler SetProgress; - public event EventHandler SetMessage; + public void ProcessPath(string path, bool rootPath, bool removePathOnFinish) + { + try + { + SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty); - public bool ImportRom(string path) + SetMessage?.Invoke(this, new MessageEventArgs + { + Message = "Enumerating files..." + }); + + string[] files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); + _totalFiles += files.LongLength; + + SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs + { + Minimum = 0, + Maximum = _totalFiles + }); + + foreach(string file in files) + { + SetProgress?.Invoke(this, new ProgressEventArgs + { + Value = _position + }); + + SetMessage?.Invoke(this, new MessageEventArgs + { + Message = string.Format("Importing {0}...", Path.GetFileName(file)) + }); + + bool ret = ImportRom(file); + + if(ret) + { + ImportedRom?.Invoke(this, new ImportedRomItemEventArgs + { + Item = new ImportRomItem + { + Filename = Path.GetFileName(file), + Status = "OK" + } + }); + } + else + { + ImportedRom?.Invoke(this, new ImportedRomItemEventArgs + { + Item = new ImportRomItem + { + Filename = Path.GetFileName(file), + Status = string.Format("Error: {0}", _lastMessage) + } + }); + } + + _position++; + } + + if(removePathOnFinish) + { + SetMessage?.Invoke(this, new MessageEventArgs + { + Message = "Removing temporary path..." + }); + + Directory.Delete(path, true); + } + + if(!rootPath) + return; + + SaveChanges(); + Finished?.Invoke(this, System.EventArgs.Empty); + } + catch(Exception) + { + // TODO: Send error back + if(rootPath) + Finished?.Invoke(this, System.EventArgs.Empty); + } + } + + bool ImportRom(string path) { try { @@ -40,7 +134,7 @@ namespace RomRepoMgr.Core.Workers byte[] dataBuffer; - SetMessage?.Invoke(this, new MessageEventArgs + SetMessage2?.Invoke(this, new MessageEventArgs { Message = "Hashing file..." }); @@ -49,7 +143,7 @@ namespace RomRepoMgr.Core.Workers if(inFs.Length > BUFFER_SIZE) { - SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs + SetProgressBounds2?.Invoke(this, new ProgressBoundsEventArgs { Minimum = 0, Maximum = inFs.Length @@ -60,7 +154,7 @@ namespace RomRepoMgr.Core.Workers for(offset = 0; offset < inFs.Length - remainder; offset += (int)BUFFER_SIZE) { - SetProgress?.Invoke(this, new ProgressEventArgs + SetProgress2?.Invoke(this, new ProgressEventArgs { Value = offset }); @@ -70,7 +164,7 @@ namespace RomRepoMgr.Core.Workers checksumWorker.Update(dataBuffer); } - SetProgress?.Invoke(this, new ProgressEventArgs + SetProgress2?.Invoke(this, new ProgressEventArgs { Value = offset }); @@ -81,7 +175,7 @@ namespace RomRepoMgr.Core.Workers } else { - SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty); + SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty); dataBuffer = new byte[inFs.Length]; inFs.Read(dataBuffer, 0, (int)inFs.Length); checksumWorker.Update(dataBuffer); @@ -112,7 +206,7 @@ namespace RomRepoMgr.Core.Workers { if(_onlyKnown) { - LastMessage = "Unknown file."; + _lastMessage = "Unknown file."; return false; } @@ -232,13 +326,13 @@ namespace RomRepoMgr.Core.Workers Stream zStream = null; zStream = new LZipStream(outFs, CompressionMode.Compress); - SetProgressBounds?.Invoke(this, new ProgressBoundsEventArgs + SetProgressBounds2?.Invoke(this, new ProgressBoundsEventArgs { Minimum = 0, Maximum = inFs.Length }); - SetMessage?.Invoke(this, new MessageEventArgs + SetMessage2?.Invoke(this, new MessageEventArgs { Message = "Compressing file..." }); @@ -247,7 +341,7 @@ namespace RomRepoMgr.Core.Workers while(inFs.Position + BUFFER_SIZE <= inFs.Length) { - SetProgress?.Invoke(this, new ProgressEventArgs + SetProgress2?.Invoke(this, new ProgressEventArgs { Value = inFs.Position }); @@ -258,7 +352,7 @@ namespace RomRepoMgr.Core.Workers buffer = new byte[inFs.Length - inFs.Position]; - SetProgress?.Invoke(this, new ProgressEventArgs + SetProgress2?.Invoke(this, new ProgressEventArgs { Value = inFs.Position }); @@ -266,9 +360,9 @@ namespace RomRepoMgr.Core.Workers inFs.Read(buffer, 0, buffer.Length); zStream.Write(buffer, 0, buffer.Length); - SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty); + SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty); - SetMessage?.Invoke(this, new MessageEventArgs + SetMessage2?.Invoke(this, new MessageEventArgs { Message = "Finishing..." }); @@ -290,17 +384,17 @@ namespace RomRepoMgr.Core.Workers } catch(Exception e) { - LastMessage = "Unhandled exception when importing file."; + _lastMessage = "Unhandled exception when importing file."; return false; } } - public void SaveChanges() + void SaveChanges() { - SetIndeterminateProgress?.Invoke(this, System.EventArgs.Empty); + SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty); - SetMessage?.Invoke(this, new MessageEventArgs + SetMessage2?.Invoke(this, new MessageEventArgs { Message = "Saving changes to database..." }); diff --git a/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs b/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs index c5d05fc..863e4be 100644 --- a/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs +++ b/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs @@ -25,14 +25,13 @@ using System; using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IO; using System.Reactive; using System.Threading.Tasks; using Avalonia.Threading; using JetBrains.Annotations; using ReactiveUI; using RomRepoMgr.Core.EventArgs; +using RomRepoMgr.Core.Models; using RomRepoMgr.Core.Workers; using RomRepoMgr.Views; @@ -69,7 +68,7 @@ namespace RomRepoMgr.ViewModels _removeFilesChecked = false; _knownOnlyChecked = true; _recurseArchivesChecked = Settings.Settings.UnArUsable; - ImportResults = new ObservableCollection(); + ImportResults = new ObservableCollection(); CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand); StartCommand = ReactiveCommand.Create(ExecuteStartCommand); IsReady = true; @@ -203,11 +202,11 @@ namespace RomRepoMgr.ViewModels [NotNull] public string Title => "Import ROM files from folder..."; - public ObservableCollection ImportResults { get; } - public string ResultFilenameLabel => "Filename"; - public string ResultStatusLabel => "Status"; - public string CloseLabel => "Close"; - public string StartLabel => "Start"; + public ObservableCollection ImportResults { get; } + public string ResultFilenameLabel => "Filename"; + public string ResultStatusLabel => "Status"; + public string CloseLabel => "Close"; + public string StartLabel => "Start"; public bool CanClose { @@ -228,106 +227,68 @@ namespace RomRepoMgr.ViewModels void ExecuteStartCommand() { - IsReady = false; - ProgressVisible = true; - ProgressIsIndeterminate = true; - StatusMessage = "Enumerating files..."; - IsImporting = true; - CanStart = false; - CanClose = false; + IsReady = false; + ProgressVisible = true; + IsImporting = true; + CanStart = false; + CanClose = false; - Task.Run(() => - { - var watch = new Stopwatch(); - string[] files = Directory.GetFiles(FolderPath, "*", SearchOption.AllDirectories); + var worker = new FileImporter(KnownOnlyChecked, RemoveFilesChecked); + worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress; + worker.SetMessage += OnWorkerOnSetMessage; + worker.SetProgress += OnWorkerOnSetProgress; + worker.SetProgressBounds += OnWorkerOnSetProgressBounds; + worker.SetIndeterminateProgress2 += OnWorkerOnSetIndeterminateProgress2; + worker.SetMessage2 += OnWorkerOnSetMessage2; + worker.SetProgress2 += OnWorkerOnSetProgress2; + worker.SetProgressBounds2 += OnWorkerOnSetProgressBounds2; + worker.Finished += OnWorkerOnFinished; + worker.ImportedRom += OnWorkerOnImportedRom; - Dispatcher.UIThread.Post(() => - { - ProgressIsIndeterminate = false; - ProgressMinimum = 0; - ProgressMaximum = files.LongLength; - ProgressValue = 0; - Progress2Visible = true; - }); - - var worker = new FileImporter(KnownOnlyChecked, RemoveFilesChecked); - worker.SetIndeterminateProgress += OnWorkerOnSetIndeterminateProgress; - worker.SetMessage += OnWorkerOnSetMessage; - worker.SetProgress += OnWorkerOnSetProgress; - worker.SetProgressBounds += OnWorkerOnSetProgressBounds; - - long position = 0; - watch.Start(); - - foreach(string file in files) - { - Dispatcher.UIThread.Post(() => - { - StatusMessage = string.Format("Importing {0}...", Path.GetFileName(file)); - ProgressValue = position; - }); - - bool ret = worker.ImportRom(file); - - Dispatcher.UIThread.Post(() => - { - if(ret) - { - ImportResults.Add(new ImportRomFolderItem - { - Filename = Path.GetFileName(file), - Status = "OK" - }); - } - else - { - ImportResults.Add(new ImportRomFolderItem - { - Filename = Path.GetFileName(file), - Status = string.Format("Error: {0}", worker.LastMessage) - }); - } - }); - - position++; - } - - worker.SaveChanges(); - - watch.Stop(); - - Dispatcher.UIThread.Post(() => - { - ProgressVisible = false; - StatusMessage = "Finished!"; - CanClose = true; - Progress2Visible = false; - - Console.WriteLine($"Took {watch.Elapsed.TotalSeconds} seconds"); - }); - }); + Task.Run(() => worker.ProcessPath(FolderPath, true, false)); } + void OnWorkerOnImportedRom(object? sender, ImportedRomItemEventArgs args) => + Dispatcher.UIThread.Post(() => ImportResults.Add(args.Item)); + + void OnWorkerOnFinished(object? sender, EventArgs args) => Dispatcher.UIThread.Post(() => + { + ProgressVisible = false; + StatusMessage = "Finished!"; + CanClose = true; + Progress2Visible = false; + }); + void OnWorkerOnSetProgressBounds(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() => + { + ProgressIsIndeterminate = false; + ProgressMaximum = args.Maximum; + ProgressMinimum = args.Minimum; + }); + + void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) => + Dispatcher.UIThread.Post(() => ProgressValue = args.Value); + + void OnWorkerOnSetMessage(object sender, MessageEventArgs args) => + Dispatcher.UIThread.Post(() => StatusMessage = args.Message); + + void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) => + Dispatcher.UIThread.Post(() => ProgressIsIndeterminate = true); + + void OnWorkerOnSetProgressBounds2(object sender, ProgressBoundsEventArgs args) => Dispatcher.UIThread.Post(() => { Progress2IsIndeterminate = false; Progress2Maximum = args.Maximum; Progress2Minimum = args.Minimum; }); - void OnWorkerOnSetProgress(object sender, ProgressEventArgs args) => + void OnWorkerOnSetProgress2(object sender, ProgressEventArgs args) => Dispatcher.UIThread.Post(() => Progress2Value = args.Value); - void OnWorkerOnSetMessage(object sender, MessageEventArgs args) => + void OnWorkerOnSetMessage2(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() => Status2Message = args.Message); - void OnWorkerOnSetIndeterminateProgress(object sender, EventArgs args) => + void OnWorkerOnSetIndeterminateProgress2(object sender, EventArgs args) => Dispatcher.UIThread.Post(() => Progress2IsIndeterminate = true); } - - public sealed class ImportRomFolderItem - { - public string Filename { get; set; } - public string Status { get; set; } - } } \ No newline at end of file