2023-04-13 11:51:03 +08:00
|
|
|
|
using Aitex.Core.RT.Log;
|
|
|
|
|
using Caliburn.Micro;
|
|
|
|
|
using Caliburn.Micro.Core;
|
|
|
|
|
using MECF.Framework.Common.DataCenter;
|
|
|
|
|
using MECF.Framework.UI.Client.CenterViews.Editors.Sequence;
|
|
|
|
|
using MECF.Framework.UI.Client.ClientBase;
|
|
|
|
|
using OpenSEMI.ClientBase;
|
|
|
|
|
using OpenSEMI.ClientBase.Command;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Linq;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
using System.Threading.Tasks;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
using System.Windows;
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
using System.Windows.Media;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
using System.Windows.Threading;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension.CustomColumn;
|
|
|
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
|
|
|
|
|
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
|
|
|
|
|
using Microsoft.Win32;
|
2023-06-15 14:53:21 +08:00
|
|
|
|
using MECF.Framework.UI.Client.CenterViews.Configs.Roles;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
namespace MECF.Framework.UI.Client.CenterViews.Editors.Recipe
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public class RecipeEditorViewModel : UiViewModelBase, IHandle<UserMode> //BaseModel
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#region Variables
|
|
|
|
|
|
|
|
|
|
private readonly IRecipeGasFlowCalculator _recipeGasFlowCalculator;
|
|
|
|
|
private RecipeData _currentRecipe;
|
|
|
|
|
private bool _isLoading;
|
2023-06-15 14:53:21 +08:00
|
|
|
|
private int _errorsCount;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
private Window _winValidationInfo;
|
|
|
|
|
private EditMode _editMode;
|
|
|
|
|
private readonly RecipeFormatBuilder _columnBuilder;
|
|
|
|
|
private readonly RecipeProvider _recipeProvider;
|
|
|
|
|
private ObservableCollection<ProcessTypeFileItem> _processTypeFileList;
|
|
|
|
|
private Point? _lastPosOfValidationWin = null;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#endregion
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#region Constructors
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public RecipeEditorViewModel()
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var eventAggregator = IoC.Get<IEventAggregator>();
|
|
|
|
|
eventAggregator?.Subscribe(this);
|
|
|
|
|
|
|
|
|
|
_recipeGasFlowCalculator = IoC.Get<IRecipeGasFlowCalculator>();
|
|
|
|
|
_columnBuilder = new RecipeFormatBuilder();
|
|
|
|
|
_recipeProvider = new RecipeProvider();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Commands
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
private ICommand _RenameFolderCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand RenameFolderCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_RenameFolderCommand == null)
|
|
|
|
|
_RenameFolderCommand = new BaseCommand(() => RenameFolder());
|
|
|
|
|
return _RenameFolderCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ICommand _DeleteFolderCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand DeleteFolderCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_DeleteFolderCommand == null)
|
|
|
|
|
_DeleteFolderCommand = new BaseCommand(() => DeleteFolder());
|
|
|
|
|
return _DeleteFolderCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ICommand _NewFolderCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand NewFolderCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_NewFolderCommand == null)
|
|
|
|
|
_NewFolderCommand = new BaseCommand(() => NewFolder());
|
|
|
|
|
return _NewFolderCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
private ICommand _NewFolderRootCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand NewFolderRootCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_NewFolderRootCommand == null)
|
|
|
|
|
_NewFolderRootCommand = new BaseCommand(() => NewFolderRoot());
|
|
|
|
|
return _NewFolderRootCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ICommand _NewRecipeCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand NewRecipeCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_NewRecipeCommand == null)
|
|
|
|
|
_NewRecipeCommand = new BaseCommand(() => NewRecipe());
|
|
|
|
|
return _NewRecipeCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ICommand _NewRecipeRootCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand NewRecipeRootCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_NewRecipeRootCommand == null)
|
|
|
|
|
_NewRecipeRootCommand = new BaseCommand(() => NewRecipeRoot());
|
|
|
|
|
return _NewRecipeRootCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
private ICommand _RenameRecipeCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand RenameRecipeCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_RenameRecipeCommand == null)
|
|
|
|
|
_RenameRecipeCommand = new BaseCommand(() => RenameRecipe());
|
|
|
|
|
return _RenameRecipeCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
private ICommand _DeleteRecipeCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand DeleteRecipeCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_DeleteRecipeCommand == null)
|
|
|
|
|
_DeleteRecipeCommand = new BaseCommand(() => DeleteRecipe());
|
|
|
|
|
return _DeleteRecipeCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
private ICommand _SaveAsRecipeCommand;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public ICommand SaveAsRecipeCommand
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_SaveAsRecipeCommand == null)
|
|
|
|
|
_SaveAsRecipeCommand = new BaseCommand(() => SaveAsRecipe());
|
|
|
|
|
return _SaveAsRecipeCommand;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#endregion
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
public ObservableCollection<ProcessTypeFileItem> ProcessTypeFileList
|
|
|
|
|
{
|
|
|
|
|
get => _processTypeFileList;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_processTypeFileList = value;
|
|
|
|
|
NotifyOfPropertyChange(nameof(ProcessTypeFileList));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RecipeData CurrentRecipe
|
|
|
|
|
{
|
|
|
|
|
get => _currentRecipe;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_currentRecipe = value;
|
2023-06-15 14:53:21 +08:00
|
|
|
|
NotifyOfPropertyChange();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsPermission => Permission == 3; //&& RtStatus != "AutoRunning";
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public FileNode CurrentFileNode { get; set; }
|
|
|
|
|
|
|
|
|
|
private bool IsChanged => _editMode == EditMode.Edit || CurrentRecipe.IsChanged;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public Dictionary<string, List<EditorDataGridTemplateColumnBase>> DicColunms { get; set; }
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
public bool EnableNew { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableReName { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableCopy { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableDelete { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableSave { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
public bool EnableImportExport { get; set; }
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableStep { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableReload { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableSaveToAll { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public bool EnableSaveTo { get; set; }
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public bool EnableLeftTabPanel { get; set; }
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public bool EnableRefreshRecipeList { get; set; }
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public bool EnableFilterTreeList { get; set; }
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public bool EnableCellPermButton { get; set; }
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 返回是否显示单元格访问权限编辑按钮。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsShowCellAccessPermEditButton { get; private set; }
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public int ErrorsCount
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
set
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
// 如果错误数没发生变化,不要修改Badge的值,以免触发Badge动画。
|
|
|
|
|
if (value == _errorsCount)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if(value == 0)
|
|
|
|
|
((RecipeEditorView)View).txtErrorCount.Badge = null;
|
|
|
|
|
else
|
|
|
|
|
((RecipeEditorView)View).txtErrorCount.Badge = value;
|
|
|
|
|
|
|
|
|
|
_errorsCount = value;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
private int _countAccessibleWhitelist;
|
|
|
|
|
|
|
|
|
|
private int AccessibleWhitelistCount
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
set
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
if (value == _countAccessibleWhitelist)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (value == 0)
|
|
|
|
|
((RecipeEditorView)View).txtCellAccessPremCount.Badge = null;
|
|
|
|
|
else
|
|
|
|
|
((RecipeEditorView)View).txtCellAccessPremCount.Badge = value;
|
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
_countAccessibleWhitelist = value;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 是否正在加载配方。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsLoading
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
get => _isLoading;
|
|
|
|
|
private set
|
|
|
|
|
{
|
|
|
|
|
_isLoading = value;
|
|
|
|
|
NotifyOfPropertyChange(nameof(IsLoading));
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public List<RecipeStep> SelectedRecipeSteps { get; set; }
|
|
|
|
|
|
|
|
|
|
public ObservableCollection<string> ChamberType { get; set; }
|
|
|
|
|
|
|
|
|
|
public int ChamberTypeIndexSelection { get; set; }
|
|
|
|
|
|
|
|
|
|
public int ProcessTypeIndexSelection { get; set; }
|
|
|
|
|
|
|
|
|
|
public string CurrentChamberType => ChamberType[ChamberTypeIndexSelection];
|
|
|
|
|
|
|
|
|
|
public string CurrentProcessType => ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
|
|
|
|
|
|
|
|
|
public Visibility MultiChamberVisibility { get; set; }
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
public ObservableCollection<string> Chambers { get; set; }
|
|
|
|
|
|
|
|
|
|
public string SelectedChamber { get; set; }
|
|
|
|
|
|
|
|
|
|
public object View { get; set; }
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
protected override void OnInitialize()
|
|
|
|
|
{
|
|
|
|
|
base.OnInitialize();
|
|
|
|
|
|
|
|
|
|
var chamberType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedChamberType");
|
|
|
|
|
if (chamberType == null)
|
|
|
|
|
{
|
|
|
|
|
ChamberType = new ObservableCollection<string>() { "Default" };
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ChamberType = new ObservableCollection<string>(((string)(chamberType)).Split(','));
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
ChamberTypeIndexSelection = 0;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var processType = "Process,Routine,Clean";
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
ProcessTypeFileList = new ObservableCollection<ProcessTypeFileItem>();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipeProcessType = ((string)processType).Split(',');
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
for (var i = 0; i < recipeProcessType.Length; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
var type = new ProcessTypeFileItem();
|
|
|
|
|
type.ProcessType = recipeProcessType[i];
|
|
|
|
|
var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{recipeProcessType[i]}";
|
|
|
|
|
var recipes = _recipeProvider.GetXmlRecipeList(prefix);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
type.FileListByProcessType =
|
|
|
|
|
RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes)[0].Files;
|
|
|
|
|
type.FilterFileListByProcessType = type.FileListByProcessType;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
ProcessTypeFileList.Add(type);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
DicColunms = new Dictionary<string, List<EditorDataGridTemplateColumnBase>>();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
UpdateRecipeFormat();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
protected override void OnActivate()
|
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
//初始化RoleManager
|
|
|
|
|
var roleManager = new RoleManager();
|
|
|
|
|
roleManager.Initialize();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
//得到当前登录的RoleItem
|
2023-06-15 19:19:41 +08:00
|
|
|
|
var role = roleManager.GetRoleByName(BaseApp.Instance.UserContext.RoleName);
|
|
|
|
|
|
|
|
|
|
CurrentRecipe.UpdatePermission(role);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
UpdateView();
|
|
|
|
|
|
|
|
|
|
// 根据角色权限设置判断是否显示按钮。
|
2023-06-15 14:53:21 +08:00
|
|
|
|
IsShowCellAccessPermEditButton = GetCapeModeButtonPerm();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
NotifyOfPropertyChange(nameof(IsShowCellAccessPermEditButton));
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
base.OnActivate();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取角色权限配置中“Recipe.Behaviour.AllowEditCellAccessPerm”的配置。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2023-06-15 14:53:21 +08:00
|
|
|
|
private bool GetCapeModeButtonPerm()
|
2023-06-14 17:42:00 +08:00
|
|
|
|
{
|
|
|
|
|
var roleID = BaseApp.Instance.UserContext.RoleID;
|
|
|
|
|
var val = RoleAccountProvider.Instance.GetMenuPermission(roleID, "Recipe.Behaviour.AllowEditCellAccessPerm");
|
|
|
|
|
return val != (int)MenuPermissionEnum.MP_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
protected override void OnDeactivate(bool close)
|
|
|
|
|
{
|
|
|
|
|
base.OnDeactivate(close);
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (IsChanged)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
|
|
|
|
|
$"Recipe {CurrentRecipe.Name} content is changed, do you want to save it?") == DialogButton.Yes)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
SaveRecipe();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
_winValidationInfo?.Close();
|
|
|
|
|
|
|
|
|
|
// 锁定编辑器
|
|
|
|
|
((RecipeEditorView)View).editorLocker.Lock();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnViewLoaded(object view)
|
|
|
|
|
{
|
|
|
|
|
View = view;
|
|
|
|
|
base.OnViewLoaded(view);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
2023-06-15 14:53:21 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public void TabSelectionChanged()
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
UpdateRecipeFormat();
|
|
|
|
|
OnViewLoaded(View);
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public void UpdateRecipeFormat()
|
|
|
|
|
{
|
|
|
|
|
var chamber = QueryDataClient.Instance.Service.GetConfig("System.Recipe.ChamberModules");
|
|
|
|
|
if (chamber == null)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
chamber = "PM1";
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
Chambers = new ObservableCollection<string>(((string)chamber).Split(','));
|
|
|
|
|
if (Chambers.Count > 1)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
for (var i = 0; i < Chambers.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var isPmInstall =
|
|
|
|
|
(bool)QueryDataClient.Instance.Service.GetConfig(
|
|
|
|
|
$"System.SetUp.Is{Chambers[i].ToString()}Installed");
|
|
|
|
|
{
|
|
|
|
|
if (!isPmInstall)
|
|
|
|
|
{
|
|
|
|
|
Chambers.RemoveAt(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (Chambers.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
Chambers = new ObservableCollection<string>(new string[] { "PM1" });
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
SelectedChamber = Chambers[0];
|
2023-06-15 19:19:41 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe = new RecipeData(_recipeGasFlowCalculator);
|
2023-06-15 19:19:41 +08:00
|
|
|
|
CurrentRecipe.BuildFormat($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, BaseApp.Instance.UserContext.RoleName);
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.OnValidated += (sender, args) =>
|
|
|
|
|
{
|
|
|
|
|
ErrorsCount = CurrentRecipe.ValidationErrorCount;
|
|
|
|
|
};
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.OnAccessibleWhitelistChanged += (sender, count) =>
|
|
|
|
|
{
|
|
|
|
|
AccessibleWhitelistCount = count;
|
|
|
|
|
};
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
_editMode = EditMode.None;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
MultiChamberVisibility = Chambers.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
|
|
|
|
|
}
|
2023-06-15 14:53:21 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Chamber变更时重新加载Recipe。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async void ChamberSelectionChanged()
|
|
|
|
|
{
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
|
|
|
|
DialogType.CONFIRM,
|
|
|
|
|
$"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
IsLoading = true;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
await CurrentRecipe.ChangeChamber(CurrentRecipe.Columns
|
2023-06-14 17:42:00 +08:00
|
|
|
|
, _columnBuilder.Configs, SelectedChamber, GetLoadingDispatcher());
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
IsLoading = false;
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 左侧Recipe列表选择改变时,重新加载Recipe。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="node"></param>
|
|
|
|
|
public async void TreeSelectChanged(FileNode node)
|
|
|
|
|
{
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
|
|
|
|
DialogType.CONFIRM,
|
|
|
|
|
$"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentFileNode = node;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (node != null && node.IsFile)
|
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
await LoadRecipe(node.PrefixPath, node.FullPath);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ClearData();
|
|
|
|
|
_editMode = EditMode.None;
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
UpdateView();
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#region folder
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public void NewFolder()
|
|
|
|
|
{
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
|
|
|
|
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
|
|
|
|
if (selection == DialogButton.Cancel)
|
|
|
|
|
return;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new InputFileNameDialogViewModel("Input New Folder Name");
|
|
|
|
|
dialog.FileName = "new folder";
|
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var name = dialog.FileName.Trim();
|
|
|
|
|
if (string.IsNullOrEmpty(name))
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
DialogBox.ShowWarning("Folder name should not be empty");
|
|
|
|
|
return;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var prefix = ChamberType[ChamberTypeIndexSelection] + "\\" +
|
|
|
|
|
ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
|
|
|
|
var processType = string.Empty;
|
|
|
|
|
var newFolder = string.Empty;
|
|
|
|
|
if (CurrentFileNode != null)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
prefix = CurrentFileNode.PrefixPath;
|
|
|
|
|
var folder = CurrentFileNode.FullPath;
|
|
|
|
|
if (CurrentFileNode.IsFile)
|
|
|
|
|
{
|
|
|
|
|
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
|
|
|
|
if (!string.IsNullOrEmpty(folder))
|
|
|
|
|
newFolder = folder;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
newFolder = folder + "\\";
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
newFolder = newFolder + name;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (IsExist(newFolder, false))
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder with the same name already exist.");
|
|
|
|
|
return;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (newFolder.Length > 200)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder name too long, should be less 200.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
_recipeProvider.CreateRecipeFolder(prefix, newFolder);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true);
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
public void NewFolderRoot()
|
|
|
|
|
{
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
|
|
|
|
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (selection == DialogButton.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new InputFileNameDialogViewModel("Input New Folder Name");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
dialog.FileName = "new folder";
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var name = dialog.FileName.Trim();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning("Folder name should not be empty");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IsExist(name, false))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {name}, Folder with the same name already exist.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name.Length > 200)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {name}, Folder name too long, should be less 200.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var prefix = ChamberType[ChamberTypeIndexSelection] + "\\" +
|
|
|
|
|
ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
_recipeProvider.CreateRecipeFolder(prefix, name);
|
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, name, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeleteFolder()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentFileNode == null || CurrentFileNode.IsFile)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (CurrentFileNode.Files.Count > 0)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
DialogBox.ShowWarning(
|
|
|
|
|
$"Can not delete non-empty folder, Remove the files or folders under \r\n{CurrentFileNode.FullPath}.");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
|
|
|
|
|
$"Are you sure you want to delete \r\n {CurrentFileNode.FullPath}?");
|
|
|
|
|
if (selection == DialogButton.No)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var nextFocus = CurrentFileNode.Parent.FullPath;
|
|
|
|
|
var isFolder = true;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (CurrentFileNode.Parent.Files.Count > 1)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
for (var i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
if (CurrentFileNode.Parent.Files[i] == CurrentFileNode)
|
|
|
|
|
{
|
|
|
|
|
if (i == 0)
|
|
|
|
|
{
|
|
|
|
|
nextFocus = CurrentFileNode.Parent.Files[i + 1].FullPath;
|
|
|
|
|
isFolder = !CurrentFileNode.Parent.Files[i + 1].IsFile;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nextFocus = CurrentFileNode.Parent.Files[i - 1].FullPath;
|
|
|
|
|
isFolder = !CurrentFileNode.Parent.Files[i - 1].IsFile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_recipeProvider.DeleteRecipeFolder(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath);
|
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, nextFocus, isFolder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RenameFolder()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentFileNode == null || CurrentFileNode.IsFile)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new InputFileNameDialogViewModel("Input New Folder Name");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
dialog.FileName = CurrentFileNode.Name;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var name = dialog.FileName.Trim();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var newFolder = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(newFolder))
|
|
|
|
|
newFolder = newFolder + name;
|
|
|
|
|
else
|
|
|
|
|
newFolder = name;
|
|
|
|
|
|
|
|
|
|
if (newFolder == CurrentFileNode.FullPath)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsExist(newFolder, false))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not rename to {newFolder}, Folder with the same name already exist.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newFolder.Length > 200)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder name too long, should be less 200.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_recipeProvider.RenameFolder(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath, newFolder);
|
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region recipe
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public void NewRecipe()
|
|
|
|
|
{
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
|
|
|
|
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (selection == DialogButton.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new InputFileNameDialogViewModel("Input New Name");
|
|
|
|
|
dialog.FileName = "";
|
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipeName = dialog.FileName.Trim();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (string.IsNullOrEmpty(dialog.FileName))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning("Recipe file name should not be empty");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
|
|
|
|
var processType = string.Empty;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (CurrentFileNode != null)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var folder = CurrentFileNode.FullPath;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (CurrentFileNode.IsFile)
|
|
|
|
|
{
|
|
|
|
|
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
|
|
|
|
//if (!string.IsNullOrEmpty(folder))
|
|
|
|
|
// folder = folder;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
folder = folder + "\\";
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
recipeName = folder + recipeName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsExist(recipeName, true))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create {recipeName}, Recipe with the same name already exist.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (recipeName.Length > 200)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipe = new RecipeData(_recipeGasFlowCalculator);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
recipe.Name = recipeName;
|
|
|
|
|
recipe.PrefixPath = prefix;
|
|
|
|
|
recipe.Creator = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
recipe.CreateTime = DateTime.Now;
|
|
|
|
|
recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
recipe.ReviseTime = DateTime.Now;
|
|
|
|
|
recipe.Description = string.Empty;
|
|
|
|
|
|
|
|
|
|
if (!Save(recipe, true))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var types = prefix.Split('\\');
|
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(types[0], types[1], recipeName, false);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void NewRecipeRoot()
|
|
|
|
|
{
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
|
|
|
|
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (selection == DialogButton.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
dialog.FileName = "new recipe";
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipeName = dialog.FileName.Trim();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (string.IsNullOrEmpty(dialog.FileName))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning("Recipe file name should not be empty");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsExist(recipeName, true))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create {recipeName}, Recipe with the same name already exist.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (recipeName.Length > 200)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipe = new RecipeData(_recipeGasFlowCalculator);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
recipe.Name = recipeName;
|
|
|
|
|
recipe.PrefixPath = CurrentChamberType + "\\" + CurrentProcessType;
|
|
|
|
|
recipe.Creator = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
recipe.CreateTime = DateTime.Now;
|
|
|
|
|
recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
recipe.ReviseTime = DateTime.Now;
|
|
|
|
|
recipe.Description = string.Empty;
|
|
|
|
|
|
|
|
|
|
if (!Save(recipe, true))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
private void ReloadRecipeFileList(string chamberType, string processType, string selectedFile,
|
|
|
|
|
bool selectionIsFolder)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var item = ProcessTypeFileList.FirstOrDefault(x => x.ProcessType == processType);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (item == null)
|
|
|
|
|
{
|
|
|
|
|
LOG.Write("error reload recipe file list, type = " + processType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{item.ProcessType}";
|
|
|
|
|
var recipes = _recipeProvider.GetXmlRecipeList(prefix);
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
item.FileListByProcessType =
|
|
|
|
|
RecipeSequenceTreeBuilder.BuildFileNode(prefix, selectedFile, selectionIsFolder, recipes)[0].Files;
|
|
|
|
|
item.FilterFileListByProcessType = item.FileListByProcessType;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
item.InvokePropertyChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsExist(string fullPath, bool isFile)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
for (var i = 0; i < ProcessTypeFileList.Count; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
if (ProcessTypeFileList[i].ProcessType == CurrentProcessType)
|
|
|
|
|
{
|
|
|
|
|
if (ProcessTypeFileList[i].FileListByProcessType.Count == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return FindFile(fullPath, ProcessTypeFileList[i].FileListByProcessType[0].Parent, isFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool FindFile(string path, FileNode root, bool isFile)
|
|
|
|
|
{
|
|
|
|
|
if (root.FullPath == path && !isFile)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var node in root.Files)
|
|
|
|
|
{
|
|
|
|
|
if (isFile && node.IsFile && node.FullPath == path)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (!node.IsFile && FindFile(path, node, isFile))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SaveAsRecipe()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentFileNode == null || !CurrentFileNode.IsFile)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
|
|
|
|
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (selection == DialogButton.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
dialog.FileName = CurrentFileNode.Name;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipeName = dialog.FileName.Trim();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (string.IsNullOrEmpty(dialog.FileName))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning("Recipe file name should not be empty");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
|
|
|
|
var processType = string.Empty;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var folder = CurrentFileNode.FullPath;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (CurrentFileNode.IsFile)
|
|
|
|
|
{
|
|
|
|
|
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(folder))
|
|
|
|
|
recipeName = folder + "\\" + recipeName;
|
|
|
|
|
|
|
|
|
|
if (CurrentFileNode.FullPath == recipeName)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsExist(recipeName, true))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not copy to {recipeName}, Recipe with the same name already exist.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (recipeName.Length > 200)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentRecipe.Creator = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.CreateTime = DateTime.Now;
|
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
CurrentRecipe.Description = CurrentRecipe.Description + ". Renamed from " + CurrentFileNode.Name;
|
|
|
|
|
|
|
|
|
|
_recipeProvider.SaveAsRecipe(prefix, recipeName, CurrentRecipe.GetXmlString());
|
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RenameRecipe()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentFileNode == null || !CurrentFileNode.IsFile)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsChanged)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
|
|
|
|
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (selection == DialogButton.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (selection == DialogButton.Yes)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
CurrentRecipe.ReviseTime = DateTime.Now;
|
|
|
|
|
Save(CurrentRecipe, false);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
dialog.FileName = CurrentFileNode.Name;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipeName = dialog.FileName.Trim();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (string.IsNullOrEmpty(dialog.FileName))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning("Recipe file name should not be empty");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
|
|
|
|
var processType = string.Empty;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var newName = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(newName))
|
|
|
|
|
newName = newName + recipeName;
|
|
|
|
|
else
|
|
|
|
|
newName = recipeName;
|
|
|
|
|
|
|
|
|
|
if (newName == CurrentFileNode.FullPath)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsExist(newName, true))
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not rename to {newName}, Recipe with the same name already exist.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (newName.Length > 200)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowWarning($"Can not create folder {newName}, Folder name too long, should be less 200.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_recipeProvider.RenameRecipe(prefix, CurrentFileNode.FullPath, newName);
|
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newName, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeleteRecipe()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentFileNode == null || !CurrentFileNode.IsFile)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
|
|
|
|
|
$"Are you sure you want to delete \r\n {CurrentFileNode.FullPath}?");
|
|
|
|
|
if (selection == DialogButton.No)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var nextFocus = CurrentFileNode.Parent.FullPath;
|
|
|
|
|
var isFolder = true;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (CurrentFileNode.Parent.Files.Count > 1)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
for (var i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
if (CurrentFileNode.Parent.Files[i] == CurrentFileNode)
|
|
|
|
|
{
|
|
|
|
|
if (i == 0)
|
|
|
|
|
{
|
|
|
|
|
nextFocus = CurrentFileNode.Parent.Files[i + 1].FullPath;
|
|
|
|
|
isFolder = !CurrentFileNode.Parent.Files[i + 1].IsFile;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nextFocus = CurrentFileNode.Parent.Files[i - 1].FullPath;
|
|
|
|
|
isFolder = !CurrentFileNode.Parent.Files[i - 1].IsFile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_recipeProvider.DeleteRecipe(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath);
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.DeleteAccessibleWhiteList();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, nextFocus, isFolder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RefreshRecipe()
|
|
|
|
|
{
|
|
|
|
|
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, "", false);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public async void ReloadRecipe()
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_editMode == EditMode.Normal || _editMode == EditMode.Edit)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (CurrentRecipe == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (CurrentRecipe.IsChanged)
|
|
|
|
|
{
|
|
|
|
|
var ret = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
|
|
|
|
DialogType.CONFIRM,
|
|
|
|
|
$"Recipe {CurrentRecipe.Name} has changed, discard and reload?");
|
|
|
|
|
if (ret == DialogButton.No)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
await LoadRecipe(CurrentRecipe.PrefixPath, CurrentRecipe.Name);
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.Validate();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
UpdateView();
|
2023-06-15 14:53:21 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
foreach (var step in CurrentRecipe.Steps)
|
|
|
|
|
step.Save();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SaveToAll()
|
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.Validate();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
DialogBox.ShowWarning($"Saving failed, {CurrentRecipe.Name} is not a valid recipe file");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
//var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
|
|
|
|
// DialogType.CONFIRM,
|
|
|
|
|
// $"Do you want to save to all chambers? \r\n This will replace all the other chambers recipe content");
|
|
|
|
|
//if (selection == DialogButton.No)
|
|
|
|
|
// return;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
CurrentRecipe.SaveTo(Chambers.ToArray());
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
Save(CurrentRecipe, false);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SaveTo()
|
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.Validate();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
DialogBox.ShowWarning($"Saving failed, {CurrentRecipe.Name} is not a valid recipe file.");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog =
|
|
|
|
|
new SaveToDialogViewModel("Select the chamber to copy to", SelectedChamber, Chambers.ToList());
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var dialogReturn = wm.ShowDialog(dialog);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var chambers = new List<string>();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
foreach (var dialogChamber in dialog.Chambers)
|
|
|
|
|
{
|
|
|
|
|
if (dialogChamber.IsEnabled && dialogChamber.IsChecked)
|
|
|
|
|
chambers.Add(dialogChamber.Name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chambers.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CurrentRecipe.SaveTo(chambers.ToArray());
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
Save(CurrentRecipe, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 导入Recipe。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void ImportRecipe()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
IsLoading = true;
|
|
|
|
|
|
|
|
|
|
// 选择文件
|
|
|
|
|
var openFileDialog = new OpenFileDialog()
|
|
|
|
|
{
|
|
|
|
|
Filter = "Sic Recipe File|*.srp",
|
|
|
|
|
Title = "Import Recipe",
|
|
|
|
|
DefaultExt = ".srp",
|
|
|
|
|
Multiselect = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var prefix = ProcessTypeFileItem.GetProcessFilesPrefix(ProcessTypeFileItem.ProcessFileTypes.Process);
|
|
|
|
|
|
|
|
|
|
if (openFileDialog.ShowDialog() != true)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
#region 选择要导入的文件夹
|
|
|
|
|
|
|
|
|
|
var dialog = new RecipeSelectDialogViewModel(true, true, ProcessTypeFileItem.ProcessFileTypes.Process)
|
|
|
|
|
{
|
|
|
|
|
DisplayName = "Select Folder to Import ..."
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var bret = wm.ShowDialog(dialog);
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
if (bret != true)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var recipeFolderToImport
|
|
|
|
|
= dialog.DialogResult;
|
|
|
|
|
|
|
|
|
|
// 从文件夹名移除Prefix
|
|
|
|
|
recipeFolderToImport = recipeFolderToImport.Replace(prefix + "\\", "");
|
|
|
|
|
|
|
|
|
|
var fns = openFileDialog.FileNames;
|
|
|
|
|
|
|
|
|
|
// 是否覆盖所有Recipe,该选项通过Overwrite对话框给值。
|
|
|
|
|
var isOverwriteAll = false;
|
|
|
|
|
|
|
|
|
|
foreach (var fn in fns)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var recipePath = $"{recipeFolderToImport}\\{Path.GetFileNameWithoutExtension(fn)}";
|
|
|
|
|
|
|
|
|
|
// 检查Recipe是否已存在
|
|
|
|
|
if (IsExist(recipePath.TrimStart('\\'), true) && !isOverwriteAll)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
var ret = DialogBox.ShowDialog(
|
|
|
|
|
DialogButton.Yes | DialogButton.YesToAll | DialogButton.Cancel,
|
|
|
|
|
DialogType.WARNING,
|
|
|
|
|
$"{recipePath} has existed, overwrite?\r\n\r\nATTENTION: Press 'Yes To All' to overwrite all files.");
|
|
|
|
|
if (ret == DialogButton.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (ret == DialogButton.YesToAll)
|
|
|
|
|
isOverwriteAll = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RecipeData.ImportRecipe(fn, out var xmlContent);
|
|
|
|
|
|
|
|
|
|
// 保存文件。
|
|
|
|
|
_recipeProvider.WriteRecipeFile(prefix, recipePath, xmlContent);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowError($"Unable to import {fn}, {ex}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 刷新Recipe列表
|
|
|
|
|
ReloadRecipeFileList("Sic", "Process", "", false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
IsLoading = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 到处Recipe。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void ExportRecipe()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentRecipe == null)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("No recipe selected.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(CurrentRecipe.Name))
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("No recipe loaded.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 选择保存路径和文件名
|
|
|
|
|
var dialog = new SaveFileDialog
|
|
|
|
|
{
|
|
|
|
|
Filter = "Sic Recipe File|*.srp",
|
|
|
|
|
Title = "Export Recipe",
|
|
|
|
|
DefaultExt = ".srp",
|
|
|
|
|
FileName = CurrentRecipe.Name.Split('\\').Last()
|
|
|
|
|
};
|
|
|
|
|
var ret = dialog.ShowDialog();
|
|
|
|
|
if (!ret.HasValue || ret == false)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// 保存文件
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
CurrentRecipe.ExportRecipe(dialog.FileName);
|
|
|
|
|
DialogBox.ShowInfo($"Export done! {dialog.FileName}");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
DialogBox.ShowError($"Unable to export recipe, {ex}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
#region Steps
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public void SaveRecipe()
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/*if (Save(CurrentRecipe, false))
|
|
|
|
|
MessageBox.Show($"The recipe has been saved successfully!", "Succeeded", MessageBoxButton.OK,
|
|
|
|
|
MessageBoxImage.Information);*/
|
|
|
|
|
|
|
|
|
|
Save(CurrentRecipe, false);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void PopSetting(string controlName, Param paramData)
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var stepNum = Convert.ToInt32(((StepParam)paramData.Parent[1]).Value);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var dialog = new PublicPopSettingDialogViewModel();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
dialog.DisplayName = paramData.DisplayName;
|
|
|
|
|
|
2023-06-16 09:51:51 +08:00
|
|
|
|
var step = CurrentRecipe.PopSettingSteps[controlName][stepNum - 1];
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-16 09:51:51 +08:00
|
|
|
|
var controlParameters = new RecipeStep(null);
|
|
|
|
|
var brandParameters = new ObservableCollection<BandParam>();
|
|
|
|
|
foreach (var item in step)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
if (item.Name.Contains("Band"))
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var name = item.Name.Replace("Wavelength", "").Replace("Bandwidth", "");
|
|
|
|
|
var displayName = item.DisplayName.Replace("Wavelength", "").Replace("Bandwidth", "");
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-16 09:51:51 +08:00
|
|
|
|
if (brandParameters.All(x => x.Name != name))
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-16 09:51:51 +08:00
|
|
|
|
brandParameters.Add(new BandParam()
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
Name = name,
|
|
|
|
|
DisplayName = displayName
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (item.Name.Contains("Wavelength"))
|
|
|
|
|
{
|
2023-06-16 09:51:51 +08:00
|
|
|
|
brandParameters.First(x => x.Name == name).WavelengthDoubleParam = item;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
else if (item.Name.Contains("Bandwidth"))
|
|
|
|
|
{
|
2023-06-16 09:51:51 +08:00
|
|
|
|
brandParameters.First(x => x.Name == name).BandwidthDoubleParam = item;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2023-06-16 09:51:51 +08:00
|
|
|
|
controlParameters.Add(item);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-16 09:51:51 +08:00
|
|
|
|
dialog.Parameters = step;
|
|
|
|
|
dialog.ControlParameters = controlParameters;
|
|
|
|
|
dialog.BandParameters = brandParameters;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var wm = new WindowManager();
|
|
|
|
|
var bret = wm.ShowDialog(dialog);
|
|
|
|
|
if (bret == true)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe.PopSettingSteps[controlName][stepNum - 1] = dialog.Parameters;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
private bool Save(RecipeData recipe, bool createNew)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(recipe.Name))
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
MessageBox.Show("Recipe name can't be empty", "Error",
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
if (CurrentRecipe.Validate() == false)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
{
|
2023-06-16 09:51:51 +08:00
|
|
|
|
var mbr = DialogBox.ShowDialog(
|
2023-06-16 10:12:14 +08:00
|
|
|
|
DialogButton.Yes | DialogButton.No,
|
|
|
|
|
DialogType.WARNING,
|
|
|
|
|
$"Are you sure to continue to save with errors?\r\n\r\n" +
|
|
|
|
|
$"{CurrentRecipe.ValidationErrorSummary}");
|
2023-06-16 09:51:51 +08:00
|
|
|
|
if (mbr == DialogButton.No)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var result = false;
|
|
|
|
|
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
|
|
|
|
recipe.ReviseTime = DateTime.Now;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
result = _recipeProvider.WriteRecipeFile(recipe.PrefixPath, recipe.Name, recipe.GetXmlString());
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
recipe.MarkAsSaved();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
_editMode = EditMode.Normal;
|
|
|
|
|
UpdateView();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("Save failed!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void AddStep()
|
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
CurrentRecipe.AddStep();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
|
|
|
|
_editMode = EditMode.Edit;
|
2023-06-15 14:53:21 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
UpdateView();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public void InsertStepToLeft()
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
if (CurrentRecipe == null)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
return;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
if (CurrentRecipe.Steps.SelectedSteps.Count != 1)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
return;
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
var step = CurrentRecipe.Steps.SelectedSteps[0];
|
|
|
|
|
CurrentRecipe.InsertToLeft(step);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
|
|
|
|
_editMode = EditMode.Edit;
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
UpdateView();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InsertStepToRight()
|
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
if (CurrentRecipe == null)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
return;
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
if(CurrentRecipe.Steps.SelectedSteps.Count != 1)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
return;
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
var step = CurrentRecipe.Steps.SelectedSteps[0];
|
|
|
|
|
CurrentRecipe.InsertToRight(step);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
|
|
|
|
_editMode = EditMode.Edit;
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
UpdateView();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
/// <summary>
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// 拷贝所有选中的Steps。
|
|
|
|
|
/// </summary>
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public void CopyStep()
|
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
CurrentRecipe?.CopySteps();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在左侧粘贴Step。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async void PasteStepToLeft()
|
|
|
|
|
{
|
|
|
|
|
await Paste(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在右侧粘贴Step。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async void PasteStepToRight()
|
|
|
|
|
{
|
|
|
|
|
await Paste(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 粘贴Step。
|
|
|
|
|
/// <para>注意:async Task 标记的方法不能直接应用于Caliburn.Message.Attach 方法。</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="isToLeft">是否粘贴到当前选中的Step的左侧。</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private async Task Paste(bool isToLeft)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
if (CurrentRecipe == null)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
return;
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
await CurrentRecipe.Paste(isToLeft);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
|
|
|
|
_editMode = EditMode.Edit;
|
|
|
|
|
|
|
|
|
|
UpdateView();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在左侧复制Step。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async void DuplicateStepToLeft()
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
await Duplicate(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在右侧复制Step。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async void DuplicateStepToRight()
|
|
|
|
|
{
|
|
|
|
|
await Duplicate(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 复制选中的Step。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="isToLeft">是否复制到选中的Step的左侧。</param>
|
|
|
|
|
private async Task Duplicate(bool isToLeft)
|
|
|
|
|
{
|
|
|
|
|
if (SelectedRecipeSteps == null || SelectedRecipeSteps.Count != 1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CopyStep();
|
|
|
|
|
await Paste(isToLeft);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 删除步骤。
|
|
|
|
|
/// </summary>
|
2023-04-13 11:51:03 +08:00
|
|
|
|
public void DeleteStep()
|
|
|
|
|
{
|
2023-06-15 19:19:41 +08:00
|
|
|
|
if (CurrentRecipe == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CurrentRecipe.DeleteSteps();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
|
|
|
|
_editMode = EditMode.Edit;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
UpdateView();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CreateValidationDetailWindow()
|
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
_winValidationInfo = new RecipeEditorValidationDetailWindow(
|
|
|
|
|
CurrentRecipe.ValidationErrorInfo,
|
|
|
|
|
_lastPosOfValidationWin);
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
_winValidationInfo.DataContext = this;
|
|
|
|
|
_winValidationInfo.Closed += (sender, args) =>
|
|
|
|
|
{
|
|
|
|
|
_lastPosOfValidationWin = new Point(_winValidationInfo.Left, _winValidationInfo.Top);
|
2023-06-16 11:44:52 +08:00
|
|
|
|
_currentRecipe.Steps.ResetHighlight();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ShowValidationDetailWindow()
|
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.Validate();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
if (Application.Current.Windows.OfType<RecipeEditorValidationDetailWindow>().Any())
|
|
|
|
|
_winValidationInfo.Activate();
|
|
|
|
|
else
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CreateValidationDetailWindow();
|
|
|
|
|
_winValidationInfo.Show();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private TreeViewItem GetParentObjectEx<TreeViewItem>(DependencyObject obj) where TreeViewItem : FrameworkElement
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var parent = VisualTreeHelper.GetParent(obj);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
while (parent != null)
|
|
|
|
|
{
|
|
|
|
|
if (parent is TreeViewItem)
|
|
|
|
|
{
|
|
|
|
|
return (TreeViewItem)parent;
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
parent = VisualTreeHelper.GetParent(parent);
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void TreeRightMouseDown(MouseButtonEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var item = GetParentObjectEx<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
|
|
|
|
|
if (item != null)
|
|
|
|
|
{
|
|
|
|
|
item.Focus();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// <summary>
|
2023-06-15 14:53:21 +08:00
|
|
|
|
/// 滚动到并高亮指定的参数单元格。
|
2023-06-14 17:42:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="param"></param>
|
|
|
|
|
public void FocusToParam(IParam param)
|
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
((RecipeEditorView)View).dgCustom.FocusToParam(param);
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
#region Cell-Access-Perm-Edit Mode
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
public void SwitchCellAccessPermEditMode()
|
2023-06-14 17:42:00 +08:00
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
var mode = CurrentRecipe.IsAccessibleWhitelistEditMode;
|
|
|
|
|
if (mode)
|
2023-06-15 19:19:41 +08:00
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
CurrentRecipe.LeaveAccessibleWhitelistEditMode();
|
2023-06-15 19:19:41 +08:00
|
|
|
|
_editMode = EditMode.Normal;
|
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
if (!CurrentRecipe.EnterAccessibleWhitelistEditMode(out var reason))
|
2023-06-14 17:42:00 +08:00
|
|
|
|
{
|
2023-06-15 14:53:21 +08:00
|
|
|
|
DialogBox.ShowError($"Unable to enter cell accessible whitelist edit mode, {reason}");
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
2023-06-15 19:19:41 +08:00
|
|
|
|
|
|
|
|
|
_editMode = EditMode.EditWhitelist;
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
UpdateView();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
#endregion
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-06-15 14:53:21 +08:00
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
private void ClearData()
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
_editMode = EditMode.None;
|
|
|
|
|
CurrentRecipe.Clear();
|
|
|
|
|
CurrentRecipe.Name = string.Empty;
|
|
|
|
|
CurrentRecipe.Description = string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据配置获取Cascade方式呈现Recipe的Dispatcher,或返回null。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private static Dispatcher GetLoadingDispatcher()
|
|
|
|
|
{
|
|
|
|
|
// 判断Step呈现方式
|
|
|
|
|
var isCascadeLoading = (bool)QueryDataClient.Instance.Service.GetConfig("System.RecipeCascadeLoading");
|
|
|
|
|
var dispatcher = isCascadeLoading ? Dispatcher.CurrentDispatcher : null;
|
|
|
|
|
return dispatcher;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
private async Task LoadRecipe(string prefixPath, string recipeName)
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
IsLoading = true;
|
|
|
|
|
|
2023-04-13 11:51:03 +08:00
|
|
|
|
CurrentRecipe.Clear();
|
2023-06-14 17:42:00 +08:00
|
|
|
|
CurrentRecipe.Steps.Save(); // 重置为已保存状态
|
|
|
|
|
ErrorsCount = 0;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var recipeContent = _recipeProvider.ReadRecipeFile(prefixPath, recipeName);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(recipeContent))
|
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid.",
|
|
|
|
|
"Error",
|
|
|
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
2023-04-13 11:51:03 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 19:19:41 +08:00
|
|
|
|
await CurrentRecipe.LoadFile(prefixPath, recipeName, recipeContent, SelectedChamber,
|
|
|
|
|
GetLoadingDispatcher());
|
2023-06-14 17:42:00 +08:00
|
|
|
|
|
|
|
|
|
_editMode = EditMode.Normal;
|
|
|
|
|
IsLoading = false;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateView()
|
|
|
|
|
{
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
var isFileSelected = CurrentFileNode != null && CurrentFileNode.IsFile;
|
|
|
|
|
|
|
|
|
|
EnableImportExport = true;
|
|
|
|
|
EnableLeftTabPanel = true;
|
|
|
|
|
EnableFilterTreeList = true;
|
|
|
|
|
EnableRefreshRecipeList = true;
|
|
|
|
|
EnableNew = true;
|
|
|
|
|
|
|
|
|
|
EnableCellPermButton = isFileSelected;
|
|
|
|
|
EnableReload = isFileSelected;
|
|
|
|
|
EnableNew = isFileSelected;
|
|
|
|
|
EnableReName = isFileSelected;
|
|
|
|
|
EnableCopy = isFileSelected;
|
|
|
|
|
EnableDelete = isFileSelected;
|
|
|
|
|
EnableSave = isFileSelected;
|
|
|
|
|
EnableStep = isFileSelected;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
EnableSaveTo = isFileSelected;
|
|
|
|
|
EnableSaveToAll = isFileSelected;
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (_editMode == EditMode.None)
|
|
|
|
|
{
|
|
|
|
|
EnableNew = true;
|
|
|
|
|
EnableReName = false;
|
|
|
|
|
EnableCopy = false;
|
|
|
|
|
EnableDelete = false;
|
|
|
|
|
EnableStep = false;
|
|
|
|
|
EnableSave = false;
|
|
|
|
|
EnableReload = true;
|
|
|
|
|
|
|
|
|
|
}
|
2023-06-15 19:19:41 +08:00
|
|
|
|
//else if (CurrentRecipe.IsAccessibleWhitelistEditMode)
|
|
|
|
|
else if (_editMode == EditMode.EditWhitelist)
|
2023-06-14 17:42:00 +08:00
|
|
|
|
{
|
|
|
|
|
EnableNew = false;
|
|
|
|
|
EnableReName = false;
|
|
|
|
|
EnableCopy = false;
|
|
|
|
|
EnableDelete = false;
|
|
|
|
|
EnableStep = false;
|
|
|
|
|
EnableSave = false;
|
|
|
|
|
EnableReload = false;
|
|
|
|
|
EnableSaveTo = false;
|
|
|
|
|
EnableSaveToAll = false;
|
|
|
|
|
EnableLeftTabPanel = false;
|
|
|
|
|
EnableFilterTreeList = false;
|
|
|
|
|
EnableRefreshRecipeList = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableNew));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableReName));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableCopy));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableDelete));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableSave));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableImportExport));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableStep));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableSaveTo));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableSaveToAll));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableLeftTabPanel));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableFilterTreeList));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableRefreshRecipeList));
|
|
|
|
|
NotifyOfPropertyChange(nameof(EnableCellPermButton));
|
|
|
|
|
NotifyOfPropertyChange(nameof(CurrentRecipe));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string _currentCriteria = string.Empty;
|
|
|
|
|
|
|
|
|
|
public string CurrentCriteria
|
|
|
|
|
{
|
|
|
|
|
get => _currentCriteria;
|
|
|
|
|
set
|
2023-04-13 11:51:03 +08:00
|
|
|
|
{
|
2023-06-14 17:42:00 +08:00
|
|
|
|
if (value == _currentCriteria)
|
|
|
|
|
return;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
_currentCriteria = value;
|
|
|
|
|
NotifyOfPropertyChange(nameof(CurrentCriteria));
|
|
|
|
|
ApplyFilter();
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
2023-06-14 17:42:00 +08:00
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
private void ApplyFilter()
|
|
|
|
|
{
|
|
|
|
|
ProcessTypeFileList[ProcessTypeIndexSelection].FilterFileListByProcessType =
|
|
|
|
|
new ObservableCollection<FileNode>(ProcessTypeFileList[ProcessTypeIndexSelection].FileListByProcessType
|
|
|
|
|
.Where(d => d.Name.IndexOf(CurrentCriteria, StringComparison.OrdinalIgnoreCase) >= 0));
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
public void ClearFilter()
|
|
|
|
|
{
|
|
|
|
|
CurrentCriteria = "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当主窗口状态Login状态发生变化时处理当前窗口状态。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="message"></param>
|
|
|
|
|
public void Handle(UserMode message)
|
|
|
|
|
{
|
|
|
|
|
switch (message)
|
|
|
|
|
{
|
|
|
|
|
case UserMode.None:
|
|
|
|
|
break;
|
|
|
|
|
case UserMode.Normal:
|
|
|
|
|
break;
|
|
|
|
|
case UserMode.Lock:
|
|
|
|
|
case UserMode.Logoff:
|
|
|
|
|
case UserMode.Exit:
|
|
|
|
|
case UserMode.Shutdown:
|
|
|
|
|
case UserMode.Breakdown:
|
|
|
|
|
_winValidationInfo?.Close();
|
|
|
|
|
break;
|
2023-04-13 11:51:03 +08:00
|
|
|
|
|
2023-06-14 17:42:00 +08:00
|
|
|
|
default:
|
|
|
|
|
// ignore
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-13 11:51:03 +08:00
|
|
|
|
}
|