diff --git a/App/App.csproj b/App/App.csproj index 5cc92b7..43db4a0 100644 --- a/App/App.csproj +++ b/App/App.csproj @@ -1,7 +1,7 @@ WinExe - net472 + net48 osu! Collection Manager Gui Copyright © 2017-present Piotrekol diff --git a/App/BeatmapListingActionsHandler.cs b/App/BeatmapListingActionsHandler.cs index 958f99e..a02dae4 100644 --- a/App/BeatmapListingActionsHandler.cs +++ b/App/BeatmapListingActionsHandler.cs @@ -9,10 +9,16 @@ using CollectionManagerExtensionsDll.Utils; using Common; using GuiComponents.Interfaces; +using SharpCompress.Archives.Zip; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; +using System.IO; +using System.IO.Compression; using System.Linq; +using System.Text; +using System.Threading; namespace App { @@ -42,24 +48,124 @@ public BeatmapListingActionsHandler(ICollectionEditor collectionEditor, IUserDia {BeatmapListingAction.OpenBeatmapPages, OpenBeatmapPages }, {BeatmapListingAction.OpenBeatmapFolder, OpenBeatmapFolder }, {BeatmapListingAction.PullWholeMapSet, PullWholeMapsets }, + {BeatmapListingAction.ExportBeatmapSets, ExportBeatmapSets }, }; } - public void Bind(IBeatmapListingModel beatmapListingModel) + public void Bind(IBeatmapListingModel beatmapListingModel, ICollectionListingModel collectionListingModel = null) { beatmapListingModel.BeatmapOperation += BeatmapListingModel_BeatmapOperation; + if (collectionListingModel != null) + collectionListingModel.CollectionEditing += CollectionListingModel_CollectionEditing; } - - public void UnBind(IBeatmapListingModel beatmapListingModel) + public void UnBind(IBeatmapListingModel beatmapListingModel, ICollectionListingModel collectionListingModel = null) { beatmapListingModel.BeatmapOperation -= BeatmapListingModel_BeatmapOperation; + if (collectionListingModel != null) + collectionListingModel.CollectionEditing -= CollectionListingModel_CollectionEditing; } private void BeatmapListingModel_BeatmapOperation(object sender, BeatmapListingAction args) { _beatmapOperationHandlers[args](sender); } + private void CollectionListingModel_CollectionEditing(object sender, CollectionEditArgs e) + { + if (e.Action != CollectionManager.Enums.CollectionEdit.ExportBeatmaps) + return; + + ExportBeatmapSets(e.Collections.AllBeatmaps().Cast().ToList()); + } + + private void ExportBeatmapSets(object sender) + { + if (sender is not IBeatmapListingModel beatmapListingModel) + return; + + ExportBeatmapSets(beatmapListingModel.SelectedBeatmaps?.ToList()); + } + + private void ExportBeatmapSets(List beatmaps) + { + if (beatmaps?.Count == 0) + { + _userDialogs.OkMessageBox("No beatmaps selected", "Info"); + return; + } + + var saveDirectory = _userDialogs.SelectDirectory("Select directory for exported maps", true); + var beatmapSets = beatmaps.Where(b => !string.IsNullOrWhiteSpace(b.Dir)).Select(b => (Beatmap: b, FileName: OsuDownloadManager.CreateOszFileName(b))) + .GroupBy(e => e.FileName).Select(e => e.First()).ToList(); + if (!Directory.Exists(saveDirectory)) + return; + + var backgroundWorker = new BackgroundWorker(); + var stringProgress = new Progress(); + var percentageProgress = new Progress(); + using var cancelationTokenSource = new CancellationTokenSource(); + var progressForm = _userDialogs.ProgressForm(stringProgress, percentageProgress); + progressForm.AbortClicked += (_, __) => cancelationTokenSource.Cancel(); + backgroundWorker.DoWork += (_, eventArgs) => + { + var cancellationToken = cancelationTokenSource.Token; + var totalCount = beatmapSets.Count(); + var stringProgressReporter = (IProgress)stringProgress; + var percentageProgressReporter = (IProgress)percentageProgress; + var failedMapSets = new StringBuilder(); + var failedMapSetsCount = 0; + for (int i = 0; i < totalCount; i++) + { + var beatmapset = beatmapSets[i]; + if (cancellationToken.IsCancellationRequested) + { + progressForm.Close(); + return; + } + + stringProgressReporter.Report($"Processing map set {i + 1} of {totalCount}.{Environment.NewLine}\"{beatmapset.FileName}\""); + var fileSaveLocation = Path.Combine(saveDirectory, beatmapset.FileName); + if (File.Exists(fileSaveLocation)) + { + percentageProgressReporter.Report(Convert.ToInt32((double)(i + 1) / totalCount * 100)); + continue; + } + + var beatmapDirectory = beatmapset.Beatmap.BeatmapDirectory(); + if (!Directory.Exists(beatmapDirectory)) + { + failedMapSets.AppendFormat("map set directory \"{0}\" doesn't exist - set skipped(mapId:{1} setId:{2} hash:{3}) {4}{4}", beatmapDirectory, beatmapset.Beatmap.MapId.ToString(), beatmapset.Beatmap.MapSetId.ToString(), beatmapset.Beatmap.Md5, Environment.NewLine); + failedMapSetsCount++; + } + else + { + try + { + ZipFile.CreateFromDirectory(beatmapDirectory, fileSaveLocation); + } + catch (Exception e) + { + failedMapSets.AppendFormat("failed processing map set located at \"{0}\" with exception:{2}{1}{2}{2}", beatmapDirectory, e, Environment.NewLine); + failedMapSetsCount++; + } + + percentageProgressReporter.Report(Convert.ToInt32((double)(i + 1) / totalCount * 100)); + } + } + + if (failedMapSetsCount > 0) + { + File.WriteAllText(Path.Combine(saveDirectory, "log.txt"), failedMapSets.ToString()); + stringProgressReporter.Report($"Processed {totalCount - failedMapSetsCount} of {totalCount} map sets.{Environment.NewLine}{failedMapSetsCount} map sets failed to save, see full log in log.txt file in export directory"); + } + else + stringProgressReporter.Report($"Processed {totalCount} map sets without issues."); + }; + + backgroundWorker.RunWorkerAsync(); + progressForm.ShowAndBlock(); + } + private void PullWholeMapsets(object sender) { var model = (IBeatmapListingModel)sender; diff --git a/App/CollectionEditor.cs b/App/CollectionEditor.cs index faea4df..18c9689 100644 --- a/App/CollectionEditor.cs +++ b/App/CollectionEditor.cs @@ -48,7 +48,7 @@ public void EditCollection(CollectionEditArgs e) break; } } - else if (e.Action == CollectionEdit.Intersect) + else if (e.Action == CollectionEdit.Intersect || e.Action == CollectionEdit.Difference) { if (e.Collections.Count < 2) return; diff --git a/App/GuiActionsHandler.cs b/App/GuiActionsHandler.cs index 63cfbaa..ede4595 100644 --- a/App/GuiActionsHandler.cs +++ b/App/GuiActionsHandler.cs @@ -22,7 +22,7 @@ public GuiActionsHandler(OsuFileIo osuFileIo, ICollectionEditor collectionEditor SidePanelActionsHandler = new SidePanelActionsHandler(osuFileIo, collectionEditor, userDialogs, mainFormView, this, mainFormPresenter, loginForm); _beatmapListingActionsHandler = new BeatmapListingActionsHandler(collectionEditor, userDialogs, loginForm, osuFileIo); - _beatmapListingActionsHandler.Bind(mainFormPresenter.BeatmapListingModel); + _beatmapListingActionsHandler.Bind(mainFormPresenter.BeatmapListingModel, mainFormPresenter.CollectionListingModel); Initalizer.CollectionsManager.LoadedCollections.CollectionChanged += LoadedCollectionsOnCollectionChanged; } @@ -47,12 +47,12 @@ private void LoadedCollectionsOnCollectionChanged(object sender, NotifyCollectio public void Bind(IBeatmapListingModel model) { - _beatmapListingActionsHandler.Bind(model); + _beatmapListingActionsHandler.Bind(model, null); } public void UnBind(IBeatmapListingModel model) { - _beatmapListingActionsHandler.UnBind(model); + _beatmapListingActionsHandler.UnBind(model, null); } } } \ No newline at end of file diff --git a/App/Initalizer.cs b/App/Initalizer.cs index 72fa9b3..0ef2654 100644 --- a/App/Initalizer.cs +++ b/App/Initalizer.cs @@ -1,18 +1,17 @@ -using System; using System.IO; +using System.Threading.Tasks; using System.Windows.Forms; using App.Interfaces; using App.Misc; using App.Models; using App.Models.Forms; +using App.Presenters.Controls; using App.Presenters.Forms; using App.Properties; using CollectionManager.DataTypes; using CollectionManager.Modules.CollectionsManager; using CollectionManager.Modules.FileIO; using CollectionManagerExtensionsDll.Modules.API.osustats; -using CollectionManagerExtensionsDll.Utils; -using Common; using GuiComponents.Interfaces; namespace App @@ -27,51 +26,14 @@ public class Initalizer : ApplicationContext public static CollectionEditor CollectionEditor { get; private set; } private IUserDialogs UserDialogs { get; set; }// = new GuiComponents.UserDialogs(); public static OsuStatsApi WebCollectionProvider = new OsuStatsApi("", OsuFileIo.LoadedMaps); - public void Run(string[] args) + public static StartupPresenter StartupPresenter; + + public async Task Run(string[] args) { //IUserDialogs can be implemented in WinForm or WPF or Gtk or Console or...? UserDialogs = GuiComponentsProvider.Instance.GetClassImplementing(); - if (Settings.Default.DontAskAboutOsuDirectory) - OsuDirectory = OsuFileIo.OsuPathResolver.GetOsuDir(_ => false, _ => Settings.Default.OsuDirectory); - else - OsuDirectory = OsuFileIo.OsuPathResolver.GetOsuDir(dir => - { - var result = UserDialogs.YesNoMessageBox($"Detected osu! in \"{dir}\"{Environment.NewLine}Is that correct?", "osu! directory", MessageBoxType.Question, - "Don't ask me again"); - Settings.Default.DontAskAboutOsuDirectory = result.doNotAskAgain; - Settings.Default.Save(); - return result.Result; - }, UserDialogs.SelectDirectory); - - if (string.IsNullOrEmpty(OsuDirectory) && UserDialogs.YesNoMessageBox( - "osu! could not be found. Do you want to continue regardless?" + Environment.NewLine + - "This will cause all .db collections to show only as beatmap hashes.", "osu! location", - MessageBoxType.Question) == false) - { - Quit(); - } - - if (!string.IsNullOrEmpty(OsuDirectory)) - { - Settings.Default.OsuDirectory = OsuDirectory; - Settings.Default.Save(); - //Load osu database and setting files - var osuDbFile = Path.Combine(OsuDirectory, @"osu!.db"); - var osuScoresFile = Path.Combine(OsuDirectory, @"scores.db"); - OsuFileIo.OsuDatabase.Load(osuDbFile); - OsuFileIo.OsuSettings.Load(OsuDirectory); - try - { - OsuFileIo.ScoresLoader.ReadDb(osuScoresFile); - } - catch (Exception e) - { - UserDialogs.OkMessageBox("Warning", "osu! scores database could not be loaded. Score related searches will not work in this session." + Environment.NewLine + Environment.NewLine + e); - } - BeatmapUtils.OsuSongsDirectory = OsuFileIo.OsuSettings.CustomBeatmapDirectoryLocation; - } //Init "main" classes CollectionsManager = new CollectionsManagerWithCounts(LoadedBeatmaps); @@ -89,6 +51,11 @@ public void Run(string[] args) //set initial text info and update events SetTextData(infoTextModel); + var loginForm = GuiComponentsProvider.Instance.GetClassImplementing(); + var guiActionsHandler = new GuiActionsHandler(OsuFileIo, CollectionsManager, UserDialogs, mainForm, mainPresenter, loginForm); + + if (!string.IsNullOrWhiteSpace(Settings.Default.Osustats_apiKey)) + guiActionsHandler.SidePanelActionsHandler.OsustatsLogin(null, Settings.Default.Osustats_apiKey); if (args.Length > 0) { @@ -98,13 +65,12 @@ public void Run(string[] args) } } - var loginForm = GuiComponentsProvider.Instance.GetClassImplementing(); - var guiActionsHandler = new GuiActionsHandler(OsuFileIo, CollectionsManager, UserDialogs, mainForm, mainPresenter, loginForm); - - if (!string.IsNullOrWhiteSpace(Settings.Default.Osustats_apiKey)) - guiActionsHandler.SidePanelActionsHandler.OsustatsLogin(null, Settings.Default.Osustats_apiKey); + StartupPresenter = new StartupPresenter(GuiComponentsProvider.Instance.GetClassImplementing(), guiActionsHandler.SidePanelActionsHandler, UserDialogs, CollectionsManager); + await StartupPresenter.Run(); + mainForm.ShowAndBlock(); + Quit(); } @@ -125,7 +91,7 @@ private void SetTextData(IInfoTextModel model) } - private static void Quit() + public static void Quit() { Settings.Default.Save(); diff --git a/App/Misc/CollectionEditArgsExtension.cs b/App/Misc/CollectionEditArgsExtension.cs new file mode 100644 index 0000000..4d6f4bf --- /dev/null +++ b/App/Misc/CollectionEditArgsExtension.cs @@ -0,0 +1,26 @@ +using CollectionManager.DataTypes; +using CollectionManager.Enums; +using CollectionManager.Modules.CollectionsManager; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace App.Misc +{ + internal class CollectionEditArgsExtension : CollectionEditArgs + { + public CollectionEditArgsExtension(CollectionEdit action) : base(action) + { + } + + public static CollectionEditArgs ExportBeatmaps(Collections collections) + { + return new CollectionEditArgsExtension(CollectionEdit.ExportBeatmaps) + { + Collections = collections + }; + } + } +} diff --git a/App/Models/StartupSettings.cs b/App/Models/StartupSettings.cs new file mode 100644 index 0000000..917c63c --- /dev/null +++ b/App/Models/StartupSettings.cs @@ -0,0 +1,12 @@ +using Common; + +namespace App.Models +{ + public class StartupSettings + { + public StartupDatabaseAction StartupDatabaseAction { get; set; } + public StartupCollectionAction StartupCollectionAction { get; set; } + public bool AutoLoadMode { get; set; } + public string OsuLocation { get; set; } + } +} \ No newline at end of file diff --git a/App/OsuDownloadManager.cs b/App/OsuDownloadManager.cs index 4ef2841..70060b0 100644 --- a/App/OsuDownloadManager.cs +++ b/App/OsuDownloadManager.cs @@ -156,7 +156,7 @@ private DownloadItem GetDownloadItem(Beatmap beatmap) if (beatmap.MapSetId < 1 || ListedMapSetIds.Contains(beatmap.MapSetId)) return null; long currentId = ++_downloadId; - var oszFileName = CreateFileName(beatmap); + var oszFileName = CreateOszFileName(beatmap); var downloadUrl = string.Format(SelectedDownloadSource.BaseDownloadUrl, beatmap.MapSetId) + (DownloadWithVideo != null && DownloadWithVideo.Value ? string.Empty : "?noVideo=1"); var downloadItem = _mapDownloader.DownloadFileAsync(downloadUrl, oszFileName, string.Format(SelectedDownloadSource.Referer, beatmap.MapSetId), currentId,SelectedDownloadSource.RequestTimeout); @@ -164,7 +164,7 @@ private DownloadItem GetDownloadItem(Beatmap beatmap) return downloadItem; } - private string CreateFileName(Beatmap map) + public static string CreateOszFileName(Beatmap map) { var filename = map.MapSetId + " " + map.ArtistRoman + " - " + map.TitleRoman; return Helpers.StripInvalidFileNameCharacters(filename, "_") + ".osz"; diff --git a/App/Presenters/Controls/BeatmapThumbnailPresenter.cs b/App/Presenters/Controls/BeatmapThumbnailPresenter.cs index a1fc521..eff096c 100644 --- a/App/Presenters/Controls/BeatmapThumbnailPresenter.cs +++ b/App/Presenters/Controls/BeatmapThumbnailPresenter.cs @@ -57,7 +57,7 @@ private void LoadData(BeatmapExtension beatmap) if (imgPath != "") img = Image.FromFile(imgPath); else if (beatmap.MapSetId > 0) - url = "https://assets.ppy.sh//beatmaps/"+beatmap.MapSetId+"/covers/card.jpg"; + url = "https://assets.ppy.sh/beatmaps/"+beatmap.MapSetId+"/covers/card.jpg"; if (currentId != Interlocked.Read(ref changeId)) { img?.Dispose(); diff --git a/App/Presenters/Controls/CollectionListingPresenter.cs b/App/Presenters/Controls/CollectionListingPresenter.cs index 08b6e9e..55dea2d 100644 --- a/App/Presenters/Controls/CollectionListingPresenter.cs +++ b/App/Presenters/Controls/CollectionListingPresenter.cs @@ -7,6 +7,8 @@ using System.Windows.Forms; using System.Collections.Specialized; using App.Misc; +using Common; +using App.Properties; namespace App.Presenters.Controls { @@ -15,7 +17,8 @@ public class CollectionListingPresenter ICollectionListingView _view; private Collections _collections; - private ICollectionListingModel _model; + private readonly ICollectionListingModel _model; + private readonly IUserDialogs _userDialogs; public Collections Collections { @@ -32,23 +35,39 @@ public Collections Collections _view.SelectedCollection = selectedCollection; } } - public CollectionListingPresenter(ICollectionListingView view, ICollectionListingModel model) + public CollectionListingPresenter(ICollectionListingView view, ICollectionListingModel model, IUserDialogs userDialogs) { _view = view; _view.RightClick += _view_RightClick; _view.SelectedCollectionsChanged += ViewOnSelectedCollectionsChanged; _view.BeatmapsDropped += ViewOnBeatmapsDropped; + _view.OnCollectionReorder += ViewOnCollectionReorder; _model = model; + _userDialogs = userDialogs; _model.CollectionsChanged += ModelOnCollectionsChanged; Collections = _model.GetCollections(); } + private void ViewOnCollectionReorder(object sender, Collections collections, Collection targetCollection, bool placeBefore) + { + if (!Settings.Default.DontAskAboutReorderingCollections) + { + var result = _userDialogs.YesNoMessageBox($"Reordering collections will rename all loaded collections, proceed?", "Reordering", MessageBoxType.Question, + "Don't ask me again"); + Settings.Default.DontAskAboutReorderingCollections = result.doNotAskAgain; + Settings.Default.Save(); + if (!result.Result) + return; + } + + _model.EmitCollectionEditing(CollectionEditArgs.ReorderCollections(collections, targetCollection, placeBefore)); + } + private void ViewOnBeatmapsDropped(object sender, Beatmaps args, string collectionName) { _model.EmitCollectionEditing(CollectionEditArgs.AddBeatmaps(collectionName, args)); } - private void ViewOnSelectedCollectionsChanged(object sender, EventArgs eventArgs) { Collections selectedCollections = new Collections(); @@ -85,6 +104,11 @@ private void _view_RightClick(object sender, Gui.Misc.StringEventArgs e) return; args = CollectionEditArgs.InverseCollections(selectedCollections, selectedCollections[0].Name); break; + case "Difference": + if (selectedCollections == null) + return; + args = CollectionEditArgs.DifferenceCollections(selectedCollections, selectedCollections[0].Name); + break; case "Create": args = CollectionEditArgs.AddCollections(null); break; @@ -99,6 +123,12 @@ private void _view_RightClick(object sender, Gui.Misc.StringEventArgs e) args = CollectionEditArgs.DuplicateCollection(_view.SelectedCollection); break; + case "Export": + if (selectedCollections == null) + return; + + args = CollectionEditArgsExtension.ExportBeatmaps(selectedCollections); + break; case "Copy": if (selectedCollections == null) return; diff --git a/App/Presenters/Controls/CombinedListingPresenter.cs b/App/Presenters/Controls/CombinedListingPresenter.cs index 2bfa93f..33e5c59 100644 --- a/App/Presenters/Controls/CombinedListingPresenter.cs +++ b/App/Presenters/Controls/CombinedListingPresenter.cs @@ -14,9 +14,10 @@ public class CombinedListingPresenter private readonly ICollectionListingView _collectionsView; public readonly IBeatmapListingModel BeatmapListingModel; private readonly IWebCollectionProvider _webCollectionProvider; + private readonly IUserDialogs _userDialogs; private readonly ICollectionListingModel _collectionListingModel; - public CombinedListingPresenter(ICombinedListingView view, ICollectionListingModel collectionListingModel, IBeatmapListingModel beatmapListingModel, IWebCollectionProvider webCollectionProvider) + public CombinedListingPresenter(ICombinedListingView view, ICollectionListingModel collectionListingModel, IBeatmapListingModel beatmapListingModel, IWebCollectionProvider webCollectionProvider, IUserDialogs userDialogs) { _view = view; _beatmapsView = _view.beatmapListingView; @@ -26,8 +27,9 @@ public CombinedListingPresenter(ICombinedListingView view, ICollectionListingMod BeatmapListingModel = beatmapListingModel; _webCollectionProvider = webCollectionProvider; + _userDialogs = userDialogs; new BeatmapListingPresenter(_beatmapsView, BeatmapListingModel); - new CollectionListingPresenter(_collectionsView, collectionListingModel); + new CollectionListingPresenter(_collectionsView, collectionListingModel, userDialogs); BeatmapListingModel.SelectedBeatmapsChanged += BeatmapListingModelOnSelectedBeatmapsChanged; _collectionsView.SelectedCollectionChanged += CollectionsViewOnSelectedCollectionChanged; diff --git a/App/Presenters/Controls/MusicControlPresenter.cs b/App/Presenters/Controls/MusicControlPresenter.cs index c7088fc..5bf1d34 100644 --- a/App/Presenters/Controls/MusicControlPresenter.cs +++ b/App/Presenters/Controls/MusicControlPresenter.cs @@ -112,7 +112,7 @@ private void ModelOnBeatmapChanged(object sender, EventArgs eventArgs) if (map == null || !_view.IsAutoPlayEnabled) return; var audioLocation = ((BeatmapExtension)map).FullAudioFileLocation(); - if (ShouldSkipTrack(audioLocation)) + if (ShouldSkipTrack(map, audioLocation)) { //Run as worker to avoid eventual stack overflow exception (eg. too many maps with no audio file in a row) RunAsWorker(() => _model.EmitNextMapRequest()); @@ -122,29 +122,47 @@ private void ModelOnBeatmapChanged(object sender, EventArgs eventArgs) PlayBeatmap(map); } - private bool ShouldSkipTrack(string audioLocation) + private bool ShouldSkipTrack(Beatmap map, string audioLocation) { - if ((_lastAudioFileLocation == audioLocation || string.IsNullOrWhiteSpace(audioLocation)) && - _view.IsMusicPlayerMode && !musicPlayer.IsPlaying) + //Skip repeating _audio files_(diferent diffs in same mapset) whenever _playing_ in _music player mode_ + if (_view.IsMusicPlayerMode && _lastAudioFileLocation == audioLocation && !musicPlayer.IsPlaying) return true; - return !File.Exists(audioLocation); + //Play if we have _audio file_ localy + if (File.Exists(audioLocation)) + return false; + + //Skip since we don't have local audio file in _music player mode_ + if (_view.IsMusicPlayerMode) + return true; + + //this is user-invoked play request (_music player mode_ check above) + //Is there a chance that preview of this beatmap exists in online source? + return map.MapSetId <= 20; } + private void PlayBeatmap(Beatmap map) { var audioLocation = ((BeatmapExtension)map).FullAudioFileLocation(); - if (audioLocation != string.Empty) + bool onlineSource = false; + if (audioLocation == string.Empty) { - RunAsWorker(() => - { - resetEvent.WaitOne(250); - if (map.Equals(_model.CurrentBeatmap)) - { - musicPlayer.Play(audioLocation, - _view.IsMusicPlayerMode ? 0 : Convert.ToInt32(Math.Round(map.PreviewTime / 1000f))); - } - }); + if (map.MapSetId <= 20) + return; + + onlineSource = true; + audioLocation = $@"https://b.ppy.sh/preview/{map.MapSetId}.mp3"; } + + RunAsWorker(() => + { + resetEvent.WaitOne(250); + if (map.Equals(_model.CurrentBeatmap)) + { + musicPlayer.Play(audioLocation, + _view.IsMusicPlayerMode || onlineSource ? 0 : Convert.ToInt32(Math.Round(map.PreviewTime / 1000f))); + } + }); } private void RunAsWorker(Action action) { diff --git a/App/Presenters/Controls/StartupPresenter.cs b/App/Presenters/Controls/StartupPresenter.cs new file mode 100644 index 0000000..6572d40 --- /dev/null +++ b/App/Presenters/Controls/StartupPresenter.cs @@ -0,0 +1,200 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using App.Models; +using App.Properties; +using CollectionManager.Modules.CollectionsManager; +using CollectionManagerExtensionsDll.Utils; +using Common; +using GuiComponents.Interfaces; +using Newtonsoft.Json; + +namespace App.Presenters.Controls +{ + public class StartupPresenter + { + private readonly IStartupForm _form; + private readonly IStartupView _view; + private readonly SidePanelActionsHandler _sidePanelActionsHandler; + private readonly IUserDialogs _userDialogs; + private readonly CollectionsManagerWithCounts _collectionsManager; + private StartupSettings _startupSettings; + private CancellationTokenSource _cancellationTokenSource; + private Progress _databaseLoadProgressReporter; + private Task _databaseLoadTask; + private bool _formClosedManually; + + public StartupPresenter(IStartupForm view, SidePanelActionsHandler sidePanelActionsHandler, IUserDialogs userDialogs, CollectionsManagerWithCounts collectionsManager) + { + _form = view; + _view = view.StartupView; + _sidePanelActionsHandler = sidePanelActionsHandler; + _userDialogs = userDialogs; + _collectionsManager = collectionsManager; + _startupSettings = JsonConvert.DeserializeObject(Settings.Default.StartupSettings) ?? new StartupSettings(); + _cancellationTokenSource = new CancellationTokenSource(); + _databaseLoadProgressReporter = new Progress(report => + { + if (string.IsNullOrEmpty(Initalizer.OsuDirectory)) + _view.LoadDatabaseStatusText = report; + else + _view.LoadDatabaseStatusText = $"osu! location: \"{Initalizer.OsuDirectory}\"{Environment.NewLine}{report}"; + }); + + _view.UseSelectedOptionsOnStartup = _startupSettings.AutoLoadMode; + _form.Closing += _view_Closing; + _view.StartupCollectionOperation += _view_StartupCollectionOperation; + _view.StartupDatabaseOperation += _view_StartupDatabaseOperation; + } + + public async Task Run() + { + if (_startupSettings.AutoLoadMode && _startupSettings.StartupDatabaseAction == StartupDatabaseAction.Unload) + { + DoCollectionAction(); + return; + } + + var loadedCollectionFromFile = _collectionsManager.CollectionsCount != 0; + Application.UseWaitCursor = loadedCollectionFromFile || _startupSettings.AutoLoadMode; + _view.UseSelectedOptionsOnStartupEnabled = !loadedCollectionFromFile; + _view.CollectionButtonsEnabled = !(loadedCollectionFromFile || _startupSettings.AutoLoadMode); + _view.DatabaseButtonsEnabled = true; + _view.CollectionStatusText = loadedCollectionFromFile + ? $"Going to load {_collectionsManager.CollectionsCount} collections with {_collectionsManager.BeatmapsInCollectionsCount} beatmaps" + : string.Empty; + + _databaseLoadTask = Task.Run(() => + { + LoadDatabase(_cancellationTokenSource.Token); + Application.UseWaitCursor = false; + _view.CollectionButtonsEnabled = true; + }); + if (_startupSettings.AutoLoadMode) + _form.Show(); + else + _form.ShowAndBlock(); + + await _databaseLoadTask; + _startupSettings.AutoLoadMode = _view.UseSelectedOptionsOnStartup; + if (!loadedCollectionFromFile) + SaveSettings(); + + DoCollectionAction(); + CloseForm(); + } + + private void DoCollectionAction() + { + switch (_startupSettings.StartupCollectionAction) + { + case StartupCollectionAction.None: + break; + case StartupCollectionAction.LoadCollectionFromFile: + _sidePanelActionsHandler.LoadCollectionFile(); + break; + case StartupCollectionAction.LoadOsuCollection: + _sidePanelActionsHandler.LoadOsuCollection(); + break; + } + } + + private async void _view_StartupDatabaseOperation(object sender, StartupDatabaseAction args) + { + _startupSettings.StartupDatabaseAction = args; + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = new CancellationTokenSource(); + await _databaseLoadTask; + switch (args) + { + case StartupDatabaseAction.Unload: + Initalizer.OsuFileIo.OsuDatabase.LoadedMaps.UnloadBeatmaps(); + Initalizer.OsuFileIo.ScoresDatabase.Clear(); + Initalizer.OsuDirectory = null; + _view.LoadOsuCollectionButtonEnabled = false; + GC.Collect(); + ((IProgress)_databaseLoadProgressReporter).Report("osu! database unloaded"); + break; + case StartupDatabaseAction.LoadFromDifferentLocation: + var osuDirectory = Initalizer.OsuFileIo.OsuPathResolver.GetManualOsuDir(_userDialogs.SelectDirectory); + if (!string.IsNullOrEmpty(osuDirectory)) + { + _view.LoadOsuCollectionButtonEnabled = true; + _startupSettings.OsuLocation = osuDirectory; + _databaseLoadTask = Task.Run(() => LoadDatabase(_cancellationTokenSource.Token)); + } + + break; + case StartupDatabaseAction.None: + break; + } + } + + private async void _view_StartupCollectionOperation(object sender, StartupCollectionAction args) + { + _startupSettings.StartupCollectionAction = args; + _view.CollectionButtonsEnabled = _view.DatabaseButtonsEnabled = false; + Application.UseWaitCursor = true; + await _databaseLoadTask; + Application.UseWaitCursor = false; + CloseForm(); + } + + private void CloseForm() + { + _formClosedManually = true; + _form.Close(); + } + + private void _view_Closing(object sender, EventArgs eventArgs) + { + if (eventArgs is not FormClosingEventArgs formEventArgs || formEventArgs.CloseReason != CloseReason.UserClosing || _formClosedManually) + return; + + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + Initalizer.Quit(); + } + + private void LoadDatabase(CancellationToken cancellationToken) + { + var osuFileIo = Initalizer.OsuFileIo; + var osuDirectory = Initalizer.OsuDirectory = string.IsNullOrEmpty(_startupSettings.OsuLocation) + ? osuFileIo.OsuPathResolver.GetOsuDir() + : _startupSettings.OsuLocation; + + if (string.IsNullOrEmpty(osuDirectory) || !Directory.Exists(osuDirectory)) + { + _view.LoadDatabaseStatusText = "osu! could not be found. Select osu! location manually"; + return; + } + + osuFileIo.OsuDatabase.LoadedMaps.UnloadBeatmaps(); + osuFileIo.ScoresDatabase.Clear(); + osuFileIo.OsuDatabase.Load(Path.Combine(osuDirectory, @"osu!.db"), _databaseLoadProgressReporter, cancellationToken); + osuFileIo.OsuSettings.Load(osuDirectory); + try + { + osuFileIo.ScoresLoader.ReadDb(Path.Combine(osuDirectory, @"scores.db"), cancellationToken); + _view.LoadDatabaseStatusText += $"{Environment.NewLine}Loaded {osuFileIo.ScoresDatabase.Scores.Count} scores"; + } + catch (Exception) + { + _view.LoadDatabaseStatusText += $"{Environment.NewLine}Could not load scores"; + } + + _view.LoadOsuCollectionButtonEnabled = true; + BeatmapUtils.OsuSongsDirectory = Initalizer.OsuFileIo.OsuSettings.CustomBeatmapDirectoryLocation; + } + + private void SaveSettings() + { + + Settings.Default.StartupSettings = JsonConvert.SerializeObject(_startupSettings); + Settings.Default.Save(); + } + } +} \ No newline at end of file diff --git a/App/Presenters/Forms/MainFormPresenter.cs b/App/Presenters/Forms/MainFormPresenter.cs index 11d3415..3f821e1 100644 --- a/App/Presenters/Forms/MainFormPresenter.cs +++ b/App/Presenters/Forms/MainFormPresenter.cs @@ -33,7 +33,7 @@ public MainFormPresenter(IMainFormView view, IMainFormModel mainFormModel, IInfo CollectionListingModel = new CollectionListingModel(Initalizer.LoadedCollections, _mainFormModel.GetCollectionEditor()); CollectionListingModel.CollectionEditing += CollectionListing_CollectionEditing; CollectionListingModel.SelectedCollectionsChanged += CollectionListing_SelectedCollectionsChanged; - new CombinedListingPresenter(_view.CombinedListingView, CollectionListingModel, BeatmapListingModel, webCollectionProvider); + new CombinedListingPresenter(_view.CombinedListingView, CollectionListingModel, BeatmapListingModel, webCollectionProvider, mainFormModel.GetUserDialogs()); //Beatmap preview stuff (images, beatmap info like ar,cs,stars...) _combinedBeatmapPreviewModel = new CombinedBeatmapPreviewModel(); diff --git a/App/Program.cs b/App/Program.cs index 807cd0d..9cb6218 100644 --- a/App/Program.cs +++ b/App/Program.cs @@ -26,8 +26,12 @@ static int Main(string[] args) if (exArgs.ExceptionObject is Exception exception) HandleException(exception); }; - Application.ThreadException += (_, exArgs) => HandleException(exArgs.Exception); - TaskScheduler.UnobservedTaskException += (_, exArgs) => HandleException(exArgs.Exception); + Application.ThreadException += (_, exArgs) + => + HandleException(exArgs.Exception); + TaskScheduler.UnobservedTaskException += (_, exArgs) + => + HandleException(exArgs.Exception); if (args.Length > 0 && !File.Exists(args[0])) { diff --git a/App/Properties/Resources.Designer.cs b/App/Properties/Resources.Designer.cs index 5881f1b..b1229d8 100644 --- a/App/Properties/Resources.Designer.cs +++ b/App/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace App.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/App/Properties/Settings.Designer.cs b/App/Properties/Settings.Designer.cs index ad3049e..3913f0e 100644 --- a/App/Properties/Settings.Designer.cs +++ b/App/Properties/Settings.Designer.cs @@ -8,31 +8,27 @@ // //------------------------------------------------------------------------------ -namespace App.Properties -{ +namespace App.Properties { + + + internal sealed partial class Settings { - - internal sealed partial class Settings - { public void Save() { } public void Reset() { } - private static Settings instance = new Settings(); - public static Settings Default - { - get - { - return instance; + private static Settings defaultInstance = new Settings(); + + public static Settings Default { + get { + return defaultInstance; } } - - public bool DontAskAboutOsuDirectory - { - get - { - return false; + + public string StartupSettings { + get { + return string.Empty; } - set - { + set { + } } @@ -79,26 +75,20 @@ public string Osustats_apiKey { } } - - public string OsuDirectory - { - get - { + + public string DownloadManager_DownloaderSettings { + get { return string.Empty; } - set - { + set { } } - - public string DownloadManager_DownloaderSettings - { - get - { - return "{}"; + + public bool DontAskAboutReorderingCollections { + get { + return false; } - set - { + set { } } } diff --git a/App/Properties/Settings.settings b/App/Properties/Settings.settings index 452c5bb..e01ac22 100644 --- a/App/Properties/Settings.settings +++ b/App/Properties/Settings.settings @@ -2,8 +2,8 @@ - - False + + {} False @@ -17,11 +17,11 @@ - - - {} + + False + \ No newline at end of file diff --git a/App/Properties/launchSettings.json b/App/Properties/launchSettings.json new file mode 100644 index 0000000..45eed2b --- /dev/null +++ b/App/Properties/launchSettings.json @@ -0,0 +1,7 @@ +{ + "profiles": { + "App": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/App/SidePanelActionsHandler.cs b/App/SidePanelActionsHandler.cs index 7ca3c51..8ffe0d3 100644 --- a/App/SidePanelActionsHandler.cs +++ b/App/SidePanelActionsHandler.cs @@ -95,6 +95,10 @@ private void BindMainFormActions() _mainForm.Closing += FormOnClosing; } + public void LoadOsuCollection() => LoadDefaultCollection(null, null); + + public void LoadCollectionFile() => LoadCollectionFile(null); + private void ResetApplicationSettings(object arg1, object arg2) { if (_userDialogs.YesNoMessageBox( diff --git a/App/app.config b/App/app.config index 214ccb9..38fd813 100644 --- a/App/app.config +++ b/App/app.config @@ -8,8 +8,8 @@ - - False + + {} False @@ -23,12 +23,12 @@ - - - {} + + False + diff --git a/CollectionGenerator/CollectionGenerator.csproj b/CollectionGenerator/CollectionGenerator.csproj index 822a0ec..e406d66 100644 --- a/CollectionGenerator/CollectionGenerator.csproj +++ b/CollectionGenerator/CollectionGenerator.csproj @@ -1,7 +1,7 @@  Exe - net472 + net48 true CollectionGenerator CollectionGenerator diff --git a/CollectionManager.sln b/CollectionManager.sln index 03fdcc3..0f5d185 100644 --- a/CollectionManager.sln +++ b/CollectionManager.sln @@ -1,7 +1,7 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.452 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32526.322 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CollectionManagerDll", "CollectionManagerDll\CollectionManagerDll.csproj", "{533AB47A-D1B5-45DB-A37E-F053FA3699C4}" EndProject diff --git a/CollectionManagerDll/CollectionManagerDll.csproj b/CollectionManagerDll/CollectionManagerDll.csproj index c577da8..ed003de 100644 --- a/CollectionManagerDll/CollectionManagerDll.csproj +++ b/CollectionManagerDll/CollectionManagerDll.csproj @@ -3,7 +3,7 @@ {533AB47A-D1B5-45DB-A37E-F053FA3699C4} CollectionManager CollectionManager - netstandard20;net471 + netstandard20;net48 CollectionManager Implements read/write access to osu! db & osdb collection files, along with ability to edit these in a reasonable manner diff --git a/CollectionManagerDll/DataTypes/Beatmap.cs b/CollectionManagerDll/DataTypes/Beatmap.cs index f62d533..7fd98a5 100644 --- a/CollectionManagerDll/DataTypes/Beatmap.cs +++ b/CollectionManagerDll/DataTypes/Beatmap.cs @@ -61,7 +61,7 @@ public string MapLink { if (MapId == 0) return MapSetLink; - return @"http://osu.ppy.sh/b/" + MapId; + return @"https://osu.ppy.sh/b/" + MapId; } } @@ -71,7 +71,7 @@ public string MapSetLink { if (MapSetId == 0) return string.Empty; - return @"http://osu.ppy.sh/s/" + MapSetId; + return @"https://osu.ppy.sh/s/" + MapSetId; } } //TODO: add helper functions for adding/removing star values diff --git a/CollectionManagerDll/DataTypes/Collection.cs b/CollectionManagerDll/DataTypes/Collection.cs index a627c54..f8353cd 100644 --- a/CollectionManagerDll/DataTypes/Collection.cs +++ b/CollectionManagerDll/DataTypes/Collection.cs @@ -37,7 +37,7 @@ public class Collection : IEnumerable, ICollection /// public Beatmaps KnownBeatmaps { get; } = new Beatmaps(); - + public override string ToString() => $"osu! map Collection: \"{Name}\" Count: {BeatmapHashes.Count}"; /// /// Total number of beatmaps contained in this collection diff --git a/CollectionManagerDll/Enums/CollectionEdit.cs b/CollectionManagerDll/Enums/CollectionEdit.cs index 42379b0..0dd2710 100644 --- a/CollectionManagerDll/Enums/CollectionEdit.cs +++ b/CollectionManagerDll/Enums/CollectionEdit.cs @@ -13,5 +13,9 @@ public enum CollectionEdit Duplicate=8, Intersect=9, Inverse=10, + Difference=11, + Reorder=12, + + ExportBeatmaps=100, } } \ No newline at end of file diff --git a/CollectionManagerDll/Interfaces/IScoreDataStorer.cs b/CollectionManagerDll/Interfaces/IScoreDataStorer.cs index f8179e4..1d4f5f2 100644 --- a/CollectionManagerDll/Interfaces/IScoreDataStorer.cs +++ b/CollectionManagerDll/Interfaces/IScoreDataStorer.cs @@ -7,6 +7,7 @@ public interface IScoreDataStorer Scores Scores { get; } void StartMassStoring(); void EndMassStoring(); + void Clear(); void Store(Score score); } } \ No newline at end of file diff --git a/CollectionManagerDll/Modules/CollectionsManager/CollectionEditArgs.cs b/CollectionManagerDll/Modules/CollectionsManager/CollectionEditArgs.cs index b7b510e..58bc41a 100644 --- a/CollectionManagerDll/Modules/CollectionsManager/CollectionEditArgs.cs +++ b/CollectionManagerDll/Modules/CollectionsManager/CollectionEditArgs.cs @@ -7,12 +7,14 @@ namespace CollectionManager.Modules.CollectionsManager { public class CollectionEditArgs : EventArgs { - public CollectionEdit Action { get; private set; } - public string OrginalName { get; private set; } - public string NewName { get; set; } - public Collections Collections { get; private set; } - public Beatmaps Beatmaps { get; private set; } - public IList CollectionNames { get; private set; } + public CollectionEdit Action { get; protected set; } + public string OrginalName { get; protected set; } + public string NewName { get; protected set; } + public Collections Collections { get; protected set; } + public Collection TargetCollection { get; protected set; } + public Beatmaps Beatmaps { get; protected set; } + public IList CollectionNames { get; protected set; } + public bool PlaceCollectionsBefore { get; protected set; } public CollectionEditArgs(CollectionEdit action) { Action = action; @@ -88,6 +90,16 @@ public static CollectionEditArgs InverseCollections(Collections collections, str }; } #endregion + #region Difference Collections + public static CollectionEditArgs DifferenceCollections(Collections collections, string newName) + { + return new CollectionEditArgs(CollectionEdit.Difference) + { + Collections = collections, + NewName = newName + }; + } + #endregion #region Clear Collections public static CollectionEditArgs ClearCollections() { @@ -104,6 +116,17 @@ public static CollectionEditArgs AddBeatmaps(string collectionName, Beatmaps bea }; } + #endregion + #region Reorder collections using special characters placed at the begining of the name, this modifies ALL collection names + public static CollectionEditArgs ReorderCollections(Collections collections, Collection targetCollection, bool placeBefore) + { + return new CollectionEditArgs(CollectionEdit.Reorder) + { + Collections = collections, + TargetCollection = targetCollection, + PlaceCollectionsBefore = placeBefore + }; + } #endregion #region Remove beatmaps from collection public static CollectionEditArgs RemoveBeatmaps(string collectionName, Beatmaps beatmaps) diff --git a/CollectionManagerDll/Modules/CollectionsManager/CollectionsManager.cs b/CollectionManagerDll/Modules/CollectionsManager/CollectionsManager.cs index 80156a9..d74f924 100644 --- a/CollectionManagerDll/Modules/CollectionsManager/CollectionsManager.cs +++ b/CollectionManagerDll/Modules/CollectionsManager/CollectionsManager.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; +using System.Text; using App.Interfaces; using CollectionManager.DataTypes; using CollectionManager.Enums; @@ -12,10 +13,18 @@ public class CollectionsManager : ICollectionEditor, ICollectionNameValidator { public readonly Collections LoadedCollections = new Collections(); public Beatmaps LoadedBeatmaps; + private readonly char[] ReorderChars; + private readonly char[] ReorderCharsWithSeparator; + private readonly string ReorderCharsString; + private const string reorderSeparator = "| "; public CollectionsManager(Beatmaps loadedBeatmaps) { LoadedBeatmaps = loadedBeatmaps; + ReorderCharsString = "0123456789";//!$)]},.? ABCDEFGHIJKLMNOPQRSTUVWXYZ @#%^&*(+[{;':\\\"<>/ + ReorderChars = ReorderCharsString.ToArray(); + ReorderCharsWithSeparator = ReorderChars.Concat(reorderSeparator).ToArray(); } + /* add collection remove collection @@ -23,14 +32,18 @@ edit collection name merge x collections intersect x collections inverse map sum of x collections + difference x collections clear collections + reorder collections add beatmaps to collection remove beatmaps from collection */ - private void EditCollection(CollectionEditArgs args, bool suspendRefresh = false) { var action = args.Action; + if ((int)action >= 100) + return; + if (action == CollectionEdit.Add) { List collectionNames = new List(); @@ -121,10 +134,65 @@ private void EditCollection(CollectionEditArgs args, bool suspendRefresh = false EditCollection(CollectionEditArgs.AddCollections(new Collections() { targetCollection }), true); } + else if (action == CollectionEdit.Difference) + { + var targetCollection = args.Collections.Last(); + args.Collections.RemoveAt(args.Collections.Count - 1); + var mainCollection = args.Collections[0]; + args.Collections.RemoveAt(0); + var beatmaps = mainCollection.AllBeatmaps(); + foreach (var collection in args.Collections) + { + beatmaps = beatmaps.Concat(collection.AllBeatmaps()); + } + + var differenceMd5 = beatmaps.GroupBy(x => x.Md5).Where(group => group.Count() == 1).Select(group => group.Key).ToList(); + var differenceMapId = beatmaps.GroupBy(x => x.MapId).Where(group => group.Count() == 1).Select(group => group.Key).ToList(); + + foreach (var beatmap in beatmaps) + { + if (differenceMd5.Contains(beatmap.Md5) || differenceMapId.Contains(beatmap.MapId)) + { + targetCollection.AddBeatmap(beatmap); + } + } + + EditCollection(CollectionEditArgs.AddCollections(new Collections() { targetCollection }), true); + } else if (action == CollectionEdit.Clear) { LoadedCollections.Clear(); } + else if (action == CollectionEdit.Reorder) + { + var targetCollection = args.TargetCollection; + var collectionsToReorder = args.Collections.OrderBy(x => x.Name).ToList(); + var orderedLoadedCollections = LoadedCollections.OrderBy(x => x.Name).ToList(); + foreach (var coll in collectionsToReorder) + orderedLoadedCollections.Remove(coll); + + var targetCollectionIndex = orderedLoadedCollections.IndexOf(targetCollection); + orderedLoadedCollections.InsertRange(args.PlaceCollectionsBefore ? targetCollectionIndex : targetCollectionIndex + 1, collectionsToReorder); + var amountOfCharactersRequired = 0; + var variations = 0; + while (orderedLoadedCollections.Count() > variations) + variations = Enumerable.Range(1, ++amountOfCharactersRequired).Aggregate(0, (acc, i) => Convert.ToInt32(Math.Pow(ReorderChars.Length, i)) + acc); + + List reorderStrings = new List(variations); + for (int i = 1; i <= amountOfCharactersRequired; i++) + reorderStrings.AddRange(CombinationsWithRepetition(ReorderCharsString, i)); + + reorderStrings.Sort(); + var collectionIndex = 0; + foreach (var collection in orderedLoadedCollections) + { + + if (collection.Name.Contains(reorderSeparator)) + collection.Name = collection.Name.TrimStart(ReorderCharsWithSeparator); + + collection.Name = $"{reorderStrings[collectionIndex++]}{reorderSeparator} {collection.Name}"; + } + } else { var collection = GetCollectionByName(args.OrginalName); @@ -217,5 +285,26 @@ public bool IsCollectionNameValid(string name) { return !CollectionNameExists(name); } + + private static string Combinations(string symbols, int number, int stringLength) + { + var stringBuilder = new StringBuilder(); + var len = symbols.Length; + var nullSym = symbols[0]; + while (number > 0) + { + var index = number % len; + number = number / len; + stringBuilder.Insert(0, symbols[index]); + } + + return stringBuilder.ToString().PadLeft(stringLength, nullSym); + } + + private static IEnumerable CombinationsWithRepetition(string symbols, int stringLength) + { + for (var i = 0; i < Math.Pow(symbols.Length, stringLength); i++) + yield return Combinations(symbols, i, stringLength); + } } } \ No newline at end of file diff --git a/CollectionManagerDll/Modules/FileIO/OsuDb/LOsuDatabaseLoader.cs b/CollectionManagerDll/Modules/FileIO/OsuDb/LOsuDatabaseLoader.cs index 966b2f3..aeeabe7 100644 --- a/CollectionManagerDll/Modules/FileIO/OsuDb/LOsuDatabaseLoader.cs +++ b/CollectionManagerDll/Modules/FileIO/OsuDb/LOsuDatabaseLoader.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using CollectionManager.DataTypes; using CollectionManager.Interfaces; @@ -8,7 +9,7 @@ public class LOsuDatabaseLoader : OsuDatabaseLoader { private ILogger logger; public string status { get; private set; } - public LOsuDatabaseLoader(ILogger logger, IMapDataManager mapDataStorer, Beatmap tempBeatmap) : base(logger, mapDataStorer, tempBeatmap) + public LOsuDatabaseLoader(IMapDataManager mapDataStorer, Beatmap tempBeatmap) : base(mapDataStorer, tempBeatmap) { } @@ -20,17 +21,18 @@ protected override bool FileExists(string fullPath) return result; } - public override void LoadDatabase(string fullOsuDbPath) + public override void LoadDatabase(string fullOsuDbPath, IProgress progress, CancellationToken cancellationToken) { status = "Loading database"; - base.LoadDatabase(fullOsuDbPath); + base.LoadDatabase(fullOsuDbPath, progress, cancellationToken); status = $"Loaded {NumberOfLoadedBeatmaps} beatmaps"; } - protected override void ReadDatabaseEntries() + + protected override void ReadDatabaseEntries(IProgress progress, CancellationToken cancellationToken) { try { - base.ReadDatabaseEntries(); + base.ReadDatabaseEntries(progress, cancellationToken); } catch (Exception e) { diff --git a/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabase.cs b/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabase.cs index c44dcb6..cb99af7 100644 --- a/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabase.cs +++ b/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabase.cs @@ -1,4 +1,6 @@ using CollectionManager.DataTypes; +using System; +using System.Threading; namespace CollectionManager.Modules.FileIO.OsuDb { @@ -17,14 +19,16 @@ public class OsuDatabase public OsuDatabase(Beatmap beatmapBase) { - _databaseLoader = new LOsuDatabaseLoader(null, LoadedMaps, beatmapBase); + _databaseLoader = new LOsuDatabaseLoader(LoadedMaps, beatmapBase); } - public void Load(string fileDir) + public void Load(string fileDir, IProgress progress, CancellationToken cancellationToken) { OsuFileLocation = fileDir; - _databaseLoader.LoadDatabase(fileDir); + _databaseLoader.LoadDatabase(fileDir, progress, cancellationToken); } + public void Load(string fileDir, IProgress progress = null) => Load(fileDir, progress, CancellationToken.None); + } } diff --git a/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabaseReader.cs b/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabaseReader.cs index 2cbf175..4314a4d 100644 --- a/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabaseReader.cs +++ b/CollectionManagerDll/Modules/FileIO/OsuDb/OsuDatabaseReader.cs @@ -6,13 +6,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; namespace CollectionManager.Modules.FileIO.OsuDb { //TODO: refactor to allow for read/write access. public class OsuDatabaseLoader { - private readonly ILogger _logger; private readonly IMapDataManager _mapDataStorer; private FileStream _fileStream; private BinaryReader _binaryReader; @@ -27,44 +27,46 @@ public class OsuDatabaseLoader public int ExpectedNumOfBeatmaps { get; private set; } = -1; public int NumberOfLoadedBeatmaps { get; private set; } - public OsuDatabaseLoader(ILogger logger, IMapDataManager mapDataStorer, Beatmap tempBeatmap) + public OsuDatabaseLoader(IMapDataManager mapDataStorer, Beatmap tempBeatmap) { _tempBeatmap = tempBeatmap; _mapDataStorer = mapDataStorer; - _logger = logger; } - public virtual void LoadDatabase(string fullOsuDbPath) + public virtual void LoadDatabase(string fullOsuDbPath, IProgress progress, CancellationToken cancellationToken) { if (FileExists(fullOsuDbPath)) { _fileStream = new FileStream(fullOsuDbPath, FileMode.Open, FileAccess.Read); _binaryReader = new BinaryReader(_fileStream); - if (DatabaseContainsData()) + if (DatabaseContainsData(progress)) { - ReadDatabaseEntries(); + ReadDatabaseEntries(progress, cancellationToken); } DestoryReader(); } GC.Collect(); } - protected virtual void ReadDatabaseEntries() + protected virtual void ReadDatabaseEntries(IProgress progress, CancellationToken cancellationToken) { - _logger?.Log("Starting MassStoring of {0} beatmaps", ExpectedNumOfBeatmaps.ToString()); + progress?.Report($"Starting load of {ExpectedNumOfBeatmaps} beatmaps"); _mapDataStorer.StartMassStoring(); for (NumberOfLoadedBeatmaps = 0; NumberOfLoadedBeatmaps < ExpectedNumOfBeatmaps; NumberOfLoadedBeatmaps++) { if (NumberOfLoadedBeatmaps % 100 == 0) - _logger?.Log("Loading {0} of {1}", NumberOfLoadedBeatmaps.ToString(), - ExpectedNumOfBeatmaps.ToString()); + progress?.Report($"Loading {NumberOfLoadedBeatmaps} of {ExpectedNumOfBeatmaps}"); + if (cancellationToken.IsCancellationRequested) + break; ReadNextBeatmap(); } - _logger?.Log("Loaded {0} beatmaps", NumberOfLoadedBeatmaps.ToString()); + + progress?.Report($"Loaded {NumberOfLoadedBeatmaps} beatmaps"); _mapDataStorer.EndMassStoring(); - LoadedSuccessfully = true; + if (!cancellationToken.IsCancellationRequested) + LoadedSuccessfully = true; } private void ReadNextBeatmap() { @@ -361,16 +363,16 @@ private string ReadString() } return ""; } - private bool DatabaseContainsData() + private bool DatabaseContainsData(IProgress progress) { FileDate = _binaryReader.ReadInt32(); if (FileDate < 20191105) { - _logger?.Log(string.Format("Outdated osu!.db version({0}). Load failed.", FileDate.ToString())); + progress?.Report($"Outdated osu!.db version ({FileDate}). Load failed."); return false; } ExpectedNumberOfMapSets = _binaryReader.ReadInt32(); - _logger?.Log(string.Format("Expected number of mapSets: {0}", ExpectedNumberOfMapSets)); + progress?.Report($"Expected number of mapSets: {ExpectedNumberOfMapSets}"); try { bool something = _binaryReader.ReadBoolean(); @@ -378,8 +380,7 @@ private bool DatabaseContainsData() _binaryReader.BaseStream.Seek(1, SeekOrigin.Current); Username = _binaryReader.ReadString(); ExpectedNumOfBeatmaps = _binaryReader.ReadInt32(); - - _logger?.Log(string.Format("Expected number of beatmaps: {0}", ExpectedNumOfBeatmaps)); + progress?.Report($"Expected number of beatmaps: {ExpectedNumOfBeatmaps}"); if (ExpectedNumOfBeatmaps < 0) { diff --git a/CollectionManagerDll/Modules/FileIO/OsuPathResolver.cs b/CollectionManagerDll/Modules/FileIO/OsuPathResolver.cs index b40aacd..fae3a18 100644 --- a/CollectionManagerDll/Modules/FileIO/OsuPathResolver.cs +++ b/CollectionManagerDll/Modules/FileIO/OsuPathResolver.cs @@ -49,6 +49,9 @@ public string GetOsuDir(Func thisPathIsCorrect, Func _getRunningOsuDir(); + private string _getRunningOsuDir() { if (OsuIsRunning) diff --git a/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresCacher.cs b/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresCacher.cs index 067fbd9..c123325 100644 --- a/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresCacher.cs +++ b/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresCacher.cs @@ -17,6 +17,13 @@ public void EndMassStoring() { } + public void Clear() + { + ScoreList.Clear(); + Scores.Clear(); + ScoreHashes.Clear(); + } + public List GetScores(Beatmap map) { return GetScores(map.Md5); diff --git a/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresDatabaseIO.cs b/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresDatabaseIO.cs index bfdb4db..c7a50cf 100644 --- a/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresDatabaseIO.cs +++ b/CollectionManagerDll/Modules/FileIO/OsuScoresDb/ScoresDatabaseIO.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading; using CollectionManager.DataTypes; using CollectionManager.Interfaces; @@ -20,8 +21,11 @@ public ScoresDatabaseIo(IScoreDataStorer scoreDataStorer) _scoreDataStorer = scoreDataStorer; } - public virtual void ReadDb(string osuScoresDbPath) + public virtual void ReadDb(string osuScoresDbPath, CancellationToken cancellationToken) { + if (cancellationToken.IsCancellationRequested) + return; + if (FileExists(osuScoresDbPath)) { _fileStream = new FileStream(osuScoresDbPath, FileMode.Open, FileAccess.Read); @@ -37,6 +41,9 @@ public virtual void ReadDb(string osuScoresDbPath) { _scoreDataStorer.Store(Score.ReadScore(_binaryReader, true, Version)); } + + if (cancellationToken.IsCancellationRequested) + break; } _scoreDataStorer.EndMassStoring(); } diff --git a/CollectionManagerExtensionsDll/Modules/DifficultyCalculator.cs b/CollectionManagerExtensionsDll/Modules/DifficultyCalculator.cs index 976288b..1bc5ffe 100644 --- a/CollectionManagerExtensionsDll/Modules/DifficultyCalculator.cs +++ b/CollectionManagerExtensionsDll/Modules/DifficultyCalculator.cs @@ -14,6 +14,7 @@ public class DifficultyCalculatorResult public float Hp { get; set; } public double MinBpm { get; set; } public double MaxBpm { get; set; } + public double BpmMultiplier { get; set; } } readonly float od0_ms = 79.5f, od10_ms = 19.5f, @@ -36,6 +37,7 @@ public DifficultyCalculatorResult ApplyMods(Beatmap map, Mods mods, DifficultyCa result.Hp = map.HpDrainRate; result.MinBpm = map.MinBpm; result.MaxBpm = map.MaxBpm; + result.BpmMultiplier = 1; if ((mods & Mods.MapChanging) == 0) { @@ -75,7 +77,7 @@ public DifficultyCalculatorResult ApplyMods(Beatmap map, Mods mods, DifficultyCa result.MinBpm *= modifier; result.MaxBpm *= modifier; - + result.BpmMultiplier = modifier; //ar float ar_multiplier = 1; diff --git a/Common/BeatmapListingAction.cs b/Common/BeatmapListingAction.cs index 533a6e0..fc1c796 100644 --- a/Common/BeatmapListingAction.cs +++ b/Common/BeatmapListingAction.cs @@ -10,5 +10,6 @@ public enum BeatmapListingAction CopyBeatmapsAsText, //Copy text representation of selected beatmaps CopyBeatmapsAsUrls, //Copy map links of selected beatmaps PullWholeMapSet, //Finds all mapsets from selected maps and adds them to current collection + ExportBeatmapSets, //Compress selected mapsets back to .osz archives } } \ No newline at end of file diff --git a/Common/Common.csproj b/Common/Common.csproj index 2df1a9d..1801b7d 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -1,6 +1,6 @@  - net472 + net48 Common Common Copyright © 2017 diff --git a/Common/GuiHelpers.cs b/Common/GuiHelpers.cs index 1799ada..5b945aa 100644 --- a/Common/GuiHelpers.cs +++ b/Common/GuiHelpers.cs @@ -7,9 +7,11 @@ public static class GuiHelpers { public delegate void BeatmapsEventArgs(object sender, Beatmaps args); public delegate void CollectionBeatmapsEventArgs(object sender, Beatmaps args, string collectionName); + public delegate void CollectionReorderEventArgs(object sender, Collections collections, Collection targetCollection, bool placeBefore); public delegate void BeatmapListingActionArgs(object sender, BeatmapListingAction args); public delegate void SidePanelActionsHandlerArgs(object sender, MainSidePanelActions args, object data = null); public delegate void LoadFileArgs(object sender, string[] filePaths); - + public delegate void StartupCollectionEventArgs(object sender, StartupCollectionAction args); + public delegate void StartupDatabaseEventArgs(object sender, StartupDatabaseAction args); } } \ No newline at end of file diff --git a/Common/Interfaces/Controls/ICollectionListingView.cs b/Common/Interfaces/Controls/ICollectionListingView.cs index bd29dab..e2415e2 100644 --- a/Common/Interfaces/Controls/ICollectionListingView.cs +++ b/Common/Interfaces/Controls/ICollectionListingView.cs @@ -9,6 +9,7 @@ namespace GuiComponents.Interfaces public interface ICollectionListingView { event GuiHelpers.LoadFileArgs OnLoadFile; + event GuiHelpers.CollectionReorderEventArgs OnCollectionReorder; string SearchText { get; } diff --git a/Common/Interfaces/Controls/IStartupView.cs b/Common/Interfaces/Controls/IStartupView.cs new file mode 100644 index 0000000..875e2f4 --- /dev/null +++ b/Common/Interfaces/Controls/IStartupView.cs @@ -0,0 +1,18 @@ +using Gui.Misc; + +namespace GuiComponents.Interfaces +{ + public interface IStartupView + { + event GuiHelpers.StartupCollectionEventArgs StartupCollectionOperation; + event GuiHelpers.StartupDatabaseEventArgs StartupDatabaseOperation; + + string LoadDatabaseStatusText { get; set; } + string CollectionStatusText { get; set; } + bool UseSelectedOptionsOnStartup { get; set; } + bool UseSelectedOptionsOnStartupEnabled { get; set; } + bool CollectionButtonsEnabled { get; set; } + bool DatabaseButtonsEnabled { get; set; } + bool LoadOsuCollectionButtonEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Common/Interfaces/Forms/IProgressForm.cs b/Common/Interfaces/Forms/IProgressForm.cs new file mode 100644 index 0000000..cc1864d --- /dev/null +++ b/Common/Interfaces/Forms/IProgressForm.cs @@ -0,0 +1,9 @@ +using System; + +namespace GuiComponents.Interfaces +{ + public interface IProgressForm : IForm + { + event EventHandler AbortClicked; + } +} \ No newline at end of file diff --git a/Common/Interfaces/Forms/IStartupForm.cs b/Common/Interfaces/Forms/IStartupForm.cs new file mode 100644 index 0000000..27a0da2 --- /dev/null +++ b/Common/Interfaces/Forms/IStartupForm.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using Common.Interfaces; + +namespace GuiComponents.Interfaces +{ + public interface IStartupForm : IForm + { + IStartupView StartupView { get; } + } +} \ No newline at end of file diff --git a/Common/Interfaces/IUserDialogs.cs b/Common/Interfaces/IUserDialogs.cs index 290e88f..85acef9 100644 --- a/Common/Interfaces/IUserDialogs.cs +++ b/Common/Interfaces/IUserDialogs.cs @@ -1,4 +1,5 @@ using Common; +using System; namespace GuiComponents.Interfaces { @@ -11,6 +12,7 @@ public interface IUserDialogs string SaveFile(string title, string types = "all|*.*"); bool YesNoMessageBox(string text, string caption, MessageBoxType messageBoxType = MessageBoxType.Info); (bool Result, bool doNotAskAgain) YesNoMessageBox(string text, string caption, MessageBoxType messageBoxType = MessageBoxType.Info,string doNotAskAgainText = null); + IProgressForm ProgressForm(Progress userProgressMessage, Progress completionPercentage); void OkMessageBox(string text, string caption, MessageBoxType messageBoxType = MessageBoxType.Info); } } \ No newline at end of file diff --git a/Common/StartupCollectionAction.cs b/Common/StartupCollectionAction.cs new file mode 100644 index 0000000..0d3b79f --- /dev/null +++ b/Common/StartupCollectionAction.cs @@ -0,0 +1,9 @@ +namespace Common +{ + public enum StartupCollectionAction + { + None, + LoadCollectionFromFile, + LoadOsuCollection, + } +} \ No newline at end of file diff --git a/Common/StartupDatabaseAction.cs b/Common/StartupDatabaseAction.cs new file mode 100644 index 0000000..1724394 --- /dev/null +++ b/Common/StartupDatabaseAction.cs @@ -0,0 +1,9 @@ +namespace Common +{ + public enum StartupDatabaseAction + { + None, + Unload, + LoadFromDifferentLocation + } +} \ No newline at end of file diff --git a/GuiComponents/Controls/BeatmapListingView.Designer.cs b/GuiComponents/Controls/BeatmapListingView.Designer.cs index 973aa76..972226e 100644 --- a/GuiComponents/Controls/BeatmapListingView.Designer.cs +++ b/GuiComponents/Controls/BeatmapListingView.Designer.cs @@ -69,6 +69,7 @@ private void InitializeComponent() this.olvColumn9 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.olvColumn11 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.MainBpm = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); + this.exportBeatmapSetsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.BeatmapsContextMenuStrip.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.ListViewBeatmaps)).BeginInit(); this.SuspendLayout(); @@ -108,9 +109,10 @@ private void InitializeComponent() this.DeleteMapMenuStrip, this.searchToolStripMenuItem, this.copyToolStripMenuItem, - this.PullMapsetMenuStrip}); + this.PullMapsetMenuStrip, + this.exportBeatmapSetsMenuItem}); this.BeatmapsContextMenuStrip.Name = "CollectionContextMenuStrip"; - this.BeatmapsContextMenuStrip.Size = new System.Drawing.Size(172, 114); + this.BeatmapsContextMenuStrip.Size = new System.Drawing.Size(182, 136); // // OpenDlMapMenuStrip // @@ -119,7 +121,7 @@ private void InitializeComponent() this.OpenBeatmapDownloadMapMenuStrip, this.OpenBeatmapFolderMenuStrip}); this.OpenDlMapMenuStrip.Name = "OpenDlMapMenuStrip"; - this.OpenDlMapMenuStrip.Size = new System.Drawing.Size(171, 22); + this.OpenDlMapMenuStrip.Size = new System.Drawing.Size(181, 22); this.OpenDlMapMenuStrip.Text = "Open"; // // OpenBeatmapPageMapMenuStrip @@ -164,7 +166,7 @@ private void InitializeComponent() this.DeleteMapMenuStrip.Enabled = false; this.DeleteMapMenuStrip.Name = "DeleteMapMenuStrip"; this.DeleteMapMenuStrip.ShortcutKeys = System.Windows.Forms.Keys.Delete; - this.DeleteMapMenuStrip.Size = new System.Drawing.Size(171, 22); + this.DeleteMapMenuStrip.Size = new System.Drawing.Size(181, 22); this.DeleteMapMenuStrip.Text = "Delete"; this.DeleteMapMenuStrip.Click += new System.EventHandler(this.MenuStripClick); // @@ -176,7 +178,7 @@ private void InitializeComponent() this.SearchTitleMapMenuStrip}); this.searchToolStripMenuItem.Enabled = false; this.searchToolStripMenuItem.Name = "searchToolStripMenuItem"; - this.searchToolStripMenuItem.Size = new System.Drawing.Size(171, 22); + this.searchToolStripMenuItem.Size = new System.Drawing.Size(181, 22); this.searchToolStripMenuItem.Text = "Search"; // // SearchMapsetMapMenuStrip @@ -203,7 +205,7 @@ private void InitializeComponent() this.copyUrlMenuStrip, this.copyAsTextMenuStrip}); this.copyToolStripMenuItem.Name = "copyToolStripMenuItem"; - this.copyToolStripMenuItem.Size = new System.Drawing.Size(171, 22); + this.copyToolStripMenuItem.Size = new System.Drawing.Size(181, 22); this.copyToolStripMenuItem.Text = "Copy"; // // copyUrlMenuStrip @@ -223,7 +225,7 @@ private void InitializeComponent() // PullMapsetMenuStrip // this.PullMapsetMenuStrip.Name = "PullMapsetMenuStrip"; - this.PullMapsetMenuStrip.Size = new System.Drawing.Size(171, 22); + this.PullMapsetMenuStrip.Size = new System.Drawing.Size(181, 22); this.PullMapsetMenuStrip.Text = "Pull whole mapset"; this.PullMapsetMenuStrip.Click += new System.EventHandler(this.MenuStripClick); // @@ -431,6 +433,13 @@ private void InitializeComponent() this.MainBpm.IsVisible = false; this.MainBpm.Text = "MainBpm"; // + // exportBeatmapSetsMenuItem + // + this.exportBeatmapSetsMenuItem.Name = "exportBeatmapSetsMenuItem"; + this.exportBeatmapSetsMenuItem.Size = new System.Drawing.Size(181, 22); + this.exportBeatmapSetsMenuItem.Text = "Export beatmap sets"; + this.exportBeatmapSetsMenuItem.Click += new System.EventHandler(this.MenuStripClick); + // // BeatmapListingView // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -490,5 +499,6 @@ private void InitializeComponent() private BrightIdeasSoftware.OLVColumn olvColumn9; private BrightIdeasSoftware.OLVColumn olvColumn11; private BrightIdeasSoftware.OLVColumn MainBpm; + private System.Windows.Forms.ToolStripMenuItem exportBeatmapSetsMenuItem; } } diff --git a/GuiComponents/Controls/BeatmapListingView.cs b/GuiComponents/Controls/BeatmapListingView.cs index b5819ad..e78dc64 100644 --- a/GuiComponents/Controls/BeatmapListingView.cs +++ b/GuiComponents/Controls/BeatmapListingView.cs @@ -178,6 +178,14 @@ private void InitListView() var val = (DateTime)cellValue; return val > d ? $"{val}" : "Never"; }; + MainBpm.AspectGetter = rowObject => + { + if (rowObject is Beatmap beatmap) + { + return beatmap.MainBpm * _difficultyCalculator.ApplyMods(beatmap, _currentMods).BpmMultiplier; + } + return null; + }; MainBpm.AspectToStringConverter = delegate (object cellValue) { if (cellValue == null) return string.Empty; @@ -281,6 +289,8 @@ private void MenuStripClick(object sender, EventArgs e) BeatmapOperation?.Invoke(this, Common.BeatmapListingAction.OpenBeatmapFolder); else if (sender == PullMapsetMenuStrip) BeatmapOperation?.Invoke(this, Common.BeatmapListingAction.PullWholeMapSet); + else if (sender == exportBeatmapSetsMenuItem) + BeatmapOperation?.Invoke(this, Common.BeatmapListingAction.ExportBeatmapSets); } private void ListViewBeatmaps_KeyUp(object sender, KeyEventArgs e) diff --git a/GuiComponents/Controls/CollectionListingView.Designer.cs b/GuiComponents/Controls/CollectionListingView.Designer.cs index 35d9e9a..8c7eaf1 100644 --- a/GuiComponents/Controls/CollectionListingView.Designer.cs +++ b/GuiComponents/Controls/CollectionListingView.Designer.cs @@ -36,7 +36,6 @@ private void InitializeComponent() this.Total = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.olvColumn2 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn())); this.textBox_collectionNameSearch = new System.Windows.Forms.TextBox(); - this.CollectionContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.CreateMenuStrip = new System.Windows.Forms.ToolStripMenuItem(); this.renameCollectionMenuStrip = new System.Windows.Forms.ToolStripMenuItem(); this.deleteCollectionMenuStrip = new System.Windows.Forms.ToolStripMenuItem(); @@ -45,7 +44,10 @@ private void InitializeComponent() this.DuplicateMenuStrip = new System.Windows.Forms.ToolStripMenuItem(); this.mergeWithMenuStrip = new System.Windows.Forms.ToolStripMenuItem(); this.intersectMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.differenceMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.inverseToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.CollectionContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.exportBeatmapSetsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.ListViewCollections)).BeginInit(); this.CollectionContextMenuStrip.SuspendLayout(); @@ -90,6 +92,7 @@ private void InitializeComponent() this.ListViewCollections.Name = "ListViewCollections"; this.ListViewCollections.ShowGroups = false; this.ListViewCollections.Size = new System.Drawing.Size(463, 345); + this.ListViewCollections.Sorting = System.Windows.Forms.SortOrder.Ascending; this.ListViewCollections.TabIndex = 5; this.ListViewCollections.UnfocusedHighlightBackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192))))); this.ListViewCollections.UseCompatibleStateImageBehavior = false; @@ -126,25 +129,10 @@ private void InitializeComponent() this.textBox_collectionNameSearch.Size = new System.Drawing.Size(463, 20); this.textBox_collectionNameSearch.TabIndex = 1; // - // CollectionContextMenuStrip - // - this.CollectionContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.CreateMenuStrip, - this.renameCollectionMenuStrip, - this.deleteCollectionMenuStrip, - this.copyToolStripMenuItem, - this.pasteToolStripMenuItem, - this.DuplicateMenuStrip, - this.mergeWithMenuStrip, - this.intersectMenuItem, - this.inverseToolStripMenuItem}); - this.CollectionContextMenuStrip.Name = "CollectionContextMenuStrip"; - this.CollectionContextMenuStrip.Size = new System.Drawing.Size(155, 202); - // // CreateMenuStrip // this.CreateMenuStrip.Name = "CreateMenuStrip"; - this.CreateMenuStrip.Size = new System.Drawing.Size(154, 22); + this.CreateMenuStrip.Size = new System.Drawing.Size(181, 22); this.CreateMenuStrip.Tag = "Create"; this.CreateMenuStrip.Text = "Create"; this.CreateMenuStrip.ToolTipText = "Create new collection"; @@ -154,7 +142,7 @@ private void InitializeComponent() // this.renameCollectionMenuStrip.Name = "renameCollectionMenuStrip"; this.renameCollectionMenuStrip.ShortcutKeyDisplayString = "F2"; - this.renameCollectionMenuStrip.Size = new System.Drawing.Size(154, 22); + this.renameCollectionMenuStrip.Size = new System.Drawing.Size(181, 22); this.renameCollectionMenuStrip.Tag = "Rename"; this.renameCollectionMenuStrip.Text = "Rename"; this.renameCollectionMenuStrip.ToolTipText = "Rename currently selected collection"; @@ -164,7 +152,7 @@ private void InitializeComponent() // this.deleteCollectionMenuStrip.Name = "deleteCollectionMenuStrip"; this.deleteCollectionMenuStrip.ShortcutKeyDisplayString = "Del"; - this.deleteCollectionMenuStrip.Size = new System.Drawing.Size(154, 22); + this.deleteCollectionMenuStrip.Size = new System.Drawing.Size(181, 22); this.deleteCollectionMenuStrip.Tag = "Delete"; this.deleteCollectionMenuStrip.Text = "Delete"; this.deleteCollectionMenuStrip.ToolTipText = "Delete currently selected collections"; @@ -174,7 +162,7 @@ private void InitializeComponent() // this.copyToolStripMenuItem.Name = "copyToolStripMenuItem"; this.copyToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+C"; - this.copyToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.copyToolStripMenuItem.Size = new System.Drawing.Size(181, 22); this.copyToolStripMenuItem.Tag = "Copy"; this.copyToolStripMenuItem.Text = "Copy"; this.copyToolStripMenuItem.Click += new System.EventHandler(this.MenuStripClick); @@ -183,7 +171,7 @@ private void InitializeComponent() // this.pasteToolStripMenuItem.Name = "pasteToolStripMenuItem"; this.pasteToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+V"; - this.pasteToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.pasteToolStripMenuItem.Size = new System.Drawing.Size(181, 22); this.pasteToolStripMenuItem.Tag = "Paste"; this.pasteToolStripMenuItem.Text = "Paste"; this.pasteToolStripMenuItem.Click += new System.EventHandler(this.MenuStripClick); @@ -191,7 +179,7 @@ private void InitializeComponent() // DuplicateMenuStrip // this.DuplicateMenuStrip.Name = "DuplicateMenuStrip"; - this.DuplicateMenuStrip.Size = new System.Drawing.Size(154, 22); + this.DuplicateMenuStrip.Size = new System.Drawing.Size(181, 22); this.DuplicateMenuStrip.Tag = "Duplicate"; this.DuplicateMenuStrip.Text = "Duplicate"; this.DuplicateMenuStrip.ToolTipText = "Create a copy of currently selected collection"; @@ -200,7 +188,7 @@ private void InitializeComponent() // mergeWithMenuStrip // this.mergeWithMenuStrip.Name = "mergeWithMenuStrip"; - this.mergeWithMenuStrip.Size = new System.Drawing.Size(154, 22); + this.mergeWithMenuStrip.Size = new System.Drawing.Size(181, 22); this.mergeWithMenuStrip.Tag = "Merge"; this.mergeWithMenuStrip.Text = "Merge selected"; this.mergeWithMenuStrip.ToolTipText = "Merge beatmaps from selected collections into new collection"; @@ -209,23 +197,58 @@ private void InitializeComponent() // intersectMenuItem // this.intersectMenuItem.Name = "intersectMenuItem"; - this.intersectMenuItem.Size = new System.Drawing.Size(154, 22); + this.intersectMenuItem.Size = new System.Drawing.Size(181, 22); this.intersectMenuItem.Tag = "Intersect"; this.intersectMenuItem.Text = "Intersection"; this.intersectMenuItem.ToolTipText = "Create a collection that contains beatmaps that exist in all selected collections" + ""; this.intersectMenuItem.Click += new System.EventHandler(this.MenuStripClick); // + // differenceMenuItem + // + this.differenceMenuItem.Name = "differenceMenuItem"; + this.differenceMenuItem.Size = new System.Drawing.Size(181, 22); + this.differenceMenuItem.Tag = "Difference"; + this.differenceMenuItem.Text = "Difference"; + this.differenceMenuItem.ToolTipText = "Create a collection that contains beatmaps that exist in only one of the selected" + + " collections"; + this.differenceMenuItem.Click += new System.EventHandler(this.MenuStripClick); + // // inverseToolStripMenuItem // this.inverseToolStripMenuItem.Name = "inverseToolStripMenuItem"; - this.inverseToolStripMenuItem.Size = new System.Drawing.Size(154, 22); + this.inverseToolStripMenuItem.Size = new System.Drawing.Size(181, 22); this.inverseToolStripMenuItem.Tag = "Inverse"; this.inverseToolStripMenuItem.Text = "Inverse"; - this.inverseToolStripMenuItem.ToolTipText = "Create new collection that contains every beatmap in the user\'s library that isn\'" + - "t in selected collections"; + this.inverseToolStripMenuItem.ToolTipText = "Create new collection that contains every beatmap not present in all selected col" + + "lections"; this.inverseToolStripMenuItem.Click += new System.EventHandler(this.MenuStripClick); // + // CollectionContextMenuStrip + // + this.CollectionContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.CreateMenuStrip, + this.renameCollectionMenuStrip, + this.deleteCollectionMenuStrip, + this.copyToolStripMenuItem, + this.pasteToolStripMenuItem, + this.DuplicateMenuStrip, + this.mergeWithMenuStrip, + this.intersectMenuItem, + this.differenceMenuItem, + this.inverseToolStripMenuItem, + this.exportBeatmapSetsToolStripMenuItem}); + this.CollectionContextMenuStrip.Name = "CollectionContextMenuStrip"; + this.CollectionContextMenuStrip.Size = new System.Drawing.Size(182, 268); + // + // exportBeatmapSetsToolStripMenuItem + // + this.exportBeatmapSetsToolStripMenuItem.Name = "exportBeatmapSetsToolStripMenuItem"; + this.exportBeatmapSetsToolStripMenuItem.Size = new System.Drawing.Size(181, 22); + this.exportBeatmapSetsToolStripMenuItem.Tag = "Export"; + this.exportBeatmapSetsToolStripMenuItem.Text = "Export beatmap sets"; + this.exportBeatmapSetsToolStripMenuItem.Click += new System.EventHandler(this.MenuStripClick); + // // CollectionListingView // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -249,16 +272,18 @@ private void InitializeComponent() private BrightIdeasSoftware.OLVColumn olvColumn1; private BrightIdeasSoftware.OLVColumn olvColumn2; private System.Windows.Forms.TextBox textBox_collectionNameSearch; - private System.Windows.Forms.ContextMenuStrip CollectionContextMenuStrip; + private BrightIdeasSoftware.OLVColumn Total; + private System.Windows.Forms.ToolStripMenuItem CreateMenuStrip; private System.Windows.Forms.ToolStripMenuItem renameCollectionMenuStrip; private System.Windows.Forms.ToolStripMenuItem deleteCollectionMenuStrip; - private System.Windows.Forms.ToolStripMenuItem mergeWithMenuStrip; - private System.Windows.Forms.ToolStripMenuItem CreateMenuStrip; - private BrightIdeasSoftware.OLVColumn Total; + private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem pasteToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem DuplicateMenuStrip; + private System.Windows.Forms.ToolStripMenuItem mergeWithMenuStrip; private System.Windows.Forms.ToolStripMenuItem intersectMenuItem; + private System.Windows.Forms.ToolStripMenuItem differenceMenuItem; private System.Windows.Forms.ToolStripMenuItem inverseToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem pasteToolStripMenuItem; + private System.Windows.Forms.ContextMenuStrip CollectionContextMenuStrip; + private System.Windows.Forms.ToolStripMenuItem exportBeatmapSetsToolStripMenuItem; } } diff --git a/GuiComponents/Controls/CollectionListingView.cs b/GuiComponents/Controls/CollectionListingView.cs index 6daebbd..cde5e1f 100644 --- a/GuiComponents/Controls/CollectionListingView.cs +++ b/GuiComponents/Controls/CollectionListingView.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; @@ -15,8 +14,17 @@ namespace GuiComponents.Controls public partial class CollectionListingView : UserControl, ICollectionListingView { public event GuiHelpers.LoadFileArgs OnLoadFile; + public event GuiHelpers.CollectionReorderEventArgs OnCollectionReorder; public string SearchText => textBox_collectionNameSearch.Text; - public Collections Collections { set { ListViewCollections.SetObjects(value); } } + public Collections Collections + { + set + { + var selectedCollections = SelectedCollections; + ListViewCollections.SetObjects(value); + SelectedCollections = selectedCollections; + } + } public ICollection SelectedCollection { @@ -27,7 +35,15 @@ public ICollection SelectedCollection ListViewCollections.SelectedObject = value; } } - public ArrayList SelectedCollections => (ArrayList)ListViewCollections.SelectedObjects; + public ArrayList SelectedCollections + { + get => (ArrayList)ListViewCollections.SelectedObjects; + private set + { + ListViewCollections.SelectedObjects = value; + ListViewCollections.EnsureSelectionIsVisible(); + } + } public Collections HighlightedCollections { get => _collectionRenderer.Collections; @@ -38,13 +54,16 @@ public Collections HighlightedCollections } } - public event EventHandler SearchTextChanged; public event EventHandler SelectedCollectionChanged; public event EventHandler SelectedCollectionsChanged; public event GuiHelpers.CollectionBeatmapsEventArgs BeatmapsDropped; public event EventHandler RightClick; + private CollectionRenderer _collectionRenderer = new CollectionRenderer(); + private RearrangingDropSink _dropsink = new RearrangingDropSink(); + private OLVColumn NameColumn; + public CollectionListingView() { InitializeComponent(); @@ -67,9 +86,6 @@ private void Bind() } - private CollectionRenderer _collectionRenderer = new CollectionRenderer(); - private RearrangingDropSink _dropsink = new RearrangingDropSink(); - private void init() { //ListViewCollections.SelectedIndexChanged += ListViewCollectionsSelectedIndexChanged; @@ -77,8 +93,11 @@ private void init() ListViewCollections.FullRowSelect = true; ListViewCollections.HideSelection = false; ListViewCollections.DefaultRenderer = _collectionRenderer; - - _dropsink.CanDropBetween = false; + ListViewCollections.IsSimpleDragSource = true; + ListViewCollections.PrimarySortColumn = NameColumn = ListViewCollections.AllColumns[0]; + ListViewCollections.PrimarySortOrder = SortOrder.Ascending; + + _dropsink.CanDropBetween = true; _dropsink.CanDropOnItem = true; _dropsink.CanDropOnSubItem = false; _dropsink.CanDropOnBackground = false; @@ -123,6 +142,27 @@ private void DropsinkOnModelCanDrop(object sender, ModelDropEventArgs e) e.Handled = true; e.Effect = DragDropEffects.None; } + else if (e.SourceModels[0] is Collection) + { + + if (e.DropTargetLocation != DropTargetLocation.AboveItem && e.DropTargetLocation != DropTargetLocation.BelowItem) + { + e.Handled = true; + e.Effect = DragDropEffects.None; + } + else + { + var targetCollection = (Collection)e.TargetModel; + foreach (var model in e.SourceModels) + { + if (model == targetCollection) + { + e.Handled = true; + e.Effect = DragDropEffects.None; + } + } + } + } } } @@ -151,22 +191,37 @@ protected virtual void OnSelectedCollectionChanged() { SelectedCollectionChanged?.Invoke(this, EventArgs.Empty); } + protected virtual void OnSelectedCollectionsChanged() { SelectedCollectionsChanged?.Invoke(this, EventArgs.Empty); } + private void ListViewCollections_ModelDropped(object sender, ModelDropEventArgs e) { e.Handled = true; - var collection = (Collection)e.TargetModel; - if (collection == null) return; + var targetCollection = (Collection)e.TargetModel; + if (e.SourceModels[0] is Collection) + { + if (ListViewCollections.LastSortColumn != NameColumn || ListViewCollections.LastSortOrder != SortOrder.Ascending) + ListViewCollections.Sort(ListViewCollections.AllColumns[0], SortOrder.Ascending); + + var collections = new Collections(); + foreach (var collection in e.SourceModels) + collections.Add((Collection)collection); + + OnCollectionReorder?.Invoke(this, collections, targetCollection, e.DropTargetLocation == DropTargetLocation.AboveItem); + return; + } + + if (targetCollection == null) return; var beatmaps = new Beatmaps(); foreach (var b in e.SourceModels) { beatmaps.Add((BeatmapExtension)b); } - BeatmapsDropped?.Invoke(this, beatmaps, collection.Name); + BeatmapsDropped?.Invoke(this, beatmaps, targetCollection.Name); } protected virtual void OnRightClick(StringEventArgs e) diff --git a/GuiComponents/Controls/MainSidePanelView.Designer.cs b/GuiComponents/Controls/MainSidePanelView.Designer.cs index 28ada1e..cf494d5 100644 --- a/GuiComponents/Controls/MainSidePanelView.Designer.cs +++ b/GuiComponents/Controls/MainSidePanelView.Designer.cs @@ -37,10 +37,10 @@ private void InitializeComponent() this.Menu_saveAllCollections = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_saveOsuCollection = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_collectionsSplit = new System.Windows.Forms.ToolStripMenuItem(); - this.Menu_unloadCollections = new System.Windows.Forms.ToolStripMenuItem(); - this.listingToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.listingToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_listAllCollections = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_listMissingMaps = new System.Windows.Forms.ToolStripMenuItem(); + this.Menu_unloadCollections = new System.Windows.Forms.ToolStripMenuItem(); this.onlineToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_mapDownloads = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_downloadAllMissing = new System.Windows.Forms.ToolStripMenuItem(); @@ -63,7 +63,6 @@ private void InitializeComponent() // this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.fileToolStripMenuItem, - this.listingToolStripMenuItem, this.onlineToolStripMenuItem, this.osustatsCollectionsToolStripMenuItem, this.Menu_beatmapListing, @@ -80,6 +79,7 @@ private void InitializeComponent() this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.MenuItem_Opennn, this.saveToolStripMenuItem, + this.listingToolStripMenuItem1, this.Menu_unloadCollections}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); @@ -91,7 +91,7 @@ private void InitializeComponent() this.Menu_loadCollection, this.Menu_loadDefaultCollection}); this.MenuItem_Opennn.Name = "MenuItem_Opennn"; - this.MenuItem_Opennn.Size = new System.Drawing.Size(103, 22); + this.MenuItem_Opennn.Size = new System.Drawing.Size(180, 22); this.MenuItem_Opennn.Text = "Open"; // // Menu_loadCollection @@ -113,7 +113,7 @@ private void InitializeComponent() this.Menu_saveOsuCollection, this.Menu_collectionsSplit}); this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; - this.saveToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.saveToolStripMenuItem.Text = "Save"; // // Menu_saveAllCollections @@ -134,20 +134,14 @@ private void InitializeComponent() this.Menu_collectionsSplit.Size = new System.Drawing.Size(217, 22); this.Menu_collectionsSplit.Text = "Collections in separate files"; // - // Menu_unloadCollections - // - this.Menu_unloadCollections.Name = "Menu_unloadCollections"; - this.Menu_unloadCollections.Size = new System.Drawing.Size(103, 22); - this.Menu_unloadCollections.Text = "Clear"; + // listingToolStripMenuItem1 // - // listingToolStripMenuItem - // - this.listingToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.listingToolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.Menu_listAllCollections, this.Menu_listMissingMaps}); - this.listingToolStripMenuItem.Name = "listingToolStripMenuItem"; - this.listingToolStripMenuItem.Size = new System.Drawing.Size(54, 20); - this.listingToolStripMenuItem.Text = "Listing"; + this.listingToolStripMenuItem1.Name = "listingToolStripMenuItem1"; + this.listingToolStripMenuItem1.Size = new System.Drawing.Size(180, 22); + this.listingToolStripMenuItem1.Text = "Listing"; // // Menu_listAllCollections // @@ -161,6 +155,12 @@ private void InitializeComponent() this.Menu_listMissingMaps.Size = new System.Drawing.Size(168, 22); this.Menu_listMissingMaps.Text = "List missing maps"; // + // Menu_unloadCollections + // + this.Menu_unloadCollections.Name = "Menu_unloadCollections"; + this.Menu_unloadCollections.Size = new System.Drawing.Size(180, 22); + this.Menu_unloadCollections.Text = "Clear"; + // // onlineToolStripMenuItem // this.onlineToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -244,8 +244,8 @@ private void InitializeComponent() // Menu_beatmapListing // this.Menu_beatmapListing.Name = "Menu_beatmapListing"; - this.Menu_beatmapListing.Size = new System.Drawing.Size(133, 20); - this.Menu_beatmapListing.Text = "Show beatmap listing"; + this.Menu_beatmapListing.Size = new System.Drawing.Size(101, 20); + this.Menu_beatmapListing.Text = "Beatmap listing"; // // Menu_refreshBeatmapList // @@ -286,9 +286,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem MenuItem_Opennn; private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem listingToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem Menu_listAllCollections; - private System.Windows.Forms.ToolStripMenuItem Menu_listMissingMaps; private System.Windows.Forms.ToolStripMenuItem onlineToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem Menu_mapDownloads; private System.Windows.Forms.ToolStripMenuItem Menu_downloadAllMissing; @@ -310,5 +307,8 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem Menu_saveOsuCollection; private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem Menu_resetSettings; + private System.Windows.Forms.ToolStripMenuItem listingToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem Menu_listAllCollections; + private System.Windows.Forms.ToolStripMenuItem Menu_listMissingMaps; } } diff --git a/GuiComponents/Controls/StartupView.Designer.cs b/GuiComponents/Controls/StartupView.Designer.cs new file mode 100644 index 0000000..73bc550 --- /dev/null +++ b/GuiComponents/Controls/StartupView.Designer.cs @@ -0,0 +1,232 @@ +namespace GuiComponents.Controls +{ + partial class StartupView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.button_LoadOsuCollection = new System.Windows.Forms.Button(); + this.checkBox_DoNotShowOnStartup = new System.Windows.Forms.CheckBox(); + this.label_title = new System.Windows.Forms.Label(); + this.button_LoadCollectionFromFile = new System.Windows.Forms.Button(); + this.button_DoNothing = new System.Windows.Forms.Button(); + this.label_LoadDatabaseStatus = new System.Windows.Forms.Label(); + this.button_LoadDatabase = new System.Windows.Forms.Button(); + this.groupBox_Step1 = new System.Windows.Forms.GroupBox(); + this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel(); + this.button_LoadDatabaseSkip = new System.Windows.Forms.Button(); + this.groupBox_Step2 = new System.Windows.Forms.GroupBox(); + this.label_OpenedCollection = new System.Windows.Forms.Label(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.groupBox_Step1.SuspendLayout(); + this.flowLayoutPanel2.SuspendLayout(); + this.groupBox_Step2.SuspendLayout(); + this.flowLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // button_LoadOsuCollection + // + this.button_LoadOsuCollection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.button_LoadOsuCollection.Font = new System.Drawing.Font("Segoe UI", 9F); + this.button_LoadOsuCollection.Location = new System.Drawing.Point(3, 37); + this.button_LoadOsuCollection.Name = "button_LoadOsuCollection"; + this.button_LoadOsuCollection.Size = new System.Drawing.Size(495, 23); + this.button_LoadOsuCollection.TabIndex = 2; + this.button_LoadOsuCollection.Text = "Load your osu! collection"; + this.button_LoadOsuCollection.UseVisualStyleBackColor = true; + this.button_LoadOsuCollection.Click += new System.EventHandler(this.button_StartupAction_Click); + // + // checkBox_DoNotShowOnStartup + // + this.checkBox_DoNotShowOnStartup.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkBox_DoNotShowOnStartup.AutoSize = true; + this.checkBox_DoNotShowOnStartup.Font = new System.Drawing.Font("Segoe UI", 9F); + this.checkBox_DoNotShowOnStartup.Location = new System.Drawing.Point(4, 396); + this.checkBox_DoNotShowOnStartup.Name = "checkBox_DoNotShowOnStartup"; + this.checkBox_DoNotShowOnStartup.Size = new System.Drawing.Size(191, 19); + this.checkBox_DoNotShowOnStartup.TabIndex = 5; + this.checkBox_DoNotShowOnStartup.Text = "Use selected options on startup"; + this.checkBox_DoNotShowOnStartup.UseVisualStyleBackColor = true; + // + // label_title + // + this.label_title.AutoSize = true; + this.label_title.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold); + this.label_title.Location = new System.Drawing.Point(3, 12); + this.label_title.Name = "label_title"; + this.label_title.Size = new System.Drawing.Size(196, 21); + this.label_title.TabIndex = 2; + this.label_title.Text = "osu! Collection Manager"; + // + // button_LoadCollectionFromFile + // + this.button_LoadCollectionFromFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.button_LoadCollectionFromFile.Font = new System.Drawing.Font("Segoe UI", 9F); + this.button_LoadCollectionFromFile.Location = new System.Drawing.Point(3, 66); + this.button_LoadCollectionFromFile.Name = "button_LoadCollectionFromFile"; + this.button_LoadCollectionFromFile.Size = new System.Drawing.Size(495, 23); + this.button_LoadCollectionFromFile.TabIndex = 4; + this.button_LoadCollectionFromFile.Text = "Load osu! collection from file"; + this.button_LoadCollectionFromFile.UseVisualStyleBackColor = true; + this.button_LoadCollectionFromFile.Click += new System.EventHandler(this.button_StartupAction_Click); + // + // button_DoNothing + // + this.button_DoNothing.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.button_DoNothing.Font = new System.Drawing.Font("Segoe UI", 9F); + this.button_DoNothing.Location = new System.Drawing.Point(3, 95); + this.button_DoNothing.Name = "button_DoNothing"; + this.button_DoNothing.Size = new System.Drawing.Size(495, 23); + this.button_DoNothing.TabIndex = 3; + this.button_DoNothing.Text = "Continue without loading any more collections"; + this.button_DoNothing.UseVisualStyleBackColor = true; + this.button_DoNothing.Click += new System.EventHandler(this.button_StartupAction_Click); + // + // label_LoadDatabaseStatus + // + this.label_LoadDatabaseStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.label_LoadDatabaseStatus.Location = new System.Drawing.Point(3, 0); + this.label_LoadDatabaseStatus.Name = "label_LoadDatabaseStatus"; + this.label_LoadDatabaseStatus.Size = new System.Drawing.Size(511, 49); + this.label_LoadDatabaseStatus.TabIndex = 6; + this.label_LoadDatabaseStatus.Text = "AAA\r\nBBB\r\nCCC"; + this.label_LoadDatabaseStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // button_LoadDatabase + // + this.button_LoadDatabase.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.button_LoadDatabase.Font = new System.Drawing.Font("Segoe UI", 9F); + this.button_LoadDatabase.Location = new System.Drawing.Point(3, 52); + this.button_LoadDatabase.Name = "button_LoadDatabase"; + this.button_LoadDatabase.Size = new System.Drawing.Size(495, 23); + this.button_LoadDatabase.TabIndex = 0; + this.button_LoadDatabase.Text = "Load beatmaps from different location"; + this.button_LoadDatabase.UseVisualStyleBackColor = true; + this.button_LoadDatabase.Click += new System.EventHandler(this.button_DatabaseAction_Click); + // + // groupBox_Step1 + // + this.groupBox_Step1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox_Step1.Controls.Add(this.flowLayoutPanel2); + this.groupBox_Step1.Location = new System.Drawing.Point(7, 36); + this.groupBox_Step1.Name = "groupBox_Step1"; + this.groupBox_Step1.Size = new System.Drawing.Size(525, 135); + this.groupBox_Step1.TabIndex = 8; + this.groupBox_Step1.TabStop = false; + this.groupBox_Step1.Text = "Load osu! database"; + // + // flowLayoutPanel2 + // + this.flowLayoutPanel2.Controls.Add(this.label_LoadDatabaseStatus); + this.flowLayoutPanel2.Controls.Add(this.button_LoadDatabase); + this.flowLayoutPanel2.Controls.Add(this.button_LoadDatabaseSkip); + this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel2.Location = new System.Drawing.Point(3, 16); + this.flowLayoutPanel2.Name = "flowLayoutPanel2"; + this.flowLayoutPanel2.Size = new System.Drawing.Size(519, 116); + this.flowLayoutPanel2.TabIndex = 10; + // + // button_LoadDatabaseSkip + // + this.button_LoadDatabaseSkip.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.button_LoadDatabaseSkip.Font = new System.Drawing.Font("Segoe UI", 9F); + this.button_LoadDatabaseSkip.Location = new System.Drawing.Point(3, 81); + this.button_LoadDatabaseSkip.Name = "button_LoadDatabaseSkip"; + this.button_LoadDatabaseSkip.Size = new System.Drawing.Size(495, 23); + this.button_LoadDatabaseSkip.TabIndex = 1; + this.button_LoadDatabaseSkip.Text = "Skip"; + this.button_LoadDatabaseSkip.UseVisualStyleBackColor = true; + this.button_LoadDatabaseSkip.Click += new System.EventHandler(this.button_DatabaseAction_Click); + // + // groupBox_Step2 + // + this.groupBox_Step2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox_Step2.Controls.Add(this.flowLayoutPanel1); + this.groupBox_Step2.Location = new System.Drawing.Point(7, 177); + this.groupBox_Step2.Name = "groupBox_Step2"; + this.groupBox_Step2.Size = new System.Drawing.Size(525, 168); + this.groupBox_Step2.TabIndex = 9; + this.groupBox_Step2.TabStop = false; + this.groupBox_Step2.Text = "Starting point"; + // + // label_OpenedCollection + // + this.label_OpenedCollection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.label_OpenedCollection.Location = new System.Drawing.Point(3, 0); + this.label_OpenedCollection.Name = "label_OpenedCollection"; + this.label_OpenedCollection.Size = new System.Drawing.Size(511, 34); + this.label_OpenedCollection.TabIndex = 7; + this.label_OpenedCollection.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Controls.Add(this.label_OpenedCollection); + this.flowLayoutPanel1.Controls.Add(this.button_LoadOsuCollection); + this.flowLayoutPanel1.Controls.Add(this.button_LoadCollectionFromFile); + this.flowLayoutPanel1.Controls.Add(this.button_DoNothing); + this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel1.Location = new System.Drawing.Point(3, 16); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(519, 149); + this.flowLayoutPanel1.TabIndex = 10; + // + // StartupView + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.Controls.Add(this.groupBox_Step2); + this.Controls.Add(this.groupBox_Step1); + this.Controls.Add(this.label_title); + this.Controls.Add(this.checkBox_DoNotShowOnStartup); + this.Name = "StartupView"; + this.Size = new System.Drawing.Size(535, 418); + this.groupBox_Step1.ResumeLayout(false); + this.flowLayoutPanel2.ResumeLayout(false); + this.groupBox_Step2.ResumeLayout(false); + this.flowLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button_LoadOsuCollection; + private System.Windows.Forms.CheckBox checkBox_DoNotShowOnStartup; + private System.Windows.Forms.Label label_title; + private System.Windows.Forms.Button button_LoadCollectionFromFile; + private System.Windows.Forms.Button button_DoNothing; + private System.Windows.Forms.Label label_LoadDatabaseStatus; + private System.Windows.Forms.Button button_LoadDatabase; + private System.Windows.Forms.GroupBox groupBox_Step1; + private System.Windows.Forms.GroupBox groupBox_Step2; + private System.Windows.Forms.Button button_LoadDatabaseSkip; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2; + private System.Windows.Forms.Label label_OpenedCollection; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + } +} diff --git a/GuiComponents/Controls/StartupView.cs b/GuiComponents/Controls/StartupView.cs new file mode 100644 index 0000000..f516274 --- /dev/null +++ b/GuiComponents/Controls/StartupView.cs @@ -0,0 +1,179 @@ +using Common; +using Gui.Misc; +using GuiComponents.Interfaces; +using System; +using System.Windows.Forms; + +namespace GuiComponents.Controls +{ + public partial class StartupView : UserControl, IStartupView + { + public event GuiHelpers.StartupCollectionEventArgs StartupCollectionOperation; + public event GuiHelpers.StartupDatabaseEventArgs StartupDatabaseOperation; + + public string LoadDatabaseStatusText + { + get => label_LoadDatabaseStatus.Text; + set + { + if (label_LoadDatabaseStatus.InvokeRequired) + { + label_LoadDatabaseStatus.Invoke((MethodInvoker)(() => + { + label_LoadDatabaseStatus.Text = value; + })); + return; + } + + label_LoadDatabaseStatus.Text = value; + } + } + + public bool UseSelectedOptionsOnStartup + { + get => checkBox_DoNotShowOnStartup.Checked; + set + { + if (checkBox_DoNotShowOnStartup.InvokeRequired) + { + checkBox_DoNotShowOnStartup.Invoke((MethodInvoker)(() => + { + checkBox_DoNotShowOnStartup.Checked = value; + })); + return; + } + + checkBox_DoNotShowOnStartup.Checked = value; + } + } + + public bool LoadOsuCollectionButtonEnabled + { + get => button_LoadOsuCollection.Enabled; + set + { + if (button_LoadOsuCollection.InvokeRequired) + { + button_LoadOsuCollection.Invoke((MethodInvoker)(() => + { + button_LoadOsuCollection.Enabled = value; + })); + return; + } + + button_LoadOsuCollection.Enabled = value; + } + } + + + public string CollectionStatusText + { + get => label_OpenedCollection.Text; + set + { + if (label_OpenedCollection.InvokeRequired) + { + label_OpenedCollection.Invoke((MethodInvoker)(() => + { + label_OpenedCollection.Visible = !string.IsNullOrEmpty(value); + label_OpenedCollection.Text = value; + })); + return; + } + + label_OpenedCollection.Visible = !string.IsNullOrEmpty(value); + label_OpenedCollection.Text = value; + } + } + + public bool CollectionButtonsEnabled + { + get => button_LoadCollectionFromFile.Enabled; + set + { + if (button_LoadCollectionFromFile.InvokeRequired) + { + button_LoadCollectionFromFile.Invoke((MethodInvoker)(() => + { + button_DoNothing.Enabled + = button_LoadCollectionFromFile.Enabled + = value; + + button_LoadOsuCollection.Enabled = LoadOsuCollectionButtonEnabled && value; + })); + return; + } + + button_DoNothing.Enabled + = button_LoadCollectionFromFile.Enabled + = value; + + button_LoadOsuCollection.Enabled = LoadOsuCollectionButtonEnabled && value; + } + } + + public bool DatabaseButtonsEnabled + { + get => button_LoadDatabase.Enabled; + set + { + if (button_LoadDatabase.InvokeRequired) + { + button_LoadDatabase.Invoke((MethodInvoker)(() => + { + button_LoadDatabase.Enabled + = button_LoadDatabaseSkip.Enabled + = value; + })); + return; + } + + button_LoadDatabase.Enabled + = button_LoadDatabaseSkip.Enabled + = value; + } + } + + public bool UseSelectedOptionsOnStartupEnabled + { + get => checkBox_DoNotShowOnStartup.Enabled; + set + { + if (checkBox_DoNotShowOnStartup.InvokeRequired) + { + checkBox_DoNotShowOnStartup.Invoke((MethodInvoker)(() => + { + checkBox_DoNotShowOnStartup.Enabled = value; + })); + return; + } + + checkBox_DoNotShowOnStartup.Enabled = value; + } + } + + public StartupView() + { + InitializeComponent(); + flowLayoutPanel1.SetFlowBreak(button_DoNothing, true); + button_DoNothing.Tag = StartupCollectionAction.None; + button_LoadOsuCollection.Tag = StartupCollectionAction.LoadOsuCollection; + button_LoadCollectionFromFile.Tag = StartupCollectionAction.LoadCollectionFromFile; + + button_LoadDatabase.Tag = StartupDatabaseAction.LoadFromDifferentLocation; + button_LoadDatabaseSkip.Tag = StartupDatabaseAction.Unload; + } + + private void button_StartupAction_Click(object sender, EventArgs e) + { + var button = (Button)sender; + StartupCollectionOperation?.Invoke(this, (StartupCollectionAction)button.Tag); + } + + private void button_DatabaseAction_Click(object sender, EventArgs e) + { + var button = (Button)sender; + StartupDatabaseOperation?.Invoke(this, (StartupDatabaseAction)button.Tag); + } + } +} diff --git a/GuiComponents/Controls/StartupView.resx b/GuiComponents/Controls/StartupView.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/GuiComponents/Controls/StartupView.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + \ No newline at end of file diff --git a/GuiComponents/Forms/BaseForm.cs b/GuiComponents/Forms/BaseForm.cs index c4cff12..96cbea1 100644 --- a/GuiComponents/Forms/BaseForm.cs +++ b/GuiComponents/Forms/BaseForm.cs @@ -9,14 +9,15 @@ public class BaseForm : Form, IForm { protected BaseForm() { - FormClosing += (s, a) => Closing?.Invoke(this, EventArgs.Empty); + FormClosing += (s, e) => Closing?.Invoke(this, e); StartPosition = FormStartPosition.CenterParent; Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); Font = new Font("Segoe UI", 9f); } + public void ShowAndBlock() { - this.ShowDialog(); + ShowDialog(); } public event EventHandler Closing; diff --git a/GuiComponents/Forms/MainFormView.cs b/GuiComponents/Forms/MainFormView.cs index b978a7a..f3bb6ca 100644 --- a/GuiComponents/Forms/MainFormView.cs +++ b/GuiComponents/Forms/MainFormView.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Windows.Forms; using Gui.Misc; using GuiComponents.Interfaces; @@ -41,5 +42,11 @@ private void Form1_DragDrop(object sender, DragEventArgs e) var files = (string[]) e.Data.GetData(DataFormats.FileDrop); OnLoadFile?.Invoke(this, files); } + + protected override void OnShown(EventArgs e) + { + Activate(); + base.OnShown(e); + } } } \ No newline at end of file diff --git a/GuiComponents/Forms/StartupForm.Designer.cs b/GuiComponents/Forms/StartupForm.Designer.cs new file mode 100644 index 0000000..4123dcf --- /dev/null +++ b/GuiComponents/Forms/StartupForm.Designer.cs @@ -0,0 +1,66 @@ +namespace GuiComponents.Forms +{ + partial class StartupForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.startupView1 = new GuiComponents.Controls.StartupView(); + this.SuspendLayout(); + // + // startupView1 + // + this.startupView1.CollectionButtonsEnabled = true; + this.startupView1.CollectionStatusText = ""; + this.startupView1.DatabaseButtonsEnabled = true; + this.startupView1.LoadDatabaseStatusText = "..."; + this.startupView1.LoadOsuCollectionButtonEnabled = true; + this.startupView1.Location = new System.Drawing.Point(0, 0); + this.startupView1.Name = "startupView1"; + this.startupView1.Size = new System.Drawing.Size(519, 379); + this.startupView1.TabIndex = 0; + this.startupView1.UseSelectedOptionsOnStartup = false; + // + // StartupForm + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.ClientSize = new System.Drawing.Size(519, 379); + this.Controls.Add(this.startupView1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(535, 418); + this.MinimumSize = new System.Drawing.Size(535, 418); + this.Name = "StartupForm"; + this.Text = "osu! Collection Manager"; + this.ResumeLayout(false); + + } + + #endregion + + private Controls.StartupView startupView1; + } +} \ No newline at end of file diff --git a/GuiComponents/Forms/StartupForm.cs b/GuiComponents/Forms/StartupForm.cs new file mode 100644 index 0000000..cd276e2 --- /dev/null +++ b/GuiComponents/Forms/StartupForm.cs @@ -0,0 +1,15 @@ +using GuiComponents.Interfaces; +using System.Windows.Forms; + +namespace GuiComponents.Forms +{ + public partial class StartupForm : BaseForm, IStartupForm + { + public StartupForm() + { + InitializeComponent(); + } + + public IStartupView StartupView => startupView1; + } +} diff --git a/GuiComponents/Forms/StartupForm.resx b/GuiComponents/Forms/StartupForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/GuiComponents/Forms/StartupForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + \ No newline at end of file diff --git a/GuiComponents/GuiComponents.csproj b/GuiComponents/GuiComponents.csproj index d192ca0..03ec3b8 100644 --- a/GuiComponents/GuiComponents.csproj +++ b/GuiComponents/GuiComponents.csproj @@ -1,15 +1,17 @@  - net472 + net48 GuiComponents GuiComponents Copyright © 2017 latest + true true + diff --git a/GuiComponents/ProgressForm.Designer.cs b/GuiComponents/ProgressForm.Designer.cs new file mode 100644 index 0000000..0de6760 --- /dev/null +++ b/GuiComponents/ProgressForm.Designer.cs @@ -0,0 +1,87 @@ +namespace GuiComponents +{ + partial class ProgressForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label_text = new System.Windows.Forms.Label(); + this.button_cancel = new System.Windows.Forms.Button(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.SuspendLayout(); + // + // label_text + // + this.label_text.Location = new System.Drawing.Point(12, 9); + this.label_text.MaximumSize = new System.Drawing.Size(415, 91); + this.label_text.Name = "label_text"; + this.label_text.Size = new System.Drawing.Size(415, 81); + this.label_text.TabIndex = 4; + this.label_text.Text = "Text\r\n\r\nText\r\n\r\nText\r\n\r\nText\r\n"; + this.label_text.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // button_cancel + // + this.button_cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.button_cancel.DialogResult = System.Windows.Forms.DialogResult.No; + this.button_cancel.Location = new System.Drawing.Point(314, 138); + this.button_cancel.Name = "button_cancel"; + this.button_cancel.Size = new System.Drawing.Size(117, 27); + this.button_cancel.TabIndex = 5; + this.button_cancel.Text = "Cancel"; + this.button_cancel.UseVisualStyleBackColor = true; + // + // progressBar1 + // + this.progressBar1.Location = new System.Drawing.Point(13, 108); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(418, 23); + this.progressBar1.TabIndex = 6; + // + // ProgressForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(443, 177); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.button_cancel); + this.Controls.Add(this.label_text); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProgressForm"; + this.Text = "ProgressForm"; + this.ResumeLayout(false); + + } + + #endregion + + public System.Windows.Forms.Label label_text; + private System.Windows.Forms.Button button_cancel; + private System.Windows.Forms.ProgressBar progressBar1; + } +} \ No newline at end of file diff --git a/GuiComponents/ProgressForm.cs b/GuiComponents/ProgressForm.cs new file mode 100644 index 0000000..5225acb --- /dev/null +++ b/GuiComponents/ProgressForm.cs @@ -0,0 +1,44 @@ +using GuiComponents.Forms; +using GuiComponents.Interfaces; +using System; +using System.Windows.Forms; + +namespace GuiComponents +{ + public partial class ProgressForm : BaseForm, IProgressForm + { + public event EventHandler AbortClicked; + public ProgressForm() + { + InitializeComponent(); + } + + private const int CP_NOCLOSE_BUTTON = 0x200; + protected override CreateParams CreateParams + { + get + { + CreateParams myCp = base.CreateParams; + myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON; + return myCp; + } + } + internal static IProgressForm ShowDialog(Progress userProgressMessage, Progress completionPercentage) + { + var form = new ProgressForm(); + userProgressMessage.ProgressChanged += (_, message) => form.label_text.Text = message; + completionPercentage.ProgressChanged += form.CompletionPercentage_ProgressChanged; + form.button_cancel.Click += (_, __) => form.AbortClicked?.Invoke(form, EventArgs.Empty); + + form.Text = $"Collection Manager - Beatmap Export"; + return form; + } + + private void CompletionPercentage_ProgressChanged(object sender, int percentage) + { + progressBar1.Value = percentage; + if (percentage == progressBar1.Maximum) + button_cancel.Text = "Close"; + } + } +} diff --git a/GuiComponents/ProgressForm.resx b/GuiComponents/ProgressForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/GuiComponents/ProgressForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + \ No newline at end of file diff --git a/GuiComponents/UserDialogs.cs b/GuiComponents/UserDialogs.cs index c87d72e..6056c24 100644 --- a/GuiComponents/UserDialogs.cs +++ b/GuiComponents/UserDialogs.cs @@ -3,6 +3,7 @@ using System.Windows.Forms; using Common; using GuiComponents.Interfaces; +using Microsoft.WindowsAPICodePack.Dialogs; namespace GuiComponents { @@ -14,39 +15,46 @@ public bool IsThisPathCorrect(string path) "Detected osu in: " + Environment.NewLine + path + Environment.NewLine + "Is this correct?", "osu! directory", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk); return dialogResult == DialogResult.Yes; - } + } public string SelectDirectory(string text) { return SelectDirectory(text, false); } + public string SelectDirectory(string text, bool showNewFolder = false) { - FolderBrowserDialog dialog = new FolderBrowserDialog(); - //set description and base folder for browsing - - dialog.ShowNewFolderButton = true; - dialog.Description = text; - dialog.RootFolder = Environment.SpecialFolder.MyComputer; - if (dialog.ShowDialog() == DialogResult.OK && Directory.Exists((dialog.SelectedPath))) + var dialog = new CommonOpenFileDialog { - return dialog.SelectedPath; - } + IsFolderPicker = true, + Title = text + }; + if (dialog.ShowDialog() == CommonFileDialogResult.Ok && Directory.Exists(dialog.FileName)) + return dialog.FileName; + return string.Empty; } - public string SelectFile(string text, string types = "", string filename = "") + + public string SelectFile(string text, string filters = "", string filename = "") { - OpenFileDialog openFileDialog = new OpenFileDialog(); - openFileDialog.Filter = types; //"Collection database (*.db)|*.db"; - openFileDialog.FileName = filename; //"collection.db"; - openFileDialog.Multiselect = false; - var result = openFileDialog.ShowDialog(); - if (result == DialogResult.OK) - return openFileDialog.FileName; - else - return string.Empty; + var dialog = new CommonOpenFileDialog + { + Multiselect = false, + Title = text + }; + if (!string.IsNullOrEmpty(filters)) + { + var split = filters.Split(new[] { '|' }, 2); + dialog.Filters.Add(new CommonFileDialogFilter(split[0], split[1])); + } + + if (dialog.ShowDialog() == CommonFileDialogResult.Ok) + return dialog.FileName; + + return string.Empty; } + public string SaveFile(string title, string types = "all|*.*") { SaveFileDialog saveFileDialog = new SaveFileDialog @@ -79,6 +87,11 @@ public bool YesNoMessageBox(string text, string caption, MessageBoxType messageB return (result.dialogResult == DialogResult.Yes, result.doNotAskAgain); } + public IProgressForm ProgressForm(Progress userProgressMessage, Progress completionPercentage) + { + return GuiComponents.ProgressForm.ShowDialog(userProgressMessage, completionPercentage); + } + public void OkMessageBox(string text, string caption, MessageBoxType messageBoxType = MessageBoxType.Info) { var icon = GetMessageBoxIcon(messageBoxType); diff --git a/InnoSetup/script.iss b/InnoSetup/script.iss index b67e438..f7ab9fe 100644 --- a/InnoSetup/script.iss +++ b/InnoSetup/script.iss @@ -51,21 +51,23 @@ Name: osdbAssociation; Description: "Associate "".osdb"" extension (Collection f Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 [Files] -Source: "..\App\bin\Release\net472\App.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\downloadSources.json"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\CollectionManager.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\CollectionManagerExtensionsDll.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\Common.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\GuiComponents.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\MusicPlayer.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\NAudio.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\Newtonsoft.Json.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\ObjectListView.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\System.Security.Principal.Windows.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\Microsoft.Win32.Registry.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\System.Security.AccessControl.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\SharpCompress.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\App\bin\Release\net472\CommandLine.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\App.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\downloadSources.json"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\CollectionManager.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\CollectionManagerExtensionsDll.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\Common.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\GuiComponents.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\MusicPlayer.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\NAudio.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\Newtonsoft.Json.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\ObjectListView.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\System.Security.Principal.Windows.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\Microsoft.Win32.Registry.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\System.Security.AccessControl.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\SharpCompress.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\CommandLine.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\Microsoft.WindowsAPICodePack.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\App\bin\Release\net48\Microsoft.WindowsAPICodePack.Shell.dll"; DestDir: "{app}"; Flags: ignoreversion ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] diff --git a/MusicPlayer/MusicPlayer.csproj b/MusicPlayer/MusicPlayer.csproj index 0846055..7abbce6 100644 --- a/MusicPlayer/MusicPlayer.csproj +++ b/MusicPlayer/MusicPlayer.csproj @@ -1,6 +1,6 @@  - net472 + net48 MusicPlayer MusicPlayer Copyright © 2017 diff --git a/MusicPlayer/MusicPlayerManager.cs b/MusicPlayer/MusicPlayerManager.cs index 9159705..5eae08d 100644 --- a/MusicPlayer/MusicPlayerManager.cs +++ b/MusicPlayer/MusicPlayerManager.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using System.Linq; +using System.Net; namespace MusicPlayer { @@ -45,6 +47,34 @@ public void SetSpeed(float speed) public void Play(string audioFile, int startTime) { + Uri uri = new Uri(audioFile); + + if (uri.HostNameType == UriHostNameType.Dns) + { + var tempFolderPath = Path.Combine(Path.GetTempPath(), "CM-previews"); + Directory.CreateDirectory(tempFolderPath); + var directoryInfo = new DirectoryInfo(tempFolderPath); + var files = directoryInfo.GetFiles(); + if (files.Length > 100) + { + foreach (var file in files.OrderBy(f => f.LastWriteTimeUtc).Take(30)) + { + file.Delete(); + } + } + + var tempFilePath = Path.Combine(tempFolderPath, uri.Segments.Last()); + if (!File.Exists(tempFilePath)) + { + using (WebClient ws = new WebClient()) + { + ws.DownloadFile(audioFile, tempFilePath); + } + } + + audioFile = tempFilePath; + } + musicPlayer.Play(audioFile, startTime); } diff --git a/README.md b/README.md index 219ebc7..a6b4b13 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,10 @@ The following opinions are made available by right clicking in the left panel: The new collection is named using the selected collection closest to the top of the listing, with `_0` appended to its name. +- Difference: Differentiates all selected collections by making a new collection with only maps that are present in only one selected collection. + + The new collection is named using the selected collection closest to the top of the listing, with `_0` appended to its name. + - Inverse: Inverses all selected collections by making a new collection with only maps that are not present in any of the selected collections but are present in your osu! songs folder. The new collection is named using the selected collection closest to the top of the listing, with `_0` appended to its name.