Add dialog to update database statistics.

This commit is contained in:
2020-09-20 19:52:28 +01:00
parent 39ac75742f
commit b8b41121e3
8 changed files with 544 additions and 0 deletions

View File

@@ -710,5 +710,47 @@ namespace RomRepoMgr.Resources {
return ResourceManager.GetString("RomSetCategoryLabel", resourceCulture);
}
}
internal static string DatabaseMenuText {
get {
return ResourceManager.GetString("DatabaseMenuText", resourceCulture);
}
}
internal static string DatabaseMenuUpdateStatsText {
get {
return ResourceManager.GetString("DatabaseMenuUpdateStatsText", resourceCulture);
}
}
internal static string UpdateStatsConfirmationDialogText {
get {
return ResourceManager.GetString("UpdateStatsConfirmationDialogText", resourceCulture);
}
}
internal static string UpdateStatsTitle {
get {
return ResourceManager.GetString("UpdateStatsTitle", resourceCulture);
}
}
internal static string CalculatingStatisticsForRomSet {
get {
return ResourceManager.GetString("CalculatingStatisticsForRomSet", resourceCulture);
}
}
internal static string RemovingOldStatistics {
get {
return ResourceManager.GetString("RemovingOldStatistics", resourceCulture);
}
}
internal static string RetrievingRomSetsFromDatabase {
get {
return ResourceManager.GetString("RetrievingRomSetsFromDatabase", resourceCulture);
}
}
}
}

View File

@@ -346,4 +346,26 @@
<data name="RomSetCategoryLabel" xml:space="preserve">
<value>Categoría</value>
</data>
<data name="RetrievingRomSetsFromDatabase" xml:space="preserve">
<value>Recuperando sets de ROMs de la base de datos...</value>
</data>
<data name="RemovingOldStatistics" xml:space="preserve">
<value>Eliminando estadísticas antiguas</value>
</data>
<data name="CalculatingStatisticsForRomSet" xml:space="preserve">
<value>Calculando estadísticas para {0} - {1} ({2})</value>
</data>
<data name="DatabaseMenuText" xml:space="preserve">
<value>Base de datos</value>
</data>
<data name="DatabaseMenuUpdateStatsText" xml:space="preserve">
<value>Actualizar estadísticas</value>
</data>
<data name="UpdateStatsConfirmationDialogText" xml:space="preserve">
<value>¿Quieres actualizar las estadísticas de los sets de ROMs en la base de datos?
Tardará mucho tiempo...</value>
</data>
<data name="UpdateStatsTitle" xml:space="preserve">
<value>Actualizando estadísticas de sets de ROMs</value>
</data>
</root>

View File

@@ -352,4 +352,26 @@ Do you want to delete the file?</value>
<data name="RomSetCategoryLabel" xml:space="preserve">
<value>Category</value>
</data>
<data name="DatabaseMenuText" xml:space="preserve">
<value>Database</value>
</data>
<data name="DatabaseMenuUpdateStatsText" xml:space="preserve">
<value>Update statistics</value>
</data>
<data name="UpdateStatsConfirmationDialogText" xml:space="preserve">
<value>Do you want to update ROM set statistics in database?
This will take a long time...</value>
</data>
<data name="UpdateStatsTitle" xml:space="preserve">
<value>Updating ROM sets statistics</value>
</data>
<data name="CalculatingStatisticsForRomSet" xml:space="preserve">
<value>Calculating statistics for {0} - {1} ({2})</value>
</data>
<data name="RemovingOldStatistics" xml:space="preserve">
<value>Removing old statistics</value>
</data>
<data name="RetrievingRomSetsFromDatabase" xml:space="preserve">
<value>Retrieving ROM sets from database...</value>
</data>
</root>

View File

