RecipeFileManager.cs 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  1. using Aitex.Common.Util;
  2. using Aitex.Core.RT.Event;
  3. using Aitex.Core.RT.Log;
  4. using Aitex.Core.Util;
  5. using Aitex.Core.Utilities;
  6. using Aitex.Core.WCF;
  7. using MECF.Framework.Common.Equipment;
  8. using MECF.Framework.Common.Properties;
  9. using MECF.Framework.Common.RecipeCenter;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Text;
  14. using System.Text.RegularExpressions;
  15. using System.Xml;
  16. using System.Xml.Schema;
  17. using CyberX8_Core;
  18. using System.Linq;
  19. using System.Collections.ObjectModel;
  20. using Aitex.Core.RT.Routine;
  21. using System.Windows.Media.Converters;
  22. namespace Aitex.Core.RT.RecipeCenter
  23. {
  24. public class RecipeFileManager : Singleton<RecipeFileManager>
  25. {
  26. //sequence文件 统一放在 Recipes/Sequence 文件夹下面
  27. public const string SequenceFolder = "Sequence";
  28. public const string SourceModule = "Recipe";
  29. public const string ProductionFolder = "Production";
  30. public const string EngineeringFolder = "Engineering";
  31. private bool _recipeIsValid;
  32. private List<string> _validationErrors = new List<string>();
  33. private List<string> _validationWarnings = new List<string>();
  34. IRecipeFileContext _rcpContext;
  35. private ISequenceFileContext _seqContext;
  36. public void Initialize(IRecipeFileContext context)
  37. {
  38. Initialize(context, null, true);
  39. }
  40. public void Initialize(IRecipeFileContext context, bool enableService)
  41. {
  42. Initialize(context, null, enableService);
  43. }
  44. public void Initialize(IRecipeFileContext rcpContext, ISequenceFileContext seqContext, bool enableService)
  45. {
  46. _rcpContext = rcpContext == null ? new DefaultRecipeFileContext() : rcpContext;
  47. _seqContext = seqContext == null ? new DefaultSequenceFileContext() : seqContext;
  48. CultureSupported.UpdateCoreCultureResource(CultureSupported.English);
  49. //if (enableService)
  50. //{
  51. // Singleton<WcfServiceManager>.Instance.Initialize(new Type[]
  52. // {
  53. // typeof(RecipeService)
  54. // });
  55. //}
  56. var dir = string.Format("{0}{1}\\", PathManager.GetRecipeDir(), SequenceFolder);
  57. DirectoryInfo di = new DirectoryInfo(dir);
  58. if (!di.Exists)
  59. {
  60. di.Create();
  61. }
  62. }
  63. private void ValidationEventHandler(object sender, ValidationEventArgs e)
  64. {
  65. switch (e.Severity)
  66. {
  67. case XmlSeverityType.Error:
  68. _validationErrors.Add(e.Message);
  69. _recipeIsValid = false;
  70. break;
  71. case XmlSeverityType.Warning:
  72. _validationWarnings.Add(e.Message);
  73. break;
  74. }
  75. }
  76. /// <summary>
  77. /// XML schema checking
  78. /// </summary>
  79. /// <param name="chamId"></param>
  80. /// <param name="recipeName"></param>
  81. /// <param name="recipeContent"></param>
  82. /// <param name="reason"></param>
  83. /// <returns></returns>
  84. public bool ValidateRecipe(string chamberId, string recipeName, string recipeContent, out List<string> reason)
  85. {
  86. try
  87. {
  88. XmlDocument document = new XmlDocument();
  89. document.LoadXml(recipeContent);
  90. MemoryStream schemaStream = new MemoryStream(ASCIIEncoding.ASCII.GetBytes(GetRecipeSchema(chamberId)));
  91. XmlReader xmlSchemaReader = XmlReader.Create(schemaStream);
  92. XmlSchema schema1 = XmlSchema.Read(xmlSchemaReader, ValidationEventHandler);
  93. document.Schemas.Add(schema1);
  94. document.LoadXml(recipeContent);
  95. ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);
  96. _recipeIsValid = true;
  97. _validationErrors = new List<string>();
  98. _validationWarnings = new List<string>();
  99. // Validates recipe.
  100. document.Validate(eventHandler);
  101. }
  102. catch (Exception ex)
  103. {
  104. LOG.WriteExeption(ex);
  105. _recipeIsValid = false;
  106. }
  107. if (!_recipeIsValid && _validationErrors.Count == 0)
  108. {
  109. _validationErrors.Add(Resources.RecipeFileManager_ValidateRecipe_XMLSchemaValidateFailed);
  110. }
  111. reason = _validationErrors;
  112. return _recipeIsValid;
  113. }
  114. /// <summary>
  115. /// This method will be invoked by two places:
  116. /// (1) Load a recipe from server to GUI for editing (do not need validation when loading, do validation when saving);
  117. /// (2) Load a recipe from recipe engine to run process(always do a validation before run recipe);
  118. /// </summary>
  119. /// <param name="recipeName"></param>
  120. /// <param name="needValidation">indicate whether a recipe format validation is needed or not</param>
  121. /// <returns></returns>
  122. public string LoadRecipe(string chamberId, string recipeName, bool needValidation)
  123. {
  124. string rcp = string.Empty;
  125. try
  126. {
  127. using (StreamReader fs = new StreamReader(GenerateRecipeFilePath(chamberId, recipeName)))
  128. {
  129. rcp = fs.ReadToEnd();
  130. fs.Close();
  131. }
  132. }
  133. catch (Exception ex)
  134. {
  135. LOG.WriteExeption($"load recipe file failed, {recipeName}", ex);
  136. rcp = string.Empty;
  137. }
  138. return rcp;
  139. }
  140. public string LoadRecipeByPath(string path)
  141. {
  142. string rcp = string.Empty;
  143. try
  144. {
  145. using (StreamReader fs = new StreamReader(path))
  146. {
  147. rcp = fs.ReadToEnd();
  148. fs.Close();
  149. }
  150. }
  151. catch (Exception ex)
  152. {
  153. // LOG.WriteExeption($"load recipe file failed, {recipeName}", ex);
  154. rcp = string.Empty;
  155. }
  156. return rcp;
  157. }
  158. /// <summary>
  159. /// Get recipe list
  160. /// </summary>
  161. /// <param name="chamId"></param>
  162. /// <param name="includingUsedRecipe"></param>
  163. /// <returns></returns>
  164. public IEnumerable<string> GetRecipes(string chamberId, bool includingUsedRecipe)
  165. {
  166. return _rcpContext.GetRecipes(chamberId, includingUsedRecipe);
  167. }
  168. /// <summary>
  169. /// 加载工程指定类型Recipe
  170. /// </summary>
  171. /// <param name="recipeType"></param>
  172. /// <returns></returns>
  173. public ObservableCollection<RecipeNode> GetEngineeringRecipesByType(string recipeType)
  174. {
  175. try
  176. {
  177. ObservableCollection<RecipeNode> treeNodes = new ObservableCollection<RecipeNode>();
  178. string recipePath = PathManager.GetRecipeDir();
  179. var di = new DirectoryInfo(recipePath);
  180. DirectoryInfo[] infos = di.GetDirectories();
  181. var recipes = new List<string>();
  182. foreach (var info in infos)
  183. {
  184. if (info.Name == "Engineering")
  185. {
  186. FileInfo[] files = info.GetFiles();
  187. recipes.Add(info.Name);
  188. foreach (FileInfo file in files)
  189. {
  190. if (file.Name.Contains($".{recipeType}."))
  191. {
  192. RecipeNode childNode = new RecipeNode();
  193. childNode.Name = file.Name.Substring(0, file.Name.IndexOf($".{recipeType}"));
  194. childNode.NodeType = RecipeNodeType.File;
  195. childNode.RecipeLocation = info.Name;
  196. childNode.FileName = file.Name;
  197. childNode.RecipeFullFileName = file.FullName;
  198. treeNodes.Add(childNode);
  199. }
  200. }
  201. }
  202. }
  203. return treeNodes;
  204. }
  205. catch (Exception ex)
  206. {
  207. LOG.WriteExeption(ex);
  208. return new ObservableCollection<RecipeNode>();
  209. }
  210. }
  211. /// <summary>
  212. /// 加载指定类型的Recipe
  213. /// </summary>
  214. /// <param name="recipeType"></param>
  215. /// <returns></returns>
  216. public ObservableCollection<RecipeNode> GetRecipesByType(string recipeType)
  217. {
  218. try
  219. {
  220. ObservableCollection<RecipeNode> treeNodes = new ObservableCollection<RecipeNode>();
  221. string recipePath = PathManager.GetRecipeDir() ;
  222. var di = new DirectoryInfo(recipePath);
  223. DirectoryInfo[] infos= di.GetDirectories();
  224. var recipes = new List<string>();
  225. foreach (var info in infos)
  226. {
  227. RecipeNode treeNode = new RecipeNode();
  228. treeNode.Name = info.Name;
  229. treeNode.NodeType = RecipeNodeType.Directory;
  230. treeNode.Children =new ObservableCollection<RecipeNode>();
  231. FileInfo[] files = info.GetFiles();
  232. recipes.Add(info.Name);
  233. foreach(FileInfo file in files)
  234. {
  235. if (file.Name.Contains($".{recipeType}."))
  236. {
  237. RecipeNode childNode = new RecipeNode();
  238. childNode.Name = file.Name.Substring(0,file.Name.IndexOf($".{recipeType}"));
  239. childNode.NodeType = RecipeNodeType.File;
  240. childNode.RecipeLocation = info.Name;
  241. childNode.FileName = file.Name;
  242. childNode.RecipeFullFileName = file.FullName;
  243. treeNode.Children.Add(childNode);
  244. }
  245. }
  246. treeNodes.Add(treeNode);
  247. }
  248. return treeNodes;
  249. }
  250. catch (Exception ex)
  251. {
  252. LOG.WriteExeption(ex);
  253. return new ObservableCollection<RecipeNode>();
  254. }
  255. }
  256. /// <summary>
  257. /// 获取目录集合节点
  258. /// </summary>
  259. /// <param name="directories"></param>
  260. /// <returns></returns>
  261. public ObservableCollection<RecipeNode> GetRecipeByDirectoryList(List<string> directories)
  262. {
  263. try
  264. {
  265. ObservableCollection<RecipeNode> treeNodes = new ObservableCollection<RecipeNode>();
  266. string recipePath = PathManager.GetRecipeDir();
  267. var di = new DirectoryInfo(recipePath);
  268. DirectoryInfo[] infos = di.GetDirectories();
  269. var recipes = new List<string>();
  270. foreach (var info in infos)
  271. {
  272. if (directories.Contains(info.Name))
  273. {
  274. RecipeNode treeNode = new RecipeNode();
  275. treeNode.Name = info.Name;
  276. treeNode.NodeType = RecipeNodeType.Directory;
  277. treeNode.Children = new ObservableCollection<RecipeNode>();
  278. FileInfo[] files = info.GetFiles();
  279. recipes.Add(info.Name);
  280. foreach (FileInfo file in files)
  281. {
  282. if (file.Name.EndsWith($".rcp"))
  283. {
  284. RecipeNode childNode = new RecipeNode();
  285. string recipeTypeName = file.Name.Substring(0, file.Name.IndexOf($".rcp"));
  286. int recipeTypeIndex = recipeTypeName.LastIndexOf(".");
  287. if (recipeTypeIndex != -1)
  288. {
  289. childNode.Name = recipeTypeName.Substring(0, recipeTypeIndex);
  290. childNode.NodeType = RecipeNodeType.File;
  291. childNode.RecipeLocation = info.Name;
  292. childNode.FileName = file.Name;
  293. childNode.RecipeFullFileName = file.FullName;
  294. treeNode.Children.Add(childNode);
  295. }
  296. }
  297. }
  298. treeNodes.Add(treeNode);
  299. }
  300. }
  301. return treeNodes;
  302. }
  303. catch (Exception ex)
  304. {
  305. LOG.WriteExeption(ex);
  306. return new ObservableCollection<RecipeNode>();
  307. }
  308. }
  309. /// <summary>
  310. /// 删除Recipe文件
  311. /// </summary>
  312. /// <param name="fullPath"></param>
  313. /// <returns></returns>
  314. public bool DeleteRecipeByFullPath(string fullPath)
  315. {
  316. try
  317. {
  318. if (File.Exists(fullPath))
  319. {
  320. File.Delete(fullPath);
  321. }
  322. }
  323. catch (Exception ex)
  324. {
  325. LOG.WriteExeption("delete recipe file error", ex);
  326. return false;
  327. }
  328. return true;
  329. }
  330. public bool PromoteRecipe(List<string> FilePaths)
  331. {
  332. try
  333. {
  334. foreach (var SourceFilePath in FilePaths)
  335. {
  336. string TargetFilePath = SourceFilePath.Replace("Engineering", "Production");
  337. File.Copy(SourceFilePath, TargetFilePath, true);
  338. }
  339. }
  340. catch (Exception ex)
  341. {
  342. LOG.WriteExeption("Promote recipe file error", ex);
  343. return false;
  344. }
  345. return true;
  346. }
  347. /// <summary>
  348. /// 加载Recipe
  349. /// </summary>
  350. /// <typeparam name="T"></typeparam>
  351. /// <param name="recipeFileFullName"></param>
  352. /// <returns></returns>
  353. public T LoadGenericityRecipe<T>(string recipeFileFullName)
  354. {
  355. try
  356. {
  357. return CustomXmlSerializer.Deserialize<T>(new FileInfo(recipeFileFullName));
  358. }
  359. catch
  360. {
  361. return default(T);
  362. }
  363. }
  364. /// <summary>
  365. /// Get recipe list in xml format
  366. /// </summary>
  367. /// <param name="chamId"></param>
  368. /// <param name="includingUsedRecipe"></param>
  369. /// <returns></returns>
  370. public string GetXmlRecipeList(string chamberId, bool includingUsedRecipe)
  371. {
  372. XmlDocument doc = new XmlDocument();
  373. var baseFolderPath = getRecipeDirPath(chamberId);
  374. DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath);
  375. doc.AppendChild(GenerateRecipeList(chamberId, curFolderInfo, doc, includingUsedRecipe));
  376. return doc.OuterXml;
  377. }
  378. /// <summary>
  379. /// generate recipe list information in current directory
  380. /// </summary>
  381. /// <param name="chamId"></param>
  382. /// <param name="currentDir"></param>
  383. /// <param name="doc"></param>
  384. /// <returns></returns>
  385. XmlElement GenerateRecipeList(string chamberId, DirectoryInfo currentDir, XmlDocument doc, bool includingUsedRecipe)
  386. {
  387. int trimLength = getRecipeDirPath(chamberId).Length;
  388. XmlElement folderEle = doc.CreateElement("Folder");
  389. folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength));
  390. DirectoryInfo[] dirInfos = currentDir.GetDirectories();
  391. foreach (DirectoryInfo dirInfo in dirInfos)
  392. {
  393. if (!includingUsedRecipe && dirInfo.Name == "HistoryRecipe")
  394. continue;
  395. folderEle.AppendChild(GenerateRecipeList(chamberId, dirInfo, doc, includingUsedRecipe));
  396. }
  397. FileInfo[] fileInfos = currentDir.GetFiles("*.rcp");
  398. foreach (FileInfo fileInfo in fileInfos)
  399. {
  400. XmlElement fileNd = doc.CreateElement("File");
  401. string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ;
  402. fileStr = fileStr.Substring(0, fileStr.LastIndexOf("."));
  403. fileNd.SetAttribute("Name", fileStr);
  404. folderEle.AppendChild(fileNd);
  405. }
  406. return folderEle;
  407. }
  408. /// <summary>
  409. /// Delete a recipe by recipe name
  410. /// </summary>
  411. /// <param name="chamId"></param>
  412. /// <param name="recipeName"></param>
  413. /// <returns></returns>
  414. public bool DeleteRecipe(string chamberId, string recipeName)
  415. {
  416. try
  417. {
  418. var path = GenerateRecipeFilePath(chamberId, recipeName);
  419. if (!_rcpContext.EnableEdit(path))
  420. return false;
  421. File.Delete(path);
  422. InfoDialog(string.Format(Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteSucceeded, recipeName));
  423. }
  424. catch (Exception ex)
  425. {
  426. LOG.WriteExeption("Delete recipe file error", ex);
  427. WarningDialog(string.Format(Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteFailed, recipeName));
  428. return false;
  429. }
  430. return true;
  431. }
  432. /// <summary>
  433. /// Rename recipe
  434. /// </summary>
  435. /// <param name="chamId"></param>
  436. /// <param name="oldName"></param>
  437. /// <param name="newName"></param>
  438. /// <returns></returns>
  439. public bool RenameRecipe(string chamId, string oldName, string newName)
  440. {
  441. try
  442. {
  443. var path = GenerateRecipeFilePath(chamId, newName);
  444. if (!_rcpContext.EnableEdit(path))
  445. return false;
  446. if (File.Exists(path))
  447. {
  448. WarningDialog(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0FileExisted, oldName));
  449. return false;
  450. }
  451. else
  452. {
  453. File.Move(GenerateRecipeFilePath(chamId, oldName), GenerateRecipeFilePath(chamId, newName));
  454. InfoDialog(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0Renamed, oldName, newName));
  455. }
  456. }
  457. catch (Exception ex)
  458. {
  459. LOG.WriteExeption("Rename recipe file error", ex);
  460. WarningDialog(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0RenameFailed, oldName, newName));
  461. return false;
  462. }
  463. return true;
  464. }
  465. private void InfoDialog(string message)
  466. {
  467. _rcpContext.PostInfoDialogMessage(message);
  468. }
  469. private void WarningDialog(string message)
  470. {
  471. _rcpContext.PostWarningDialogMessage(message);
  472. }
  473. /// <summary>
  474. /// get recipe's file path
  475. /// </summary>
  476. /// <param name="recipeName"></param>
  477. /// <returns></returns>
  478. private string GenerateRecipeFilePath(string chamId, string recipeName)
  479. {
  480. return getRecipeDirPath(chamId) + recipeName + ".rcp";
  481. }
  482. private string GenerateRecipeFilePath2(string chamId, string type,string recipeName)
  483. {
  484. return getRecipeDirPath(chamId) +type+"\\"+ recipeName + ".rcp";
  485. }
  486. private string GenerateSequenceFilePath(string chamId, string recipeName)
  487. {
  488. return getRecipeDirPath(chamId) + recipeName + ".seq";
  489. }
  490. /// <summary>
  491. /// get recipe's dir path
  492. /// </summary>
  493. /// <param name="recipeName"></param>
  494. /// <returns></returns>
  495. private string getRecipeDirPath(string chamId)
  496. {
  497. var dir = string.Format("{0}{1}\\", PathManager.GetRecipeDir(), chamId);
  498. DirectoryInfo di = new DirectoryInfo(dir);
  499. if (!di.Exists) di.Create();
  500. return dir;
  501. }
  502. /// <summary>
  503. /// 保存Recipe
  504. /// </summary>
  505. /// <param name="root"></param>
  506. /// <param name="recipeName"></param>
  507. /// <param name="recipe"></param>
  508. /// <param name="recipeType"></param>
  509. public void SaveGenericityRecipe(string root, string recipeName, string recipeType, object recipe)
  510. {
  511. try
  512. {
  513. string recipeDir = PathManager.GetRecipeDir();
  514. string fullName = $"{recipeDir}{root}\\{recipeName}.{recipeType}.rcp";
  515. CustomXmlSerializer.Serialize(recipe, fullName);
  516. }
  517. catch (Exception ex)
  518. {
  519. LOG.Write(eEvent.ERR_EXCEPTION, "Recipe", $"Saving Recipe is failed. Can't access the target recipe file:{recipeName}.{recipeType}.rcp");
  520. }
  521. }
  522. /// <summary>
  523. /// delete a recipe folder
  524. /// </summary>
  525. /// <param name="chamId"></param>
  526. /// <param name="folderName"></param>
  527. /// <returns></returns>
  528. public bool DeleteFolder(string chamId, string folderName)
  529. {
  530. try
  531. {
  532. Directory.Delete(getRecipeDirPath(chamId) + folderName, true);
  533. InfoDialog(string.Format(Resources.RecipeFileManager_DeleteFolder_RecipeFolder0DeleteSucceeded, folderName));
  534. }
  535. catch (Exception ex)
  536. {
  537. LOG.WriteExeption("Delete recipe folder error", ex);
  538. WarningDialog(string.Format("recipe folder {0} delete failed", folderName));
  539. return false;
  540. }
  541. return true;
  542. }
  543. /// <summary>
  544. /// save as recipe content
  545. /// </summary>
  546. /// <param name="chamId"></param>
  547. /// <param name="recipeName"></param>
  548. /// <param name="recipeContent"></param>
  549. /// <returns></returns>
  550. public bool SaveAsRecipe(string chamId, string recipeName, string recipeContent)
  551. {
  552. var path = GenerateRecipeFilePath(chamId, recipeName);
  553. //if (File.Exists(path))
  554. //{
  555. // WarningDialog(string.Format(Resources.RecipeFileManager_SaveAsRecipe_RecipeFile0savefailed, recipeName));
  556. // return false;
  557. //}
  558. return SaveRecipe(chamId, recipeName, recipeContent, true, true);
  559. }
  560. public bool SaveAsRecipe2(string chamId,string type, string recipeName, string recipeContent)
  561. {
  562. var path = GenerateRecipeFilePath(chamId, recipeName);
  563. //if (File.Exists(path))
  564. //{
  565. // WarningDialog(string.Format(Resources.RecipeFileManager_SaveAsRecipe_RecipeFile0savefailed, recipeName));
  566. // return false;
  567. //}
  568. return SaveRecipe2(chamId,type, recipeName, recipeContent, true, true);
  569. }
  570. /// <summary>
  571. /// save recipe content
  572. /// </summary>
  573. /// <param name="chamId"></param>
  574. /// <param name="recipeName"></param>
  575. /// <param name="recipeContent"></param>
  576. /// <returns></returns>
  577. public bool SaveRecipe(string chamId, string recipeName, string recipeContent, bool clearBarcode, bool notifyUI)
  578. {
  579. bool ret = true;
  580. try
  581. {
  582. var path = GenerateRecipeFilePath(chamId, recipeName);
  583. if (!_rcpContext.EnableEdit(path))
  584. return false;
  585. FileInfo fi = new FileInfo(path);
  586. if (!fi.Directory.Exists)
  587. fi.Directory.Create();
  588. File.WriteAllText(path, RecipeUnity.ConvertJsonString(recipeContent), Encoding.UTF8);
  589. }
  590. catch (Exception ex)
  591. {
  592. LOG.WriteExeption("Save recipe file error", ex);
  593. if (notifyUI)
  594. {
  595. WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveFailed, recipeName));
  596. }
  597. ret = false;
  598. }
  599. return ret;
  600. }
  601. /// <summary>
  602. /// save recipe content
  603. /// </summary>
  604. /// <param name="chamId"></param>
  605. /// <param name="recipeName"></param>
  606. /// <param name="recipeContent"></param>
  607. /// <returns></returns>
  608. public bool SaveRecipe2(string chamId,string type, string recipeName, string recipeContent, bool clearBarcode, bool notifyUI)
  609. {
  610. bool ret = true;
  611. try
  612. {
  613. var path = GenerateRecipeFilePath2(chamId, type, recipeName);
  614. if (!_rcpContext.EnableEdit(path))
  615. return false;
  616. FileInfo fi = new FileInfo(path);
  617. if (!fi.Directory.Exists)
  618. fi.Directory.Create();
  619. File.WriteAllText(path, RecipeUnity.ConvertJsonString(recipeContent), Encoding.UTF8);
  620. }
  621. catch (Exception ex)
  622. {
  623. LOG.WriteExeption("Save recipe file error", ex);
  624. if (notifyUI)
  625. {
  626. WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveFailed, recipeName));
  627. }
  628. ret = false;
  629. }
  630. return ret;
  631. }
  632. /// <summary>
  633. /// move recipe file
  634. /// </summary>
  635. /// <param name="chamId"></param>
  636. /// <param name="recipeName"></param>
  637. /// <returns></returns>
  638. public bool MoveRecipeFile(string chamId, string recipeName, string tragetFolderName, bool clearBarcode, bool notifyUI)
  639. {
  640. bool ret = true;
  641. try
  642. {
  643. var path = getRecipeDirPath(chamId);
  644. string fullFileName = path + recipeName + ".rcp";
  645. string tragetFullFilePath = path + tragetFolderName;
  646. File.Move(fullFileName, tragetFullFilePath + "\\" + recipeName.Split('\\')[recipeName.Split('\\').Length - 1] + ".rcp");
  647. if (notifyUI)
  648. {
  649. InfoDialog(string.Format(Resources.RecipeFileManager_MoveRecipe_RecipeFile0MoveCompleted, recipeName));
  650. }
  651. else
  652. {
  653. LOG.Write(eEvent.EV_SEQUENCE, ModuleName.System, string.Format(Resources.RecipeFileManager_MoveRecipe_RecipeFile0MoveCompleted, recipeName));
  654. }
  655. }
  656. catch (Exception ex)
  657. {
  658. LOG.WriteExeption("Move recipe file error", ex);
  659. if (notifyUI)
  660. {
  661. WarningDialog(string.Format(Resources.RecipeFileManager_MoveRecipe_RecipeFile0MoveFailed, recipeName));
  662. }
  663. ret = false;
  664. }
  665. return ret;
  666. }
  667. /// <summary>
  668. /// create a new recipe folder
  669. /// </summary>
  670. /// <param name="chamId"></param>
  671. /// <param name="folderName"></param>
  672. /// <returns></returns>
  673. public bool CreateFolder(string chamId, string folderName)
  674. {
  675. try
  676. {
  677. Directory.CreateDirectory(getRecipeDirPath(chamId) + folderName);
  678. InfoDialog(string.Format(Resources.RecipeFileManager_CreateFolder_RecipeFolder0Created, folderName));
  679. }
  680. catch (Exception ex)
  681. {
  682. LOG.WriteExeption("Create recipe folder error", ex);
  683. WarningDialog(string.Format(Resources.RecipeFileManager_CreateFolder_RecipeFolder0CreateFailed, folderName));
  684. return false;
  685. }
  686. return true;
  687. }
  688. /// <summary>
  689. /// Rename recipe folder name
  690. /// </summary>
  691. /// <param name="chamId"></param>
  692. /// <param name="oldName"></param>
  693. /// <param name="newName"></param>
  694. /// <returns></returns>
  695. public bool RenameFolder(string chamId, string oldName, string newName)
  696. {
  697. try
  698. {
  699. string oldPath = getRecipeDirPath(chamId) + oldName;
  700. string newPath = getRecipeDirPath(chamId) + newName;
  701. Directory.Move(oldPath, newPath);
  702. InfoDialog(string.Format(Resources.RecipeFileManager_RenameFolder_RecipeFolder0renamed, oldName, newName));
  703. }
  704. catch (Exception ex)
  705. {
  706. LOG.WriteExeption("Rename recipe folder error", ex);
  707. WarningDialog(string.Format(Resources.RecipeFileManager_RenameFolder_RecipeFolder0RenameFailed, oldName, newName));
  708. return false;
  709. }
  710. return true;
  711. }
  712. private string GetRecipeBody(string chamberId, string nodePath)
  713. {
  714. if (_rcpContext == null)
  715. return string.Empty;
  716. string schema = _rcpContext.GetRecipeDefiniton(chamberId);
  717. XmlDocument dom = new XmlDocument();
  718. dom.LoadXml(schema);
  719. XmlNode node = dom.SelectSingleNode(nodePath);
  720. return node.OuterXml;
  721. }
  722. /// <summary>
  723. /// get reactor's recipe format define file
  724. /// </summary>
  725. /// <param name="chamId"></param>
  726. /// <returns></returns>
  727. public string GetRecipeFormatXml(string chamberId)
  728. {
  729. return GetRecipeBody(chamberId, "/Aitex/TableRecipeFormat");
  730. }
  731. /// <summary>
  732. /// get reactor's template recipe file
  733. /// </summary>
  734. /// <param name="chamId"></param>
  735. /// <returns></returns>
  736. public string GetRecipeTemplate(string chamberId)
  737. {
  738. if (_rcpContext != null)
  739. return _rcpContext.GetRecipeTemplate(chamberId);
  740. return GetRecipeBody(chamberId, "/Aitex/TableRecipeData");
  741. }
  742. /// <summary>
  743. /// get reactor's template recipe file
  744. /// </summary>
  745. /// <param name="chamId"></param>
  746. /// <returns></returns>
  747. public string GetRecipeSchema(string chamberId)
  748. {
  749. if (_rcpContext == null)
  750. return string.Empty;
  751. string schema = _rcpContext.GetRecipeDefiniton(chamberId);
  752. XmlDocument dom = new XmlDocument();
  753. dom.LoadXml(schema);
  754. XmlNode node = dom.SelectSingleNode("/Aitex/TableRecipeSchema");
  755. return node.InnerXml;
  756. }
  757. #region Sequence
  758. private string GetSequenceConfig(string nodePath)
  759. {
  760. if (_seqContext == null)
  761. return string.Empty;
  762. string schema = _seqContext.GetConfigXml();
  763. XmlDocument dom = new XmlDocument();
  764. dom.LoadXml(schema);
  765. XmlNode node = dom.SelectSingleNode(nodePath);
  766. return node.OuterXml;
  767. }
  768. public string GetSequence(string sequenceName, bool needValidation)
  769. {
  770. string seq = string.Empty;
  771. try
  772. {
  773. using (StreamReader fs = new StreamReader(GenerateSequenceFilePath(SequenceFolder, sequenceName)))
  774. {
  775. seq = fs.ReadToEnd();
  776. fs.Close();
  777. }
  778. if (needValidation && !_seqContext.Validation(seq))
  779. {
  780. LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"Read {sequenceName} failed, validation failed");
  781. seq = string.Empty;
  782. }
  783. }
  784. catch (Exception ex)
  785. {
  786. LOG.WriteExeption(ex);
  787. seq = string.Empty;
  788. }
  789. return seq;
  790. }
  791. private void TryAppendNode(XmlElement preOrNextNode, XmlElement curPM,XmlDocument dom, bool isLeft)
  792. {
  793. if (preOrNextNode != null && preOrNextNode.GetAttribute("Position") != "LL" && preOrNextNode.GetAttribute("Position") != "PM")
  794. {
  795. XmlElement newNode = dom.CreateElement("Step");
  796. newNode.SetAttribute("Position", "LL");
  797. newNode.SetAttribute("LLSelection", "LLA,LLB");
  798. if (isLeft)
  799. curPM.ParentNode.InsertBefore(newNode, curPM);
  800. else
  801. curPM.ParentNode.InsertAfter(newNode, curPM);
  802. }
  803. }
  804. public string GetSequenceAndTryAppendLL(string sequenceName, bool needValidation)
  805. {
  806. string seq = string.Empty;
  807. try
  808. {
  809. seq = GetSequence(sequenceName, needValidation);
  810. if(!string.IsNullOrWhiteSpace(seq))
  811. {
  812. XmlDocument dom = new XmlDocument();
  813. dom.LoadXml(seq);
  814. XmlNodeList lstStepNode = dom.SelectNodes("Aitex/TableSequenceData/Step");
  815. if (lstStepNode != null)
  816. {
  817. List<XmlElement> pmList = new List<XmlElement>();
  818. foreach (XmlElement nodeStep in lstStepNode)
  819. {
  820. var positionValue = nodeStep.GetAttribute("Position");
  821. if (positionValue == "PM")
  822. {
  823. pmList.Add(nodeStep);
  824. }
  825. }
  826. foreach (XmlElement pmNode in pmList)
  827. {
  828. TryAppendNode((XmlElement)pmNode.PreviousSibling, pmNode, dom, true);
  829. TryAppendNode((XmlElement)pmNode.NextSibling, pmNode, dom, false);
  830. }
  831. using (var ms = new MemoryStream())
  832. using (var writer = new XmlTextWriter(ms, null))
  833. {
  834. writer.Formatting = Formatting.Indented;
  835. dom.Save(writer);
  836. return Encoding.UTF8.GetString(ms.ToArray());
  837. }
  838. }
  839. }
  840. }
  841. catch(Exception ex)
  842. {
  843. LOG.WriteExeption(ex);
  844. seq = string.Empty;
  845. }
  846. return seq;
  847. }
  848. public List<string> GetSequenceNameList()
  849. {
  850. var result = new List<string>();
  851. try
  852. {
  853. string recipePath = PathManager.GetRecipeDir() + SequenceFolder + "\\";
  854. var di = new DirectoryInfo(recipePath);
  855. var fis = di.GetFiles("*.seq.*", SearchOption.AllDirectories);
  856. foreach (var fi in fis)
  857. {
  858. string str = fi.FullName.Substring(recipePath.Length);
  859. str = str.Substring(0, str.LastIndexOf('.'));
  860. result.Add(str);
  861. }
  862. }
  863. catch (Exception ex)
  864. {
  865. LOG.WriteExeption(ex);
  866. }
  867. return result;
  868. }
  869. public bool DeleteSequence(string sequenceName)
  870. {
  871. try
  872. {
  873. var path = GenerateSequenceFilePath(SequenceFolder, sequenceName);
  874. if (!_seqContext.EnableEdit(path))
  875. return false;
  876. File.Delete(path);
  877. LOG.Write(eEvent.EV_SEQUENCE, ModuleName.System, $"sequence {sequenceName} deleted");
  878. }
  879. catch (Exception ex)
  880. {
  881. LOG.WriteExeption(ex);
  882. return false;
  883. }
  884. return true;
  885. }
  886. public bool SaveSequence(string sequenceName, string sequenceContent, bool notifyUI)
  887. {
  888. bool ret = true;
  889. try
  890. {
  891. var path = GenerateSequenceFilePath(SequenceFolder, sequenceName);
  892. if (!_seqContext.EnableEdit(path))
  893. return false;
  894. FileInfo fi = new FileInfo(path);
  895. if (!fi.Directory.Exists)
  896. {
  897. fi.Directory.Create();
  898. }
  899. XmlDocument xml = new XmlDocument();
  900. xml.LoadXml(sequenceContent);
  901. XmlTextWriter writer = new XmlTextWriter(path, null);
  902. writer.Formatting = Formatting.Indented;
  903. xml.Save(writer);
  904. writer.Close();
  905. if (notifyUI)
  906. {
  907. EV.PostPopDialogMessage(EventLevel.Information, "Save Complete", $"Sequence {sequenceName} saved ");
  908. }
  909. else
  910. {
  911. LOG.Write(eEvent.EV_SEQUENCE, ModuleName.System, $"Sequence {sequenceName} saved ");
  912. }
  913. }
  914. catch (Exception ex)
  915. {
  916. LOG.WriteExeption(ex);
  917. if (notifyUI)
  918. {
  919. EV.PostPopDialogMessage(EventLevel.Alarm, "Save Error", $"save sequence {sequenceName} failed, " + ex.Message);
  920. }
  921. ret = false;
  922. }
  923. return ret;
  924. }
  925. public bool SaveAsSequence(string sequenceName, string sequenceContent)
  926. {
  927. var path = GenerateSequenceFilePath(SequenceFolder, sequenceName);
  928. if (File.Exists(path))
  929. {
  930. LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"save sequence {sequenceName} failed, already exist");
  931. return false;
  932. }
  933. return SaveSequence(sequenceName, sequenceContent, false);
  934. }
  935. public bool RenameSequence(string oldName, string newName)
  936. {
  937. try
  938. {
  939. var path = GenerateSequenceFilePath(SequenceFolder, oldName);
  940. if (!_seqContext.EnableEdit(path))
  941. return false;
  942. if (File.Exists(GenerateSequenceFilePath(SequenceFolder, newName)))
  943. {
  944. LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"{newName} already exist, rename failed");
  945. return false;
  946. }
  947. else
  948. {
  949. File.Move(path, GenerateSequenceFilePath(SequenceFolder, newName));
  950. LOG.Write(eEvent.EV_SEQUENCE, ModuleName.System, $"sequence {oldName} renamed to {newName}");
  951. }
  952. }
  953. catch (Exception ex)
  954. {
  955. LOG.WriteExeption(ex);
  956. return false;
  957. }
  958. return true;
  959. }
  960. public string GetSequenceFormatXml()
  961. {
  962. return GetSequenceConfig("/Aitex/TableSequenceFormat");
  963. }
  964. internal bool DeleteSequenceFolder(string folderName)
  965. {
  966. try
  967. {
  968. Directory.Delete(PathManager.GetRecipeDir() + SequenceFolder + "\\" + folderName, true);
  969. LOG.Write(eEvent.EV_SEQUENCE,ModuleName.System, "Folder " + folderName + "deleted");
  970. }
  971. catch (Exception ex)
  972. {
  973. //LOG.Write(ex, "delete sequence folder exception");
  974. LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"can not delete folder {folderName}, {ex.Message}");
  975. return false;
  976. }
  977. return true;
  978. }
  979. internal bool CreateSequenceFolder(string folderName)
  980. {
  981. try
  982. {
  983. Directory.CreateDirectory(PathManager.GetRecipeDir() + SequenceFolder + "\\" + folderName);
  984. LOG.Write(eEvent.EV_SEQUENCE, ModuleName.System, "Folder " + folderName + "created");
  985. }
  986. catch (Exception ex)
  987. {
  988. //LOG.Write(ex, "sequence folder create exception");
  989. LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"can not create folder {folderName}, {ex.Message}");
  990. return false;
  991. }
  992. return true;
  993. }
  994. internal bool RenameSequenceFolder(string oldName, string newName)
  995. {
  996. try
  997. {
  998. string oldPath = PathManager.GetRecipeDir() + SequenceFolder + "\\" + oldName;
  999. string newPath = PathManager.GetRecipeDir() + SequenceFolder + "\\" + newName;
  1000. Directory.Move(oldPath, newPath);
  1001. LOG.Write(eEvent.EV_SEQUENCE, ModuleName.System, $"rename folder from {oldName} to {newName}");
  1002. }
  1003. catch (Exception ex)
  1004. {
  1005. //LOG.Write(ex, "rename sequence folder failed");
  1006. LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"can not rename folder {oldName}, {ex.Message}");
  1007. return false;
  1008. }
  1009. return true;
  1010. }
  1011. public string GetXmlSequenceList(string chamberId)
  1012. {
  1013. XmlDocument doc = new XmlDocument();
  1014. DirectoryInfo curFolderInfo = new DirectoryInfo(PathManager.GetRecipeDir() + SequenceFolder + "\\");
  1015. doc.AppendChild(GenerateSequenceList(chamberId, curFolderInfo, doc));
  1016. return doc.OuterXml;
  1017. }
  1018. XmlElement GenerateSequenceList(string chamberId, DirectoryInfo currentDir, XmlDocument doc)
  1019. {
  1020. int trimLength = (PathManager.GetRecipeDir() + SequenceFolder + "\\").Length;
  1021. XmlElement folderEle = doc.CreateElement("Folder");
  1022. folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength));
  1023. DirectoryInfo[] dirInfos = currentDir.GetDirectories();
  1024. foreach (DirectoryInfo dirInfo in dirInfos)
  1025. {
  1026. folderEle.AppendChild(GenerateSequenceList(chamberId, dirInfo, doc));
  1027. }
  1028. FileInfo[] fileInfos = currentDir.GetFiles("*.seq");
  1029. foreach (FileInfo fileInfo in fileInfos)
  1030. {
  1031. XmlElement fileNd = doc.CreateElement("File");
  1032. string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ;
  1033. fileStr = fileStr.Substring(0, fileStr.LastIndexOf("."));
  1034. fileNd.SetAttribute("Name", fileStr);
  1035. folderEle.AppendChild(fileNd);
  1036. }
  1037. return folderEle;
  1038. }
  1039. /// <summary>
  1040. /// 获取Sequence(Recipes)文件路径的子目录
  1041. /// </summary>
  1042. /// <returns></returns>
  1043. public List<String> GetSequenceList(string recipeType, string sequenceType)
  1044. {
  1045. var result = new List<string>();
  1046. try
  1047. {
  1048. string recipePath;
  1049. if (sequenceType == "Engineering")
  1050. {
  1051. recipePath = PathManager.GetRecipeDir() + EngineeringFolder + "\\";
  1052. }
  1053. else if(sequenceType == "Production")
  1054. {
  1055. recipePath = PathManager.GetRecipeDir() + ProductionFolder + "\\";
  1056. }
  1057. else
  1058. {
  1059. return null;
  1060. }
  1061. var di = new DirectoryInfo(recipePath);
  1062. var fis = di.GetFiles($"*.{recipeType}.*", SearchOption.TopDirectoryOnly);
  1063. foreach (var fi in fis)
  1064. {
  1065. string str = fi.FullName.Substring(recipePath.Length);
  1066. str = str.Substring(0, str.LastIndexOf($".{recipeType}"));
  1067. result.Add(str);
  1068. }
  1069. }
  1070. catch (Exception ex)
  1071. {
  1072. LOG.WriteExeption(ex);
  1073. }
  1074. return result;
  1075. }
  1076. #endregion
  1077. #region FA相关
  1078. /// <summary>
  1079. /// 获取recipe集合
  1080. /// </summary>
  1081. /// <returns></returns>
  1082. public string[] GetProductionRecipeList()
  1083. {
  1084. List<string> lst = new List<string>();
  1085. try
  1086. {
  1087. string path = PathManager.GetRecipeDir() + ProductionFolder + "\\";
  1088. DirectoryInfo directoryInfo = new DirectoryInfo(path);
  1089. FileInfo[] files = directoryInfo.GetFiles($"*.rcp", SearchOption.TopDirectoryOnly);
  1090. foreach (var fi in files)
  1091. {
  1092. lst.Add($"{ProductionFolder}\\{fi.Name}");
  1093. }
  1094. }
  1095. catch(Exception ex)
  1096. {
  1097. LOG.WriteExeption(ex);
  1098. }
  1099. return lst.ToArray();
  1100. }
  1101. /// <summary>
  1102. /// 加载recipe内容
  1103. /// </summary>
  1104. /// <param name="recipeName"></param>
  1105. /// <returns></returns>
  1106. public string LoadRecipeContent(string recipeName)
  1107. {
  1108. string rcp = string.Empty;
  1109. try
  1110. {
  1111. string path = PathManager.GetRecipeDir() + ProductionFolder + "\\";
  1112. using (StreamReader fs = new StreamReader($"{PathManager.GetRecipeDir()}{ProductionFolder}\\{recipeName}"))
  1113. {
  1114. rcp = fs.ReadToEnd();
  1115. fs.Close();
  1116. }
  1117. }
  1118. catch (Exception ex)
  1119. {
  1120. LOG.WriteExeption($"load recipe file failed, {recipeName}", ex);
  1121. rcp = string.Empty;
  1122. }
  1123. return rcp;
  1124. }
  1125. #endregion
  1126. }
  1127. }