RecipeFileManager.cs 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows.Forms.VisualStyles;
  6. using System.Xml.Schema;
  7. using System.Xml;
  8. using System.IO;
  9. using Aitex.Core.Properties;
  10. using Aitex.Core.RT.Log;
  11. using System.Text.RegularExpressions;
  12. using Aitex.Common.Util;
  13. using Aitex.Core.RT.Event;
  14. using Aitex.Core.Util;
  15. namespace Aitex.Core.RT.RecipeCenter
  16. {
  17. public class RecipeFileManager : Singleton<RecipeFileManager>
  18. {
  19. private bool _recipeIsValid;
  20. private List<string> _validationErrors = new List<string>();
  21. private List<string> _validationWarnings = new List<string>();
  22. IRecipeFileContext _context;
  23. public void Initialize(IRecipeFileContext context)
  24. {
  25. _context = context;
  26. }
  27. private void ValidationEventHandler(object sender, ValidationEventArgs e)
  28. {
  29. switch (e.Severity)
  30. {
  31. case XmlSeverityType.Error:
  32. _validationErrors.Add(e.Message);
  33. _recipeIsValid = false;
  34. break;
  35. case XmlSeverityType.Warning:
  36. _validationWarnings.Add(e.Message);
  37. break;
  38. }
  39. }
  40. /// <summary>
  41. /// XML schema checking
  42. /// </summary>
  43. /// <param name="chamId"></param>
  44. /// <param name="recipeName"></param>
  45. /// <param name="recipeContent"></param>
  46. /// <param name="reason"></param>
  47. /// <returns></returns>
  48. public bool ValidateRecipe(string chamberId, string recipeName, string recipeContent, out List<string> reason)
  49. {
  50. try
  51. {
  52. XmlDocument document = new XmlDocument();
  53. document.LoadXml(recipeContent);
  54. MemoryStream schemaStream = new MemoryStream(ASCIIEncoding.ASCII.GetBytes(GetRecipeSchema(chamberId)));
  55. XmlReader xmlSchemaReader = XmlReader.Create(schemaStream);
  56. XmlSchema schema1 = XmlSchema.Read(xmlSchemaReader, ValidationEventHandler);
  57. document.Schemas.Add(schema1);
  58. document.LoadXml(recipeContent);
  59. ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);
  60. _recipeIsValid = true;
  61. _validationErrors = new List<string>();
  62. _validationWarnings = new List<string>();
  63. // Validates recipe.
  64. document.Validate(eventHandler);
  65. }
  66. catch (Exception ex)
  67. {
  68. LOG.Write(ex.Message);
  69. _recipeIsValid = false;
  70. }
  71. if (!_recipeIsValid && _validationErrors.Count == 0)
  72. {
  73. _validationErrors.Add( Resources.RecipeFileManager_ValidateRecipe_XMLSchemaValidateFailed);
  74. }
  75. reason = _validationErrors;
  76. return _recipeIsValid;
  77. }
  78. /// <summary>
  79. /// Check recipe content
  80. /// </summary>
  81. /// <param name="chamId"></param>
  82. /// <param name="recipeContent"></param>
  83. /// <param name="reasons"></param>
  84. /// <returns></returns>
  85. public bool CheckRecipe(string chamberId, string recipeContent, out List<string> reasons)
  86. {
  87. reasons = new List<string>();
  88. //add recipe content validation here
  89. try
  90. {
  91. var xmlFormat = new XmlDocument();
  92. xmlFormat.LoadXml(GetRecipeFormatXml(chamberId));
  93. var mfcDic = new Dictionary<string, double>(); //name + scale
  94. var pcDic = new Dictionary<string, double>(); //name + scale
  95. foreach (XmlElement mfc in xmlFormat.SelectNodes("/TableRecipeFormat/Catalog/Group/Step[@DeviceType='MFC']"))
  96. {
  97. mfcDic.Add(mfc.Attributes["ControlName"].Value, Convert.ToDouble(mfc.Attributes["Max"].Value));
  98. }
  99. foreach (XmlElement pc in xmlFormat.SelectNodes("/TableRecipeFormat/Catalog/Group/Step[@DeviceType='PC']"))
  100. {
  101. pcDic.Add(pc.Attributes["ControlName"].Value, Convert.ToDouble(pc.Attributes["Max"].Value));
  102. }
  103. //var spindleMaxSpeed = Convert.ToDouble(xmlFormat.SelectSingleNode("/TableRecipeFormat/Catalog/Group/Step[@ControlName='Spindle.Speed']").Attributes["Max"].Value);
  104. var xmlRecipe = new XmlDocument();
  105. xmlRecipe.LoadXml(recipeContent);
  106. //read in all recipe items
  107. Dictionary<int, Dictionary<string, string>> recipeItems = new Dictionary<int, Dictionary<string, string>>();
  108. var stepElements = xmlRecipe.SelectNodes("/TableRecipeData/Step");
  109. for (int stepNo = 0; stepNo < stepElements.Count; stepNo++)
  110. {
  111. var stepElement = stepElements[stepNo] as XmlElement;
  112. var step = new Dictionary<string, string>();
  113. recipeItems.Add(stepNo, step);
  114. foreach (XmlAttribute att1 in stepElement.Attributes)
  115. {
  116. step.Add(att1.Name, att1.Value);
  117. }
  118. foreach (XmlElement subNd1 in stepElement.ChildNodes)
  119. {
  120. foreach (XmlAttribute att2 in subNd1.Attributes)
  121. {
  122. step.Add(att2.Name, att2.Value);
  123. }
  124. foreach (XmlElement subNd2 in subNd1.ChildNodes)
  125. {
  126. foreach (XmlAttribute att3 in subNd2.Attributes)
  127. {
  128. step.Add(att3.Name, att3.Value);
  129. }
  130. foreach (XmlElement subNd3 in subNd2.ChildNodes)
  131. {
  132. foreach (XmlAttribute att4 in subNd3.Attributes)
  133. {
  134. step.Add(att4.Name, att4.Value);
  135. }
  136. }
  137. }
  138. }
  139. }
  140. #region check loop control
  141. for (int j = 0; j < recipeItems.Count; j++)
  142. {
  143. var loopStr = recipeItems[j]["Loop"];
  144. bool isLoopStart = Regex.IsMatch(loopStr, @"^Loop\x20\d+$");
  145. bool isLoopEnd = Regex.IsMatch(loopStr, @"^Loop End$");
  146. bool isNullOrEmpty = string.IsNullOrWhiteSpace(loopStr);
  147. if (!isLoopEnd && !isLoopStart && !isNullOrEmpty)
  148. {
  149. string reason = string.Format("Value '{0}' not valid", loopStr);
  150. reasons.Add(string.Format("第{0}步,{1}。", j + 1, reason));
  151. }
  152. if (isLoopEnd)
  153. {
  154. string reason = "Loop Start 缺失";
  155. reasons.Add(string.Format("第{0}步,{1}。", j + 1, reason));
  156. }
  157. else if (isLoopStart)
  158. {
  159. for (int k = j + 1; k < recipeItems.Count; k++)
  160. {
  161. var loopStr2 = recipeItems[k]["Loop"];
  162. bool isCurStepLoopStart = Regex.IsMatch(loopStr2, @"^Loop\x20\d+$");
  163. bool isCurStepLoopEnd = Regex.IsMatch(loopStr2, @"^Loop End$");
  164. isNullOrEmpty = string.IsNullOrWhiteSpace(loopStr2);
  165. if (!isCurStepLoopEnd && !isCurStepLoopStart && !isNullOrEmpty)
  166. {
  167. string reason = string.Format("Value '{0}' not valid", loopStr2);
  168. reasons.Add(string.Format("第{0}步,{1}。", k + 1, reason));
  169. }
  170. else if (isCurStepLoopStart)
  171. {
  172. string reason = "前面循环没有结束,不能设置新的Loop Start标志";
  173. reasons.Add(string.Format("第{0}步,{1}。", k + 1, reason));
  174. }
  175. else if (isCurStepLoopEnd)
  176. {
  177. j = k;
  178. break;
  179. }
  180. if (k == recipeItems.Count - 1)
  181. {
  182. j = k;
  183. string reason = "Loop End 缺失";
  184. reasons.Add(string.Format("第{0}步,{1}。", k + 1, reason));
  185. }
  186. }
  187. }
  188. }
  189. #endregion
  190. //check mfc range
  191. for (int stepNo = 0; stepNo < recipeItems.Count; stepNo++)
  192. {
  193. foreach (var mfcName in mfcDic.Keys)
  194. {
  195. if (recipeItems[stepNo].ContainsKey(mfcName))
  196. {
  197. var mfcSetpoint = Convert.ToDouble(recipeItems[stepNo][mfcName]);
  198. if (mfcSetpoint < 0 || mfcSetpoint > mfcDic[mfcName])
  199. {
  200. reasons.Add(string.Format("第{0}步,{1}设定{2},超出 0~{3}sccm范围。", stepNo + 1, mfcName, mfcSetpoint, mfcDic[mfcName]));
  201. }
  202. }
  203. }
  204. //check pc range
  205. foreach (var pcName in pcDic.Keys)
  206. {
  207. if (recipeItems[stepNo].ContainsKey(pcName))
  208. {
  209. var pcSetpoint = Convert.ToDouble(recipeItems[stepNo][pcName]);
  210. if (pcSetpoint < 0 || pcSetpoint > pcDic[pcName])
  211. {
  212. reasons.Add(string.Format("第{0}步,{1}设定{2},超出 0~{3}mbar范围。", stepNo + 1, pcName, pcSetpoint, pcDic[pcName]));
  213. }
  214. }
  215. }
  216. }
  217. #region recipe parameter validation
  218. //reading predefined varaible
  219. var recipePredfine = new Dictionary<string, string>();
  220. foreach (XmlElement nd in xmlFormat.SelectNodes("/TableRecipeFormat/Validation/Predefine/Item"))
  221. {
  222. recipePredfine.Add(nd.Attributes["VarName"].Value, nd.Attributes["Value"].Value);
  223. }
  224. #endregion
  225. }
  226. catch (Exception ex)
  227. {
  228. reasons.Add(Resources.RecipeFileManager_CheckRecipe_RecipeValidationFailed + ex.Message);
  229. LOG.Write(ex);
  230. return false;
  231. }
  232. return reasons.Count == 0;
  233. }
  234. /// <summary>
  235. /// This method will be invoked by two places:
  236. /// (1) Load a recipe from server to GUI for editing (do not need validation when loading, do validation when saving);
  237. /// (2) Load a recipe from recipe engine to run process(always do a validation before run recipe);
  238. /// </summary>
  239. /// <param name="recipeName"></param>
  240. /// <param name="needValidation">indicate whether a recipe format validation is needed or not</param>
  241. /// <returns></returns>
  242. public string LoadRecipe(string chamberId, string recipeName, bool needValidation)
  243. {
  244. string rcp = string.Empty;
  245. try
  246. {
  247. using (StreamReader fs = new StreamReader(GenerateRecipeFilePath(chamberId, recipeName)))
  248. {
  249. rcp = fs.ReadToEnd();
  250. fs.Close();
  251. }
  252. //if (needValidation)
  253. //{
  254. // List<string> reason;
  255. // if (!ValidateRecipe(chamberId, recipeName, rcp, out reason))
  256. // {
  257. // rcp = string.Empty;
  258. // LOG.Write("校验recipe file 出错, " + string.Join(",", reason.ToArray()));
  259. // }
  260. //}
  261. }
  262. catch (Exception ex)
  263. {
  264. LOG.Write(ex, $"load recipe file failed, {recipeName}");
  265. rcp = string.Empty;
  266. }
  267. return rcp;
  268. }
  269. public bool CheckRecipeFileExist(string chamberId, string recipeName)
  270. {
  271. return File.Exists(GenerateRecipeFilePath(chamberId, recipeName));
  272. }
  273. /// <summary>
  274. /// Get recipe list
  275. /// </summary>
  276. /// <param name="chamId"></param>
  277. /// <param name="includingUsedRecipe"></param>
  278. /// <returns></returns>
  279. public IEnumerable<string> GetRecipes(string chamberId, bool includingUsedRecipe)
  280. {
  281. return _context.GetRecipes(chamberId, includingUsedRecipe);
  282. }
  283. /// <summary>
  284. /// Get recipe list in xml format
  285. /// </summary>
  286. /// <param name="chamId"></param>
  287. /// <param name="includingUsedRecipe"></param>
  288. /// <returns></returns>
  289. public string GetXmlRecipeList(string chamberId, bool includingUsedRecipe)
  290. {
  291. XmlDocument doc = new XmlDocument();
  292. var baseFolderPath = getRecipeDirPath(chamberId);
  293. DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath);
  294. doc.AppendChild(GenerateRecipeList(chamberId, curFolderInfo, doc, includingUsedRecipe));
  295. return doc.OuterXml;
  296. }
  297. public void SaveRecipeHistory(string chamberId, string recipeName, string recipeContent, bool needSaveAs = true)
  298. {
  299. try
  300. {
  301. if (!string.IsNullOrEmpty(recipeName) && needSaveAs)
  302. {
  303. string newRecipeName = string.Format("HistoryRecipe\\{0}\\{1}", DateTime.Now.ToString("yyyyMM"), recipeName);
  304. //SaveRecipe(chamberId, newRecipeName, recipeContent, true, false);
  305. LOG.Write(string.Format("{0}通知TM保存工艺程序{1}", chamberId, recipeName));
  306. }
  307. }
  308. catch (Exception ex)
  309. {
  310. LOG.Write(ex, string.Format("保存{0}工艺程序{1}发生错误", chamberId, recipeName));
  311. }
  312. }
  313. /// <summary>
  314. /// generate recipe list information in current directory
  315. /// </summary>
  316. /// <param name="chamId"></param>
  317. /// <param name="currentDir"></param>
  318. /// <param name="doc"></param>
  319. /// <returns></returns>
  320. XmlElement GenerateRecipeList(string chamberId, DirectoryInfo currentDir, XmlDocument doc, bool includingUsedRecipe)
  321. {
  322. int trimLength = getRecipeDirPath(chamberId).LastIndexOf("\\");
  323. XmlElement folderEle = doc.CreateElement("Folder");
  324. folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength));
  325. DirectoryInfo[] dirInfos = currentDir.GetDirectories();
  326. foreach (DirectoryInfo dirInfo in dirInfos)
  327. {
  328. if (!includingUsedRecipe && dirInfo.Name == "HistoryRecipe")
  329. continue;
  330. folderEle.AppendChild(GenerateRecipeList(chamberId, dirInfo, doc, includingUsedRecipe));
  331. }
  332. FileInfo[] fileInfos = currentDir.GetFiles("*.rcp");
  333. foreach (FileInfo fileInfo in fileInfos)
  334. {
  335. XmlElement fileNd = doc.CreateElement("File");
  336. string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ;
  337. fileStr = fileStr.Substring(0, fileStr.LastIndexOf("."));
  338. fileNd.SetAttribute("Name", fileStr);
  339. folderEle.AppendChild(fileNd);
  340. }
  341. return folderEle;
  342. }
  343. /// <summary>
  344. /// Delete a recipe by recipe name
  345. /// </summary>
  346. /// <param name="chamId"></param>
  347. /// <param name="recipeName"></param>
  348. /// <returns></returns>
  349. public bool DeleteRecipe(string chamberId, string recipeName)
  350. {
  351. try
  352. {
  353. File.Delete(GenerateRecipeFilePath(chamberId, recipeName));
  354. InfoDialog(string.Format( Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteSucceeded, recipeName));
  355. }
  356. catch (Exception ex)
  357. {
  358. LOG.Write(ex, "删除recipe file 出错");
  359. WarningDialog(string.Format( Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteFailed, recipeName));
  360. return false;
  361. }
  362. return true;
  363. }
  364. /// <summary>
  365. /// Rename recipe
  366. /// </summary>
  367. /// <param name="chamId"></param>
  368. /// <param name="oldName"></param>
  369. /// <param name="newName"></param>
  370. /// <returns></returns>
  371. public bool RenameRecipe(string chamId, string oldName, string newName)
  372. {
  373. try
  374. {
  375. if (File.Exists(GenerateRecipeFilePath(chamId, newName)))
  376. {
  377. WarningDialog(string.Format( Resources.RecipeFileManager_RenameRecipe_RecipeFile0FileExisted, oldName));
  378. return false;
  379. }
  380. else
  381. {
  382. File.Move(GenerateRecipeFilePath(chamId, oldName), GenerateRecipeFilePath(chamId, newName));
  383. InfoDialog(string.Format( Resources.RecipeFileManager_RenameRecipe_RecipeFile0Renamed, oldName, newName));
  384. }
  385. }
  386. catch (Exception ex)
  387. {
  388. LOG.Write(ex, "重命名recipe file 出错");
  389. WarningDialog(string.Format( Resources.RecipeFileManager_RenameRecipe_RecipeFile0RenameFailed, oldName, newName));
  390. return false;
  391. }
  392. return true;
  393. }
  394. //private void EventInfo(string message)
  395. //{
  396. // _context.PostInfoEvent(message);
  397. //}
  398. //private void EventWarning(string message)
  399. //{
  400. // _context.PostWarningEvent(message);
  401. //}
  402. //private void EventAlarm(string message)
  403. //{
  404. // _context.PostAlarmEvent(message);
  405. //}
  406. private void InfoDialog(string message)
  407. {
  408. _context.PostInfoDialogMessage(message);
  409. }
  410. private void WarningDialog(string message)
  411. {
  412. _context.PostWarningDialogMessage(message);
  413. }
  414. //private void AlarmDialog(string message)
  415. //{
  416. // _context.PostAlarmDialogMessage(message);
  417. //}
  418. private void EventDialog(string message, List<string> reason)
  419. {
  420. string msg = message;
  421. foreach (var r in reason)
  422. {
  423. msg += "\r\n" + r;
  424. }
  425. _context.PostDialogEvent(msg);
  426. }
  427. /// <summary>
  428. /// get recipe's file path
  429. /// </summary>
  430. /// <param name="recipeName"></param>
  431. /// <returns></returns>
  432. private string GenerateRecipeFilePath(string chamId, string recipeName)
  433. {
  434. return getRecipeDirPath(chamId) + recipeName + ".rcp";
  435. }
  436. private string GenerateSequenceFilePath(string chamId, string recipeName)
  437. {
  438. return getRecipeDirPath(chamId) + recipeName + ".seq";
  439. }
  440. /// <summary>
  441. /// get recipe's dir path
  442. /// </summary>
  443. /// <param name="recipeName"></param>
  444. /// <returns></returns>
  445. private string getRecipeDirPath(string chamId)
  446. {
  447. var dir = string.Format("{0}{1}\\", PathManager.GetRecipeDir(), chamId);
  448. DirectoryInfo di = new DirectoryInfo(dir);
  449. if (!di.Exists) di.Create();
  450. return dir;
  451. }
  452. /// <summary>
  453. /// delete a recipe folder
  454. /// </summary>
  455. /// <param name="chamId"></param>
  456. /// <param name="folderName"></param>
  457. /// <returns></returns>
  458. public bool DeleteFolder(string chamId, string folderName)
  459. {
  460. try
  461. {
  462. Directory.Delete(getRecipeDirPath(chamId) + folderName, true);
  463. InfoDialog(string.Format( Resources.RecipeFileManager_DeleteFolder_RecipeFolder0DeleteSucceeded, folderName));
  464. }
  465. catch (Exception ex)
  466. {
  467. LOG.Write(ex, "删除recipe folder 出错");
  468. WarningDialog(string.Format("recipe folder {0} delete failed", folderName));
  469. return false;
  470. }
  471. return true;
  472. }
  473. /// <summary>
  474. /// save as recipe content
  475. /// </summary>
  476. /// <param name="chamId"></param>
  477. /// <param name="recipeName"></param>
  478. /// <param name="recipeContent"></param>
  479. /// <returns></returns>
  480. public bool SaveAsRecipe(string chamId, string recipeName, string recipeContent)
  481. {
  482. var path = GenerateRecipeFilePath(chamId, recipeName);
  483. if (File.Exists(path))
  484. {
  485. WarningDialog(string.Format( Resources.RecipeFileManager_SaveAsRecipe_RecipeFile0savefailed, recipeName));
  486. return false;
  487. }
  488. return SaveRecipe(chamId, recipeName, recipeContent, true, true);
  489. }
  490. /// <summary>
  491. /// save recipe content
  492. /// </summary>
  493. /// <param name="chamId"></param>
  494. /// <param name="recipeName"></param>
  495. /// <param name="recipeContent"></param>
  496. /// <returns></returns>
  497. public bool SaveRecipe(string chamId, string recipeName, string recipeContent, bool clearBarcode, bool notifyUI)
  498. {
  499. //validate recipe format when saving a recipe file
  500. //var reasons1 = new List<string>();
  501. //var reasons2 = new List<string>();
  502. //ValidateRecipe(chamId, recipeName, recipeContent, out reasons1);
  503. //CheckRecipe(chamId, recipeContent, out reasons2);
  504. //reasons1.AddRange(reasons2);
  505. //if (reasons1.Count > 0)
  506. //{
  507. // EventDialog(string.Format( Resources.RecipeFileManager_SaveRecipe_SaveRecipeContentError, recipeName), reasons1);
  508. //}
  509. bool ret = true;
  510. try
  511. {
  512. var path = GenerateRecipeFilePath(chamId, recipeName);
  513. FileInfo fi = new FileInfo(path);
  514. if (!fi.Directory.Exists)
  515. fi.Directory.Create();
  516. XmlDocument xml = new XmlDocument();
  517. xml.LoadXml(recipeContent);
  518. var rootNode = xml.SelectSingleNode("/TableRecipeData") as XmlElement;
  519. if (rootNode != null)
  520. {
  521. if (clearBarcode)
  522. {
  523. rootNode.SetAttribute("Barcode", "");
  524. }
  525. else
  526. {
  527. string barcode = rootNode.GetAttribute("Barcode");
  528. string recipe = GetRecipeByBarcode(chamId, barcode);
  529. if (!string.IsNullOrEmpty(barcode) && !string.IsNullOrEmpty(recipe) && recipe!=recipeName)
  530. {
  531. if (notifyUI)
  532. {
  533. WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_Barcode0IsDuplicatedIn1, barcode, recipe));
  534. }
  535. else
  536. {
  537. LOG.Error(string.Format(Resources.RecipeFileManager_SaveRecipe_Barcode0IsDuplicatedIn1, barcode, recipe));
  538. }
  539. return false;
  540. }
  541. }
  542. }
  543. XmlTextWriter writer = new XmlTextWriter(path, null);
  544. writer.Formatting = Formatting.Indented;
  545. xml.Save(writer);
  546. writer.Close();
  547. if (notifyUI)
  548. {
  549. InfoDialog(string.Format( Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, recipeName));
  550. }
  551. else
  552. {
  553. LOG.Write(string.Format( Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, recipeName));
  554. }
  555. }
  556. catch (Exception ex)
  557. {
  558. LOG.Write(ex, "保存recipe file 出错");
  559. if (notifyUI)
  560. {
  561. WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveFailed, recipeName));
  562. }
  563. ret = false;
  564. }
  565. return ret;
  566. }
  567. /// <summary>
  568. /// move recipe file
  569. /// </summary>
  570. /// <param name="chamId"></param>
  571. /// <param name="recipeName"></param>
  572. /// <returns></returns>
  573. public bool MoveRecipeFile(string chamId, string recipeName, string tragetFolderName, bool clearBarcode, bool notifyUI)
  574. {
  575. bool ret = true;
  576. try
  577. {
  578. var path = getRecipeDirPath(chamId);
  579. string fullFileName = path + recipeName + ".rcp";
  580. string tragetFullFilePath = path + tragetFolderName;
  581. File.Move(fullFileName, tragetFullFilePath + "\\" + recipeName.Split('\\')[recipeName.Split('\\').Length - 1] + ".rcp");
  582. if (notifyUI)
  583. {
  584. InfoDialog(string.Format(Resources.RecipeFileManager_MoveRecipe_RecipeFile0MoveCompleted, recipeName));
  585. }
  586. else
  587. {
  588. LOG.Write(string.Format(Resources.RecipeFileManager_MoveRecipe_RecipeFile0MoveCompleted, recipeName));
  589. }
  590. }
  591. catch (Exception ex)
  592. {
  593. LOG.Write(ex, "移动 recipe file 出错");
  594. if (notifyUI)
  595. {
  596. WarningDialog(string.Format(Resources.RecipeFileManager_MoveRecipe_RecipeFile0MoveFailed, recipeName));
  597. }
  598. ret = false;
  599. }
  600. return ret;
  601. }
  602. /// <summary>
  603. /// create a new recipe folder
  604. /// </summary>
  605. /// <param name="chamId"></param>
  606. /// <param name="folderName"></param>
  607. /// <returns></returns>
  608. public bool CreateFolder(string chamId, string folderName)
  609. {
  610. try
  611. {
  612. Directory.CreateDirectory(getRecipeDirPath(chamId) + folderName);
  613. InfoDialog(string.Format( Resources.RecipeFileManager_CreateFolder_RecipeFolder0Created, folderName));
  614. }
  615. catch (Exception ex)
  616. {
  617. LOG.Write(ex, "创建recipe folder 出错");
  618. WarningDialog(string.Format( Resources.RecipeFileManager_CreateFolder_RecipeFolder0CreateFailed, folderName));
  619. return false;
  620. }
  621. return true;
  622. }
  623. /// <summary>
  624. /// Rename recipe folder name
  625. /// </summary>
  626. /// <param name="chamId"></param>
  627. /// <param name="oldName"></param>
  628. /// <param name="newName"></param>
  629. /// <returns></returns>
  630. public bool RenameFolder(string chamId, string oldName, string newName)
  631. {
  632. try
  633. {
  634. string oldPath = getRecipeDirPath(chamId) + oldName;
  635. string newPath = getRecipeDirPath(chamId) + newName;
  636. Directory.Move(oldPath, newPath);
  637. InfoDialog(string.Format( Resources.RecipeFileManager_RenameFolder_RecipeFolder0renamed, oldName, newName));
  638. }
  639. catch (Exception ex)
  640. {
  641. LOG.Write(ex, "重命名recipe folder 出错");
  642. WarningDialog(string.Format( Resources.RecipeFileManager_RenameFolder_RecipeFolder0RenameFailed, oldName, newName));
  643. return false;
  644. }
  645. return true;
  646. }
  647. private string GetRecipeBody(string chamberId, string nodePath)
  648. {
  649. if (_context == null)
  650. return string.Empty;
  651. string schema = _context.GetRecipeDefiniton(chamberId);
  652. XmlDocument dom = new XmlDocument();
  653. dom.LoadXml(schema);
  654. XmlNode node = dom.SelectSingleNode(nodePath);
  655. return node.OuterXml;
  656. }
  657. /// <summary>
  658. /// get reactor's recipe format define file
  659. /// </summary>
  660. /// <param name="chamId"></param>
  661. /// <returns></returns>
  662. public string GetRecipeFormatXml(string chamberId)
  663. {
  664. return GetRecipeBody(chamberId, "/Aitex/TableRecipeFormat");
  665. }
  666. /// <summary>
  667. /// get reactor's template recipe file
  668. /// </summary>
  669. /// <param name="chamId"></param>
  670. /// <returns></returns>
  671. public string GetRecipeTemplate(string chamberId)
  672. {
  673. if (_context != null)
  674. return _context.GetRecipeTemplate(chamberId);
  675. return GetRecipeBody(chamberId, "/Aitex/TableRecipeData");
  676. }
  677. /// <summary>
  678. /// get reactor's template recipe file
  679. /// </summary>
  680. /// <param name="chamId"></param>
  681. /// <returns></returns>
  682. public string GetRecipeSchema(string chamberId)
  683. {
  684. if (_context == null)
  685. return string.Empty;
  686. string schema = _context.GetRecipeDefiniton(chamberId);
  687. XmlDocument dom = new XmlDocument();
  688. dom.LoadXml(schema);
  689. XmlNode node = dom.SelectSingleNode("/Aitex/TableRecipeSchema");
  690. return node.InnerXml;
  691. }
  692. public string GetRecipeByBarcode(string chamberId, string barcode)
  693. {
  694. try
  695. {
  696. string recipePath = PathManager.GetRecipeDir() + chamberId + "\\";
  697. var di = new DirectoryInfo(recipePath);
  698. var fis = di.GetFiles("*.rcp", SearchOption.AllDirectories);
  699. XmlDocument xml = new XmlDocument();
  700. foreach (var fi in fis)
  701. {
  702. string str = fi.FullName.Substring(recipePath.Length);
  703. if (!str.Contains("HistoryRecipe\\"))
  704. {
  705. xml.Load(fi.FullName);
  706. if (xml.SelectSingleNode(string.Format("/TableRecipeData[@Barcode='{0}']", barcode)) != null)
  707. {
  708. return str.Substring(0, str.LastIndexOf('.'));
  709. }
  710. }
  711. }
  712. return string.Empty;
  713. }
  714. catch (Exception ex)
  715. {
  716. LOG.Write(ex);
  717. return string.Empty;
  718. }
  719. }
  720. //#region Sequence
  721. //private string GetSequenceConfig(string nodePath)
  722. //{
  723. // if (_seqContext == null)
  724. // return string.Empty;
  725. // string schema = _seqContext.GetConfigXml();
  726. // XmlDocument dom = new XmlDocument();
  727. // dom.LoadXml(schema);
  728. // XmlNode node = dom.SelectSingleNode(nodePath);
  729. // return node.OuterXml;
  730. //}
  731. public bool CheckSequenceFileExist(string sequenceName)
  732. {
  733. return File.Exists(GenerateSequenceFilePath("System", sequenceName));
  734. }
  735. public string GetSequence(string sequenceName, bool needValidation)
  736. {
  737. string seq = string.Empty;
  738. try
  739. {
  740. using (StreamReader fs = new StreamReader(GenerateRecipeFilePath("System", sequenceName)))
  741. {
  742. seq = fs.ReadToEnd();
  743. fs.Close();
  744. }
  745. }
  746. catch (Exception ex)
  747. {
  748. LOG.Write(ex);
  749. EV.PostWarningLog("System", $"Read {sequenceName} failed, " + ex.Message);
  750. seq = string.Empty;
  751. }
  752. return seq;
  753. }
  754. public List<string> GetSequenceNameList()
  755. {
  756. var result = new List<string>();
  757. try
  758. {
  759. string recipePath = PathManager.GetRecipeDir() + "System" + "\\";
  760. var di = new DirectoryInfo(recipePath);
  761. var fis = di.GetFiles("*.rcp", SearchOption.AllDirectories);
  762. foreach (var fi in fis)
  763. {
  764. string str = fi.FullName.Substring(recipePath.Length);
  765. str = str.Substring(0, str.LastIndexOf('.'));
  766. if (!str.Contains("HistoryRecipe\\"))
  767. {
  768. result.Add(str);
  769. }
  770. }
  771. }
  772. catch (Exception ex)
  773. {
  774. LOG.Write(ex);
  775. }
  776. return result;
  777. }
  778. public bool DeleteSequence(string sequenceName)
  779. {
  780. try
  781. {
  782. var path = GenerateRecipeFilePath("System", sequenceName);
  783. File.Delete(path);
  784. LOG.Write($"sequence {sequenceName} deleted");
  785. }
  786. catch (Exception ex)
  787. {
  788. LOG.Write(ex);
  789. return false;
  790. }
  791. return true;
  792. }
  793. public bool SaveSequence(string sequenceName, string sequenceContent, bool notifyUI)
  794. {
  795. bool ret = true;
  796. try
  797. {
  798. var path = GenerateSequenceFilePath("System", sequenceName);
  799. FileInfo fi = new FileInfo(path);
  800. if (!fi.Directory.Exists)
  801. {
  802. fi.Directory.Create();
  803. }
  804. XmlDocument xml = new XmlDocument();
  805. xml.LoadXml(sequenceContent);
  806. XmlTextWriter writer = new XmlTextWriter(path, null);
  807. writer.Formatting = Formatting.Indented;
  808. xml.Save(writer);
  809. writer.Close();
  810. if (notifyUI)
  811. {
  812. EV.PostPopDialogMessage(EventLevel.Information, "Save Complete", $"Sequence {sequenceName} saved ");
  813. }
  814. else
  815. {
  816. EV.PostInfoLog("System", $"Sequence {sequenceName} saved ");
  817. }
  818. }
  819. catch (Exception ex)
  820. {
  821. LOG.Write(ex);
  822. EV.PostWarningLog("System", $"save sequence {sequenceName} failed, " + ex.Message);
  823. if (notifyUI)
  824. {
  825. EV.PostPopDialogMessage(EventLevel.Alarm, "Save Error", $"save sequence {sequenceName} failed, " + ex.Message);
  826. }
  827. ret = false;
  828. }
  829. return ret;
  830. }
  831. //public bool SaveAsSequence(string sequenceName, string sequenceContent)
  832. //{
  833. // var path = GenerateSequenceFilePath(SequenceFolder, sequenceName);
  834. // if (File.Exists(path))
  835. // {
  836. // EV.PostWarningLog(SourceModule, $"save sequence {sequenceName} failed, already exist");
  837. // return false;
  838. // }
  839. // return SaveSequence(sequenceName, sequenceContent, false);
  840. //}
  841. //public bool RenameSequence(string oldName, string newName)
  842. //{
  843. // try
  844. // {
  845. // var path = GenerateSequenceFilePath(SequenceFolder, oldName);
  846. // if (!_seqContext.EnableEdit(path))
  847. // return false;
  848. // if (File.Exists(GenerateSequenceFilePath(SequenceFolder, newName)))
  849. // {
  850. // EV.PostWarningLog(SourceModule, $"{newName} already exist, rename failed");
  851. // return false;
  852. // }
  853. // else
  854. // {
  855. // File.Move(path, GenerateSequenceFilePath(SequenceFolder, newName));
  856. // EV.PostInfoLog(SourceModule, $"sequence {oldName} renamed to {newName}");
  857. // }
  858. // }
  859. // catch (Exception ex)
  860. // {
  861. // LOG.Write(ex);
  862. // EV.PostWarningLog(SourceModule, $"rename {oldName} failed, " + ex.Message);
  863. // return false;
  864. // }
  865. // return true;
  866. //}
  867. //public string GetSequenceFormatXml()
  868. //{
  869. // return GetSequenceConfig("/Aitex/TableSequenceFormat");
  870. //}
  871. //internal bool DeleteSequenceFolder(string folderName)
  872. //{
  873. // try
  874. // {
  875. // Directory.Delete(PathManager.GetRecipeDir() + SequenceFolder + "\\" + folderName, true);
  876. // EV.PostInfoLog(SourceModule, "Folder " + folderName + "deleted");
  877. // }
  878. // catch (Exception ex)
  879. // {
  880. // LOG.Write(ex, "delete sequence folder exception");
  881. // EV.PostWarningLog(SourceModule, $"can not delete folder {folderName}, {ex.Message}");
  882. // return false;
  883. // }
  884. // return true;
  885. //}
  886. //internal bool CreateSequenceFolder(string folderName)
  887. //{
  888. // try
  889. // {
  890. // Directory.CreateDirectory(PathManager.GetRecipeDir() + SequenceFolder + "\\" + folderName);
  891. // EV.PostInfoLog(SourceModule, "Folder " + folderName + "created");
  892. // }
  893. // catch (Exception ex)
  894. // {
  895. // LOG.Write(ex, "sequence folder create exception");
  896. // EV.PostWarningLog(SourceModule, $"can not create folder {folderName}, {ex.Message}");
  897. // return false;
  898. // }
  899. // return true;
  900. //}
  901. //internal bool RenameSequenceFolder(string oldName, string newName)
  902. //{
  903. // try
  904. // {
  905. // string oldPath = PathManager.GetRecipeDir() + SequenceFolder + "\\" + oldName;
  906. // string newPath = PathManager.GetRecipeDir() + SequenceFolder + "\\" + newName;
  907. // Directory.Move(oldPath, newPath);
  908. // EV.PostInfoLog(SourceModule, $"rename folder from {oldName} to {newName}");
  909. // }
  910. // catch (Exception ex)
  911. // {
  912. // LOG.Write(ex, "rename sequence folder failed");
  913. // EV.PostWarningLog(SourceModule, $"can not rename folder {oldName}, {ex.Message}");
  914. // return false;
  915. // }
  916. // return true;
  917. //}
  918. //public string GetXmlSequenceList(string chamberId)
  919. //{
  920. // XmlDocument doc = new XmlDocument();
  921. // DirectoryInfo curFolderInfo = new DirectoryInfo(PathManager.GetRecipeDir() + SequenceFolder + "\\");
  922. // doc.AppendChild(GenerateSequenceList(chamberId, curFolderInfo, doc));
  923. // return doc.OuterXml;
  924. //}
  925. //XmlElement GenerateSequenceList(string chamberId, DirectoryInfo currentDir, XmlDocument doc)
  926. //{
  927. // int trimLength = (PathManager.GetRecipeDir() + SequenceFolder + "\\").Length;
  928. // XmlElement folderEle = doc.CreateElement("Folder");
  929. // folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength));
  930. // DirectoryInfo[] dirInfos = currentDir.GetDirectories();
  931. // foreach (DirectoryInfo dirInfo in dirInfos)
  932. // {
  933. // folderEle.AppendChild(GenerateSequenceList(chamberId, dirInfo, doc));
  934. // }
  935. // FileInfo[] fileInfos = currentDir.GetFiles("*.seq");
  936. // foreach (FileInfo fileInfo in fileInfos)
  937. // {
  938. // XmlElement fileNd = doc.CreateElement("File");
  939. // string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ;
  940. // fileStr = fileStr.Substring(0, fileStr.LastIndexOf("."));
  941. // fileNd.SetAttribute("Name", fileStr);
  942. // folderEle.AppendChild(fileNd);
  943. // }
  944. // return folderEle;
  945. //}
  946. //#endregion
  947. }
  948. }