@@ -65,6 +65,7 @@ namespace RomRepoMgr.ViewModels
ExportRomsCommand = ReactiveCommand.Create(ExecuteExportRomsCommand);
MountCommand = ReactiveCommand.Create(ExecuteMountCommand);
UmountCommand = ReactiveCommand.Create(ExecuteUmountCommand);
UpdateStatsCommand = ReactiveCommand.Create(ExecuteUpdateStatsCommand);
RomSets = new ObservableCollection<RomSetModel>(romSets);
}
@@ -101,6 +102,8 @@ namespace RomRepoMgr.ViewModels
public string HelpMenuText => Localization.HelpMenuText;
public string HelpMenuAboutText => Localization.HelpMenuAboutText;
public string FilesystemMenuUmountText => Localization.FilesystemMenuUmountText;
public string DatabaseMenuText => Localization.DatabaseMenuText;
public string DatabaseMenuUpdateStatsText => Localization.DatabaseMenuUpdateStatsText;
public bool NativeMenuSupported =>
NativeMenu.GetIsNativeMenuExported((Application.Current.ApplicationLifetime as
@@ -118,6 +121,7 @@ namespace RomRepoMgr.ViewModels
public ReactiveCommand<Unit, Unit> ExportRomsCommand { get; }
public ReactiveCommand<Unit, Unit> MountCommand { get; }
public ReactiveCommand<Unit, Unit> UmountCommand { get; }
public ReactiveCommand<Unit, Unit> UpdateStatsCommand { get; }
public Vfs Vfs
{
@@ -347,5 +351,21 @@ namespace RomRepoMgr.ViewModels
void VfsOnUmounted(object sender, EventArgs e) => Vfs = null;
void ExecuteUmountCommand() => Vfs?.Umount();
async void ExecuteUpdateStatsCommand()
{
ButtonResult result = await MessageBoxManager.
GetMessageBoxStandardWindow(Localization.DatabaseMenuUpdateStatsText,
Localization.UpdateStatsConfirmationDialogText,
ButtonEnum.YesNo, Icon.Database).ShowDialog(_view);
if(result == ButtonResult.No)
return;
var view = new UpdateStats();
var viewModel = new UpdateStatsViewModel(view);
view.DataContext = viewModel;
await view.ShowDialog(_view);
}
}
}

View File

@@ -0,0 +1,260 @@
/******************************************************************************
// RomRepoMgr - ROM repository manager
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2020 Natalia Portillo
*******************************************************************************/
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Threading.Tasks;
using Avalonia.Threading;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using ReactiveUI;
using RomRepoMgr.Core.Models;
using RomRepoMgr.Database;
using RomRepoMgr.Database.Models;
using RomRepoMgr.Resources;
using RomRepoMgr.Views;
namespace RomRepoMgr.ViewModels
{
public sealed class UpdateStatsViewModel : ViewModelBase
{
readonly UpdateStats _view;
bool _canClose;
double _currentValue;
bool _indeterminateProgress;
double _maximumValue;
double _minimumValue;
bool _progressVisible;
RomSetModel _selectedRomSet;
string _statusMessage;
public UpdateStatsViewModel(UpdateStats view)
{
_view = view;
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
IndeterminateProgress = true;
ProgressVisible = false;
RomSets = new ObservableCollection<RomSetModel>();
}
[NotNull]
public string Title => Localization.UpdateStatsTitle;
public string RomSetNameLabel => Localization.RomSetNameLabel;
public string RomSetVersionLabel => Localization.RomSetVersionLabel;
public string RomSetAuthorLabel => Localization.RomSetAuthorLabel;
public string RomSetCategoryLabel => Localization.RomSetCategoryLabel;
public string RomSetDateLabel => Localization.RomSetDateLabel;
public string RomSetDescriptionLabel => Localization.RomSetDescriptionLabel;
public string RomSetCommentLabel => Localization.RomSetCommentLabel;
public string RomSetTotalMachinesLabel => Localization.RomSetTotalMachinesLabel;
public string RomSetCompleteMachinesLabel => Localization.RomSetCompleteMachinesLabel;
public string RomSetIncompleteMachinesLabel => Localization.RomSetIncompleteMachinesLabel;
public string RomSetTotalRomsLabel => Localization.RomSetTotalRomsLabel;
public string RomSetHaveRomsLabel => Localization.RomSetHaveRomsLabel;
public string RomSetMissRomsLabel => Localization.RomSetMissRomsLabel;
public string StatusMessage
{
get => _statusMessage;
set => this.RaiseAndSetIfChanged(ref _statusMessage, value);
}
public bool IndeterminateProgress
{
get => _indeterminateProgress;
set => this.RaiseAndSetIfChanged(ref _indeterminateProgress, value);
}
public double MaximumValue
{
get => _maximumValue;
set => this.RaiseAndSetIfChanged(ref _maximumValue, value);
}
public double MinimumValue
{
get => _minimumValue;
set => this.RaiseAndSetIfChanged(ref _minimumValue, value);
}
public double CurrentValue
{
get => _currentValue;
set => this.RaiseAndSetIfChanged(ref _currentValue, value);
}
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
public RomSetModel SelectedRomSet
{
get => _selectedRomSet;
set => this.RaiseAndSetIfChanged(ref _selectedRomSet, value);
}
public bool CanClose
{
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
public ObservableCollection<RomSetModel> RomSets { get; }
public string CloseLabel => Localization.CloseLabel;
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
internal void OnOpened() => Task.Run(() =>
{
using var ctx = Context.Create(Settings.Settings.Current.DatabasePath);
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.RetrievingRomSetsFromDatabase;
ProgressVisible = true;
IndeterminateProgress = true;
});
long romSetCount = ctx.RomSets.LongCount();
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.RemovingOldStatistics;
});
ctx.Database.ExecuteSqlRaw("DELETE FROM \"RomSetStats\"");
Dispatcher.UIThread.Post(() =>
{
IndeterminateProgress = false;
MinimumValue = 0;
MaximumValue = romSetCount;
CurrentValue = 0;
});
long pos = 0;
foreach(RomSet romSet in ctx.RomSets)
{
long currentPos = pos;
Dispatcher.UIThread.Post(() =>
{
StatusMessage = string.Format(Localization.CalculatingStatisticsForRomSet, romSet.Name,
romSet.Version, romSet.Description);
CurrentValue = currentPos;
});
try
{
RomSetStat stats = ctx.RomSets.Where(r => r.Id == romSet.Id).Select(r => new RomSetStat
{
RomSetId = r.Id,
TotalMachines = r.Machines.Count,
CompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.All(f => f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.All(f => f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
m.Files.All(f => f.File.IsInRepo) &&
m.Disks.All(f => f.Disk.IsInRepo)),
IncompleteMachines =
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 &&
m.Files.Any(f => !f.File.IsInRepo)) +
r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 &&
m.Disks.Any(f => !f.Disk.IsInRepo)) +
r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 &&
(m.Files.Any(f => !f.File.IsInRepo) ||
m.Disks.Any(f => !f.Disk.IsInRepo))),
TotalRoms = r.Machines.Sum(m => m.Files.Count) + r.Machines.Sum(m => m.Disks.Count) +
r.Machines.Sum(m => m.Medias.Count),
HaveRoms = r.Machines.Sum(m => m.Files.Count(f => f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => f.Media.IsInRepo)),
MissRoms = r.Machines.Sum(m => m.Files.Count(f => !f.File.IsInRepo)) +
r.Machines.Sum(m => m.Disks.Count(f => !f.Disk.IsInRepo)) +
r.Machines.Sum(m => m.Medias.Count(f => !f.Media.IsInRepo))
}).FirstOrDefault();
ctx.RomSetStats.Add(stats);
Dispatcher.UIThread.Post(() =>
{
RomSets.Add(new RomSetModel
{
Id = romSet.Id,
Author = romSet.Author,
Comment = romSet.Comment,
Date = romSet.Date,
Description = romSet.Description,
Filename = romSet.Filename,
Homepage = romSet.Homepage,
Name = romSet.Name,
Sha384 = romSet.Sha384,
Version = romSet.Version,
TotalMachines = stats.TotalMachines,
CompleteMachines = stats.CompleteMachines,
IncompleteMachines = stats.IncompleteMachines,
TotalRoms = stats.TotalRoms,
HaveRoms = stats.HaveRoms,
MissRoms = stats.MissRoms,
Category = romSet.Category
});
});
}
catch(Exception)
{
// Ignored
}
pos++;
}
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.SavingChangesToDatabase;
ProgressVisible = true;
IndeterminateProgress = true;
});
ctx.SaveChanges();
Dispatcher.UIThread.Post(() =>
{
StatusMessage = Localization.Finished;
ProgressVisible = false;
CanClose = true;
});
});
void ExecuteCloseCommand() => _view.Close();
}
}

