RecipeEditorViewModel.cs 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
  1. using Aitex.Core.RT.Log;
  2. using Caliburn.Micro;
  3. using Caliburn.Micro.Core;
  4. using MECF.Framework.Common.CommonData;
  5. using MECF.Framework.Common.DataCenter;
  6. using MECF.Framework.UI.Client.CenterViews.Editors.Sequence;
  7. using MECF.Framework.UI.Client.ClientBase;
  8. using OpenSEMI.ClientBase;
  9. using OpenSEMI.ClientBase.Command;
  10. using RecipeEditorLib.DGExtension.CustomColumn;
  11. using RecipeEditorLib.RecipeModel.Params;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Collections.ObjectModel;
  15. using System.Linq;
  16. using System.Windows;
  17. using System.Windows.Controls;
  18. using System.Windows.Input;
  19. using System.Windows.Media;
  20. namespace MECF.Framework.UI.Client.CenterViews.Editors.Recipe
  21. {
  22. public class ProcessTypeFileItem : NotifiableItem
  23. {
  24. public string ProcessType { get; set; }
  25. public ObservableCollection<FileNode> FileListByProcessType { get; set; }
  26. public ProcessTypeFileItem()
  27. {
  28. FileListByProcessType = new ObservableCollection<FileNode>();
  29. }
  30. }
  31. public class ChamberTypeItem : NotifiableItem
  32. {
  33. public string ChamberType { get; set; }
  34. public ObservableCollection<ProcessTypeFileItem> FileListByChamberType { get; set; }
  35. public ChamberTypeItem()
  36. {
  37. FileListByChamberType = new ObservableCollection<ProcessTypeFileItem>();
  38. }
  39. }
  40. public class RecipeEditorViewModel : BaseModel
  41. {
  42. public bool IsPermission { get => this.Permission == 3; }//&& RtStatus != "AutoRunning";
  43. private ICommand _RenameFolderCommand;
  44. public ICommand RenameFolderCommand
  45. {
  46. get
  47. {
  48. if (this._RenameFolderCommand == null)
  49. this._RenameFolderCommand = new BaseCommand(() => this.RenameFolder());
  50. return this._RenameFolderCommand;
  51. }
  52. }
  53. private ICommand _DeleteFolderCommand;
  54. public ICommand DeleteFolderCommand
  55. {
  56. get
  57. {
  58. if (this._DeleteFolderCommand == null)
  59. this._DeleteFolderCommand = new BaseCommand(() => this.DeleteFolder());
  60. return this._DeleteFolderCommand;
  61. }
  62. }
  63. private ICommand _NewFolderCommand;
  64. public ICommand NewFolderCommand
  65. {
  66. get
  67. {
  68. if (this._NewFolderCommand == null)
  69. this._NewFolderCommand = new BaseCommand(() => this.NewFolder());
  70. return this._NewFolderCommand;
  71. }
  72. }
  73. private ICommand _NewFolderRootCommand;
  74. public ICommand NewFolderRootCommand
  75. {
  76. get
  77. {
  78. if (this._NewFolderRootCommand == null)
  79. this._NewFolderRootCommand = new BaseCommand(() => this.NewFolderRoot());
  80. return this._NewFolderRootCommand;
  81. }
  82. }
  83. private ICommand _NewRecipeCommand;
  84. public ICommand NewRecipeCommand
  85. {
  86. get
  87. {
  88. if (this._NewRecipeCommand == null)
  89. this._NewRecipeCommand = new BaseCommand(() => this.NewRecipe());
  90. return this._NewRecipeCommand;
  91. }
  92. }
  93. private ICommand _NewRecipeRootCommand;
  94. public ICommand NewRecipeRootCommand
  95. {
  96. get
  97. {
  98. if (this._NewRecipeRootCommand == null)
  99. this._NewRecipeRootCommand = new BaseCommand(() => this.NewRecipeRoot());
  100. return this._NewRecipeRootCommand;
  101. }
  102. }
  103. private ICommand _RenameRecipeCommand;
  104. public ICommand RenameRecipeCommand
  105. {
  106. get
  107. {
  108. if (this._RenameRecipeCommand == null)
  109. this._RenameRecipeCommand = new BaseCommand(() => this.RenameRecipe());
  110. return this._RenameRecipeCommand;
  111. }
  112. }
  113. private ICommand _DeleteRecipeCommand;
  114. public ICommand DeleteRecipeCommand
  115. {
  116. get
  117. {
  118. if (this._DeleteRecipeCommand == null)
  119. this._DeleteRecipeCommand = new BaseCommand(() => this.DeleteRecipe());
  120. return this._DeleteRecipeCommand;
  121. }
  122. }
  123. private ICommand _SaveAsRecipeCommand;
  124. public ICommand SaveAsRecipeCommand
  125. {
  126. get
  127. {
  128. if (this._SaveAsRecipeCommand == null)
  129. this._SaveAsRecipeCommand = new BaseCommand(() => this.SaveAsRecipe());
  130. return this._SaveAsRecipeCommand;
  131. }
  132. }
  133. public ObservableCollection<ProcessTypeFileItem> ProcessTypeFileList { get; set; }
  134. public RecipeData CurrentRecipe { get; private set; }
  135. public FileNode CurrentFileNode { get; set; }
  136. private bool IsChanged
  137. {
  138. get
  139. {
  140. return editMode == EditMode.Edit || CurrentRecipe.IsChanged;
  141. }
  142. }
  143. public ObservableCollection<EditorDataGridTemplateColumnBase> Columns { get; set; }
  144. public Dictionary<string, ObservableCollection<Param>> PopSettingColumns { get; set; }
  145. public ObservableCollection<EditorDataGridTemplateColumnBase> ColumnsTolerance { get; set; }
  146. public Dictionary<string, ObservableCollection<EditorDataGridTemplateColumnBase>> DicColunms { get; set; }
  147. public bool EnableNew { get; set; }
  148. public bool EnableReName { get; set; }
  149. public bool EnableCopy { get; set; }
  150. public bool EnableDelete { get; set; }
  151. public bool EnableSave { get; set; }
  152. public bool EnableStep { get; set; }
  153. public bool EnableReload { get; set; }
  154. public bool EnableSaveToAll { get; set; }
  155. public bool EnableSaveTo { get; set; }
  156. private RecipeFormatBuilder _columnBuilder = new RecipeFormatBuilder();
  157. private EditMode editMode;
  158. private RecipeProvider _recipeProvider = new RecipeProvider();
  159. public ObservableCollection<string> ChamberType { get; set; }
  160. public int ChamberTypeIndexSelection { get; set; }
  161. public int ProcessTypeIndexSelection { get; set; }
  162. public string CurrentChamberType
  163. {
  164. get
  165. {
  166. return ChamberType[ChamberTypeIndexSelection];
  167. }
  168. }
  169. public string CurrentProcessType
  170. {
  171. get
  172. {
  173. return ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
  174. }
  175. }
  176. public Visibility MultiChamberVisibility
  177. {
  178. get;
  179. set;
  180. }
  181. public Visibility ToleranceVisibility
  182. {
  183. get;
  184. set;
  185. }
  186. public ObservableCollection<string> Chambers { get; set; }
  187. public string SelectedChamber { get; set; }
  188. public object View { get; set; }
  189. protected override void OnInitialize()
  190. {
  191. base.OnInitialize();
  192. var chamberType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.RecipeChamberType");
  193. if (chamberType == null)
  194. {
  195. ChamberType = new ObservableCollection<string>() { "Default" };
  196. }
  197. else
  198. {
  199. ChamberType = new ObservableCollection<string>(((string)(chamberType)).Split(','));
  200. }
  201. ChamberTypeIndexSelection = 0;
  202. //Etch:Process,Clean,Chuck,Dechuck;CVD:Process,Clean;
  203. var processType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedProcessType");
  204. if (processType == null)
  205. {
  206. processType = "Process";
  207. }
  208. ProcessTypeFileList = new ObservableCollection<ProcessTypeFileItem>();
  209. string[] recipeProcessType = ((string)processType).Split(',');
  210. for (int i = 0; i < recipeProcessType.Length; i++)
  211. {
  212. var type = new ProcessTypeFileItem();
  213. type.ProcessType = recipeProcessType[i];
  214. var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{recipeProcessType[i]}";
  215. // var recipes = _recipeProvider.GetXmlRecipeList(prefix);
  216. type.FileListByProcessType = RecipeSequenceTreeBuilder.GetFileNodeParameterList(prefix);//RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes)[0].Files;
  217. ProcessTypeFileList.Add(type);
  218. }
  219. DicColunms = new Dictionary<string, ObservableCollection<EditorDataGridTemplateColumnBase>>();
  220. UpdateRecipeFormat();
  221. }
  222. protected override void OnActivate()
  223. {
  224. base.OnActivate();
  225. }
  226. protected override void OnDeactivate(bool close)
  227. {
  228. base.OnDeactivate(close);
  229. if (this.IsChanged)
  230. {
  231. if (DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} content is changed, do you want to save it?") == DialogButton.Yes)
  232. {
  233. this.SaveRecipe();
  234. }
  235. }
  236. }
  237. protected override void OnViewLoaded(object view)
  238. {
  239. View = view;
  240. base.OnViewLoaded(view);
  241. RecipeFormatBuilder.ApplyTemplate((UserControl)view, this.Columns);
  242. RecipeEditorView u = (RecipeEditorView)view;
  243. u.dgCustom.Columns.Clear();
  244. u.ToleranceGrid.Columns.Clear();
  245. this.Columns.Apply((c) =>
  246. {
  247. c.Header = c;
  248. u.dgCustom.Columns.Add(c);
  249. });
  250. RecipeFormatBuilder.ApplyTemplate((UserControl)view, this.ColumnsTolerance);
  251. ColumnsTolerance.Apply((c) =>
  252. {
  253. c.Header = c;
  254. u.ToleranceGrid.Columns.Add(c);
  255. });
  256. u.dgCustom.ItemsSource = this.CurrentRecipe.Steps;
  257. u.ToleranceGrid.ItemsSource = this.CurrentRecipe.StepTolerances;
  258. }
  259. public void TabSelectionChanged()
  260. {
  261. UpdateRecipeFormat();
  262. OnViewLoaded(View);
  263. }
  264. public void UpdateRecipeFormat()
  265. {
  266. if (DicColunms.Keys.Contains(CurrentProcessType))
  267. {
  268. this.Columns = DicColunms[CurrentProcessType];
  269. }
  270. else
  271. {
  272. this.Columns = this._columnBuilder.Build(CurrentProcessType);
  273. DicColunms[CurrentProcessType] = this.Columns;
  274. }
  275. int indexOthers = this.Columns.IndexOf(this.Columns.Where(x => x.DisplayName == "Others").FirstOrDefault());
  276. ColumnsTolerance = new ObservableCollection<EditorDataGridTemplateColumnBase>(
  277. this.Columns.Take(indexOthers));
  278. this.CurrentRecipe = new RecipeData();
  279. CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType;
  280. CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion;
  281. this.PopSettingColumns = new Dictionary<string, ObservableCollection<Param>>();
  282. this.PopSettingColumns.Add("Oes", _columnBuilder.OesConfig);
  283. this.PopSettingColumns.Add("Vat", _columnBuilder.VatConfig);
  284. this.PopSettingColumns.Add("FineTuning", _columnBuilder.FineTuningConfig);
  285. CurrentRecipe.PopEnable.Add("Oes", _columnBuilder.OesConfig.Count > 0);
  286. CurrentRecipe.PopEnable.Add("Vat", _columnBuilder.VatConfig.Count > 0);
  287. CurrentRecipe.PopEnable.Add("FineTuning", _columnBuilder.FineTuningConfig.Count > 0);
  288. CurrentRecipe.ToleranceEnable = Columns.FirstOrDefault(x => x.EnableTolerance) != null;
  289. this.editMode = EditMode.None;
  290. var chamber = QueryDataClient.Instance.Service.GetConfig("System.Recipe.ChamberModules");
  291. if (chamber == null)
  292. {
  293. chamber = "PM1";
  294. }
  295. Chambers = new ObservableCollection<string>(((string)chamber).Split(','));
  296. SelectedChamber = Chambers[0];
  297. MultiChamberVisibility = Chambers.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
  298. ToleranceVisibility = CurrentRecipe.ToleranceEnable ? Visibility.Visible : Visibility.Collapsed;
  299. }
  300. public void ChamberSelectionChanged()
  301. {
  302. if (IsChanged)
  303. {
  304. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
  305. DialogType.CONFIRM,
  306. $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  307. if (selection == DialogButton.Yes)
  308. {
  309. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  310. this.CurrentRecipe.ReviseTime = DateTime.Now;
  311. this.Save(this.CurrentRecipe, false);
  312. }
  313. }
  314. CurrentRecipe.ChangeChamber(Columns, PopSettingColumns
  315. , _columnBuilder.Configs, SelectedChamber);
  316. }
  317. public void TreeSelectChanged(FileNode node)
  318. {
  319. if (IsChanged)
  320. {
  321. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
  322. DialogType.CONFIRM,
  323. $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  324. if (selection == DialogButton.Yes)
  325. {
  326. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  327. this.CurrentRecipe.ReviseTime = DateTime.Now;
  328. this.Save(this.CurrentRecipe, false);
  329. }
  330. }
  331. CurrentFileNode = node;
  332. if (node != null && node.IsFile)
  333. {
  334. this.LoadData(node.PrefixPath, node.FullPath);
  335. }
  336. else
  337. {
  338. this.ClearData();
  339. this.editMode = EditMode.None;
  340. }
  341. this.UpdateView();
  342. }
  343. #region folder
  344. public void NewFolder()
  345. {
  346. if (IsChanged)
  347. {
  348. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  349. if (selection == DialogButton.Cancel)
  350. return;
  351. if (selection == DialogButton.Yes)
  352. {
  353. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  354. this.CurrentRecipe.ReviseTime = DateTime.Now;
  355. this.Save(this.CurrentRecipe, false);
  356. }
  357. }
  358. InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Folder Name");
  359. dialog.FileName = "new folder";
  360. WindowManager wm = new WindowManager();
  361. bool? dialogReturn = wm.ShowDialog(dialog);
  362. if (!dialogReturn.HasValue || !dialogReturn.Value)
  363. return;
  364. string name = dialog.FileName.Trim();
  365. if (string.IsNullOrEmpty(name))
  366. {
  367. DialogBox.ShowWarning("Folder name should not be empty");
  368. return;
  369. }
  370. string prefix = ChamberType[ChamberTypeIndexSelection] + "\\" + ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
  371. string processType = string.Empty;
  372. string newFolder = string.Empty;
  373. if (CurrentFileNode != null)
  374. {
  375. prefix = CurrentFileNode.PrefixPath;
  376. string folder = CurrentFileNode.FullPath;
  377. if (CurrentFileNode.IsFile)
  378. {
  379. folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
  380. if (!string.IsNullOrEmpty(folder))
  381. newFolder = folder;
  382. }
  383. else
  384. {
  385. newFolder = folder + "\\";
  386. }
  387. }
  388. newFolder = newFolder + name;
  389. if (IsExist(newFolder, false))
  390. {
  391. DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder with the same name already exist.");
  392. return;
  393. }
  394. if (newFolder.Length > 200)
  395. {
  396. DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder name too long, should be less 200.");
  397. return;
  398. }
  399. _recipeProvider.CreateRecipeFolder(prefix, newFolder);
  400. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true);
  401. }
  402. public void NewFolderRoot()
  403. {
  404. if (IsChanged)
  405. {
  406. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  407. if (selection == DialogButton.Cancel)
  408. return;
  409. if (selection == DialogButton.Yes)
  410. {
  411. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  412. this.CurrentRecipe.ReviseTime = DateTime.Now;
  413. this.Save(this.CurrentRecipe, false);
  414. }
  415. }
  416. InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Folder Name");
  417. dialog.FileName = "new folder";
  418. WindowManager wm = new WindowManager();
  419. bool? dialogReturn = wm.ShowDialog(dialog);
  420. if (!dialogReturn.HasValue || !dialogReturn.Value)
  421. return;
  422. string name = dialog.FileName.Trim();
  423. if (string.IsNullOrEmpty(name))
  424. {
  425. DialogBox.ShowWarning("Folder name should not be empty");
  426. return;
  427. }
  428. if (IsExist(name, false))
  429. {
  430. DialogBox.ShowWarning($"Can not create folder {name}, Folder with the same name already exist.");
  431. return;
  432. }
  433. if (name.Length > 200)
  434. {
  435. DialogBox.ShowWarning($"Can not create folder {name}, Folder name too long, should be less 200.");
  436. return;
  437. }
  438. string prefix = ChamberType[ChamberTypeIndexSelection] + "\\" + ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
  439. _recipeProvider.CreateRecipeFolder(prefix, name);
  440. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, name, true);
  441. }
  442. public void DeleteFolder()
  443. {
  444. if (CurrentFileNode == null || CurrentFileNode.IsFile)
  445. return;
  446. if (CurrentFileNode.Files.Count > 0)
  447. {
  448. DialogBox.ShowWarning($"Can not delete non-empty folder, Remove the files or folders under \r\n{CurrentFileNode.FullPath}.");
  449. return;
  450. }
  451. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
  452. $"Are you sure you want to delete \r\n {CurrentFileNode.FullPath}?");
  453. if (selection == DialogButton.No)
  454. return;
  455. string nextFocus = CurrentFileNode.Parent.FullPath;
  456. bool isFolder = true;
  457. if (CurrentFileNode.Parent.Files.Count > 1)
  458. {
  459. for (int i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
  460. {
  461. if (CurrentFileNode.Parent.Files[i] == CurrentFileNode)
  462. {
  463. if (i == 0)
  464. {
  465. nextFocus = CurrentFileNode.Parent.Files[i + 1].FullPath;
  466. isFolder = !CurrentFileNode.Parent.Files[i + 1].IsFile;
  467. }
  468. else
  469. {
  470. nextFocus = CurrentFileNode.Parent.Files[i - 1].FullPath;
  471. isFolder = !CurrentFileNode.Parent.Files[i - 1].IsFile;
  472. }
  473. }
  474. }
  475. }
  476. _recipeProvider.DeleteRecipeFolder(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath);
  477. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, nextFocus, isFolder);
  478. }
  479. public void RenameFolder()
  480. {
  481. if (CurrentFileNode == null || CurrentFileNode.IsFile)
  482. return;
  483. InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Folder Name");
  484. dialog.FileName = CurrentFileNode.Name;
  485. WindowManager wm = new WindowManager();
  486. bool? dialogReturn = wm.ShowDialog(dialog);
  487. if (!dialogReturn.HasValue || !dialogReturn.Value)
  488. return;
  489. string name = dialog.FileName.Trim();
  490. if (string.IsNullOrEmpty(name))
  491. return;
  492. string newFolder = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
  493. if (!string.IsNullOrEmpty(newFolder))
  494. newFolder = newFolder + name;
  495. else
  496. newFolder = name;
  497. if (newFolder == CurrentFileNode.FullPath)
  498. return;
  499. if (IsExist(newFolder, false))
  500. {
  501. DialogBox.ShowWarning($"Can not rename to {newFolder}, Folder with the same name already exist.");
  502. return;
  503. }
  504. if (newFolder.Length > 200)
  505. {
  506. DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder name too long, should be less 200.");
  507. return;
  508. }
  509. _recipeProvider.RenameFolder(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath, newFolder);
  510. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true);
  511. }
  512. #endregion
  513. #region recipe
  514. public void NewRecipe()
  515. {
  516. if (IsChanged)
  517. {
  518. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  519. if (selection == DialogButton.Cancel)
  520. return;
  521. if (selection == DialogButton.Yes)
  522. {
  523. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  524. this.CurrentRecipe.ReviseTime = DateTime.Now;
  525. this.Save(this.CurrentRecipe, false);
  526. }
  527. }
  528. InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
  529. dialog.FileName = "new recipe";
  530. WindowManager wm = new WindowManager();
  531. bool? dialogReturn = wm.ShowDialog(dialog);
  532. if (!dialogReturn.HasValue || !dialogReturn.Value)
  533. return;
  534. string recipeName = dialog.FileName.Trim();
  535. if (string.IsNullOrEmpty(dialog.FileName))
  536. {
  537. DialogBox.ShowWarning("Recipe file name should not be empty");
  538. return;
  539. }
  540. string prefix = CurrentChamberType + "\\" + CurrentProcessType;
  541. string processType = string.Empty;
  542. if (CurrentFileNode != null)
  543. {
  544. string folder = CurrentFileNode.FullPath;
  545. if (CurrentFileNode.IsFile)
  546. {
  547. folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
  548. //if (!string.IsNullOrEmpty(folder))
  549. // folder = folder;
  550. }
  551. else
  552. {
  553. folder = folder + "\\";
  554. }
  555. recipeName = folder + recipeName;
  556. }
  557. if (IsExist(recipeName, true))
  558. {
  559. DialogBox.ShowWarning($"Can not create {recipeName}, Recipe with the same name already exist.");
  560. return;
  561. }
  562. if (recipeName.Length > 200)
  563. {
  564. DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
  565. return;
  566. }
  567. RecipeData recipe = new RecipeData();
  568. recipe.Name = recipeName;
  569. recipe.PrefixPath = prefix;
  570. recipe.Creator = BaseApp.Instance.UserContext.LoginName;
  571. recipe.CreateTime = DateTime.Now;
  572. recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  573. recipe.ReviseTime = DateTime.Now;
  574. recipe.Description = string.Empty;
  575. if (!Save(recipe, true))
  576. return;
  577. var types = prefix.Split('\\');
  578. ReloadRecipeFileList(types[0], types[1], recipeName, false);
  579. }
  580. public void NewRecipeRoot()
  581. {
  582. if (IsChanged)
  583. {
  584. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  585. if (selection == DialogButton.Cancel)
  586. return;
  587. if (selection == DialogButton.Yes)
  588. {
  589. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  590. this.CurrentRecipe.ReviseTime = DateTime.Now;
  591. this.Save(this.CurrentRecipe, false);
  592. }
  593. }
  594. InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
  595. dialog.FileName = "new recipe";
  596. WindowManager wm = new WindowManager();
  597. bool? dialogReturn = wm.ShowDialog(dialog);
  598. if (!dialogReturn.HasValue || !dialogReturn.Value)
  599. return;
  600. string recipeName = dialog.FileName.Trim();
  601. if (string.IsNullOrEmpty(dialog.FileName))
  602. {
  603. DialogBox.ShowWarning("Recipe file name should not be empty");
  604. return;
  605. }
  606. if (IsExist(recipeName, true))
  607. {
  608. DialogBox.ShowWarning($"Can not create {recipeName}, Recipe with the same name already exist.");
  609. return;
  610. }
  611. if (recipeName.Length > 200)
  612. {
  613. DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
  614. return;
  615. }
  616. RecipeData recipe = new RecipeData();
  617. recipe.Name = recipeName;
  618. recipe.PrefixPath = CurrentChamberType + "\\" + CurrentProcessType;
  619. recipe.Creator = BaseApp.Instance.UserContext.LoginName;
  620. recipe.CreateTime = DateTime.Now;
  621. recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  622. recipe.ReviseTime = DateTime.Now;
  623. recipe.Description = string.Empty;
  624. if (!Save(recipe, true))
  625. return;
  626. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false);
  627. }
  628. private void ReloadRecipeFileList(string chamberType, string processType, string selectedFile, bool selectionIsFolder)
  629. {
  630. ProcessTypeFileItem item = ProcessTypeFileList.FirstOrDefault(x => x.ProcessType == processType);
  631. if (item == null)
  632. {
  633. LOG.Write("error reload recipe file list, type = " + processType);
  634. }
  635. var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{item.ProcessType}";
  636. var recipes = _recipeProvider.GetXmlRecipeList(prefix);
  637. item.FileListByProcessType = RecipeSequenceTreeBuilder.BuildFileNode(prefix, selectedFile, selectionIsFolder, recipes)[0].Files;
  638. item.InvokePropertyChanged();
  639. }
  640. private bool IsExist(string fullPath, bool isFile)
  641. {
  642. for (int i = 0; i < ProcessTypeFileList.Count; i++)
  643. {
  644. if (ProcessTypeFileList[i].ProcessType == CurrentProcessType)
  645. {
  646. if (ProcessTypeFileList[i].FileListByProcessType.Count == 0)
  647. return false;
  648. return FindFile(fullPath, ProcessTypeFileList[i].FileListByProcessType[0].Parent, isFile);
  649. }
  650. }
  651. return true;
  652. }
  653. private bool FindFile(string path, FileNode root, bool isFile)
  654. {
  655. if (root.FullPath == path && !isFile)
  656. {
  657. return true;
  658. }
  659. foreach (var node in root.Files)
  660. {
  661. if (isFile && node.IsFile && node.FullPath == path)
  662. return true;
  663. if (!node.IsFile && FindFile(path, node, isFile))
  664. return true;
  665. }
  666. return false;
  667. }
  668. public void SaveAsRecipe()
  669. {
  670. if (CurrentFileNode == null || !CurrentFileNode.IsFile)
  671. return;
  672. if (IsChanged)
  673. {
  674. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  675. if (selection == DialogButton.Cancel)
  676. return;
  677. if (selection == DialogButton.Yes)
  678. {
  679. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  680. this.CurrentRecipe.ReviseTime = DateTime.Now;
  681. this.Save(this.CurrentRecipe, false);
  682. }
  683. }
  684. InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
  685. dialog.FileName = CurrentFileNode.Name;
  686. WindowManager wm = new WindowManager();
  687. bool? dialogReturn = wm.ShowDialog(dialog);
  688. if (!dialogReturn.HasValue || !dialogReturn.Value)
  689. return;
  690. string recipeName = dialog.FileName.Trim();
  691. if (string.IsNullOrEmpty(dialog.FileName))
  692. {
  693. DialogBox.ShowWarning("Recipe file name should not be empty");
  694. return;
  695. }
  696. string prefix = CurrentChamberType + "\\" + CurrentProcessType;
  697. string processType = string.Empty;
  698. string folder = CurrentFileNode.FullPath;
  699. if (CurrentFileNode.IsFile)
  700. {
  701. folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
  702. }
  703. if (!string.IsNullOrEmpty(folder))
  704. recipeName = folder + "\\" + recipeName;
  705. if (CurrentFileNode.FullPath == recipeName)
  706. return;
  707. if (IsExist(recipeName, true))
  708. {
  709. DialogBox.ShowWarning($"Can not copy to {recipeName}, Recipe with the same name already exist.");
  710. return;
  711. }
  712. if (recipeName.Length > 200)
  713. {
  714. DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
  715. return;
  716. }
  717. CurrentRecipe.Creator = BaseApp.Instance.UserContext.LoginName;
  718. CurrentRecipe.CreateTime = DateTime.Now;
  719. CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  720. CurrentRecipe.ReviseTime = DateTime.Now;
  721. CurrentRecipe.Description = CurrentRecipe.Description + ". Renamed from " + CurrentFileNode.Name;
  722. _recipeProvider.SaveAsRecipe(prefix, recipeName, CurrentRecipe.GetXmlString());
  723. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false);
  724. }
  725. public void RenameRecipe()
  726. {
  727. if (CurrentFileNode == null || !CurrentFileNode.IsFile)
  728. return;
  729. if (IsChanged)
  730. {
  731. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel, DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
  732. if (selection == DialogButton.Cancel)
  733. return;
  734. if (selection == DialogButton.Yes)
  735. {
  736. this.CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  737. this.CurrentRecipe.ReviseTime = DateTime.Now;
  738. this.Save(this.CurrentRecipe, false);
  739. }
  740. }
  741. InputFileNameDialogViewModel dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
  742. dialog.FileName = CurrentFileNode.Name;
  743. WindowManager wm = new WindowManager();
  744. bool? dialogReturn = wm.ShowDialog(dialog);
  745. if (!dialogReturn.HasValue || !dialogReturn.Value)
  746. return;
  747. string recipeName = dialog.FileName.Trim();
  748. if (string.IsNullOrEmpty(dialog.FileName))
  749. {
  750. DialogBox.ShowWarning("Recipe file name should not be empty");
  751. return;
  752. }
  753. string prefix = CurrentChamberType + "\\" + CurrentProcessType;
  754. string processType = string.Empty;
  755. string newName = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
  756. if (!string.IsNullOrEmpty(newName))
  757. newName = newName + recipeName;
  758. else
  759. newName = recipeName;
  760. if (newName == CurrentFileNode.FullPath)
  761. return;
  762. if (IsExist(newName, true))
  763. {
  764. DialogBox.ShowWarning($"Can not rename to {newName}, Recipe with the same name already exist.");
  765. return;
  766. }
  767. if (newName.Length > 200)
  768. {
  769. DialogBox.ShowWarning($"Can not create folder {newName}, Folder name too long, should be less 200.");
  770. return;
  771. }
  772. _recipeProvider.RenameRecipe(prefix, CurrentFileNode.FullPath, newName);
  773. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newName, false);
  774. }
  775. public void DeleteRecipe()
  776. {
  777. if (CurrentFileNode == null || !CurrentFileNode.IsFile)
  778. return;
  779. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
  780. $"Are you sure you want to delete \r\n {CurrentFileNode.FullPath}?");
  781. if (selection == DialogButton.No)
  782. return;
  783. string nextFocus = CurrentFileNode.Parent.FullPath;
  784. bool isFolder = true;
  785. if (CurrentFileNode.Parent.Files.Count > 1)
  786. {
  787. for (int i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
  788. {
  789. if (CurrentFileNode.Parent.Files[i] == CurrentFileNode)
  790. {
  791. if (i == 0)
  792. {
  793. nextFocus = CurrentFileNode.Parent.Files[i + 1].FullPath;
  794. isFolder = !CurrentFileNode.Parent.Files[i + 1].IsFile;
  795. }
  796. else
  797. {
  798. nextFocus = CurrentFileNode.Parent.Files[i - 1].FullPath;
  799. isFolder = !CurrentFileNode.Parent.Files[i - 1].IsFile;
  800. }
  801. }
  802. }
  803. }
  804. _recipeProvider.DeleteRecipe(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath);
  805. ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, nextFocus, isFolder);
  806. }
  807. public void ReloadRecipe()
  808. {
  809. if (this.editMode == EditMode.Normal || this.editMode == EditMode.Edit)
  810. {
  811. this.LoadData(CurrentRecipe.PrefixPath, CurrentRecipe.Name);
  812. this.UpdateView();
  813. }
  814. }
  815. public void SaveToAll()
  816. {
  817. if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
  818. {
  819. DialogBox.ShowWarning($"Save failed, {CurrentRecipe.Name} is not a valid recipe file");
  820. return;
  821. }
  822. var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
  823. DialogType.CONFIRM, $"Do you want to save to all? \r\n This will replace all the other chamber recipe content");
  824. if (selection == DialogButton.No)
  825. return;
  826. CurrentRecipe.SaveTo(Chambers.ToArray());
  827. Save(this.CurrentRecipe, false);
  828. }
  829. public void SaveTo()
  830. {
  831. if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
  832. {
  833. DialogBox.ShowWarning($"Save failed, {CurrentRecipe.Name} is not a valid recipe file");
  834. return;
  835. }
  836. SaveToDialogViewModel dialog = new SaveToDialogViewModel("Select which chamber to copy to", SelectedChamber, Chambers.ToList());
  837. WindowManager wm = new WindowManager();
  838. bool? dialogReturn = wm.ShowDialog(dialog);
  839. if (!dialogReturn.HasValue || !dialogReturn.Value)
  840. return;
  841. List<string> chambers = new List<string>();
  842. foreach (var dialogChamber in dialog.Chambers)
  843. {
  844. if (dialogChamber.IsEnabled && dialogChamber.IsChecked)
  845. chambers.Add(dialogChamber.Name);
  846. }
  847. if (chambers.Count == 0)
  848. return;
  849. CurrentRecipe.SaveTo(chambers.ToArray());
  850. Save(this.CurrentRecipe, false);
  851. }
  852. #endregion
  853. #region Steps
  854. public void ParamsExpanded(ExpanderColumn col)
  855. {
  856. int index = this.Columns.IndexOf(col);
  857. for (var i = index + 1; i < this.Columns.Count; i++)
  858. {
  859. if (this.Columns[i] is ExpanderColumn)
  860. break;
  861. this.Columns[i].Visibility = Visibility.Visible;
  862. }
  863. }
  864. public void ParamsCollapsed(ExpanderColumn col)
  865. {
  866. int index = this.Columns.IndexOf(col);
  867. for (var i = index + 1; i < this.Columns.Count; i++)
  868. {
  869. if (this.Columns[i] is ExpanderColumn)
  870. break;
  871. this.Columns[i].Visibility = Visibility.Collapsed;
  872. }
  873. }
  874. public void SaveRecipe()
  875. {
  876. if (this.IsChanged)
  877. {
  878. this.Save(this.CurrentRecipe, false);
  879. }
  880. }
  881. public void PopSetting(string controlName, Param paramData)
  882. {
  883. int stepNum = Convert.ToInt32(((StepParam)paramData.Parent[1]).Value);
  884. PublicPopSettingDialogViewModel dialog = new PublicPopSettingDialogViewModel();
  885. dialog.DisplayName = paramData.DisplayName;
  886. ObservableCollection<Param> Parameters = new ObservableCollection<Param>();
  887. Parameters = this.CurrentRecipe.PopSettingSteps[controlName][stepNum - 1];
  888. ObservableCollection<Param> ControlParameters = new ObservableCollection<Param>();
  889. ObservableCollection<BandParam> BrandParameters = new ObservableCollection<BandParam>();
  890. foreach (var item in Parameters)
  891. {
  892. if (item.Name.Contains("Band"))
  893. {
  894. string name = item.Name.Replace("Wavelength", "").Replace("Bandwidth", "");
  895. string displayName = item.DisplayName.Replace("Wavelength", "").Replace("Bandwidth", "");
  896. if (BrandParameters.Where(x => x.Name == name).Count() == 0)
  897. {
  898. BrandParameters.Add(new BandParam()
  899. {
  900. Name = name,
  901. DisplayName = displayName
  902. });
  903. }
  904. if (item.Name.Contains("Wavelength"))
  905. {
  906. BrandParameters.First(x => x.Name == name).WavelengthDoubleParam = item;
  907. }
  908. else if (item.Name.Contains("Bandwidth"))
  909. {
  910. BrandParameters.First(x => x.Name == name).BandwidthDoubleParam = item;
  911. }
  912. }
  913. else
  914. ControlParameters.Add(item);
  915. }
  916. dialog.Parameters = Parameters;
  917. dialog.ControlParameters = ControlParameters;
  918. dialog.BandParameters = BrandParameters;
  919. WindowManager wm = new WindowManager();
  920. bool? bret = wm.ShowDialog(dialog);
  921. if ((bool)bret)
  922. {
  923. this.CurrentRecipe.PopSettingSteps[controlName][stepNum - 1] = dialog.Parameters;
  924. }
  925. }
  926. public bool Save(RecipeData recipe, bool createNew)
  927. {
  928. bool result = false;
  929. if (string.IsNullOrEmpty(recipe.Name))
  930. {
  931. MessageBox.Show("Recipe name can't be empty");
  932. return false;
  933. }
  934. recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
  935. recipe.ReviseTime = DateTime.Now;
  936. result = this._recipeProvider.SaveRecipe(recipe.PrefixPath, recipe.Name, recipe.GetXmlString());
  937. if (result)
  938. {
  939. recipe.DataSaved();
  940. this.editMode = EditMode.Normal;
  941. this.UpdateView();
  942. CurrentRecipe.ChangeChamber(Columns, PopSettingColumns, _columnBuilder.Configs, SelectedChamber);
  943. }
  944. else
  945. {
  946. MessageBox.Show("Save failed!");
  947. }
  948. return result;
  949. }
  950. public void AddStep()
  951. {
  952. this.CurrentRecipe.Steps.Add(this.CurrentRecipe.CreateStep(this.Columns));
  953. foreach (string key in PopSettingColumns.Keys)
  954. {
  955. if (!this.CurrentRecipe.PopSettingSteps.ContainsKey(key))
  956. {
  957. this.CurrentRecipe.PopSettingSteps.Add(key, new ObservableCollection<ObservableCollection<Param>>());
  958. }
  959. this.CurrentRecipe.PopSettingSteps[key].Add(this.PopSettingColumns[key]);
  960. }
  961. if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
  962. this.editMode = EditMode.Edit;
  963. int index = 1;
  964. foreach (ObservableCollection<Param> parameters in this.CurrentRecipe.Steps)
  965. {
  966. (parameters[1] as StepParam).Value = index.ToString();
  967. index++;
  968. }
  969. this.UpdateView();
  970. }
  971. public void AppendStep()
  972. {
  973. int index = -1;
  974. bool found = false;
  975. for (var i = 0; i < this.CurrentRecipe.Steps.Count; i++)
  976. {
  977. if (this.CurrentRecipe.Steps[i][1] is StepParam && ((StepParam)this.CurrentRecipe.Steps[i][1]).Checked)
  978. {
  979. index = i;
  980. found = true;
  981. break;
  982. }
  983. }
  984. if (found)
  985. {
  986. if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
  987. this.editMode = EditMode.Edit;
  988. this.CurrentRecipe.Steps.Insert(index, this.CurrentRecipe.CreateStep(this.Columns));
  989. if (this.CurrentRecipe.PopSettingSteps.Count != 0)
  990. {
  991. foreach (string key in PopSettingColumns.Keys)
  992. {
  993. this.CurrentRecipe.PopSettingSteps[key].Insert(index, this.PopSettingColumns[key]);
  994. }
  995. }
  996. index = 1;
  997. foreach (ObservableCollection<Param> parameters in this.CurrentRecipe.Steps)
  998. {
  999. (parameters[1] as StepParam).Value = index.ToString();
  1000. index++;
  1001. }
  1002. }
  1003. }
  1004. private ObservableCollection<ObservableCollection<Param>> copySteps = new ObservableCollection<ObservableCollection<Param>>();
  1005. private Dictionary<string, ObservableCollection<ObservableCollection<Param>>> popCopySteps = new Dictionary<string, ObservableCollection<ObservableCollection<Param>>>();
  1006. public void CopyStep()
  1007. {
  1008. this.copySteps.Clear();
  1009. this.popCopySteps.Clear();
  1010. for (var i = 0; i < this.CurrentRecipe.Steps.Count; i++)
  1011. {
  1012. if (this.CurrentRecipe.Steps[i][1] is StepParam && ((StepParam)this.CurrentRecipe.Steps[i][1]).Checked)
  1013. {
  1014. this.copySteps.Add(this.CurrentRecipe.CloneStep(this.Columns, this.CurrentRecipe.Steps[i]));
  1015. foreach (string key in PopSettingColumns.Keys)
  1016. {
  1017. if (!this.popCopySteps.ContainsKey(key))
  1018. {
  1019. this.popCopySteps.Add(key, new ObservableCollection<ObservableCollection<Param>>());
  1020. }
  1021. if (this.CurrentRecipe.PopSettingSteps.Count != 0)
  1022. {
  1023. this.popCopySteps[key].Add(this.CurrentRecipe.PopSettingSteps[key][i]);
  1024. }
  1025. }
  1026. }
  1027. }
  1028. CurrentRecipe.ValidLoopData();
  1029. }
  1030. public void PasteStep()
  1031. {
  1032. if (this.copySteps.Count > 0)
  1033. {
  1034. if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
  1035. this.editMode = EditMode.Edit;
  1036. for (var i = 0; i < this.CurrentRecipe.Steps.Count; i++)
  1037. {
  1038. if (this.CurrentRecipe.Steps[i][1] is StepParam && ((StepParam)this.CurrentRecipe.Steps[i][1]).Checked)
  1039. {
  1040. for (var copyindex = 0; copyindex < this.copySteps.Count; copyindex++)
  1041. {
  1042. this.CurrentRecipe.Steps.Insert(i, this.CurrentRecipe.CloneStep(this.Columns, this.copySteps[copyindex]));
  1043. if (this.CurrentRecipe.PopSettingSteps.Count != 0)
  1044. {
  1045. foreach (string key in PopSettingColumns.Keys)
  1046. {
  1047. this.CurrentRecipe.PopSettingSteps[key].Insert(i, this.popCopySteps[key][copyindex]);
  1048. }
  1049. }
  1050. i++;
  1051. }
  1052. break;
  1053. }
  1054. }
  1055. int index = 1;
  1056. foreach (ObservableCollection<Param> parameters in this.CurrentRecipe.Steps)
  1057. {
  1058. (parameters[1] as StepParam).Value = index.ToString();
  1059. index++;
  1060. }
  1061. CurrentRecipe.ValidLoopData();
  1062. this.UpdateView();
  1063. }
  1064. }
  1065. public void DeleteStep()
  1066. {
  1067. if (this.editMode != EditMode.New && this.editMode != EditMode.ReName)
  1068. this.editMode = EditMode.Edit;
  1069. List<ObservableCollection<Param>> steps = this.CurrentRecipe.Steps.ToList();
  1070. for (var i = 0; i < steps.Count; i++)
  1071. {
  1072. if (steps[i][1] is StepParam && ((StepParam)steps[i][1]).Checked)
  1073. {
  1074. this.CurrentRecipe.Steps.Remove(steps[i]);
  1075. foreach (string key in PopSettingColumns.Keys)
  1076. {
  1077. if (CurrentRecipe.PopSettingSteps.ContainsKey(key) && CurrentRecipe.PopSettingSteps[key].Count > i)
  1078. CurrentRecipe.PopSettingSteps[key].Remove(this.CurrentRecipe.PopSettingSteps[key][i]);
  1079. }
  1080. }
  1081. }
  1082. int index = 1;
  1083. foreach (ObservableCollection<Param> parameters in this.CurrentRecipe.Steps)
  1084. {
  1085. (parameters[1] as StepParam).Value = index.ToString();
  1086. index++;
  1087. }
  1088. }
  1089. private TreeViewItem GetParentObjectEx<TreeViewItem>(DependencyObject obj) where TreeViewItem : FrameworkElement
  1090. {
  1091. DependencyObject parent = VisualTreeHelper.GetParent(obj);
  1092. while (parent != null)
  1093. {
  1094. if (parent is TreeViewItem)
  1095. {
  1096. return (TreeViewItem)parent;
  1097. }
  1098. parent = VisualTreeHelper.GetParent(parent);
  1099. }
  1100. return null;
  1101. }
  1102. public void TreeRightMouseDown(MouseButtonEventArgs e)
  1103. {
  1104. var item = GetParentObjectEx<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
  1105. if (item != null)
  1106. {
  1107. item.Focus();
  1108. }
  1109. }
  1110. #endregion
  1111. private void ClearData()
  1112. {
  1113. this.editMode = EditMode.None;
  1114. this.CurrentRecipe.Clear();
  1115. this.CurrentRecipe.Name = string.Empty;
  1116. this.CurrentRecipe.Description = string.Empty;
  1117. }
  1118. private void LoadData(string prefixPath, string recipeName)
  1119. {
  1120. CurrentRecipe.Clear();
  1121. var recipeContent = _recipeProvider.LoadRecipe(prefixPath, recipeName);
  1122. if (string.IsNullOrEmpty(recipeContent))
  1123. {
  1124. MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid.");
  1125. return;
  1126. }
  1127. CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType;
  1128. CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion;
  1129. CurrentRecipe.InitData(prefixPath, recipeName, recipeContent, Columns, PopSettingColumns, _columnBuilder.Configs, SelectedChamber);
  1130. this.editMode = EditMode.Normal;
  1131. }
  1132. private void UpdateView()
  1133. {
  1134. bool isFileSelected = CurrentFileNode != null && CurrentFileNode.IsFile;
  1135. this.EnableNew = isFileSelected;
  1136. this.EnableReName = isFileSelected;
  1137. this.EnableCopy = isFileSelected;
  1138. this.EnableDelete = isFileSelected;
  1139. this.EnableSave = isFileSelected;
  1140. this.EnableStep = isFileSelected;
  1141. EnableSaveTo = isFileSelected;
  1142. EnableSaveToAll = isFileSelected;
  1143. EnableReload = isFileSelected;
  1144. if (this.editMode == EditMode.None)
  1145. {
  1146. this.EnableNew = true;
  1147. this.EnableReName = false;
  1148. this.EnableCopy = false;
  1149. this.EnableDelete = false;
  1150. this.EnableStep = false;
  1151. this.EnableSave = false;
  1152. }
  1153. this.NotifyOfPropertyChange("EnableNew");
  1154. this.NotifyOfPropertyChange("EnableReName");
  1155. this.NotifyOfPropertyChange("EnableCopy");
  1156. this.NotifyOfPropertyChange("EnableDelete");
  1157. this.NotifyOfPropertyChange("EnableSave");
  1158. this.NotifyOfPropertyChange("EnableStep");
  1159. this.NotifyOfPropertyChange("EnableSaveTo");
  1160. this.NotifyOfPropertyChange("EnableSaveToAll");
  1161. this.NotifyOfPropertyChange("EnableReload");
  1162. this.NotifyOfPropertyChange("CurrentRecipe");
  1163. }
  1164. }
  1165. }