添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,442 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Models;
|
||||
using MainShell.Recipe.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MainShell.Recipe.ViewModel
|
||||
{
|
||||
public abstract class RecipeViewModelBase<TRecipe> : BaseScreen, IRecipeViewModel
|
||||
where TRecipe : RecipeBase, new()
|
||||
{
|
||||
private string _lastSavedSnapshot = string.Empty;
|
||||
protected string LastSavedSnapshot => _lastSavedSnapshot;
|
||||
private bool _skipLeaveCheck;
|
||||
private RecipeWrap _selectedRecipeWrap;
|
||||
|
||||
public ObservableCollection<RecipeWrap> RecipeWraps { get; protected set; } = new ObservableCollection<RecipeWrap>();
|
||||
|
||||
public RecipeWrap SelectedRecipeWrap
|
||||
{
|
||||
get { return _selectedRecipeWrap; }
|
||||
set
|
||||
{
|
||||
if (_selectedRecipeWrap == value)
|
||||
return;
|
||||
|
||||
if (!_skipLeaveCheck && _selectedRecipeWrap != null && value != null && !TryLeaveCurrentRecipeContext())
|
||||
{
|
||||
NotifyOfPropertyChange(() => SelectedRecipeWrap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SetAndNotify(ref _selectedRecipeWrap, value))
|
||||
{
|
||||
LoadRecipeFromWrap(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RecipeButtonGroupViewModel RecipeButtonGroupViewModel { get; protected set; }
|
||||
public virtual bool CanCopyRecipe => true;
|
||||
public virtual bool CanImportRecipe => false;
|
||||
public virtual bool CanExportRecipe => false;
|
||||
public bool HasUnsavedChanges => IsRecipeDirty();
|
||||
public string CurrentRecipeDisplayName => CurrentRecipe != null ? CurrentRecipe.RecipeName : EmptyRecipeDisplayName;
|
||||
public RecipeManager RecipeManager { get; }
|
||||
|
||||
protected RecipeViewModelBase(RecipeManager recipeManager)
|
||||
{
|
||||
RecipeManager = recipeManager;
|
||||
}
|
||||
|
||||
protected abstract TRecipe CurrentRecipe { get; set; }
|
||||
protected abstract string RecipeFolderPath { get; }
|
||||
protected abstract string EmptyRecipeDisplayName { get; }
|
||||
protected abstract string GetActiveRecipeName();
|
||||
protected abstract void SwitchActiveRecipe(string recipeName);
|
||||
protected abstract void ClearActiveRecipe();
|
||||
protected virtual void OnRecipeLoaded(TRecipe recipe, RecipeWrap recipeWrap) { }
|
||||
protected virtual string GetUnsavedChangesMessage() => $"<22>䷽<EFBFBD><E4B7BD>{CurrentRecipeDisplayName}<7D><><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD><EFBFBD><EFBFBD>ģ<DEB8><C4A3>Ƿ<EFBFBD><C7B7>ȱ<EFBFBD><C8B1>棿";
|
||||
protected virtual void AfterDeleteCurrentRecipe(string deletedRecipeName) { }
|
||||
protected virtual void AfterRecipeRenamed(string oldRecipeName, string newRecipeName) { }
|
||||
|
||||
public virtual bool TryLeaveCurrentRecipeContext()
|
||||
{
|
||||
if (!HasUnsavedChanges)
|
||||
return true;
|
||||
|
||||
var result = MwMessageBox.Show(GetUnsavedChangesMessage(), "δ<><CEB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ", System.Windows.MessageBoxButton.YesNoCancel, System.Windows.MessageBoxImage.Warning);
|
||||
if (result == System.Windows.MessageBoxResult.Cancel)
|
||||
return false;
|
||||
|
||||
if (result == System.Windows.MessageBoxResult.Yes)
|
||||
SaveCurrentRecipe(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SaveCurrentRecipeSilently()
|
||||
{
|
||||
SaveCurrentRecipe(false);
|
||||
}
|
||||
|
||||
protected void RegisterButtonGroupEvents()
|
||||
{
|
||||
RecipeButtonGroupViewModel = new RecipeButtonGroupViewModel();
|
||||
RecipeButtonGroupViewModel.CreateNewRequested -= OnCreateNewRecipe;
|
||||
RecipeButtonGroupViewModel.ApplyRequested -= OnApplyRecipe;
|
||||
RecipeButtonGroupViewModel.DeleteRequested -= OnDeleteRecipe;
|
||||
RecipeButtonGroupViewModel.CopyRequested -= OnCopyRecipe;
|
||||
RecipeButtonGroupViewModel.ImportRequested -= OnImportRecipe;
|
||||
RecipeButtonGroupViewModel.SaveRequested -= OnSaveRecipe;
|
||||
RecipeButtonGroupViewModel.ExportRequested -= OnExportRecipe;
|
||||
RecipeButtonGroupViewModel.ReNameRequested -= OnReNameRecipe;
|
||||
RecipeButtonGroupViewModel.ClearRequested -= OnClearRecipe;
|
||||
RecipeButtonGroupViewModel.CreateNewRequested += OnCreateNewRecipe;
|
||||
RecipeButtonGroupViewModel.ApplyRequested += OnApplyRecipe;
|
||||
RecipeButtonGroupViewModel.DeleteRequested += OnDeleteRecipe;
|
||||
RecipeButtonGroupViewModel.CopyRequested += OnCopyRecipe;
|
||||
RecipeButtonGroupViewModel.ImportRequested += OnImportRecipe;
|
||||
RecipeButtonGroupViewModel.SaveRequested += OnSaveRecipe;
|
||||
RecipeButtonGroupViewModel.ExportRequested += OnExportRecipe;
|
||||
RecipeButtonGroupViewModel.ReNameRequested += OnReNameRecipe;
|
||||
RecipeButtonGroupViewModel.ClearRequested += OnClearRecipe;
|
||||
}
|
||||
|
||||
public virtual void OnCreateNewRecipe(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs is RecipeEventArgs args)
|
||||
{
|
||||
if (!TryLeaveCurrentRecipeContext())
|
||||
return;
|
||||
|
||||
var recipeWrap = new RecipeWrap
|
||||
{
|
||||
RecipeName = args.RecipeName,
|
||||
CreateTime = DateTime.UtcNow,
|
||||
ModifiedTime = DateTime.UtcNow,
|
||||
};
|
||||
|
||||
RecipeWraps.Add(recipeWrap);
|
||||
SelectRecipeWrapInternal(recipeWrap);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnDeleteRecipe(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (SelectedRecipeWrap == null)
|
||||
return;
|
||||
|
||||
if (!TryLeaveCurrentRecipeContext())
|
||||
return;
|
||||
|
||||
var deletedRecipeName = SelectedRecipeWrap.RecipeName;
|
||||
if (!RecipeManager.DeleteRecipeFolder(RecipeFolderPath, deletedRecipeName, out var error))
|
||||
{
|
||||
MwMessageBox.Show(error);
|
||||
return;
|
||||
}
|
||||
|
||||
RecipeWraps.Remove(SelectedRecipeWrap);
|
||||
AfterDeleteCurrentRecipe(deletedRecipeName);
|
||||
|
||||
if (RecipeWraps.Count > 0)
|
||||
{
|
||||
SelectRecipeWrapInternal(RecipeWraps[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedRecipeWrap = null;
|
||||
CurrentRecipe = null;
|
||||
ClearActiveRecipe();
|
||||
CaptureSavedSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnCopyRecipe(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (!(eventArgs is RecipeEventArgs args) || SelectedRecipeWrap == null)
|
||||
return;
|
||||
|
||||
var sourceRecipeName = SelectedRecipeWrap.RecipeName;
|
||||
if (string.IsNullOrWhiteSpace(sourceRecipeName) || string.IsNullOrWhiteSpace(args.RecipeName))
|
||||
return;
|
||||
|
||||
if (CurrentRecipe != null &&
|
||||
string.Equals(CurrentRecipe.RecipeName, sourceRecipeName, StringComparison.Ordinal) &&
|
||||
HasUnsavedChanges)
|
||||
{
|
||||
SaveCurrentRecipe(false);
|
||||
}
|
||||
|
||||
if (!RecipeManager.CopyRecipeFolder(RecipeFolderPath, sourceRecipeName, args.RecipeName, out var error))
|
||||
{
|
||||
MwMessageBox.Show(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var copiedRecipeWrap = new RecipeWrap
|
||||
{
|
||||
RecipeName = args.RecipeName,
|
||||
CreateTime = DateTime.UtcNow,
|
||||
ModifiedTime = DateTime.UtcNow,
|
||||
};
|
||||
|
||||
RecipeWraps.Add(copiedRecipeWrap);
|
||||
SelectRecipeWrapInternal(copiedRecipeWrap);
|
||||
}
|
||||
|
||||
public virtual void OnApplyRecipe(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs is RecipeEventArgs args)
|
||||
{
|
||||
var recipeWrap = RecipeWraps.FirstOrDefault(p => p.RecipeName == args.RecipeName);
|
||||
if (recipeWrap == null)
|
||||
return;
|
||||
|
||||
if (!ReferenceEquals(SelectedRecipeWrap, recipeWrap))
|
||||
{
|
||||
if (!TryLeaveCurrentRecipeContext())
|
||||
return;
|
||||
|
||||
SelectRecipeWrapInternal(recipeWrap);
|
||||
}
|
||||
|
||||
if (SelectedRecipeWrap == null)
|
||||
return;
|
||||
|
||||
if (CurrentRecipe != null && IsRecipeDirty())
|
||||
{
|
||||
SaveCurrentRecipe(false);
|
||||
}
|
||||
|
||||
SwitchActiveRecipe(SelectedRecipeWrap.RecipeName);
|
||||
UpdateInUseState(SelectedRecipeWrap);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void OnImportRecipe(object sender, EventArgs eventArgs);
|
||||
|
||||
public virtual void OnSaveRecipe(object sender, EventArgs eventArgs)
|
||||
{
|
||||
CommonUti.RunOnUi(() =>
|
||||
{
|
||||
if (eventArgs is RecipeEventArgs)
|
||||
{
|
||||
SaveCurrentRecipe(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public abstract void OnExportRecipe(object sender, EventArgs eventArgs);
|
||||
public abstract void OnReNameRecipe(object sender, EventArgs eventArgs);
|
||||
|
||||
public virtual void OnClearRecipe(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (!TryLeaveCurrentRecipeContext())
|
||||
return;
|
||||
|
||||
if (SelectedRecipeWrap == null)
|
||||
return;
|
||||
|
||||
var clearedRecipe = new TRecipe
|
||||
{
|
||||
RecipeName = SelectedRecipeWrap.RecipeName
|
||||
};
|
||||
|
||||
CurrentRecipe = clearedRecipe;
|
||||
OnRecipeLoaded(clearedRecipe, SelectedRecipeWrap);
|
||||
NotifyOfPropertyChange(() => HasUnsavedChanges);
|
||||
}
|
||||
|
||||
protected bool IsRecipeDirty()
|
||||
{
|
||||
if (CurrentRecipe == null)
|
||||
return false;
|
||||
|
||||
var path = Path.Combine(CurrentRecipe.Dir ?? string.Empty, CurrentRecipe.FileName ?? string.Empty);
|
||||
if (!File.Exists(path))
|
||||
return true;
|
||||
|
||||
return !AreSnapshotsEquivalent(_lastSavedSnapshot, CurrentRecipe.CreateSnapshot());
|
||||
}
|
||||
|
||||
protected void CaptureSavedSnapshot()
|
||||
{
|
||||
_lastSavedSnapshot = CurrentRecipe != null ? CurrentRecipe.CreateSnapshot() : string.Empty;
|
||||
NotifyOfPropertyChange(() => HasUnsavedChanges);
|
||||
NotifyOfPropertyChange(() => CurrentRecipeDisplayName);
|
||||
}
|
||||
|
||||
protected bool TryRenameRecipe(RecipeRenameEventArgs args)
|
||||
{
|
||||
if (args == null)
|
||||
return false;
|
||||
|
||||
var recipeWrap = RecipeWraps.FirstOrDefault(p => p.RecipeName == args.OldRecipeName);
|
||||
if (recipeWrap == null)
|
||||
return false;
|
||||
|
||||
if (!RecipeManager.RenameFolder(RecipeFolderPath, args.OldRecipeName, args.NewRecipeName, out var error))
|
||||
{
|
||||
MwMessageBox.Show(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
recipeWrap.RecipeName = args.NewRecipeName;
|
||||
recipeWrap.ModifiedTime = DateTime.UtcNow;
|
||||
|
||||
if (CurrentRecipe != null && string.Equals(CurrentRecipe.RecipeName, args.OldRecipeName, StringComparison.Ordinal))
|
||||
{
|
||||
CurrentRecipe.RecipeName = args.NewRecipeName;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(recipeWrap, SelectedRecipeWrap))
|
||||
{
|
||||
SwitchActiveRecipe(args.NewRecipeName);
|
||||
}
|
||||
|
||||
CaptureSavedSnapshot();
|
||||
AfterRecipeRenamed(args.OldRecipeName, args.NewRecipeName);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void SaveCurrentRecipe(bool showSuccessMessage)
|
||||
{
|
||||
if (CurrentRecipe == null)
|
||||
return;
|
||||
|
||||
CurrentRecipe.Write();
|
||||
CaptureSavedSnapshot();
|
||||
|
||||
if (SelectedRecipeWrap != null)
|
||||
{
|
||||
SelectedRecipeWrap.ModifiedTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
if (showSuccessMessage)
|
||||
{
|
||||
MwMessageBox.Show("<22><><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AreSnapshotsEquivalent(string leftSnapshot, string rightSnapshot)
|
||||
{
|
||||
var left = string.IsNullOrWhiteSpace(leftSnapshot) ? null : ParseSnapshotToken(leftSnapshot);
|
||||
var right = string.IsNullOrWhiteSpace(rightSnapshot) ? null : ParseSnapshotToken(rightSnapshot);
|
||||
|
||||
if (left == null || right == null)
|
||||
return false;
|
||||
|
||||
return JToken.DeepEquals(left, right);
|
||||
}
|
||||
|
||||
private static JToken ParseSnapshotToken(string snapshot)
|
||||
{
|
||||
try
|
||||
{
|
||||
return JToken.Parse(snapshot);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void SelectRecipeWrapInternal(RecipeWrap recipeWrap)
|
||||
{
|
||||
try
|
||||
{
|
||||
_skipLeaveCheck = true;
|
||||
SelectedRecipeWrap = recipeWrap;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_skipLeaveCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void InitializeSelection(string activeRecipeName)
|
||||
{
|
||||
SyncSelection(activeRecipeName, true);
|
||||
}
|
||||
|
||||
protected virtual void UpdateInUseState(RecipeWrap activeRecipeWrap)
|
||||
{
|
||||
foreach (var wrap in RecipeWraps)
|
||||
{
|
||||
wrap.IsInUse = ReferenceEquals(wrap, activeRecipeWrap);
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncSelectionFromActiveRecipe()
|
||||
{
|
||||
SyncSelection(GetActiveRecipeName(), false);
|
||||
}
|
||||
|
||||
private void SyncSelection(string recipeName, bool fallbackToFirst)
|
||||
{
|
||||
if (RecipeWraps == null || RecipeWraps.Count == 0)
|
||||
{
|
||||
UpdateInUseState(null);
|
||||
return;
|
||||
}
|
||||
|
||||
var target = string.IsNullOrWhiteSpace(recipeName)
|
||||
? null
|
||||
: RecipeWraps.FirstOrDefault(p => string.Equals(p.RecipeName, recipeName, StringComparison.Ordinal));
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
UpdateInUseState(null);
|
||||
if (!fallbackToFirst)
|
||||
return;
|
||||
|
||||
target = RecipeWraps[0];
|
||||
}
|
||||
|
||||
if (ReferenceEquals(SelectedRecipeWrap, target))
|
||||
{
|
||||
UpdateInUseState(target);
|
||||
return;
|
||||
}
|
||||
|
||||
SelectRecipeWrapInternal(target);
|
||||
}
|
||||
|
||||
private void LoadRecipeFromWrap(RecipeWrap recipeWrap)
|
||||
{
|
||||
if (recipeWrap == null)
|
||||
{
|
||||
UpdateInUseStateByActiveRecipe();
|
||||
return;
|
||||
}
|
||||
|
||||
var newRecipe = new TRecipe
|
||||
{
|
||||
RecipeName = recipeWrap.RecipeName
|
||||
};
|
||||
newRecipe.Read();
|
||||
|
||||
CurrentRecipe = newRecipe;
|
||||
CaptureSavedSnapshot();
|
||||
UpdateInUseStateByActiveRecipe();
|
||||
OnRecipeLoaded(newRecipe, recipeWrap);
|
||||
}
|
||||
|
||||
private void UpdateInUseStateByActiveRecipe()
|
||||
{
|
||||
var activeRecipeName = GetActiveRecipeName();
|
||||
var activeRecipeWrap = RecipeWraps == null || string.IsNullOrWhiteSpace(activeRecipeName)
|
||||
? null
|
||||
: RecipeWraps.FirstOrDefault(p => string.Equals(p.RecipeName, activeRecipeName, StringComparison.Ordinal));
|
||||
|
||||
UpdateInUseState(activeRecipeWrap);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user