View File

@@ -41,6 +41,10 @@
<MenuItem Header="{Binding RomSetsMenuDeleteText}" Command="{Binding DeleteRomSetCommand}" />
<Separator />
</MenuItem>
<MenuItem Header="{Binding DatabaseMenuText}">
<MenuItem Header="{Binding DatabaseMenuUpdateStatsText}" Command="{Binding UpdateStatsCommand}" />
<Separator />
</MenuItem>
<MenuItem Header="{Binding HelpMenuText}">
<MenuItem Header="{Binding HelpMenuAboutText}" Name="AboutMenuItem"
IsVisible="{Binding !NativeMenuSupported}" Command="{Binding AboutCommand}" />

View File

@@ -0,0 +1,129 @@
<!--
// /***************************************************************************
// RomRepoMgr - ROM repository manager
//
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// [ License ]
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General public License for more details.
//
// You should have received a copy of the GNU General public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Copyright © 2020 Natalia Portillo
// ****************************************************************************/
-->
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:RomRepoMgr.ViewModels;assembly=RomRepoMgr" mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450" x:Class="RomRepoMgr.Views.UpdateStats" Icon="/Assets/avalonia-logo.ico" CanResize="False"
Title="{Binding Title}" WindowStartupLocation="CenterOwner">
<Design.DataContext>
<vm:UpdateStatsViewModel />
</Design.DataContext>
<Border Padding="15">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding StatusMessage}" HorizontalAlignment="Center" />
<ProgressBar Grid.Row="1" IsIndeterminate="{Binding IndeterminateProgress}"
Maximum="{Binding MaximumValue}" Minimum="{Binding MinimumValue}"
Value="{Binding CurrentValue}" HorizontalAlignment="Stretch"
IsVisible="{Binding ProgressVisible}" />
<DataGrid Grid.Row="2" Items="{Binding RomSets}" HorizontalScrollBarVisibility="Visible"
SelectedItem="{Binding SelectedRomSet, Mode=TwoWay}" CanUserSortColumns="True"
CanUserResizeColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetNameLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Version}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetVersionLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Author}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetAuthorLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Category}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetCategoryLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Date}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetDateLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Description}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetDescriptionLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Comment}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetCommentLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Homepage}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetHomepageLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding TotalMachines}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetTotalMachinesLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding CompleteMachines}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetCompleteMachinesLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding IncompleteMachines}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetIncompleteMachinesLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding TotalRoms}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetTotalRomsLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding HaveRoms}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetHaveRomsLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MissRoms}" Width="Auto" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="{Binding RomSetMissRomsLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="3" HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding CanClose}"
Command="{Binding CloseCommand}">
<TextBlock Text="{Binding CloseLabel}" />
</Button>
</Grid>
</Border>
</Window>

View File

@@ -0,0 +1,45 @@
/******************************************************************************
// RomRepoMgr - ROM repository manager
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2020 Natalia Portillo
*******************************************************************************/
using System;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using RomRepoMgr.ViewModels;
namespace RomRepoMgr.Views
{
public sealed class UpdateStats : Window
{
public UpdateStats() => InitializeComponent();
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
(DataContext as UpdateStatsViewModel)?.OnOpened();
}
}
}