using Aitex.Core.RT.Log; using Caliburn.Micro; using Caliburn.Micro.Core; using FurnaceUI.Common; using FurnaceUI.Models; using FurnaceUI.Views.Editors; using MECF.Framework.Common.CommonData; using MECF.Framework.Common.DataCenter; using MECF.Framework.Common.Utilities; 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.RecipeModel.Params; 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; namespace FurnaceUI.Views.Recipes { public class ProcessTypeFileItem : NotifiableItem { public string ProcessType { get; set; } public ObservableCollection FileListByProcessType { get; set; } public ProcessTypeFileItem() { FileListByProcessType = new ObservableCollection(); } } public class ChamberTypeItem : NotifiableItem { public string ChamberType { get; set; } public ObservableCollection FileListByChamberType { get; set; } public ChamberTypeItem() { FileListByChamberType = new ObservableCollection(); } } public class RecipeViewModel : FurnaceUIViewModelBase { 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 ICommand _EditRecipeCommand; public ICommand EditRecipeCommand { get { if (this._EditRecipeCommand == null) this._EditRecipeCommand = new BaseCommand(() => this.EditRecipe()); return this._EditRecipeCommand; } } private ICommand _SelectRecipeTypeCommand; public ICommand SelectRecipeTypeCommand { get { if (this._SelectRecipeTypeCommand == null) this._SelectRecipeTypeCommand = new BaseCommand(() => this.SelectRecipeType()); return this._SelectRecipeTypeCommand; } } private ICommand _ViewRecipeCommand; public ICommand ViewRecipeCommand { get { if (this._ViewRecipeCommand == null) this._ViewRecipeCommand = new BaseCommand(() => this.ViewRecipe()); return this._ViewRecipeCommand; } } private ICommand _ChangePermission; public ICommand ChangePermission { get { if (this._ChangePermission == null) this._ChangePermission = new BaseCommand(() => this.SavePermission()); return this._ChangePermission; } } private ICommand _ExportRecipeCommand; public ICommand ExportRecipeCommand { get { if (this._ExportRecipeCommand == null) this._ExportRecipeCommand = new BaseCommand(() => this.ExportRecipe()); return this._ExportRecipeCommand; } } private ICommand _historyRecipeCommand; public ICommand HistoryRecipeCommand { get { if (this._historyRecipeCommand == null) this._historyRecipeCommand = new BaseCommand(() => this.HistoryRecipe()); return this._historyRecipeCommand; } } public ObservableCollection ProcessTypeFileList { get; set; } = new ObservableCollection(); public RecipeDataBase CurrentRecipe { get; private set; } public FileNode CurrentFileNode { get; set; } public bool IsCurrentNodePath { get => CurrentFileNode != null; } public bool IsCurrentNodeFile { get => CurrentFileNode != null && CurrentFileNode.IsFile; } private bool _isReadAndWritePermission = false; public bool IsReadAndWritePermission { get { // _isReadAndWritePermission = IsSelectPermission; return _isReadAndWritePermission; } set { _isReadAndWritePermission = value; NotifyOfPropertyChange(nameof(IsReadAndWritePermission)); } } private bool _isFreePermission = false; public bool IsFreePermission { get { //_isFreePermission = IsSelectPermission; return _isFreePermission; } set { _isFreePermission = value; NotifyOfPropertyChange(nameof(IsFreePermission)); } } private bool _isSelectPermission = false; public bool IsSelectPermission { get { _isSelectPermission = LevelDisplay != "LEVEL1" && IsCurrentNodeFile; return _isSelectPermission; } set { _isSelectPermission = value; NotifyOfPropertyChange(nameof(IsSelectPermission)); } } public bool IsSingleSelectPermission { get => _isSelectPermission && !IsSingleFile; } private bool _isEnabledFolderPermission = false; public bool IsEnabledFolderPermission { get { _isEnabledFolderPermission = !IsCurrentNodeFile && !IsSingleFile; return _isEnabledFolderPermission; } set { _isEnabledFolderPermission = value; NotifyOfPropertyChange(nameof(IsEnabledFolderPermission)); } } public bool IsEnabledNewRecipe { get { return !IsSingleFile; } } private bool IsChanged { get { return editMode == EditMode.Edit || (CurrentRecipe != null && CurrentRecipe.IsChanged); } } private RecipeFormatBuilder _columnBuilder = new RecipeFormatBuilder(); private EditMode editMode; private RecipeProvider _recipeProvider = new RecipeProvider(); public ObservableCollection ChamberType { get; set; } = new ObservableCollection(); public int ChamberTypeIndexSelection { get; set; } private int _ProcessTypeIndexSelection; public int ProcessTypeIndexSelection { get { return _ProcessTypeIndexSelection; } set { _ProcessTypeIndexSelection = value; NotifyOfPropertyChange(nameof(ProcessTypeIndexSelection)); } } public string CurrentChamberType { get { return ChamberType[ChamberTypeIndexSelection]; } } public string CurrentProcessType { get { return ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType; } } public Visibility MultiChamberVisibility { get; set; } public Visibility ToleranceVisibility { get; set; } public ObservableCollection Chambers { get; set; } public string SelectedChamber { get; set; } public object View { get; set; } private string _SelectRecipeTypeName; public string SelectRecipeTypeName { get { return _SelectRecipeTypeName; } set { _SelectRecipeTypeName = value; NotifyOfPropertyChange("SelectRecipeTypeName"); } } private bool IsSingleFile { get; set; } = false; protected override void OnInitialize() { base.OnInitialize(); InitializeDefault(); } private void InitializeDefault() { var chamberType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedChamberType"); ChamberType.Clear(); if (chamberType == null) { ChamberType.Add("Default"); } else { (((string)(chamberType)).Split(',')).ToList().ForEach(x => ChamberType.Add(x)); } ChamberTypeIndexSelection = 0; //Etch:Process,Clean,Chuck,Dechuck;CVD:Process,Clean; var processType = QueryDataClient.Instance.Service.GetConfig($"System.Recipe.{CurrentMenuID}"); if (processType == null) { processType = CurrentMenuID; } if (processType == null) processType = "alarm"; string[] recipeProcessType = ((string)processType).Split(','); for (int 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.GetFileNodeParameterList(prefix);// RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes)[0].Files; ProcessTypeFileList.Add(type); } //if (ProcessTypeFileList[0].FileListByProcessType.Count > 0) // CurrentFileNode = ProcessTypeFileList[0].FileListByProcessType[ProcessTypeFileList[0].FileListByProcessType.Count - 1]; SelectRecipeTypeName = processType + " Recipe"; UpdateRecipeFormat(); if (CurrentFileNode != null && CurrentFileNode.IsFile) { if (CurrentRecipe != null) { CurrentRecipe.PrefixPath = CurrentFileNode.PrefixPath; CurrentRecipe.Name = CurrentFileNode.FullPath; } //this.LoadData(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath); } GetRecipeType(); } private void GetRecipeType() { var single = QueryDataClient.Instance.Service.GetConfig($"System.Recipe.SingleRecipeFileType"); if (single != null && !string.IsNullOrEmpty((string)single)) { string[] singleTypes = ((string)single).ToLower().Split(';'); if (singleTypes != null) { int findIndex = Array.IndexOf(singleTypes, CurrentMenuID.ToLower()); if (findIndex != -1) { CreateDefaultRecipe(); IsSingleFile = true; } } } } private void CreateDefaultRecipe() { var defaultFileName = QueryDataClient.Instance.Service.GetConfig($"System.Recipe.DefaultFileName"); string fileName = "default"; if (defaultFileName != null && !string.IsNullOrEmpty((string)defaultFileName)) { fileName = (string)defaultFileName; } string recipeName = fileName.Trim(); string description = ""; string prefix = CurrentChamberType + "\\" + CurrentProcessType; if (!IsExist(recipeName.ToLower(), true)) { RecipeDataBase recipe = new RecipeDataBase(); recipe.Name = recipeName; recipe.PrefixPath = prefix; recipe.Creator = BaseApp.Instance.UserContext.LoginName; recipe.CreateTime = DateTime.Now; recipe.Revisor = BaseApp.Instance.UserContext.LoginName; recipe.RecipeChamberType = CurrentProcessType; recipe.ReviseTime = DateTime.Now; recipe.Description = description; recipe.RecipeLevel = LevelDisplay; recipe.RecipePermission = "Free"; var step = recipe.CreateStep(); recipe.Steps.Add(step); if (!Save(recipe, true)) return; } ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false); ProcessTypeFileItem item = ProcessTypeFileList.FirstOrDefault(x => x.ProcessType == CurrentProcessType); var tempFile = item.FileListByProcessType.FirstOrDefault(x => x.Name == fileName); if (tempFile != null) { TreeSelectChanged(tempFile); } } protected override void OnActivate() { 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(); } } } public void TabSelectionChanged() { UpdateRecipeFormat(); OnViewLoaded(View); } public void UpdateRecipeFormat() { this.CurrentRecipe = new RecipeDataBase(); CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType; CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion; this.editMode = EditMode.None; var chamber = QueryDataClient.Instance.Service.GetConfig("System.Recipe.ChamberModules"); if (chamber == null) { chamber = "PM1"; } Chambers = new ObservableCollection(((string)chamber).Split(',')); SelectedChamber = Chambers[0]; MultiChamberVisibility = Chambers.Count > 1 ? Visibility.Visible : Visibility.Collapsed; ToleranceVisibility = CurrentRecipe.ToleranceEnable ? Visibility.Visible : Visibility.Collapsed; } 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; IsFreePermission = true; IsReadAndWritePermission = true; NotifyOfPropertyChange(nameof(IsCurrentNodeFile)); NotifyOfPropertyChange(nameof(IsCurrentNodePath)); NotifyOfPropertyChange(nameof(IsSelectPermission)); NotifyOfPropertyChange(nameof(IsSingleSelectPermission)); NotifyOfPropertyChange(nameof(IsEnabledFolderPermission)); if (node != null && node.IsFile) { if (CurrentRecipe != null) { CurrentRecipe.Name = node.Name; CurrentRecipe.PrefixPath = node.PrefixPath; } // this.LoadData(node.PrefixPath, node.FullPath); } else { this.ClearData(); this.editMode = EditMode.None; } this.UpdateView(); } #region folder public void SelectRecipeType() { var windowManager = IoC.Get(); RecipeSelectRecipeTypeViewModel recipeSelectRecipeTypeViewModel = new RecipeSelectRecipeTypeViewModel(); (windowManager as WindowManager)?.ShowDialogWithTitle(recipeSelectRecipeTypeViewModel, null, "Select Recipe Type"); if (recipeSelectRecipeTypeViewModel.SelectRecipeType != null) { var selectRecipeType = recipeSelectRecipeTypeViewModel.SelectRecipeType; var processType = QueryDataClient.Instance.Service.GetConfig($"System.Recipe.{selectRecipeType}"); if (processType == null) { processType = selectRecipeType; } ProcessTypeFileList = new ObservableCollection(); string[] recipeProcessType = ((string)processType).Split(','); for (int 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.GetFileNodeParameterList(prefix);// RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes)[0].Files; ProcessTypeFileList.Add(type); } SelectRecipeTypeName = processType + " Recipe"; this.NotifyOfPropertyChange("ProcessTypeFileList"); if (ProcessTypeFileList[0].FileListByProcessType.Count > 0) CurrentFileNode = ProcessTypeFileList[0].FileListByProcessType[ProcessTypeFileList[0].FileListByProcessType.Count - 1]; NotifyOfPropertyChange(nameof(IsCurrentNodeFile)); NotifyOfPropertyChange(nameof(IsCurrentNodePath)); NotifyOfPropertyChange(nameof(IsSelectPermission)); NotifyOfPropertyChange(nameof(IsReadAndWritePermission)); // NotifyOfPropertyChange(nameof(IsFreePermission)); ProcessTypeIndexSelection = 0; } } 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); } } InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Folder Name", ProcessTypeFileList[0].FileListByProcessType, "", Visibility.Visible, Visibility.Collapsed); // dialog.FileName = "new folder"; WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; if (string.IsNullOrWhiteSpace(dialog.FileName)) { DialogBox.ShowWarning("Folder name should not be empty"); } else { string name = dialog.FileName.Trim(); FileNode selectNode = dialog.SelectNode; string prefix = ChamberType[ChamberTypeIndexSelection] + "\\" + ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType; string newFolder = string.Empty; string folder = string.Empty; if (selectNode != null) { prefix = selectNode.PrefixPath; folder = selectNode.FullPath.Replace($"{prefix}\\", ""); newFolder = $"{folder}\\{ name}"; } else { 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; } prefix = GetPrefix(prefix, selectNode); _recipeProvider.CreateRecipeFolder(prefix, name); ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true); } } private string GetPrefix(string prefix, FileNode CurrentFileNode) { string temppreFix = prefix; if (CurrentFileNode != null) { if (string.IsNullOrEmpty(CurrentFileNode.AllParentPath)) { if (CurrentFileNode.IsFile) { return temppreFix; } else { temppreFix = CurrentFileNode.FullPath; } } else { if (CurrentFileNode.IsFile) { if (temppreFix.EndsWith("\\")) { temppreFix = $"{temppreFix}{CurrentFileNode.AllParentPath}"; } else { temppreFix = $"{temppreFix}\\{CurrentFileNode.AllParentPath}"; } } else { temppreFix = $"{temppreFix}\\{CurrentFileNode.AllParentPath}\\{CurrentFileNode.Name}"; } } } return temppreFix; } 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); } } InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Folder Name", ProcessTypeFileList[0].FileListByProcessType); dialog.FileName = "new folder"; WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; string 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; } string 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 prefix = GetPrefix(CurrentFileNode.PrefixPath, CurrentFileNode); var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM, $"Are you sure you want to delete \r\n {prefix}?"); if (selection == DialogButton.No) return; //string nextFocus = CurrentFileNode.Parent.FullPath; //bool isFolder = true; //if (CurrentFileNode.Parent!=null&&CurrentFileNode.Parent.Files.Count > 1) //{ // for (int 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; // } // } // } //} prefix = prefix.Replace($"\\{CurrentFileNode.Name}", ""); _recipeProvider.DeleteRecipeFolder(prefix, CurrentFileNode.Name); ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, "", false); } public void RenameFolder() { if (CurrentFileNode == null || CurrentFileNode.IsFile) return; InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Folder Name", ProcessTypeFileList[0].FileListByProcessType, "", Visibility.Hidden, Visibility.Collapsed); dialog.FileName = CurrentFileNode.Name; WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; string name = dialog.FileName.Trim(); if (string.IsNullOrEmpty(name)) return; string 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; } if (_recipeProvider.RenameFolder(CurrentFileNode.PrefixPath, CurrentFileNode.Name, name)) { foreach (var node in CurrentFileNode.Files) { UIGlobalVariable.Instance.ProcessModifiedRecipe[node.FullPath] = $"Folder Rename from [{CurrentFileNode.FullPath}] to [{name}] {DateTime.Now}"; } } 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); } } InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name", ProcessTypeFileList[0].FileListByProcessType, ""); //dialog.FileName = (string)QueryDataClient.Instance.Service.GetConfig($"System.Recipe.DefaultProcessRecipeName"); WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; string recipeName = dialog.FileName.Trim(); string filepath = dialog.FilePath; string description = dialog.Comment; if (string.IsNullOrEmpty(dialog.FileName)) { DialogBox.ShowWarning("Recipe file name should not be empty"); return; } string prefix; if (filepath.Contains("\\")) { prefix = filepath; } else { prefix = CurrentChamberType + "\\" + CurrentProcessType + "\\" + filepath; if (CurrentFileNode != null) { //获取目录 prefix = GetPrefix(CurrentFileNode.PrefixPath, CurrentFileNode); } } if (IsExist(recipeName.ToLower(), true)) { DialogBox.ShowWarning($"Can not create {recipeName}, Recipe with the same name already exist."); return; } if ((prefix + recipeName).Length > 200) { DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200."); return; } RecipeDataBase recipe = new RecipeDataBase(); recipe.Name = recipeName; recipe.PrefixPath = prefix; recipe.Creator = BaseApp.Instance.UserContext.LoginName; recipe.CreateTime = DateTime.Now; recipe.Revisor = BaseApp.Instance.UserContext.LoginName; recipe.RecipeChamberType = CurrentProcessType; recipe.ReviseTime = DateTime.Now; recipe.Description = description; recipe.RecipeLevel = LevelDisplay; recipe.RecipePermission = "Free"; if (recipe.RecipeChamberType == RecipeDataBase.ProcessType) { recipe.Steps.Add(recipe.CreateStandbyStep()); recipe.Steps.Add(recipe.CreateFirstStep()); recipe.Steps.Add(recipe.CreateEndStep()); } else { var step = recipe.CreateStep(); if (SelectRecipeTypeName.Contains("sub")) { step.TemperatureControlMode = new StringParam() { Name = "TemperatureControlMode", Value = "Furnace" }; } recipe.Steps.Add(step); } if (!Save(recipe, true)) return; var types = prefix.Split('\\'); string newfile = string.Empty; if (types.Length > 2) { newfile = $"{ string.Join("\\", types.Skip(2))}\\{recipeName}"; } else { newfile = recipeName; } ReloadRecipeFileList(types[0], types[1], newfile, 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); } } InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name", ProcessTypeFileList[0].FileListByProcessType, CurrentRecipe.Description); dialog.FileName = "new recipe"; WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; string recipeName = dialog.FileName.Trim(); string description = dialog.Comment; 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; } RecipeDataBase recipe = new RecipeDataBase(); 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; recipe.Description = description; recipe.RecipeLevel = LevelDisplay; recipe.RecipePermission = "Free"; if (!Save(recipe, true)) return; ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false); } private void ReloadRecipeFileList(string chamberType, string processType, string selectedFile, bool selectionIsFolder) { ProcessTypeFileItem 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.GetFileNodeParameterList(prefix);// RecipeSequenceTreeBuilder.BuildFileNode(prefix, selectedFile, selectionIsFolder, recipes)[0].Files; FindSelectedFile(item.FileListByProcessType, $"{prefix}\\{selectedFile}"); item.InvokePropertyChanged(); } private bool FindSelectedFile(ObservableCollection nodes, string selectedFile) { foreach (var recipe in nodes) { recipe.IsSelected = false; if (!recipe.IsFile) { if (recipe.FullPath == selectedFile && recipe.Files.Count == 0) { recipe.IsSelected = true; return true; } else { if (FindSelectedFile(recipe.Files, selectedFile)) return true; } } else { string filepath = string.Empty; if (string.IsNullOrEmpty(recipe.AllParentPath)) { filepath = recipe.Name; } else { filepath = recipe.AllParentPath + "\\" + recipe.Name; } if (filepath == selectedFile.Replace($"{recipe.PrefixPath}\\", "")) { recipe.IsSelected = true; return true; } } } return false; } private bool IsExist(string fullPath, bool isFile) { for (int i = 0; i < ProcessTypeFileList.Count; i++) { if (ProcessTypeFileList[i].ProcessType == CurrentProcessType) { if (ProcessTypeFileList[i].FileListByProcessType.Count == 0) return false; foreach (var item in ProcessTypeFileList[i].FileListByProcessType) { if (FindFile(fullPath, item, isFile)) { return true; } } return false; } } return true; } private bool FindFile(string path, FileNode root, bool isFile) { if (root.FullPath.ToLower() == path && !isFile) { return true; } if (root.IsFile && isFile) { return root.FullPath.ToLower().Equals(path); } else if (!root.IsFile && isFile) { foreach (var node in root.Files) { if (isFile && node.IsFile && node.FullPath.ToLower() == 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); } } this.LoadData(CurrentRecipe.PrefixPath, CurrentFileNode.FullPath); InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name", ProcessTypeFileList[0].FileListByProcessType); dialog.FileName = CurrentFileNode.Name; WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; string recipeName = dialog.FileName.Trim(); string filepath = dialog.FilePath; FileNode selectNode = dialog.SelectNode; if (string.IsNullOrEmpty(dialog.FileName)) { DialogBox.ShowWarning("Recipe file name should not be empty"); return; } string prefix = CurrentChamberType + "\\" + CurrentProcessType;// + "\\" + filepath; string processType = string.Empty; // string folder = CurrentFileNode.FullPath; // string folder = filepath.Substring(filepath.LastIndexOf("\\") + 1); string folder = filepath.Replace($"{prefix}\\", ""); //if (!string.IsNullOrEmpty(folder)) // recipeName = folder + "\\" + recipeName; // var newPrefix = GetPrefix(CurrentChamberType + "\\" + CurrentProcessType, selectNode); if (!string.IsNullOrEmpty(folder)) { recipeName = $"{folder}\\{recipeName}"; } if (IsExist(prefix + "\\" + 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); } } InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name", ProcessTypeFileList[0].FileListByProcessType, CurrentRecipe.Description, Visibility.Hidden); dialog.FileName = CurrentFileNode.Name; WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; string recipeName = dialog.FileName.Trim(); if (string.IsNullOrEmpty(dialog.FileName)) { DialogBox.ShowWarning("Recipe file name should not be empty"); return; } string prefix = CurrentChamberType + "\\" + CurrentProcessType; string processType = string.Empty; string 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; } prefix = GetPrefix(prefix, CurrentFileNode); if (_recipeProvider.RenameRecipe(prefix, CurrentFileNode.Name, recipeName)) { UIGlobalVariable.Instance.ProcessModifiedRecipe[CurrentFileNode.FullPath] = $"Rename Recipe from [{CurrentFileNode.FullPath}] to [{recipeName}] {DateTime.Now}"; } CurrentRecipe.Name = dialog.FileName; CurrentRecipe.Description = dialog.Comment; // this.Save(CurrentRecipe, false); 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; //string nextFocus = CurrentFileNode.Parent.FullPath; //bool isFolder = true; //if (CurrentFileNode.Parent.Files.Count > 1) //{ // for (int 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; // } // } // } //} var prefixPath = GetPrefix(CurrentFileNode.PrefixPath, CurrentFileNode); if (_recipeProvider.DeleteRecipe(prefixPath, CurrentFileNode.Name)) { UIGlobalVariable.Instance.ProcessModifiedRecipe[CurrentFileNode.FullPath] = $"Delet Recipe from [{CurrentFileNode.FullPath}] {DateTime.Now}"; } 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() { 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() { if (!CurrentRecipe.IsCompatibleWithCurrentFormat) { DialogBox.ShowWarning($"Save failed, {CurrentRecipe.Name} is not a valid recipe file"); return; } SaveToDialogViewModel dialog = new SaveToDialogViewModel("Select which chamber to copy to", SelectedChamber, Chambers.ToList()); WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; List chambers = new List(); 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); } public void EditRecipe() { CGlobal.RecipeProcessEditViewEnable = true; MECF.Framework.UI.Client.CenterViews.Editors.Recipe.CGlobal.RecipeProcessEditViewEnable = true; if (PopupPage()) { UIGlobalVariable.Instance.ProcessModifiedRecipe[CurrentFileNode.FullPath] = $"Edit {DateTime.Now}"; this.editMode = EditMode.Normal; ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, CurrentFileNode.FullPath, false); this.UpdateView(); } } public void ViewRecipe() { CGlobal.RecipeProcessEditViewEnable = false; MECF.Framework.UI.Client.CenterViews.Editors.Recipe.CGlobal.RecipeProcessEditViewEnable = false; if (PopupPage()) { this.editMode = EditMode.Normal; ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, CurrentFileNode.FullPath, false); this.UpdateView(); } } private string GetTimeFormat(string value) { try { if (value != null && value.Length > 1 && value.Split(':').Length > 2) { var timeH = value.Split(':')[0]; var timeM = value.Split(':')[1]; var timeS = value.Split(':')[2]; if (timeS.Contains('.')) { var timesArray = timeS.Split('.'); return $"{timeH}:{timeM.PadLeft(2, '0')}:{timesArray[0].PadLeft(2, '0')}.{timesArray[1].Substring(0, 1)}"; } else { return $"{timeH}:{timeM.PadLeft(2, '0')}:{timeS.PadLeft(2, '0')}.0"; } } else { return value; } } catch { return value; } } public void ExportRecipe() { try { if (CurrentRecipe == null) { MessageBox.Show("No choice recipe or Step is null"); return; } CurrentRecipe.Clear(); // var prefixPath = GetPrefix(CurrentRecipe.PrefixPath, CurrentFileNode); var recipeContent = _recipeProvider.LoadRecipe(CurrentRecipe.PrefixPath, CurrentFileNode.FullPath); if (string.IsNullOrEmpty(recipeContent)) { MessageBox.Show($"{CurrentRecipe.PrefixPath}\\{CurrentRecipe.Name} is empty, please confirm the file is valid."); return; } CurrentRecipe.InitData(CurrentRecipe.PrefixPath, CurrentRecipe.Name, recipeContent, "PM1"); if (CurrentRecipe.Steps.Count == 0) { MessageBox.Show("Step is null"); } Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog(); dlg.DefaultExt = ".xlsx"; // Default file extension dlg.FileName = $"{CurrentRecipe.Name}_{DateTime.Now:yyyyMMdd_HHmmss}"; dlg.Filter = "Excel数据表格文件(*.xlsx)|*.xlsx"; // Filter files by extension Nullable result = dlg.ShowDialog();// Show open file dialog box if (result == true) // Process open file dialog box results { System.Data.DataSet ds = new System.Data.DataSet(); if (CurrentRecipe.GetIsTableType) { SaveTablesStepsToTable(ds); } else { SaveStepsToTable(ds); } if (!ExcelHelper.ExportToExcel(dlg.FileName, ds, out string reason)) { MessageBox.Show($"Export failed, {reason}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning); return; } MessageBox.Show($"Export succeed, file save as {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information); } } catch (Exception ex) { LOG.Write(ex); MessageBox.Show("导出系统日志发生错误", "导出失败", MessageBoxButton.OK, MessageBoxImage.Warning); } } public void HistoryRecipe() { if (CurrentRecipe == null || CurrentFileNode == null) { return; } RecipeHistoryViewModel dialog = new RecipeHistoryViewModel(); WindowManager wm = new WindowManager(); dialog.FilePath = $"{CurrentFileNode.PrefixPath}\\{CurrentFileNode.FullPath}"; dialog.CurrentRecipe = CurrentRecipe; bool? dialogReturn = wm.ShowDialogWithTitle(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; } private void SaveStepsToTable(System.Data.DataSet ds) { ds.Tables.Add(new System.Data.DataTable("Recipe")); Step step = CurrentRecipe.Steps[0]; ds.Tables[0].Columns.Add("StepNo"); ds.Tables[0].Columns.Add("Name"); ds.Tables[0].Columns.Add("Time"); ds.Tables[0].Columns.Add("Command"); ds.Tables[0].Columns.Add("EndBy"); ds.Tables[0].Columns.Add("ConditionCheck"); ds.Tables[0].Columns.Add("SkipWait"); ds.Tables[0].Columns.Add("AbortRecipeTableIndex"); ds.Tables[0].Columns.Add("Temperature.ControlMode"); ds.Tables[0].Columns.Add("Temperature.Correct"); ds.Tables[0].Columns.Add("Temperature.PID"); foreach (var item in step.TemperatureSets) { ds.Tables[0].Columns.Add($"{item.Name}.ZoneName"); ds.Tables[0].Columns.Add($"{item.Name}.Set"); ds.Tables[0].Columns.Add($"{item.Name}.SetUnit"); ds.Tables[0].Columns.Add($"{item.Name}.Ramprate"); ds.Tables[0].Columns.Add($"{item.Name}.RamprateUnit"); ds.Tables[0].Columns.Add($"{item.Name}.Check"); ds.Tables[0].Columns.Add($"{item.Name}.High"); ds.Tables[0].Columns.Add($"{item.Name}.Low"); ds.Tables[0].Columns.Add($"{item.Name}.Unit"); } foreach (var item in step.MFCSets) { ds.Tables[0].Columns.Add($"{item.ControlName}.Set"); ds.Tables[0].Columns.Add($"{item.ControlName}.SetUnit"); ds.Tables[0].Columns.Add($"{item.ControlName}.Ramprate"); ds.Tables[0].Columns.Add($"{item.ControlName}.RamprateUnit"); ds.Tables[0].Columns.Add($"{item.ControlName}.Check"); ds.Tables[0].Columns.Add($"{item.ControlName}.High"); ds.Tables[0].Columns.Add($"{item.ControlName}.Low"); ds.Tables[0].Columns.Add($"{item.ControlName}.Unit"); } ds.Tables[0].Columns.Add("Press.Command"); ds.Tables[0].Columns.Add("Press.PID"); ds.Tables[0].Columns.Add("Press.Set"); ds.Tables[0].Columns.Add("Press.SlowVacSet"); ds.Tables[0].Columns.Add("Press.ValveAngleSet"); ds.Tables[0].Columns.Add("Press.IsWait"); ds.Tables[0].Columns.Add("Press.LowWait"); ds.Tables[0].Columns.Add("Press.HighWait"); ds.Tables[0].Columns.Add("Press.WaitUnit"); ds.Tables[0].Columns.Add("Press.LowPressWait"); ds.Tables[0].Columns.Add("Press.WaitPress"); foreach (var item in step.ValveSets) { ds.Tables[0].Columns.Add(item.Name); } ds.Tables[0].Columns.Add("Loader.Command"); ds.Tables[0].Columns.Add("Loader.Speed1"); ds.Tables[0].Columns.Add("Loader.Speed2"); ds.Tables[0].Columns.Add("Loader.Speed3"); ds.Tables[0].Columns.Add("Loader.RPM"); foreach (var item in step.MFMSets.Keys) { ds.Tables[0].Columns.Add(item); } foreach (var item in step.EXOUSets.Keys) { ds.Tables[0].Columns.Add(item); } ds.Tables[0].Columns.Add("AlarmTableIndex"); ds.Tables[0].Columns.Add("FilmThickFormula"); foreach (var tempstep in CurrentRecipe.Steps) { var row = ds.Tables[0].NewRow(); row["StepNo"] = tempstep.StepNo; row["Name"] = tempstep.Name; row["EndBy"] = tempstep.EndBy; row["Time"] = GetTimeFormat(tempstep.Time); row["SkipWait"] = tempstep.SkipWait; row["ConditionCheck"] = tempstep.IsnoneConditionCheck; row["Command"] = tempstep.Command; row["AbortRecipeTableIndex"] = tempstep.AbortRecipeTableIndex; foreach (var item in tempstep.ValveSets) { row[item.Name] = item.Value ? "Open" : "Close"; } foreach (var item in tempstep.MFCSets) { row[$"{item.ControlName}.Set"] = item.SetValue.Value; row[$"{item.ControlName}.SetUnit"] = item.SetUnit.Value; row[$"{item.ControlName}.Ramprate"] = item.Rampng.Value; row[$"{item.ControlName}.RamprateUnit"] = item.RampngUnit.Value; row[$"{item.ControlName}.Check"] = item.IsCheck.Value.ToString(); row[$"{item.ControlName}.High"] = item.MaxValue.Value; row[$"{item.ControlName}.Low"] = item.MinValue.Value; row[$"{item.ControlName}.Unit"] = item.Unit; } foreach (var item in tempstep.MFMSets.Keys) { row[item] = tempstep.MFMSets[item]; } foreach (var item in tempstep.EXOUSets.Keys) { row[item] = tempstep.EXOUSets[item]; } foreach (var item in tempstep.TemperatureSets) { row[$"{item.Name}.ZoneName"] = item.Name; row[$"{item.Name}.Set"] = item.SetValue.Value; row[$"{item.Name}.SetUnit"] = item.SetUnit.Value; row[$"{item.Name}.Ramprate"] = item.RampngValue.Value; row[$"{item.Name}.RamprateUnit"] = item.RampngUnit.Value; row[$"{item.Name}.Check"] = item.IsCheck.Value.ToString(); row[$"{item.Name}.High"] = item.HighValue.Value; row[$"{item.Name}.Low"] = item.LowValue.Value; row[$"{item.Name}.Unit"] = item.Unit; } row["Temperature.ControlMode"] = tempstep.TemperatureControlMode.Value; row["Temperature.Correct"] = tempstep.TemperatureCorrect.Value; row["Temperature.PID"] = tempstep.TemperaturePID.Value; row["Loader.Command"] = tempstep.LoaderCommand.Value; row["Loader.Speed1"] = tempstep.LoaderSpeed1.Value; row["Loader.Speed2"] = tempstep.LoaderSpeed2.Value; row["Loader.Speed3"] = tempstep.LoaderSpeed3.Value; row["Loader.RPM"] = tempstep.LoaderRPM.Value; row["Press.Command"] = tempstep.PressCommand.Value; row["Press.PID"] = RecipeDataBase.GetPressPidValue(tempstep); row["Press.Set"] = RecipeDataBase.GetPressSetValue(tempstep);// tempstep.PressSet.Value; row["Press.SlowVacSet"] = RecipeDataBase.GetPressSlowVacSet(tempstep);// tempstep.PressSlowVacSet.Value; row["Press.ValveAngleSet"] = RecipeDataBase.GetValveAngleSet(tempstep); //tempstep.PressValveAngleSet.Value; row["Press.IsWait"] = tempstep.PressIsWait.Value; row["Press.LowWait"] = tempstep.PressLowWait.Value; row["Press.HighWait"] = tempstep.PressHighWait.Value; row["Press.WaitUnit"] = tempstep.PressWaitUnit.Value; row["Press.LowPressWait"] = tempstep.PressLowPressWait.Value; row["Press.WaitPress"] = RecipeDataBase.GetWaitPress(tempstep);//tempstep.WaitPress.Value; row["AlarmTableIndex"] = tempstep.AlarmConditionTable.Value; row["FilmThickFormula"] = tempstep.FilmThickFormula; ds.Tables[0].Rows.Add(row); } } private void SaveTablesStepsToTable(System.Data.DataSet ds) { foreach (var table in CurrentRecipe.Tables) { if (table.TableData.Steps == null || table.TableData.Steps.Count == 0) { continue; } string tableStr = $"table{table.Index}"; ds.Tables.Add(new System.Data.DataTable(tableStr)); Step step = table.TableData.Steps[0]; ds.Tables[tableStr].Columns.Add("StepNo"); ds.Tables[tableStr].Columns.Add("Name"); ds.Tables[tableStr].Columns.Add("Time"); ds.Tables[tableStr].Columns.Add("Command"); ds.Tables[tableStr].Columns.Add("EndBy"); ds.Tables[tableStr].Columns.Add("ConditionCheck"); ds.Tables[tableStr].Columns.Add("SkipWait"); ds.Tables[tableStr].Columns.Add("AbortRecipeTableIndex"); ds.Tables[tableStr].Columns.Add("Temperature.ControlMode"); ds.Tables[tableStr].Columns.Add("Temperature.Correct"); ds.Tables[tableStr].Columns.Add("Temperature.PID"); foreach (var item in step.TemperatureSets) { ds.Tables[tableStr].Columns.Add($"{item.Name}.ZoneName"); ds.Tables[tableStr].Columns.Add($"{item.Name}.Set"); ds.Tables[tableStr].Columns.Add($"{item.Name}.SetUnit"); ds.Tables[tableStr].Columns.Add($"{item.Name}.Ramprate"); ds.Tables[tableStr].Columns.Add($"{item.Name}.RamprateUnit"); ds.Tables[tableStr].Columns.Add($"{item.Name}.Check"); ds.Tables[tableStr].Columns.Add($"{item.Name}.High"); ds.Tables[tableStr].Columns.Add($"{item.Name}.Low"); ds.Tables[tableStr].Columns.Add($"{item.Name}.Unit"); } foreach (var item in step.MFCSets) { ds.Tables[tableStr].Columns.Add($"{item.ControlName}.Set"); ds.Tables[tableStr].Columns.Add($"{item.ControlName}.SetUnit"); ds.Tables[tableStr].Columns.Add($"{item.ControlName}.Ramprate"); ds.Tables[tableStr].Columns.Add($"{item.ControlName}.RamprateUnit"); ds.Tables[tableStr].Columns.Add($"{item.ControlName}.Check"); ds.Tables[tableStr].Columns.Add($"{item.ControlName}.High"); ds.Tables[tableStr].Columns.Add($"{item.ControlName}.Low"); ds.Tables[tableStr].Columns.Add($"{item.ControlName}.Unit"); } ds.Tables[tableStr].Columns.Add("Press.Command"); ds.Tables[tableStr].Columns.Add("Press.PID"); ds.Tables[tableStr].Columns.Add("Press.Set"); ds.Tables[tableStr].Columns.Add("Press.SlowVacSet"); ds.Tables[tableStr].Columns.Add("Press.ValveAngleSet"); ds.Tables[tableStr].Columns.Add("Press.IsWait"); ds.Tables[tableStr].Columns.Add("Press.LowWait"); ds.Tables[tableStr].Columns.Add("Press.HighWait"); ds.Tables[tableStr].Columns.Add("Press.WaitUnit"); ds.Tables[tableStr].Columns.Add("Press.LowPressWait"); ds.Tables[tableStr].Columns.Add("Press.WaitPress"); foreach (var item in step.ValveSets) { ds.Tables[tableStr].Columns.Add(item.Name); } ds.Tables[tableStr].Columns.Add("Loader.Command"); ds.Tables[tableStr].Columns.Add("Loader.Speed1"); ds.Tables[tableStr].Columns.Add("Loader.Speed2"); ds.Tables[tableStr].Columns.Add("Loader.Speed3"); ds.Tables[tableStr].Columns.Add("Loader.RPM"); foreach (var item in step.MFMSets.Keys) { ds.Tables[tableStr].Columns.Add(item); } foreach (var item in step.EXOUSets.Keys) { ds.Tables[tableStr].Columns.Add(item); } ds.Tables[tableStr].Columns.Add("AlarmTableIndex"); ds.Tables[tableStr].Columns.Add("FilmThickFormula"); foreach (var tempstep in table.TableData.Steps) { var row = ds.Tables[tableStr].NewRow(); row["StepNo"] = tempstep.StepNo; row["Name"] = tempstep.Name; row["EndBy"] = tempstep.EndBy; row["Time"] = GetTimeFormat(tempstep.Time); row["SkipWait"] = tempstep.SkipWait; row["ConditionCheck"] = tempstep.IsnoneConditionCheck; row["Command"] = tempstep.Command; row["AbortRecipeTableIndex"] = tempstep.AbortRecipeTableIndex; foreach (var item in tempstep.ValveSets) { row[item.Name] = item.Value ? "Open" : "Close"; } foreach (var item in tempstep.MFCSets) { row[$"{item.ControlName}.Set"] = item.SetValue.Value; row[$"{item.ControlName}.SetUnit"] = item.SetUnit.Value; row[$"{item.ControlName}.Ramprate"] = item.Rampng.Value; row[$"{item.ControlName}.RamprateUnit"] = item.RampngUnit.Value; row[$"{item.ControlName}.Check"] = item.IsCheck.Value.ToString(); row[$"{item.ControlName}.High"] = item.MaxValue.Value; row[$"{item.ControlName}.Low"] = item.MinValue.Value; row[$"{item.ControlName}.Unit"] = item.Unit; } foreach (var item in tempstep.MFMSets.Keys) { row[item] = tempstep.MFMSets[item].Value; } foreach (var item in tempstep.EXOUSets.Keys) { row[item] = tempstep.EXOUSets[item]; } foreach (var item in tempstep.TemperatureSets) { row[$"{item.Name}.ZoneName"] = item.Name; row[$"{item.Name}.Set"] = item.SetValue.Value; row[$"{item.Name}.SetUnit"] = item.SetUnit.Value; row[$"{item.Name}.Ramprate"] = item.RampngValue.Value; row[$"{item.Name}.RamprateUnit"] = item.RampngUnit.Value; row[$"{item.Name}.Check"] = item.IsCheck.Value.ToString(); row[$"{item.Name}.High"] = item.HighValue.Value; row[$"{item.Name}.Low"] = item.LowValue.Value; row[$"{item.Name}.Unit"] = item.Unit; } row["Temperature.ControlMode"] = tempstep.TemperatureControlMode.Value; row["Temperature.Correct"] = tempstep.TemperatureCorrect.Value; row["Temperature.PID"] = tempstep.TemperaturePID.Value; row["Loader.Command"] = tempstep.LoaderCommand.Value; row["Loader.Speed1"] = tempstep.LoaderSpeed1.Value; row["Loader.Speed2"] = tempstep.LoaderSpeed2.Value; row["Loader.Speed3"] = tempstep.LoaderSpeed3.Value; row["Loader.RPM"] = tempstep.LoaderRPM.Value; row["Press.Command"] = tempstep.PressCommand.Value; row["Press.PID"] = tempstep.PressPID.Value.Replace(",", ":"); row["Press.Set"] = RecipeDataBase.GetPressSetValue(tempstep);// tempstep.PressSet.Value; row["Press.SlowVacSet"] = RecipeDataBase.GetPressSlowVacSet(tempstep);// tempstep.PressSlowVacSet.Value; row["Press.ValveAngleSet"] = RecipeDataBase.GetValveAngleSet(tempstep);//tempstep.PressValveAngleSet.Value; row["Press.IsWait"] = tempstep.PressIsWait.Value; row["Press.LowWait"] = tempstep.PressLowWait.Value; row["Press.HighWait"] = tempstep.PressHighWait.Value; row["Press.WaitUnit"] = tempstep.PressWaitUnit.Value; row["Press.LowPressWait"] = tempstep.PressLowPressWait.Value; row["Press.WaitPress"] = RecipeDataBase.GetWaitPress(tempstep);//tempstep.WaitPress.Value; row["AlarmTableIndex"] = tempstep.AlarmConditionTable.Value; row["FilmThickFormula"] = tempstep.FilmThickFormula; ds.Tables[tableStr].Rows.Add(row); } } } #endregion #region Steps public void SaveRecipe() { if (this.IsChanged) { this.Save(this.CurrentRecipe, false); } } public void PopSetting(string controlName, Param paramData) { int stepNum = Convert.ToInt32(((StepParam)paramData.Parent[1]).Value); PublicPopSettingDialogViewModel dialog = new PublicPopSettingDialogViewModel(); dialog.DisplayName = paramData.DisplayName; ObservableCollection Parameters = new ObservableCollection(); Parameters = this.CurrentRecipe.PopSettingSteps[controlName][stepNum - 1]; ObservableCollection ControlParameters = new ObservableCollection(); ObservableCollection BrandParameters = new ObservableCollection(); foreach (var item in Parameters) { if (item.Name.Contains("Band")) { string name = item.Name.Replace("Wavelength", "").Replace("Bandwidth", ""); string 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; WindowManager wm = new WindowManager(); bool? bret = wm.ShowDialog(dialog); if ((bool)bret) { this.CurrentRecipe.PopSettingSteps[controlName][stepNum - 1] = dialog.Parameters; } } public void SavePermission() { CurrentRecipe.Clear(); var prefixPath = GetPrefix(CurrentRecipe.PrefixPath, CurrentFileNode); var recipeContent = _recipeProvider.LoadRecipe(prefixPath, CurrentRecipe.Name); if (string.IsNullOrEmpty(recipeContent)) { MessageBox.Show($"{CurrentRecipe.PrefixPath}\\{CurrentRecipe.Name} is empty, please confirm the file is valid."); return; } CurrentRecipe.InitData(prefixPath, CurrentRecipe.Name, recipeContent, "PM1"); CurrentRecipe.RecipeLevel = CurrentFileNode.Level; RecipePermissionSelectViewModel dialog = new RecipePermissionSelectViewModel("Save recipe and permission", CurrentFileNode.Permission, CurrentRecipe.Description); WindowManager wm = new WindowManager(); bool? dialogReturn = wm.ShowDialog(dialog); if (!dialogReturn.HasValue || !dialogReturn.Value) return; this.LoadData(CurrentRecipe.PrefixPath, CurrentRecipe.Name); CurrentRecipe.RecipePermission = dialog.RecipePermission; CurrentRecipe.Description = dialog.RecipeComment; CurrentRecipe.RecipeLevel = CurrentFileNode.Level; this.Save(CurrentRecipe, false); ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, CurrentFileNode.FullPath, false); } public bool Save(RecipeDataBase recipe, bool createNew) { bool 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) { this.editMode = EditMode.Normal; string fileName = CurrentFileNode != null ? CurrentFileNode.FullPath : recipe.Name; ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, fileName, false); this.UpdateView(); } else { MessageBox.Show("Save failed!"); } return result; } private TreeViewItem GetParentObjectEx(DependencyObject obj) where TreeViewItem : FrameworkElement { DependencyObject 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(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 = "OriginChamber"; CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion; CurrentRecipe.InitData(prefixPath, recipeName, recipeContent, SelectedChamber); this.editMode = EditMode.Normal; } private void UpdateView() { bool isFileSelected = CurrentFileNode != null && CurrentFileNode.IsFile; this.NotifyOfPropertyChange("CurrentRecipe"); } private string oldPrefix { get; set; } private string oldName { get; set; } private string oldStepName { get; set; } private bool PopupPage() { if (CurrentFileNode == null || !CurrentFileNode.IsFile) return false; var windowManager = IoC.Get(); RecipeProcessEditViewModel recipeEditViewModel = new RecipeProcessEditViewModel(CurrentRecipe.PrefixPath, CurrentFileNode.FullPath, CurrentFileNode.Permission); recipeEditViewModel.SetParent(Window.GetWindow((UIElement)GetView())); recipeEditViewModel.RecipeType = CurrentProcessType; this.CurrentRecipe = recipeEditViewModel.CurrentRecipe; if (!string.IsNullOrEmpty(oldPrefix) && !string.IsNullOrEmpty(oldName) && !string.IsNullOrEmpty(oldStepName) && (CurrentRecipe.PrefixPath == oldPrefix && CurrentFileNode.FullPath == oldName)) { recipeEditViewModel.SelectedStepName = oldStepName; } bool? bret = (windowManager as WindowManager)?.ShowDialogWithTitle(recipeEditViewModel, null, $"Recipe Edit"); if (recipeEditViewModel.CurrentRecipe != null && recipeEditViewModel.selectStep != null) { oldPrefix = recipeEditViewModel.CurrentRecipe.PrefixPath; oldName = recipeEditViewModel.CurrentRecipe.Name; oldStepName = recipeEditViewModel.SelectedRecipeStep.Name; } return bret == true; } } public class BringSelectedItemIntoViewBehavior { public static readonly DependencyProperty IsBringSelectedIntoViewProperty = DependencyProperty.RegisterAttached( "IsBringSelectedIntoView", typeof(bool), typeof(BringSelectedItemIntoViewBehavior), new PropertyMetadata(default(bool), PropertyChangedCallback)); public static void SetIsBringSelectedIntoView(DependencyObject element, bool value) { element.SetValue(IsBringSelectedIntoViewProperty, value); } public static bool GetIsBringSelectedIntoView(DependencyObject element) { return (bool)element.GetValue(IsBringSelectedIntoViewProperty); } private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var treeViewItem = dependencyObject as TreeViewItem; if (treeViewItem == null) { return; } if (!((bool)dependencyPropertyChangedEventArgs.OldValue) && ((bool)dependencyPropertyChangedEventArgs.NewValue)) { treeViewItem.Unloaded += TreeViewItemOnUnloaded; treeViewItem.Selected += TreeViewItemOnSelected; } } private static void TreeViewItemOnUnloaded(object sender, RoutedEventArgs routedEventArgs) { var treeViewItem = sender as TreeViewItem; if (treeViewItem == null) { return; } treeViewItem.Unloaded -= TreeViewItemOnUnloaded; treeViewItem.Selected -= TreeViewItemOnSelected; } private static void TreeViewItemOnSelected(object sender, RoutedEventArgs routedEventArgs) { var treeViewItem = sender as TreeViewItem; treeViewItem?.BringIntoView(); } } }