2195 lines
84 KiB
C#
2195 lines
84 KiB
C#
using Aitex.Core.RT.Log;
|
||
using Aitex.Core.RT.SCCore;
|
||
using Caliburn.Micro;
|
||
using Caliburn.Micro.Core;
|
||
using MECF.Framework.Common.CommonData;
|
||
using MECF.Framework.Common.DataCenter;
|
||
using MECF.Framework.UI.Client.CenterViews.Editors;
|
||
using MECF.Framework.UI.Client.CenterViews.Editors.Recipe;
|
||
using MECF.Framework.UI.Client.CenterViews.Editors.Sequence;
|
||
using MECF.Framework.UI.Client.ClientBase;
|
||
using OpenSEMI.ClientBase;
|
||
using OpenSEMI.ClientBase.Command;
|
||
using RecipeEditorLib.DGExtension.CustomColumn;
|
||
using RecipeEditorLib.RecipeModel.Params;
|
||
using SicUI.Client;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Linq;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Input;
|
||
using System.Windows.Media;
|
||
|
||
using Aitex.Core.Util;
|
||
using MECF.Framework.Common.OperationCenter;
|
||
using MECF.Framework.UI.Client.CenterViews.Configs.Roles;
|
||
|
||
namespace SicUI.Models.RecipeEditors
|
||
{
|
||
//Recipe列名编号(名称带_的为组名)
|
||
enum RecipColNo
|
||
{
|
||
Step_Information = 0,
|
||
Step,
|
||
Name,
|
||
StepTime,
|
||
SHFlow_SHTotalFlow,
|
||
ArH2Switch,
|
||
SHTotalFlow,
|
||
CarrayGasFlow,
|
||
SHTotalFlowSplitRatio,
|
||
FlowSetMode,
|
||
Pressure_Rotation,
|
||
PressureSet,
|
||
RotationSet,
|
||
Temperature_ControlMode,
|
||
PSUControlMode,
|
||
PSUSetMode,
|
||
SCRControlMode,
|
||
SCRSetMode,
|
||
Temperature_TempSetting,
|
||
PSUInnerTempSet,
|
||
PSUMiddleTempSet,
|
||
PSUOuterTempSet,
|
||
SCRTempSet,
|
||
Temperature_HeaterOutput,
|
||
PSUInnerRatioSet,
|
||
PSUMiddleRatioSet,
|
||
PSUOuterRatioSet,
|
||
SCRUpperRatioSet,
|
||
SCRMiddleRatioSet,
|
||
SCRLowerRatioSet,
|
||
SHFlow_SiSourceSi_SourceTotalFlow,
|
||
SiSourceTotalFlow,
|
||
SHFlow_SiSource_SiH4Flow,
|
||
SiH4FlowMode,
|
||
SiH4Flow,
|
||
SHFlow_SiSource_TCSFlow,
|
||
TCSFlowMode,
|
||
TCSBubbLowFlow,
|
||
TCSBubbHighFlow,
|
||
TCSPushFlow,
|
||
TCSBubbPressure,
|
||
SHFlow_SiSource_HCLFlow,
|
||
HCLFlowMode,
|
||
HCLFlow,
|
||
SHFlow_SiSource_SiSourSplit,
|
||
SiSourceSplitRatio,
|
||
SiSourcePushPressure,
|
||
SiSourceInnerFlow,
|
||
SiSourceMiddleFlow,
|
||
SiSourceOuterFlow,
|
||
SHFlow_CSource_CSourceTotalFlow,
|
||
CSourceTotalFlow,
|
||
SHFlow_CSource_C2H4Flow,
|
||
C2H4FlowMode,
|
||
C2H4Flow,
|
||
SHFlow_CSource_CSourceSplit,
|
||
CSourceSplitRatio,
|
||
CSourcePushPressure,
|
||
CSourceInnerFlow,
|
||
CSourceMiddleFlow,
|
||
CSourceOuterFlow,
|
||
SHFlow_Dope_DopeTotalFlow,
|
||
DopeTotalFlow,
|
||
SHFlow_Dope_N2Flow,
|
||
N2FlowMode,
|
||
N2ActualFlow,
|
||
N2LowFlow,
|
||
DilutFlowForN2,
|
||
DilutedN2Flow,
|
||
N2PostDilutPressure,
|
||
N2HighFlowMode,
|
||
N2HighFlow,
|
||
SHFlow_Dope_TMAFlow,
|
||
TMAFlowMode,
|
||
TMABubbFlow,
|
||
TMAPushFlow,
|
||
TMABubbPressure,
|
||
SHFlow_Dope_DopeSplit,
|
||
DopeSplitRatio,
|
||
DopePushPressure,
|
||
DopeInnerFlow,
|
||
DopeMiddleFlow,
|
||
DopeOuterFlow,
|
||
SHFlow_SHPushFlow,
|
||
SHPushTotalFlow,
|
||
SHInnerFlow,
|
||
SHMiddleFlow,
|
||
SHOuterFlow,
|
||
InnerPushFlow,
|
||
MiddlePushFlow,
|
||
OuterPushFlow,
|
||
Purge_SHPeripheryPurge,
|
||
SHPurgeFlow,
|
||
GRPurgeMainFlow,
|
||
Purge_ChamberPeripheryPurge,
|
||
OpticPurgeMainFlow,
|
||
ChamberPurgeFlow,
|
||
RotationUpPurgeFlow,
|
||
ShutterPurgeFlow,
|
||
HeaterWFPurgeFlow,
|
||
Purge_VentFlow,
|
||
TotalVentFlow,
|
||
VentPushFlow,
|
||
VentPreExhaustPressure
|
||
}
|
||
|
||
public class ProcessTypeFileItem : NotifiableItem
|
||
{
|
||
public string ProcessType { get; set; }
|
||
public ObservableCollection<FileNode> FileListByProcessType { get; set; }
|
||
|
||
private ObservableCollection<FileNode> filterFileListByProcessType;
|
||
public ObservableCollection<FileNode> FilterFileListByProcessType
|
||
{
|
||
get
|
||
{
|
||
return filterFileListByProcessType;
|
||
}
|
||
set
|
||
{
|
||
filterFileListByProcessType = value;
|
||
InvokePropertyChanged("FilterFileListByProcessType");
|
||
}
|
||
}
|
||
|
||
public ProcessTypeFileItem()
|
||
{
|
||
FileListByProcessType = new ObservableCollection<FileNode>();
|
||
FilterFileListByProcessType = new ObservableCollection<FileNode>();
|
||
}
|
||
}
|
||
|
||
public class ChamberTypeItem : NotifiableItem
|
||
{
|
||
public string ChamberType { get; set; }
|
||
public ObservableCollection<ProcessTypeFileItem> FileListByChamberType { get; set; }
|
||
|
||
public ChamberTypeItem()
|
||
{
|
||
FileListByChamberType = new ObservableCollection<ProcessTypeFileItem>();
|
||
}
|
||
}
|
||
|
||
public class RecipeEditorViewModel : UiViewModelBase //BaseModel
|
||
{
|
||
public enum FlowMode
|
||
{
|
||
Purge,
|
||
Vent,
|
||
Run,
|
||
Close,
|
||
}
|
||
|
||
public bool IsPermission { get => this.Permission == 3; }//&& RtStatus != "AutoRunning";
|
||
|
||
private ICommand _RenameFolderCommand;
|
||
public ICommand RenameFolderCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._RenameFolderCommand == null)
|
||
this._RenameFolderCommand = new BaseCommand(() => this.RenameFolder());
|
||
return this._RenameFolderCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _DeleteFolderCommand;
|
||
public ICommand DeleteFolderCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._DeleteFolderCommand == null)
|
||
this._DeleteFolderCommand = new BaseCommand(() => this.DeleteFolder());
|
||
return this._DeleteFolderCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _NewFolderCommand;
|
||
public ICommand NewFolderCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._NewFolderCommand == null)
|
||
this._NewFolderCommand = new BaseCommand(() => this.NewFolder());
|
||
return this._NewFolderCommand;
|
||
}
|
||
}
|
||
private ICommand _NewFolderRootCommand;
|
||
public ICommand NewFolderRootCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._NewFolderRootCommand == null)
|
||
this._NewFolderRootCommand = new BaseCommand(() => this.NewFolderRoot());
|
||
return this._NewFolderRootCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _NewRecipeCommand;
|
||
public ICommand NewRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._NewRecipeCommand == null)
|
||
this._NewRecipeCommand = new BaseCommand(() => this.NewRecipe());
|
||
return this._NewRecipeCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _NewRecipeRootCommand;
|
||
public ICommand NewRecipeRootCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._NewRecipeRootCommand == null)
|
||
this._NewRecipeRootCommand = new BaseCommand(() => this.NewRecipeRoot());
|
||
return this._NewRecipeRootCommand;
|
||
}
|
||
}
|
||
private ICommand _RenameRecipeCommand;
|
||
public ICommand RenameRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._RenameRecipeCommand == null)
|
||
this._RenameRecipeCommand = new BaseCommand(() => this.RenameRecipe());
|
||
return this._RenameRecipeCommand;
|
||
}
|
||
}
|
||
private ICommand _DeleteRecipeCommand;
|
||
public ICommand DeleteRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._DeleteRecipeCommand == null)
|
||
this._DeleteRecipeCommand = new BaseCommand(() => this.DeleteRecipe());
|
||
return this._DeleteRecipeCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _SaveAsRecipeCommand;
|
||
public ICommand SaveAsRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (this._SaveAsRecipeCommand == null)
|
||
this._SaveAsRecipeCommand = new BaseCommand(() => this.SaveAsRecipe());
|
||
return this._SaveAsRecipeCommand;
|
||
}
|
||
}
|
||
|
||
|
||
private ObservableCollection<ProcessTypeFileItem> processTypeFileList;
|
||
public ObservableCollection<ProcessTypeFileItem> ProcessTypeFileList
|
||
{
|
||
get
|
||
{
|
||
return processTypeFileList;
|
||
}
|
||
set
|
||
{
|
||
processTypeFileList = value;
|
||
NotifyOfPropertyChange("ProcessTypeFileList");
|
||
}
|
||
}
|
||
|
||
public RecipeData currentRecipe;
|
||
public RecipeData CurrentRecipe
|
||
{
|
||
get
|
||
{
|
||
return currentRecipe;
|
||
}
|
||
set
|
||
{
|
||
currentRecipe = value;
|
||
NotifyOfPropertyChange("CurrentRecipe");
|
||
}
|
||
}
|
||
|
||
public FileNode CurrentFileNode { get; set; }
|
||
|
||
private bool IsChanged
|
||
{
|
||
get
|
||
{
|
||
return editMode == EditMode.Edit || CurrentRecipe.IsChanged;
|
||
}
|
||
}
|
||
|
||
public ObservableCollection<EditorDataGridTemplateColumnBase> Columns { get; set; }
|
||
|
||
public Dictionary<string, ObservableCollection<EditorDataGridTemplateColumnBase>> DicColunms { get; set; }
|
||
|
||
public bool EnableNew { get; set; }
|
||
public bool EnableReName { get; set; }
|
||
public bool EnableCopy { get; set; }
|
||
public bool EnableDelete { get; set; }
|
||
public bool EnableSave { get; set; }
|
||
public bool EnableStep { get; set; }
|
||
|
||
public bool EnableReload { get =>IsPermission; }
|
||
|
||
public bool EnableSaveToAll { get; set; }
|
||
public bool EnableSaveTo { get; set; }
|
||
|
||
|
||
private RecipeFormatBuilder _columnBuilder = new RecipeFormatBuilder();
|
||
|
||
private EditMode editMode;
|
||
|
||
private RecipeProvider _recipeProvider = new RecipeProvider();
|
||
|
||
public ObservableCollection<string> ChamberType { get; set; }
|
||
|
||
public int ChamberTypeIndexSelection { get; set; }
|
||
|
||
public int ProcessTypeIndexSelection { get; set; }
|
||
|
||
public string CurrentChamberType
|
||
{
|
||
get
|
||
{
|
||
return ChamberType[ChamberTypeIndexSelection];
|
||
}
|
||
}
|
||
|
||
public string CurrentProcessType
|
||
{
|
||
get
|
||
{
|
||
return ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
||
}
|
||
}
|
||
|
||
public Visibility MultiChamberVisibility
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
|
||
public ObservableCollection<string> Chambers { get; set; }
|
||
|
||
public string SelectedChamber { get; set; }
|
||
|
||
public object View { get; set; }
|
||
|
||
private bool isRunPrugeSwitch;
|
||
private bool isTMANotInstall;
|
||
private bool isHClNotInstall;
|
||
private bool isHClFlowNotInstall;
|
||
|
||
#region Password check
|
||
private bool _editorEnabled = false;
|
||
public bool EditorEnable
|
||
{
|
||
get { return _editorEnabled; }
|
||
set { _editorEnabled = value; }
|
||
}
|
||
public Visibility EditorEnableV
|
||
{
|
||
get
|
||
{
|
||
return EditorEnable ? Visibility.Visible : Visibility.Hidden;
|
||
}
|
||
}
|
||
private string _loginText = "Log In";
|
||
public string LoginText
|
||
{
|
||
get { return _loginText; }
|
||
set { LoginText = value; }
|
||
}
|
||
[Subscription("PM1.Recipe.EditPassword")]
|
||
public string EPassword { get; set; }
|
||
|
||
public void ChangePassword()
|
||
{
|
||
var pcg = new EditorPassChangeView(this);
|
||
pcg.Password = EPassword;
|
||
|
||
var bRes = pcg.ShowDialog();
|
||
}
|
||
public bool ChanagePasswordReal(string sNewPassword)
|
||
{
|
||
try
|
||
{
|
||
//EPassword = sNewPassword;
|
||
InvokeClient.Instance.Service.DoOperation("PM1.Recipe.EditorChangePassword", sNewPassword);
|
||
System.Threading.Thread.Sleep(1000);
|
||
|
||
return (sNewPassword == EPassword);
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
//return true;
|
||
}
|
||
public void EditLogin()
|
||
{
|
||
|
||
if (EditorEnable)
|
||
{
|
||
EditorEnable = false;
|
||
_loginText = "Log In";
|
||
}
|
||
else
|
||
{
|
||
EditorEnable = PasswordCheck();
|
||
if (EditorEnable)
|
||
{
|
||
_loginText = "Log out";
|
||
|
||
}
|
||
}
|
||
//已更换继承的父类,这里不再使用Notify
|
||
//NotifyOfPropertyChange("LoginText");
|
||
//NotifyOfPropertyChange("EditorEnable");
|
||
|
||
|
||
}
|
||
private bool PasswordCheck()
|
||
{
|
||
var pc = new EditorPassCheckView(this);
|
||
pc.Password = EPassword;
|
||
|
||
if (pc.Password == "0")
|
||
{
|
||
MessageBox.Show("First time to use. Please click ChgPass button to Change Password.");
|
||
return false;
|
||
}
|
||
|
||
var bRes = pc.ShowDialog();
|
||
//
|
||
if (bRes == true)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
//
|
||
return false;
|
||
}
|
||
|
||
//
|
||
#endregion
|
||
|
||
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(','));
|
||
}
|
||
|
||
ChamberTypeIndexSelection = 0;
|
||
|
||
var processType = "Process,Routine,Clean";
|
||
|
||
ProcessTypeFileList = new ObservableCollection<ProcessTypeFileItem>();
|
||
var recipeProcessType = ((string)processType).Split(',');
|
||
|
||
for (var i = 0; i < recipeProcessType.Length; i++)
|
||
{
|
||
var type = new ProcessTypeFileItem();
|
||
type.ProcessType = recipeProcessType[i];
|
||
var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{recipeProcessType[i]}";
|
||
var recipes = _recipeProvider.GetXmlRecipeList(prefix);
|
||
type.FileListByProcessType = RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes)[0].Files;
|
||
type.FilterFileListByProcessType = type.FileListByProcessType;
|
||
ProcessTypeFileList.Add(type);
|
||
}
|
||
|
||
DicColunms = new Dictionary<string, ObservableCollection<EditorDataGridTemplateColumnBase>>();
|
||
UpdateRecipeFormat();
|
||
}
|
||
|
||
protected override void OnActivate()
|
||
{
|
||
|
||
//初始化RoleManager
|
||
var roleManager = new RoleManager();
|
||
roleManager.Initialize();
|
||
|
||
//得到当前登录的RoleItem
|
||
var roleItem = roleManager.GetRoleByName(ClientApp.Instance.UserContext.RoleName);
|
||
var menuPermission = new MenuPermission();
|
||
menuPermission.ParsePermission(roleItem.Role.MenuPermission);
|
||
|
||
foreach (var col in Columns)
|
||
{
|
||
if (menuPermission.MenuPermissionDictionary.ContainsKey(col.DisplayName.Replace(" ", "")) &&
|
||
menuPermission.MenuPermissionDictionary[col.DisplayName.Replace(" ", "")] ==
|
||
MenuPermissionEnum.MP_NONE)
|
||
{
|
||
col.Visibility = Visibility.Hidden;
|
||
}
|
||
|
||
if (col.ControlName == "StepNo")
|
||
continue;
|
||
|
||
|
||
if (CurrentProcessType.EndsWith("Process") &&
|
||
menuPermission.MenuPermissionDictionary.ContainsKey(col.DisplayName.Replace(" ", "")))
|
||
{
|
||
RecipeFormatBuilder.SetCellEnable(col,
|
||
menuPermission.MenuPermissionDictionary[col.DisplayName.Replace(" ", "")]);
|
||
}
|
||
}
|
||
|
||
//this.Columns = this._columnBuilder.Build($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, true, ClientApp.Instance.UserContext.RoleName);
|
||
|
||
base.OnActivate();
|
||
}
|
||
|
||
protected override void OnDeactivate(bool close)
|
||
{
|
||
base.OnDeactivate(close);
|
||
|
||
if (this.IsChanged)
|
||
{
|
||
if (DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} content is changed, do you want to save it?") == DialogButton.Yes)
|
||
{
|
||
this.SaveRecipe();
|
||
}
|
||
}
|
||
}
|
||
|
||
protected override void OnViewLoaded(object view)
|
||
{
|
||
View = view;
|
||
base.OnViewLoaded(view);
|
||
RecipeFormatBuilder.ApplyTemplate((UserControl)view, this.Columns);
|
||
var u = (RecipeEditorView)view;
|
||
u.dgCustom.Columns.Clear();
|
||
|
||
this.Columns.Apply((c) =>
|
||
{
|
||
c.Header = c;
|
||
u.dgCustom.Columns.Add(c);
|
||
|
||
});
|
||
|
||
u.dgCustom.ItemsSource = this.CurrentRecipe.Steps;
|
||
|
||
u.dgCustom.LostFocus += DgCustom_LostFocus;
|
||
|
||
u.dgCustom.FrozenColumnCount = 4;
|
||
}
|
||
|
||
private void LostFocusFunc()
|
||
{
|
||
isRunPrugeSwitch = false;
|
||
isTMANotInstall = false;
|
||
isHClNotInstall = false;
|
||
isHClFlowNotInstall = false;
|
||
|
||
CurrentRecipe.RecipeTotalTime = 0;
|
||
|
||
for (var selectIndex = 0; selectIndex < this.CurrentRecipe.Steps.Count; selectIndex++)
|
||
{
|
||
var previousIndex = selectIndex == 0 ? 0 : selectIndex - 1;
|
||
var currentIndex = selectIndex;
|
||
var nextIndex = selectIndex == this.CurrentRecipe.Steps.Count - 1 ? selectIndex : selectIndex + 1;
|
||
|
||
var previousStep = this.CurrentRecipe.Steps[previousIndex];
|
||
var currentStep = this.CurrentRecipe.Steps[currentIndex];
|
||
var nextStep = this.CurrentRecipe.Steps[nextIndex];
|
||
|
||
//判断每步与上一步值是否相同,不同则以颜色区分
|
||
JudgeStepSameValue(previousStep, currentStep);
|
||
|
||
//如果是Routine则在下面代码不执行,在这里continue
|
||
if (CurrentProcessType == ProcessTypeFileList[1].ProcessType)
|
||
{
|
||
//如果是Routine,则总时间需*循环次数
|
||
var loopTimes = int.Parse((currentStep[8] as DoubleParam).Value) == 0 ? 1 : int.Parse((currentStep[8] as DoubleParam).Value);
|
||
CurrentRecipe.RecipeTotalTime += int.Parse((currentStep[(int)RecipColNo.StepTime] as DoubleParam).Value) * loopTimes;
|
||
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
//如果是Recipe则总时间直接加
|
||
CurrentRecipe.RecipeTotalTime += int.Parse((currentStep[(int)RecipColNo.StepTime] as DoubleParam).Value);
|
||
}
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.StepTime] as DoubleParam).Value, out var stepTime);
|
||
|
||
PurgeRunSwitch(previousStep, currentStep, nextStep);
|
||
|
||
NotIntallDevice(currentStep);
|
||
|
||
if (stepTime > 0)
|
||
{
|
||
CalRecipeParameterForRunVent(previousStep, currentStep, stepTime);
|
||
}
|
||
}
|
||
|
||
//如果是Routine则在下面代码不执行,在这里返回
|
||
if (CurrentProcessType == ProcessTypeFileList[1].ProcessType)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (isRunPrugeSwitch)
|
||
MessageBox.Show("Flow mode 'Run' and 'Purge' can't switch directly", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
|
||
if (isTMANotInstall)
|
||
MessageBox.Show("TMA is not install, only Purge mode is valid", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
|
||
if (isHClNotInstall)
|
||
MessageBox.Show("GR Purge HCl is not install, only Disable is valid", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
|
||
if (isHClFlowNotInstall)
|
||
MessageBox.Show("GR Purge HCl Flow is not install, lock the value as zero", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
}
|
||
|
||
private void DgCustom_LostFocus(object sender, RoutedEventArgs e)
|
||
{
|
||
LostFocusFunc();
|
||
}
|
||
|
||
private void JudgeStepSameValue(ObservableCollection<Param> previousStep, ObservableCollection<Param> currentStep)
|
||
{
|
||
for (var i = 0; i < currentStep.Count; i++)
|
||
{
|
||
if(currentStep[i].GetType() == typeof(DoubleParam))
|
||
{
|
||
if ((previousStep[i] as DoubleParam).Value != (currentStep[i] as DoubleParam).Value)
|
||
{
|
||
(currentStep[i] as DoubleParam).Foreground = "Green";
|
||
}
|
||
else
|
||
{
|
||
(currentStep[i] as DoubleParam).Foreground = "Black";
|
||
}
|
||
}
|
||
|
||
if (currentStep[i].GetType() == typeof(ComboxParam))
|
||
{
|
||
if ((previousStep[i] as ComboxParam).Value != (currentStep[i] as ComboxParam).Value)
|
||
{
|
||
(currentStep[i] as ComboxParam).Foreground = "Green";
|
||
}
|
||
else
|
||
{
|
||
(currentStep[i] as ComboxParam).Foreground = "Black";
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
private void PurgeRunSwitch(ObservableCollection<Param> previousStep, ObservableCollection<Param> currentStep,
|
||
ObservableCollection<Param> nextStep)
|
||
{
|
||
var previousSiH4FlowMode = previousStep[(int)RecipColNo.SiH4FlowMode] as ComboxParam;
|
||
var previousTCSFlowMode = previousStep[(int)RecipColNo.TCSFlowMode] as ComboxParam;
|
||
var previousHClFlowMode = previousStep[(int)RecipColNo.HCLFlowMode] as ComboxParam;
|
||
var previousC2H4FlowMode = previousStep[(int)RecipColNo.C2H4FlowMode] as ComboxParam;
|
||
var previousN2FlowMode = previousStep[(int)RecipColNo.N2FlowMode] as ComboxParam;
|
||
var previousN2HighFlowMode = previousStep[(int)RecipColNo.N2HighFlowMode] as ComboxParam;
|
||
var previousTMAFlowMode = previousStep[(int)RecipColNo.TMAFlowMode] as ComboxParam;
|
||
|
||
var currentSiH4FlowMode = currentStep[(int)RecipColNo.SiH4FlowMode] as ComboxParam;
|
||
var currentTCSFlowMode = currentStep[(int)RecipColNo.TCSFlowMode] as ComboxParam;
|
||
var currentHClFlowMode = currentStep[(int)RecipColNo.HCLFlowMode] as ComboxParam;
|
||
var currentC2H4FlowMode = currentStep[(int)RecipColNo.C2H4FlowMode] as ComboxParam;
|
||
var currentN2FlowMode = currentStep[(int)RecipColNo.N2FlowMode] as ComboxParam;
|
||
var currentN2HighFlowMode = currentStep[(int)RecipColNo.N2HighFlowMode] as ComboxParam;
|
||
var currentTMAFlowMode = currentStep[(int)RecipColNo.TMAFlowMode] as ComboxParam;
|
||
|
||
var nextSiH4FlowMode = nextStep[(int)RecipColNo.SiH4FlowMode] as ComboxParam;
|
||
var nextTCSFlowMode = nextStep[(int)RecipColNo.TCSFlowMode] as ComboxParam;
|
||
var nextHClFlowMode = nextStep[(int)RecipColNo.HCLFlowMode] as ComboxParam;
|
||
var nextC2H4FlowMode = nextStep[(int)RecipColNo.C2H4FlowMode] as ComboxParam;
|
||
var nextN2FlowMode = nextStep[(int)RecipColNo.N2FlowMode] as ComboxParam;
|
||
var nextN2HighFlowMode = nextStep[(int)RecipColNo.N2HighFlowMode] as ComboxParam;
|
||
var nextTMAFlowMode = nextStep[(int)RecipColNo.TMAFlowMode] as ComboxParam;
|
||
|
||
var previousFlowMode = new List<ComboxParam>() { previousSiH4FlowMode, previousTCSFlowMode, previousHClFlowMode,
|
||
previousC2H4FlowMode, previousN2FlowMode,previousN2FlowMode, previousN2HighFlowMode, previousTMAFlowMode};
|
||
|
||
var currentFlowMode = new List<ComboxParam>() { currentSiH4FlowMode, currentTCSFlowMode, currentHClFlowMode,
|
||
currentC2H4FlowMode, currentN2FlowMode,currentN2FlowMode, currentN2HighFlowMode, currentTMAFlowMode};
|
||
|
||
var nextFlowMode = new List<ComboxParam>() { nextSiH4FlowMode, nextTCSFlowMode, nextHClFlowMode,
|
||
nextC2H4FlowMode, nextN2FlowMode,nextN2FlowMode, nextN2HighFlowMode, nextTMAFlowMode};
|
||
|
||
for (var i = 0; i < currentFlowMode.Count; i++)
|
||
{
|
||
if (previousFlowMode[i].Value == FlowMode.Run.ToString() && currentFlowMode[i].Value == FlowMode.Purge.ToString()
|
||
|| previousFlowMode[i].Value == FlowMode.Purge.ToString() && currentFlowMode[i].Value == FlowMode.Run.ToString())
|
||
{
|
||
isRunPrugeSwitch = true;
|
||
currentFlowMode[i].Value = FlowMode.Vent.ToString();
|
||
}
|
||
|
||
if (nextFlowMode[i].Value == FlowMode.Run.ToString() && currentFlowMode[i].Value == FlowMode.Purge.ToString()
|
||
|| nextFlowMode[i].Value == FlowMode.Purge.ToString() && currentFlowMode[i].Value == FlowMode.Run.ToString())
|
||
{
|
||
isRunPrugeSwitch = true;
|
||
currentFlowMode[i].Value = FlowMode.Vent.ToString();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void NotIntallDevice(ObservableCollection<Param> currentStep)
|
||
{
|
||
var currentTMAFlowMode = currentStep[(int)RecipColNo.TMAFlowMode] as ComboxParam;
|
||
//var currentGRPurgeHCl = currentStep[(int)RecipColNo.HeaterUpPurgeHCL] as ComboxParam;
|
||
//var currentGRPurgeHClFlow = currentStep[(int)RecipColNo.GRPurgeHCLFlow] as DoubleParam;
|
||
|
||
if (currentTMAFlowMode.Value != FlowMode.Purge.ToString())
|
||
{
|
||
currentTMAFlowMode.Value = FlowMode.Purge.ToString();
|
||
isTMANotInstall = true;
|
||
}
|
||
|
||
//if (currentGRPurgeHCl.Value != "Disable")
|
||
//{
|
||
// currentGRPurgeHCl.Value = "Disable";
|
||
// isHClNotInstall = true;
|
||
//}
|
||
|
||
//if(currentGRPurgeHClFlow != null)
|
||
//{
|
||
// double.TryParse(currentGRPurgeHClFlow.Value, out double value);
|
||
|
||
// if (value != 0)
|
||
// {
|
||
// currentGRPurgeHClFlow.Value = "0";
|
||
// isHClFlowNotInstall = true;
|
||
// }
|
||
//}
|
||
}
|
||
|
||
private void CalRecipeParameterForRunVent(ObservableCollection<Param> previousStep, ObservableCollection<Param> currentStep, double stepTime)
|
||
{
|
||
#region SH Total flow
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.SHTotalFlow] as DoubleParam).Value, out var currentSHTotalFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.CarrayGasFlow] as DoubleParam).Value, out var currentSurroundingFlow);
|
||
|
||
var arrSHTotalFlowSplitRatio = (currentStep[(int)RecipColNo.SHTotalFlowSplitRatio] as StringParam).Value.Split(':');
|
||
var currentSHTotalFlowSplitRatio = new double[3];
|
||
if (arrSHTotalFlowSplitRatio.Length == 3)
|
||
{
|
||
double.TryParse(arrSHTotalFlowSplitRatio[0], out currentSHTotalFlowSplitRatio[0]);
|
||
double.TryParse(arrSHTotalFlowSplitRatio[1], out currentSHTotalFlowSplitRatio[1]);
|
||
double.TryParse(arrSHTotalFlowSplitRatio[2], out currentSHTotalFlowSplitRatio[2]);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Si Source
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.SiH4Flow] as DoubleParam).Value, out var currentSiH4Flow);
|
||
double.TryParse((currentStep[(int)RecipColNo.TCSBubbLowFlow] as DoubleParam).Value, out var currentTCSBubbLowFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.TCSBubbHighFlow] as DoubleParam).Value, out var currentTCSBubbHighFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.TCSPushFlow] as DoubleParam).Value, out var currentTCSPushFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.HCLFlow] as DoubleParam).Value, out var currentHClFlow);
|
||
|
||
var arrSiSourSplitRatio = (currentStep[(int)RecipColNo.SiSourceSplitRatio] as StringParam).Value.Split(':');
|
||
var currentSiSourSplitRatio = new double[3];
|
||
if (arrSiSourSplitRatio.Length == 3)
|
||
{
|
||
double.TryParse(arrSiSourSplitRatio[0], out currentSiSourSplitRatio[0]);
|
||
double.TryParse(arrSiSourSplitRatio[1], out currentSiSourSplitRatio[1]);
|
||
double.TryParse(arrSiSourSplitRatio[2], out currentSiSourSplitRatio[2]);
|
||
}
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.SiSourceTotalFlow] as DoubleParam).Value, out var currentSiSourTotalFlow);
|
||
|
||
var currentSiH4FlowMode = (currentStep[(int)RecipColNo.SiH4FlowMode] as ComboxParam).Value;
|
||
var currentTCSFlowMode = (currentStep[(int)RecipColNo.TCSFlowMode] as ComboxParam).Value;
|
||
var currentHClFlowMode = (currentStep[(int)RecipColNo.HCLFlowMode] as ComboxParam).Value;
|
||
|
||
double TCSFlow = 0;
|
||
var TCS_Eff = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SelectedChamber}.Efficiency.TCS-Eff");
|
||
if (currentTCSFlowMode == FlowMode.Run.ToString() || currentTCSFlowMode == FlowMode.Vent.ToString())
|
||
TCSFlow = (currentTCSBubbHighFlow + currentTCSBubbLowFlow) * TCS_Eff + currentTCSPushFlow;
|
||
else if (currentTCSFlowMode == FlowMode.Purge.ToString())
|
||
TCSFlow = currentTCSBubbHighFlow + currentTCSBubbLowFlow + currentTCSPushFlow;
|
||
|
||
//double currentSiSourPushFlow = currentSiSourTotalFlow - (currentSiH4FlowMode == FlowMode.Run.ToString() ? currentSiH4Flow : 0)
|
||
// - (currentTCSFlowMode == FlowMode.Run.ToString() ? TCSFlow : 0) - (currentHClFlowMode == FlowMode.Run.ToString() ? currentHClFlow : 0);
|
||
|
||
//(currentStep[(int)RecipColNo.SiSourceOuterFlow] as DoubleParam).Value = currentSiSourPushFlow.ToString("F1");
|
||
|
||
double currentSiSourInnerFlow = 0;
|
||
double currentSiSourMidFlow = 0;
|
||
double currentSiSourOutFlow = 0;
|
||
|
||
if (currentSiSourSplitRatio.Length == 3)
|
||
{
|
||
var rationSum = currentSiSourSplitRatio[0] + currentSiSourSplitRatio[1] + currentSiSourSplitRatio[2];
|
||
|
||
currentSiSourInnerFlow = currentSiSourTotalFlow / rationSum * currentSiSourSplitRatio[0];
|
||
currentSiSourMidFlow = currentSiSourTotalFlow / rationSum * currentSiSourSplitRatio[1];
|
||
currentSiSourOutFlow = currentSiSourTotalFlow / rationSum * currentSiSourSplitRatio[2];
|
||
}
|
||
|
||
(currentStep[(int)RecipColNo.SiSourceInnerFlow] as DoubleParam).Value = currentSiSourInnerFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.SiSourceMiddleFlow] as DoubleParam).Value = currentSiSourMidFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.SiSourceOuterFlow] as DoubleParam).Value = currentSiSourOutFlow.ToString("F1");
|
||
|
||
#endregion
|
||
|
||
#region C Source
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.C2H4Flow] as DoubleParam).Value, out var currentC2H4Flow);
|
||
|
||
var arrCSourSplitRatio = (currentStep[(int)RecipColNo.CSourceSplitRatio] as StringParam).Value.Split(':');
|
||
var currentCSourSplitRatio = new double[3];
|
||
if (arrCSourSplitRatio.Length == 3)
|
||
{
|
||
double.TryParse(arrCSourSplitRatio[0], out currentCSourSplitRatio[0]);
|
||
double.TryParse(arrCSourSplitRatio[1], out currentCSourSplitRatio[1]);
|
||
double.TryParse(arrCSourSplitRatio[2], out currentCSourSplitRatio[2]);
|
||
}
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.CSourceTotalFlow] as DoubleParam).Value, out var currentCSourTotalFlow);
|
||
|
||
var currentC2H4FlowMode = (currentStep[(int)RecipColNo.C2H4FlowMode] as ComboxParam).Value;
|
||
var currentCSourPushFlow = currentCSourTotalFlow - (currentC2H4FlowMode == FlowMode.Run.ToString() ? currentC2H4Flow : 0);
|
||
|
||
(currentStep[(int)RecipColNo.CSourceOuterFlow] as DoubleParam).Value = currentCSourPushFlow.ToString("F1");
|
||
|
||
double currentCSourInnerFlow = 0;
|
||
double currentCSourMidFlow = 0;
|
||
double currentCSourOuterFlow = 0;
|
||
|
||
if (currentCSourSplitRatio.Length == 3)
|
||
{
|
||
var ratioSum = currentCSourSplitRatio[0] + currentCSourSplitRatio[1] + currentCSourSplitRatio[2];
|
||
|
||
currentCSourInnerFlow = currentCSourTotalFlow / ratioSum * currentCSourSplitRatio[0];
|
||
currentCSourMidFlow = currentCSourTotalFlow / ratioSum * currentCSourSplitRatio[1];
|
||
currentCSourOuterFlow= currentCSourTotalFlow / ratioSum * currentCSourSplitRatio[2];
|
||
}
|
||
|
||
(currentStep[(int)RecipColNo.CSourceInnerFlow] as DoubleParam).Value = currentCSourInnerFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.CSourceMiddleFlow] as DoubleParam).Value = currentCSourMidFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.CSourceOuterFlow] as DoubleParam).Value = currentCSourOuterFlow.ToString("F1");
|
||
|
||
#endregion
|
||
|
||
#region Dope
|
||
double.TryParse((currentStep[(int)RecipColNo.DopeTotalFlow] as DoubleParam).Value, out var currentDopeTotalFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.N2ActualFlow] as DoubleParam).Value, out var currentN2ActualFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.N2LowFlow] as DoubleParam).Value, out var currentN2LowFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.DilutFlowForN2] as DoubleParam).Value, out var currentDiluFlowForN2);
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.N2HighFlow] as DoubleParam).Value, out var currentN2HighFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.TMABubbFlow] as DoubleParam).Value, out var currentTMABubbFlow);
|
||
double.TryParse((currentStep[(int)RecipColNo.TMAPushFlow] as DoubleParam).Value, out var currentTMAPushFlow);
|
||
|
||
var currentDilutedN2Flow = (currentN2LowFlow + currentDiluFlowForN2) * currentN2ActualFlow / currentN2LowFlow;
|
||
(currentStep[(int)RecipColNo.DilutedN2Flow] as DoubleParam).Value = currentDilutedN2Flow.ToString("F1");
|
||
|
||
var arrDopeSplitRatio = (currentStep[(int)RecipColNo.DopeSplitRatio] as StringParam).Value.Split(':');
|
||
var currentDopeSplitRatio = new double[3];
|
||
if (arrDopeSplitRatio.Length == 3)
|
||
{
|
||
double.TryParse(arrDopeSplitRatio[0], out currentDopeSplitRatio[0]);
|
||
double.TryParse(arrDopeSplitRatio[1], out currentDopeSplitRatio[1]);
|
||
double.TryParse(arrDopeSplitRatio[2], out currentDopeSplitRatio[2]);
|
||
}
|
||
|
||
var currentN2FlowMode = (currentStep[(int)RecipColNo.N2FlowMode] as ComboxParam).Value;
|
||
var currentN2HighFlowMode = (currentStep[(int)RecipColNo.N2HighFlowMode] as ComboxParam).Value;
|
||
var currentTMAFlowMode = (currentStep[(int)RecipColNo.TMAFlowMode] as ComboxParam).Value;
|
||
|
||
double TMAFlow = 0;
|
||
var TMA_Eff = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SelectedChamber}.Efficiency.TMA-Eff");
|
||
if (currentTMAFlowMode == FlowMode.Run.ToString() || currentTMAFlowMode == FlowMode.Vent.ToString())
|
||
TMAFlow = currentTMABubbFlow * TMA_Eff + currentTMAPushFlow;
|
||
else if (currentTMAFlowMode == FlowMode.Purge.ToString())
|
||
TMAFlow = currentTMABubbFlow + currentTMAPushFlow;
|
||
|
||
//double currentDopePushFlow = currentDopeTotalFlow
|
||
// - (currentN2FlowMode == FlowMode.Run.ToString() ? currentDilutedN2Flow : 0)
|
||
// - (currentN2HighFlowMode == FlowMode.Run.ToString() ? currentN2HighFlow : 0)
|
||
// - (currentTMAFlowMode == FlowMode.Run.ToString() ? TMAFlow : 0);
|
||
|
||
//(currentStep[(int)RecipColNo.DopeOuterFlow] as DoubleParam).Value = currentDopePushFlow.ToString("F1");
|
||
|
||
double currentDopeInnerFlow = 0;
|
||
double currentDopeMidFlow = 0;
|
||
double currentDopeOuterFlow = 0;
|
||
|
||
if (currentDopeSplitRatio.Length == 3)
|
||
{
|
||
var ratioSum = currentDopeSplitRatio[0] + currentDopeSplitRatio[1] + currentDopeSplitRatio[2];
|
||
|
||
currentDopeInnerFlow = currentDopeTotalFlow / ratioSum * currentDopeSplitRatio[0];
|
||
currentDopeMidFlow = currentDopeTotalFlow / ratioSum * currentDopeSplitRatio[1];
|
||
currentDopeOuterFlow = currentDopeTotalFlow / ratioSum * currentDopeSplitRatio[2];
|
||
}
|
||
|
||
(currentStep[(int)RecipColNo.DopeInnerFlow] as DoubleParam).Value = currentDopeInnerFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.DopeMiddleFlow] as DoubleParam).Value = currentDopeMidFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.DopeOuterFlow] as DoubleParam).Value = currentDopeOuterFlow.ToString("F1");
|
||
|
||
#endregion
|
||
|
||
#region SH Supp. Flow
|
||
|
||
var currentSHSuppTotalFlow = currentSHTotalFlow - currentSurroundingFlow - currentSiSourTotalFlow - currentCSourTotalFlow - currentDopeTotalFlow;
|
||
var sumSHTotalFlowSplitRatio = currentSHTotalFlowSplitRatio[0] + currentSHTotalFlowSplitRatio[1] + currentSHTotalFlowSplitRatio[2];
|
||
var currentSHInnerFlow = (currentSHTotalFlow - currentSurroundingFlow) / sumSHTotalFlowSplitRatio * currentSHTotalFlowSplitRatio[0];
|
||
var currentSHMidFlow = (currentSHTotalFlow - currentSurroundingFlow) / sumSHTotalFlowSplitRatio * currentSHTotalFlowSplitRatio[1];
|
||
var currentSHOutterFlow = (currentSHTotalFlow - currentSurroundingFlow) / sumSHTotalFlowSplitRatio * currentSHTotalFlowSplitRatio[2];
|
||
var currentInnerSuppFlow = currentSHInnerFlow - currentSiSourInnerFlow - currentCSourInnerFlow - currentDopeInnerFlow;
|
||
var currentMidSuppFlow = currentSHMidFlow - currentSiSourMidFlow - currentCSourMidFlow - currentDopeMidFlow;
|
||
var currentOutterSuppFlow = currentSHSuppTotalFlow - currentInnerSuppFlow - currentMidSuppFlow;
|
||
|
||
(currentStep[(int)RecipColNo.SHPushTotalFlow] as DoubleParam).Value = currentSHSuppTotalFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.SHInnerFlow] as DoubleParam).Value = currentSHInnerFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.SHMiddleFlow] as DoubleParam).Value = currentSHMidFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.SHOuterFlow] as DoubleParam).Value = currentSHOutterFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.InnerPushFlow] as DoubleParam).Value = currentInnerSuppFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.MiddlePushFlow] as DoubleParam).Value = currentMidSuppFlow.ToString("F1");
|
||
(currentStep[(int)RecipColNo.OuterPushFlow] as DoubleParam).Value = currentOutterSuppFlow.ToString("F1");
|
||
|
||
#endregion
|
||
|
||
#region Vent Flow
|
||
|
||
double.TryParse((currentStep[(int)RecipColNo.TotalVentFlow] as DoubleParam).Value, out var currentTotalVentFlow);
|
||
|
||
var currentSiSourTotalFlowForPurge = (currentSiH4FlowMode != FlowMode.Run.ToString() ? currentSiH4Flow : 0)
|
||
+ (currentTCSFlowMode != FlowMode.Run.ToString() ? TCSFlow : 0) + (currentHClFlowMode != FlowMode.Run.ToString() ? currentHClFlow : 0);
|
||
|
||
var currentCSourTotalFlowForPurge = currentC2H4FlowMode != FlowMode.Run.ToString() ? currentC2H4Flow : 0;
|
||
|
||
var N2Flow = (currentN2FlowMode != FlowMode.Run.ToString() ? currentDilutedN2Flow : 0) + (currentN2HighFlowMode != FlowMode.Run.ToString() ? currentN2HighFlow : 0);
|
||
|
||
var currentDopeTotalFlowForPurge = N2Flow + (currentTMAFlowMode != FlowMode.Run.ToString() ? TMAFlow : 0);
|
||
|
||
var currentVentPushFlow = currentTotalVentFlow - currentSiSourTotalFlowForPurge - currentCSourTotalFlowForPurge - currentDopeTotalFlowForPurge;
|
||
|
||
(currentStep[(int)RecipColNo.VentPushFlow] as DoubleParam).Value = currentVentPushFlow.ToString("F1");
|
||
|
||
#endregion
|
||
}
|
||
|
||
public void TabSelectionChanged()
|
||
{
|
||
UpdateRecipeFormat();
|
||
OnViewLoaded(View);
|
||
}
|
||
|
||
public void UpdateRecipeFormat()
|
||
{
|
||
var chamber = QueryDataClient.Instance.Service.GetConfig("System.Recipe.ChamberModules");
|
||
if (chamber == null)
|
||
{
|
||
chamber = "PM1";
|
||
}
|
||
|
||
Chambers = new ObservableCollection<string>(((string)chamber).Split(','));
|
||
if (Chambers.Count > 1)
|
||
{
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (Chambers.Count == 0)
|
||
{
|
||
Chambers = new ObservableCollection<string>(new string[] { "PM1" });
|
||
}
|
||
SelectedChamber = Chambers[0];
|
||
|
||
if (DicColunms.Keys.Contains(CurrentProcessType))
|
||
{
|
||
this.Columns = DicColunms[CurrentProcessType];
|
||
}
|
||
else
|
||
{
|
||
this.Columns = this._columnBuilder.Build($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, true,ClientApp.Instance.UserContext.RoleName);
|
||
|
||
DicColunms[CurrentProcessType] = this.Columns;
|
||
}
|
||
|
||
this.CurrentRecipe = new RecipeData();
|
||
CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType;
|
||
CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion;
|
||
|
||
this.editMode = EditMode.None;
|
||
|
||
MultiChamberVisibility = Chambers.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
|
||
}
|
||
|
||
public 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?");
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
CurrentRecipe.ChangeChamber(Columns
|
||
, _columnBuilder.Configs, SelectedChamber);
|
||
}
|
||
|
||
public 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?");
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
CurrentFileNode = node;
|
||
|
||
if (node != null && node.IsFile)
|
||
{
|
||
this.LoadData(node.PrefixPath, node.FullPath);
|
||
}
|
||
else
|
||
{
|
||
this.ClearData();
|
||
this.editMode = EditMode.None;
|
||
}
|
||
this.UpdateView();
|
||
//OnViewLoaded(View);//zyx debug
|
||
}
|
||
|
||
#region folder
|
||
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;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
var name = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(name))
|
||
{
|
||
DialogBox.ShowWarning("Folder name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = ChamberType[ChamberTypeIndexSelection] + "\\" + ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
||
var processType = string.Empty;
|
||
var newFolder = string.Empty;
|
||
if (CurrentFileNode != null)
|
||
{
|
||
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 + "\\";
|
||
}
|
||
|
||
}
|
||
|
||
newFolder = newFolder + name;
|
||
|
||
if (IsExist(newFolder, false))
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {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.CreateRecipeFolder(prefix, newFolder);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true);
|
||
}
|
||
|
||
public void NewFolderRoot()
|
||
{
|
||
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;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
var name = dialog.FileName.Trim();
|
||
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;
|
||
}
|
||
|
||
var prefix = ChamberType[ChamberTypeIndexSelection] + "\\" + ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
||
|
||
_recipeProvider.CreateRecipeFolder(prefix, name);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, name, true);
|
||
}
|
||
|
||
public void DeleteFolder()
|
||
{
|
||
if (CurrentFileNode == null || CurrentFileNode.IsFile)
|
||
return;
|
||
|
||
if (CurrentFileNode.Files.Count > 0)
|
||
{
|
||
DialogBox.ShowWarning($"Can not delete non-empty folder, Remove the files or folders under \r\n{CurrentFileNode.FullPath}.");
|
||
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;
|
||
|
||
var nextFocus = CurrentFileNode.Parent.FullPath;
|
||
var isFolder = true;
|
||
if (CurrentFileNode.Parent.Files.Count > 1)
|
||
{
|
||
for (var i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
|
||
{
|
||
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;
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Folder Name");
|
||
dialog.FileName = CurrentFileNode.Name;
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var name = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(name))
|
||
return;
|
||
|
||
var newFolder = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
|
||
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
|
||
public void NewRecipe()
|
||
{
|
||
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;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Name");
|
||
dialog.FileName = "";
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(dialog.FileName))
|
||
{
|
||
DialogBox.ShowWarning("Recipe file name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
||
var processType = string.Empty;
|
||
if (CurrentFileNode != null)
|
||
{
|
||
var folder = CurrentFileNode.FullPath;
|
||
|
||
|
||
if (CurrentFileNode.IsFile)
|
||
{
|
||
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
||
//if (!string.IsNullOrEmpty(folder))
|
||
// folder = folder;
|
||
}
|
||
else
|
||
{
|
||
folder = folder + "\\";
|
||
}
|
||
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;
|
||
}
|
||
|
||
var recipe = new RecipeData();
|
||
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)
|
||
{
|
||
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;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
||
dialog.FileName = "new recipe";
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
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;
|
||
}
|
||
|
||
var recipe = new RecipeData();
|
||
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);
|
||
}
|
||
|
||
private void ReloadRecipeFileList(string chamberType, string processType, string selectedFile, bool selectionIsFolder)
|
||
{
|
||
var item = ProcessTypeFileList.FirstOrDefault(x => x.ProcessType == processType);
|
||
if (item == null)
|
||
{
|
||
LOG.Write("error reload recipe file list, type = " + processType);
|
||
}
|
||
|
||
var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{item.ProcessType}";
|
||
var recipes = _recipeProvider.GetXmlRecipeList(prefix);
|
||
|
||
item.FileListByProcessType = RecipeSequenceTreeBuilder.BuildFileNode(prefix, selectedFile, selectionIsFolder, recipes)[0].Files;
|
||
item.FilterFileListByProcessType = item.FileListByProcessType;
|
||
|
||
item.InvokePropertyChanged();
|
||
}
|
||
|
||
private bool IsExist(string fullPath, bool isFile)
|
||
{
|
||
for (var i = 0; i < ProcessTypeFileList.Count; i++)
|
||
{
|
||
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;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public void SaveAsRecipe()
|
||
{
|
||
if (CurrentFileNode == null || !CurrentFileNode.IsFile)
|
||
return;
|
||
|
||
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;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
||
dialog.FileName = CurrentFileNode.Name;
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(dialog.FileName))
|
||
{
|
||
DialogBox.ShowWarning("Recipe file name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
||
var processType = string.Empty;
|
||
|
||
var folder = CurrentFileNode.FullPath;
|
||
if (CurrentFileNode.IsFile)
|
||
{
|
||
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
||
}
|
||
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)
|
||
{
|
||
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;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
this.CurrentRecipe.ReviseTime = DateTime.Now;
|
||
this.Save(this.CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
||
dialog.FileName = CurrentFileNode.Name;
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(dialog.FileName))
|
||
{
|
||
DialogBox.ShowWarning("Recipe file name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
||
var processType = string.Empty;
|
||
|
||
var newName = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
|
||
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;
|
||
|
||
var nextFocus = CurrentFileNode.Parent.FullPath;
|
||
var isFolder = true;
|
||
if (CurrentFileNode.Parent.Files.Count > 1)
|
||
{
|
||
for (var i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
|
||
{
|
||
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);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, nextFocus, isFolder);
|
||
}
|
||
|
||
public void RefreshRecipe()
|
||
{
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, "", false);
|
||
}
|
||
|
||
public void ReloadRecipe()
|
||
{
|
||
if (this.editMode == EditMode.Normal || this.editMode == EditMode.Edit)
|
||
{
|
||
this.LoadData(CurrentRecipe.PrefixPath, CurrentRecipe.Name);
|
||
this.UpdateView();
|
||
}
|
||
}
|
||
|
||
public void SaveToAll()
|
||
{
|
||
LostFocusFunc();
|
||
|
||
if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
|
||
{
|
||
DialogBox.ShowWarning($"Save failed, {CurrentRecipe.Name} is not a valid recipe file");
|
||
return;
|
||
}
|
||
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
||
DialogType.CONFIRM, $"Do you want to save to all? \r\n This will replace all the other chamber recipe content");
|
||
if (selection == DialogButton.No)
|
||
return;
|
||
|
||
CurrentRecipe.SaveTo(Chambers.ToArray());
|
||
|
||
Save(this.CurrentRecipe, false);
|
||
}
|
||
|
||
public void SaveTo()
|
||
{
|
||
LostFocusFunc();
|
||
|
||
if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
|
||
{
|
||
DialogBox.ShowWarning($"Save failed, {CurrentRecipe.Name} is not a valid recipe file");
|
||
return;
|
||
}
|
||
|
||
var dialog = new SaveToDialogViewModel("Select which chamber to copy to", SelectedChamber, Chambers.ToList());
|
||
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var chambers = new List<string>();
|
||
foreach (var dialogChamber in dialog.Chambers)
|
||
{
|
||
if (dialogChamber.IsEnabled && dialogChamber.IsChecked)
|
||
chambers.Add(dialogChamber.Name);
|
||
}
|
||
|
||
if (chambers.Count == 0)
|
||
return;
|
||
|
||
CurrentRecipe.SaveTo(chambers.ToArray());
|
||
|
||
Save(this.CurrentRecipe, false);
|
||
}
|
||
#endregion
|
||
|
||
#region Steps
|
||
|
||
public void ParamsExpanded(ExpanderColumn col)
|
||
{
|
||
var index = this.Columns.IndexOf(col);
|
||
for (var i = index + 1; i < this.Columns.Count; i++)
|
||
{
|
||
if (this.Columns[i] is ExpanderColumn)
|
||
break;
|
||
this.Columns[i].Visibility = Visibility.Visible;
|
||
}
|
||
}
|
||
|
||
public void ParamsCollapsed(ExpanderColumn col)
|
||
{
|
||
var index = this.Columns.IndexOf(col);
|
||
for (var i = index + 1; i < this.Columns.Count; i++)
|
||
{
|
||
if (this.Columns[i] is ExpanderColumn)
|
||
break;
|
||
this.Columns[i].Visibility = Visibility.Collapsed;
|
||
}
|
||
}
|
||
|
||
public bool CheckColumnDataAvalible()
|
||
{
|
||
if (CurrentProcessType == ProcessTypeFileList[1].ProcessType)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
var lstNotCorrectInfo = new List<string>();
|
||
var lstOutOfRange = new List<string>();
|
||
|
||
var lstSplitColums = new List<int>() { (int)RecipColNo.SHTotalFlowSplitRatio, (int)RecipColNo.SiSourceSplitRatio, (int)RecipColNo.CSourceSplitRatio, (int)RecipColNo.DopeSplitRatio };
|
||
|
||
for (var a = 0; a < this.CurrentRecipe.Steps.Count; a++)
|
||
{
|
||
for (var i = 0; i < this.Columns.Count; i++)
|
||
{
|
||
if (this.Columns[i] is DoubleColumn)
|
||
{
|
||
var column = (DoubleColumn)this.Columns[i];
|
||
var maxValue = column.Maximun;
|
||
var minValue = column.Minimun;
|
||
|
||
if (maxValue != minValue)
|
||
{
|
||
double cValue = 0;
|
||
if (!double.TryParse((this.CurrentRecipe.Steps[a][i] as DoubleParam).Value, out cValue))
|
||
{
|
||
if ((this.CurrentRecipe.Steps[a][i] as DoubleParam).Value != "Hold")
|
||
{
|
||
lstNotCorrectInfo.Add($"Step {a + 1} {column.DisplayName}: value {(this.CurrentRecipe.Steps[a][i] as DoubleParam).Value} is incorrect numerical format ");
|
||
(this.CurrentRecipe.Steps[a][i] as DoubleParam).Foreground = "Red";
|
||
}
|
||
}
|
||
else if (cValue > maxValue || cValue < minValue)
|
||
{
|
||
lstOutOfRange.Add($"Step {a + 1} {column.DisplayName}: value {cValue} is out of range {minValue}-{maxValue}");
|
||
(this.CurrentRecipe.Steps[a][i] as DoubleParam).Foreground = "Red";
|
||
}
|
||
}
|
||
}
|
||
else if (lstSplitColums.Contains(i))
|
||
{
|
||
double a1 = 0;
|
||
double a2 = 0;
|
||
double a3 = 0;
|
||
var arrSplitRatio = (this.CurrentRecipe.Steps[a][i] as StringParam).Value.Split(':');
|
||
if (arrSplitRatio.Length != 3
|
||
|| !double.TryParse(arrSplitRatio[0], out a1) || !double.TryParse(arrSplitRatio[1], out a2) || !double.TryParse(arrSplitRatio[2], out a3)
|
||
|| a1 <= 0 || a2 <= 0 || a3 <= 0)
|
||
{
|
||
lstNotCorrectInfo.Add($"(Step {i + 1}) {this.Columns[i].DisplayName}: value is not avalible!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (lstNotCorrectInfo.Count > 0 || lstOutOfRange.Count > 0)
|
||
{
|
||
var strInfo = "";
|
||
for (var i = 0; i < lstNotCorrectInfo.Count; i++)
|
||
{
|
||
strInfo += lstNotCorrectInfo[i] + "\r\n";
|
||
}
|
||
for (var i = 0; i < lstOutOfRange.Count; i++)
|
||
{
|
||
strInfo += lstOutOfRange[i] + "\r\n";
|
||
}
|
||
MessageBox.Show(strInfo);
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
public void SaveRecipe()
|
||
{
|
||
//if (!CheckColumnDataAvalible())
|
||
//{
|
||
// return;
|
||
//}
|
||
|
||
//if (this.IsChanged)
|
||
//{
|
||
this.Save(this.CurrentRecipe, false);
|
||
//}
|
||
}
|
||
|
||
public void PopSetting(string controlName, Param paramData)
|
||
{
|
||
var stepNum = Convert.ToInt32(((StepParam)paramData.Parent[1]).Value);
|
||
|
||
var dialog = new PublicPopSettingDialogViewModel();
|
||
dialog.DisplayName = paramData.DisplayName;
|
||
var Parameters = new ObservableCollection<Param>();
|
||
|
||
Parameters = this.CurrentRecipe.PopSettingSteps[controlName][stepNum - 1];
|
||
|
||
var ControlParameters = new ObservableCollection<Param>();
|
||
var BrandParameters = new ObservableCollection<BandParam>();
|
||
foreach (var item in Parameters)
|
||
{
|
||
if (item.Name.Contains("Band"))
|
||
{
|
||
var name = item.Name.Replace("Wavelength", "").Replace("Bandwidth", "");
|
||
var displayName = item.DisplayName.Replace("Wavelength", "").Replace("Bandwidth", "");
|
||
|
||
if (BrandParameters.Where(x => x.Name == name).Count() == 0)
|
||
{
|
||
BrandParameters.Add(new BandParam()
|
||
{
|
||
Name = name,
|
||
DisplayName = displayName
|
||
});
|
||
}
|
||
|
||
if (item.Name.Contains("Wavelength"))
|
||
{
|
||
BrandParameters.First(x => x.Name == name).WavelengthDoubleParam = item;
|
||
}
|
||
else if (item.Name.Contains("Bandwidth"))
|
||
{
|
||
BrandParameters.First(x => x.Name == name).BandwidthDoubleParam = item;
|
||
}
|
||
}
|
||
else
|
||
ControlParameters.Add(item);
|
||
}
|
||
|
||
dialog.Parameters = Parameters;
|
||
dialog.ControlParameters = ControlParameters;
|
||
dialog.BandParameters = BrandParameters;
|
||
|
||
var wm = new WindowManager();
|
||
var bret = wm.ShowDialog(dialog);
|
||
if ((bool)bret)
|
||
{
|
||
this.CurrentRecipe.PopSettingSteps[controlName][stepNum - 1] = dialog.Parameters;
|
||
}
|
||
}
|
||
|
||
public bool Save(RecipeData recipe, bool createNew)
|
||
{
|
||
//保存时也要失去焦点计算一次
|
||
LostFocusFunc();
|
||
|
||
if (!CheckColumnDataAvalible())
|
||
{
|
||
//return false;
|
||
}
|
||
|
||
var result = false;
|
||
if (string.IsNullOrEmpty(recipe.Name))
|
||
{
|
||
MessageBox.Show("Recipe name can't be empty");
|
||
return false;
|
||
}
|
||
|
||
recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
recipe.ReviseTime = DateTime.Now;
|
||
|
||
result = this._recipeProvider.SaveRecipe(recipe.PrefixPath, recipe.Name, recipe.GetXmlString());
|
||
|
||
if (result)
|
||
{
|
||
recipe.DataSaved();
|
||
|
||
this.editMode = EditMode.Normal;
|
||
|
||
this.UpdateView();
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("Save failed!");
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
public void AddStep()
|
||
{
|
||
this.CurrentRecipe.Steps.Add(this.CurrentRecipe.CreateStep(this.Columns));
|
||
|
||
if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
|
||
this.editMode = EditMode.Edit;
|
||
|
||
var index = 1;
|
||
foreach (var parameters in this.CurrentRecipe.Steps)
|
||
{
|
||
(parameters[1] as StepParam).Value = index.ToString();
|
||
index++;
|
||
}
|
||
this.UpdateView();
|
||
}
|
||
|
||
public void AppendStep()
|
||
{
|
||
var index = -1;
|
||
var found = false;
|
||
for (var i = 0; i < this.CurrentRecipe.Steps.Count; i++)
|
||
{
|
||
if (this.CurrentRecipe.Steps[i][1] is StepParam && ((StepParam)this.CurrentRecipe.Steps[i][1]).Checked)
|
||
{
|
||
index = i;
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
if (found)
|
||
{
|
||
if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
|
||
this.editMode = EditMode.Edit;
|
||
|
||
this.CurrentRecipe.Steps.Insert(index, this.CurrentRecipe.CreateStep(this.Columns));
|
||
|
||
|
||
index = 1;
|
||
foreach (var parameters in this.CurrentRecipe.Steps)
|
||
{
|
||
(parameters[1] as StepParam).Value = index.ToString();
|
||
index++;
|
||
}
|
||
}
|
||
}
|
||
|
||
private ObservableCollection<ObservableCollection<Param>> copySteps = new ObservableCollection<ObservableCollection<Param>>();
|
||
private Dictionary<string, ObservableCollection<ObservableCollection<Param>>> popCopySteps = new Dictionary<string, ObservableCollection<ObservableCollection<Param>>>();
|
||
|
||
public void CopyStep()
|
||
{
|
||
this.copySteps.Clear();
|
||
this.popCopySteps.Clear();
|
||
|
||
for (var i = 0; i < this.CurrentRecipe.Steps.Count; i++)
|
||
{
|
||
if (this.CurrentRecipe.Steps[i][1] is StepParam && ((StepParam)this.CurrentRecipe.Steps[i][1]).Checked)
|
||
{
|
||
this.copySteps.Add(this.CurrentRecipe.CloneStep(this.Columns, this.CurrentRecipe.Steps[i]));
|
||
}
|
||
}
|
||
CurrentRecipe.ValidLoopData();
|
||
}
|
||
|
||
public void PasteFrontStep()
|
||
{
|
||
if (this.copySteps.Count > 0)
|
||
{
|
||
if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
|
||
this.editMode = EditMode.Edit;
|
||
for (var i = 0; i < this.CurrentRecipe.Steps.Count; i++)
|
||
{
|
||
if (this.CurrentRecipe.Steps[i][1] is StepParam && ((StepParam)this.CurrentRecipe.Steps[i][1]).Checked)
|
||
{
|
||
for (var copyindex = 0; copyindex < this.copySteps.Count; copyindex++)
|
||
{
|
||
this.CurrentRecipe.Steps.Insert(i, this.CurrentRecipe.CloneStep(this.Columns, this.copySteps[copyindex]));
|
||
i++;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
var index = 1;
|
||
foreach (var parameters in this.CurrentRecipe.Steps)
|
||
{
|
||
(parameters[1] as StepParam).Value = index.ToString();
|
||
index++;
|
||
}
|
||
CurrentRecipe.ValidLoopData();
|
||
this.UpdateView();
|
||
}
|
||
}
|
||
public void PasteBackStep()
|
||
{
|
||
if (this.copySteps.Count > 0)
|
||
{
|
||
if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
|
||
this.editMode = EditMode.Edit;
|
||
for (var i = this.CurrentRecipe.Steps.Count - 1; i >= 0; i--)
|
||
{
|
||
if (this.CurrentRecipe.Steps[i][1] is StepParam && ((StepParam)this.CurrentRecipe.Steps[i][1]).Checked)
|
||
{
|
||
for (var copyindex = 0; copyindex < this.copySteps.Count; copyindex++)
|
||
{
|
||
this.CurrentRecipe.Steps.Insert(i + 1, this.CurrentRecipe.CloneStep(this.Columns, this.copySteps[copyindex]));
|
||
i++;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
var index = 1;
|
||
foreach (var parameters in this.CurrentRecipe.Steps)
|
||
{
|
||
(parameters[1] as StepParam).Value = index.ToString();
|
||
index++;
|
||
}
|
||
CurrentRecipe.ValidLoopData();
|
||
this.UpdateView();
|
||
}
|
||
}
|
||
|
||
public void DeleteStep()
|
||
{
|
||
if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
|
||
this.editMode = EditMode.Edit;
|
||
|
||
var steps = this.CurrentRecipe.Steps.ToList();
|
||
|
||
for (var i = 0; i < steps.Count; i++)
|
||
{
|
||
if (steps[i][1] is StepParam && ((StepParam)steps[i][1]).Checked)
|
||
{
|
||
this.CurrentRecipe.Steps.Remove(steps[i]);
|
||
}
|
||
}
|
||
var index = 1;
|
||
foreach (var parameters in this.CurrentRecipe.Steps)
|
||
{
|
||
(parameters[1] as StepParam).Value = index.ToString();
|
||
index++;
|
||
}
|
||
}
|
||
|
||
private TreeViewItem GetParentObjectEx<TreeViewItem>(DependencyObject obj) where TreeViewItem : FrameworkElement
|
||
{
|
||
var parent = VisualTreeHelper.GetParent(obj);
|
||
while (parent != null)
|
||
{
|
||
if (parent is TreeViewItem)
|
||
{
|
||
return (TreeViewItem)parent;
|
||
}
|
||
parent = VisualTreeHelper.GetParent(parent);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public void TreeRightMouseDown(MouseButtonEventArgs e)
|
||
{
|
||
var item = GetParentObjectEx<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
|
||
if (item != null)
|
||
{
|
||
item.Focus();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
#endregion
|
||
private void ClearData()
|
||
{
|
||
this.editMode = EditMode.None;
|
||
this.CurrentRecipe.Clear();
|
||
this.CurrentRecipe.Name = string.Empty;
|
||
this.CurrentRecipe.Description = string.Empty;
|
||
}
|
||
|
||
private void LoadData(string prefixPath, string recipeName)
|
||
{
|
||
CurrentRecipe.Clear();
|
||
|
||
var recipeContent = _recipeProvider.LoadRecipe(prefixPath, recipeName);
|
||
|
||
if (string.IsNullOrEmpty(recipeContent))
|
||
{
|
||
MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid.");
|
||
return;
|
||
}
|
||
|
||
CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType;
|
||
CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion;
|
||
CurrentRecipe.InitData(prefixPath, recipeName, recipeContent, Columns,
|
||
_columnBuilder.Configs, SelectedChamber);
|
||
|
||
this.editMode = EditMode.Normal;
|
||
}
|
||
|
||
private void UpdateView()
|
||
{
|
||
var isFileSelected = CurrentFileNode != null && CurrentFileNode.IsFile;
|
||
|
||
this.EnableNew = isFileSelected;
|
||
this.EnableReName = isFileSelected;
|
||
this.EnableCopy = isFileSelected;
|
||
this.EnableDelete = isFileSelected;
|
||
this.EnableSave = isFileSelected;
|
||
this.EnableStep = isFileSelected;
|
||
EnableSaveTo = isFileSelected;
|
||
EnableSaveToAll = isFileSelected;
|
||
|
||
if (this.editMode == EditMode.None)
|
||
{
|
||
this.EnableNew = true;
|
||
this.EnableReName = false;
|
||
this.EnableCopy = false;
|
||
this.EnableDelete = false;
|
||
this.EnableStep = false;
|
||
this.EnableSave = false;
|
||
|
||
}
|
||
|
||
this.NotifyOfPropertyChange("EnableNew");
|
||
this.NotifyOfPropertyChange("EnableReName");
|
||
this.NotifyOfPropertyChange("EnableCopy");
|
||
this.NotifyOfPropertyChange("EnableDelete");
|
||
this.NotifyOfPropertyChange("EnableSave");
|
||
this.NotifyOfPropertyChange("EnableStep");
|
||
this.NotifyOfPropertyChange("EnableSaveTo");
|
||
this.NotifyOfPropertyChange("EnableSaveToAll");
|
||
this.NotifyOfPropertyChange("EnableReload");
|
||
|
||
this.NotifyOfPropertyChange("CurrentRecipe");
|
||
}
|
||
|
||
private string _currentCriteria = String.Empty;
|
||
public string CurrentCriteria
|
||
{
|
||
get { return _currentCriteria; }
|
||
set
|
||
{
|
||
if (value == _currentCriteria)
|
||
return;
|
||
|
||
_currentCriteria = value;
|
||
NotifyOfPropertyChange("CurrentCriteria");
|
||
ApplyFilter();
|
||
}
|
||
}
|
||
private void ApplyFilter()
|
||
{
|
||
ProcessTypeFileList[ProcessTypeIndexSelection].FilterFileListByProcessType =
|
||
new ObservableCollection<FileNode>(ProcessTypeFileList[ProcessTypeIndexSelection].FileListByProcessType.
|
||
Where(d => d.Name.IndexOf(CurrentCriteria, StringComparison.OrdinalIgnoreCase) >= 0));
|
||
}
|
||
|
||
public void ClearFilter()
|
||
{
|
||
CurrentCriteria = "";
|
||
}
|
||
|
||
}
|
||
}
|