mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00

This adds a search box to the config tool to allow filtering properties by keywords. Resolves #1889.
437 lines
11 KiB
C#
437 lines
11 KiB
C#
using Microsoft.Win32;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
using TRX_ConfigToolLib.Controls;
|
|
using TRX_ConfigToolLib.Utils;
|
|
|
|
namespace TRX_ConfigToolLib.Models;
|
|
|
|
public class MainWindowViewModel : BaseLanguageViewModel
|
|
{
|
|
private const int _minSearchLength = 3;
|
|
|
|
private readonly Configuration _configuration;
|
|
|
|
public IEnumerable<CategoryViewModel> Categories { get; private set; }
|
|
public IEnumerable<CategoryViewModel> SearchResults { get; private set; }
|
|
|
|
public MainWindowViewModel()
|
|
{
|
|
_configuration = new();
|
|
|
|
List<CategoryViewModel> categories = new();
|
|
foreach (Category category in _configuration.Categories.Where(c => c.Properties.Count > 0))
|
|
{
|
|
categories.Add(new(category));
|
|
category.Properties
|
|
.ForEach(p => p.PropertyChanged += EditorPropertyChanged);
|
|
}
|
|
|
|
Categories = categories;
|
|
SelectedCategory = Categories.FirstOrDefault();
|
|
|
|
// Search results are contained within a special category whose properties are built
|
|
// on-the-fly. Pick a random picture for it each time the application is used.
|
|
Random random = new();
|
|
SearchCategory = new(new()
|
|
{
|
|
Properties = new(),
|
|
Image = _configuration.Categories[random.Next(_configuration.Categories.Count)].Image,
|
|
});
|
|
|
|
SearchResults = new List<CategoryViewModel> { SearchCategory };
|
|
}
|
|
|
|
private void EditorPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
IsEditorDirty = _configuration.IsDataDirty();
|
|
IsEditorDefault = _configuration.IsDataDefault();
|
|
HasReadOnlyItems = _configuration.HasReadOnlyItems();
|
|
}
|
|
|
|
public void Load()
|
|
{
|
|
Open(Path.GetFullPath(TRXConstants.Instance.ConfigPath));
|
|
}
|
|
|
|
private CategoryViewModel _selectedCategory;
|
|
public CategoryViewModel SelectedCategory
|
|
{
|
|
get => _selectedCategory;
|
|
set
|
|
{
|
|
_selectedCategory = value;
|
|
NotifyPropertyChanged();
|
|
}
|
|
}
|
|
|
|
public CategoryViewModel SearchCategory { get; private set; }
|
|
|
|
private bool _isEditorDirty;
|
|
public bool IsEditorDirty
|
|
{
|
|
get => _isEditorDirty;
|
|
set
|
|
{
|
|
if (_isEditorDirty != value)
|
|
{
|
|
_isEditorDirty = value;
|
|
NotifyPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool _isEditorDefault;
|
|
public bool IsEditorDefault
|
|
{
|
|
get => _isEditorDefault;
|
|
set
|
|
{
|
|
if (_isEditorDefault != value)
|
|
{
|
|
_isEditorDefault = value;
|
|
NotifyPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool _hasReadOnlyItems;
|
|
public bool HasReadOnlyItems
|
|
{
|
|
get => _hasReadOnlyItems;
|
|
set
|
|
{
|
|
if (_hasReadOnlyItems != value)
|
|
{
|
|
_hasReadOnlyItems = value;
|
|
NotifyPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
private string _selectedFile;
|
|
public string SelectedFile
|
|
{
|
|
get => _selectedFile;
|
|
set
|
|
{
|
|
if (_selectedFile != value)
|
|
{
|
|
_selectedFile = value;
|
|
NotifyPropertyChanged();
|
|
NotifyPropertyChanged(nameof(IsEditorActive));
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsEditorActive
|
|
{
|
|
get => SelectedFile != null;
|
|
}
|
|
|
|
private RelayCommand _openCommand;
|
|
public ICommand OpenCommand
|
|
{
|
|
get => _openCommand ??= new RelayCommand(Open);
|
|
}
|
|
|
|
private void Open()
|
|
{
|
|
if (!ConfirmEditorSaveState())
|
|
{
|
|
return;
|
|
}
|
|
|
|
OpenFileDialog dialog = new()
|
|
{
|
|
Filter = ViewText["file_dialog_filter"] + TRXConstants.Instance.ConfigFilterExtension
|
|
};
|
|
if (IsEditorActive)
|
|
{
|
|
dialog.InitialDirectory = Path.GetDirectoryName(SelectedFile);
|
|
}
|
|
if (dialog.ShowDialog() ?? false)
|
|
{
|
|
Open(dialog.FileName);
|
|
}
|
|
}
|
|
|
|
private void Open(string filePath)
|
|
{
|
|
try
|
|
{
|
|
_configuration.Read(filePath, TRXConstants.Instance.GameflowName);
|
|
SelectedFile = filePath;
|
|
IsEditorDirty = false;
|
|
IsEditorDefault = _configuration.IsDataDefault();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBoxUtils.ShowError(e.ToString(), ViewText["window_title_main"]);
|
|
}
|
|
}
|
|
|
|
private RelayCommand _reloadCommand;
|
|
public ICommand ReloadCommand
|
|
{
|
|
get => _reloadCommand ??= new RelayCommand(Reload, CanReload);
|
|
}
|
|
|
|
private void Reload()
|
|
{
|
|
if (ConfirmEditorReloadState())
|
|
{
|
|
Open(SelectedFile);
|
|
}
|
|
}
|
|
|
|
private bool CanReload()
|
|
{
|
|
return IsEditorActive;
|
|
}
|
|
|
|
private RelayCommand _saveCommand;
|
|
public ICommand SaveCommand
|
|
{
|
|
get => _saveCommand ??= new RelayCommand(Save, CanSave);
|
|
}
|
|
|
|
private void Save()
|
|
{
|
|
Save(SelectedFile);
|
|
}
|
|
|
|
private void Save(string filePath)
|
|
{
|
|
try
|
|
{
|
|
_configuration.Write(filePath);
|
|
SelectedFile = filePath;
|
|
IsEditorDirty = false;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBoxUtils.ShowError(e.ToString(), ViewText["window_title_main"]);
|
|
}
|
|
}
|
|
|
|
private bool CanSave()
|
|
{
|
|
return IsEditorDirty;
|
|
}
|
|
|
|
private RelayCommand _saveAsCommand;
|
|
public ICommand SaveAsCommand
|
|
{
|
|
get => _saveAsCommand ??= new RelayCommand(SaveAs, CanSaveAs);
|
|
}
|
|
|
|
private void SaveAs()
|
|
{
|
|
SaveFileDialog dialog = new()
|
|
{
|
|
Filter = ViewText["file_dialog_filter"] + TRXConstants.Instance.ConfigFilterExtension,
|
|
InitialDirectory = Path.GetDirectoryName(SelectedFile)
|
|
};
|
|
if (dialog.ShowDialog() ?? false)
|
|
{
|
|
Save(dialog.FileName);
|
|
}
|
|
}
|
|
|
|
private bool CanSaveAs()
|
|
{
|
|
return IsEditorActive;
|
|
}
|
|
|
|
private bool _beginSearch;
|
|
public bool BeginSearch
|
|
{
|
|
get => _beginSearch;
|
|
set
|
|
{
|
|
if (!value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_beginSearch = true;
|
|
NotifyPropertyChanged();
|
|
_beginSearch = false;
|
|
NotifyPropertyChanged();
|
|
}
|
|
}
|
|
|
|
private string _searchText = string.Empty;
|
|
public string SearchText
|
|
{
|
|
get => _searchText;
|
|
set
|
|
{
|
|
if (value == _searchText)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_searchText = value;
|
|
RunPropertySearch();
|
|
NotifyPropertyChanged();
|
|
NotifyPropertyChanged(nameof(IsSearchActive));
|
|
NotifyPropertyChanged(nameof(IsSearchTextDefined));
|
|
NotifyPropertyChanged(nameof(SearchFailStatus));
|
|
}
|
|
}
|
|
|
|
public bool IsSearchActive => SearchCategory.ItemsSource.Any();
|
|
public bool IsSearchTextDefined => _searchText.Length > 0;
|
|
public bool SearchFailStatus => _searchText.Trim().Length >= _minSearchLength && !IsSearchActive;
|
|
|
|
private void RunPropertySearch()
|
|
{
|
|
string text = _searchText.Trim().ToLower();
|
|
if (text.Length < _minSearchLength)
|
|
{
|
|
SearchCategory.ItemsSource.RemoveAll();
|
|
return;
|
|
}
|
|
|
|
text = TextUtilities.Normalise(text);
|
|
List<string> keywords = new(text.Split(null));
|
|
IEnumerable<BaseProperty> matchedProperties = Categories
|
|
.SelectMany(c => c.ItemsSource)
|
|
.Where(p => keywords.Any(p.NormalisedText.Contains));
|
|
|
|
SearchCategory.ItemsSource.ReplaceCollection(matchedProperties);
|
|
}
|
|
|
|
private RelayCommand _beginSearchCommand;
|
|
public ICommand BeginSearchCommand
|
|
{
|
|
get => _beginSearchCommand ??= new RelayCommand(() => BeginSearch = true);
|
|
}
|
|
|
|
private RelayCommand _closeSearchCommand;
|
|
public ICommand CloseSearchCommand
|
|
{
|
|
get => _closeSearchCommand ??= new RelayCommand(() => SearchText = string.Empty);
|
|
}
|
|
|
|
private RelayCommand _launchGameCommand;
|
|
public ICommand LaunchGameCommand
|
|
{
|
|
get => _launchGameCommand ??= new RelayCommand(() => LaunchGame());
|
|
}
|
|
|
|
public static bool CanLaunchGold
|
|
{
|
|
get => TRXConstants.Instance.GoldSupported;
|
|
}
|
|
|
|
private RelayCommand _launchGoldCommand;
|
|
public ICommand LaunchGoldCommand
|
|
{
|
|
get => _launchGoldCommand ??= new RelayCommand(() => LaunchGame(TRXConstants.Instance.GoldArgs));
|
|
}
|
|
|
|
private void LaunchGame(string arguments = null)
|
|
{
|
|
if (!ConfirmEditorSaveState())
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
ProcessUtils.Start(Path.GetFullPath(TRXConstants.Instance.ExecutableName), arguments);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBoxUtils.ShowError(e.ToString(), ViewText["window_title_main"]);
|
|
}
|
|
}
|
|
|
|
private RelayCommand<Window> _exitCommand;
|
|
public ICommand ExitCommand
|
|
{
|
|
get => _exitCommand ??= new RelayCommand<Window>(Exit);
|
|
}
|
|
|
|
private void Exit(Window window)
|
|
{
|
|
if (ConfirmEditorSaveState())
|
|
{
|
|
IsEditorDirty = false;
|
|
window.Close();
|
|
}
|
|
}
|
|
|
|
public void Exit(CancelEventArgs e)
|
|
{
|
|
if (!ConfirmEditorSaveState())
|
|
{
|
|
e.Cancel = true;
|
|
}
|
|
}
|
|
|
|
public bool ConfirmEditorSaveState()
|
|
{
|
|
if (IsEditorDirty)
|
|
{
|
|
switch (MessageBoxUtils.ShowYesNoCancel(ViewText["msgbox_unsaved_changes"], ViewText["window_title_main"]))
|
|
{
|
|
case MessageBoxResult.Yes:
|
|
Save();
|
|
break;
|
|
case MessageBoxResult.Cancel:
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool ConfirmEditorReloadState()
|
|
{
|
|
return !IsEditorDirty
|
|
|| MessageBoxUtils.ShowYesNo(ViewText["msgbox_unsaved_changes_reload"], ViewText["window_title_main"]);
|
|
}
|
|
|
|
private RelayCommand _restoreDefaultsCommand;
|
|
public ICommand RestoreDefaultsCommand
|
|
{
|
|
get => _restoreDefaultsCommand ??= new RelayCommand(RestoreDefaults, CanRestoreDefaults);
|
|
}
|
|
|
|
private void RestoreDefaults()
|
|
{
|
|
_configuration.RestoreDefaults();
|
|
}
|
|
|
|
private bool CanRestoreDefaults()
|
|
{
|
|
return IsEditorActive && !IsEditorDefault;
|
|
}
|
|
|
|
private RelayCommand _gitHubCommand;
|
|
public ICommand GitHubCommand
|
|
{
|
|
get => _gitHubCommand ??= new RelayCommand(GoToGitHub);
|
|
}
|
|
|
|
private void GoToGitHub()
|
|
{
|
|
ProcessUtils.Start(TRXConstants.Instance.GitHubURL);
|
|
}
|
|
|
|
private RelayCommand _aboutCommand;
|
|
public ICommand AboutCommand
|
|
{
|
|
get => _aboutCommand ??= new RelayCommand(ShowAboutDialog);
|
|
}
|
|
|
|
private void ShowAboutDialog()
|
|
{
|
|
new AboutWindow().ShowDialog();
|
|
}
|
|
}
|