/contrib/diff-scripts/diff-xls.js

https://github.com/YueLinHo/TortoiseGit · JavaScript · 313 lines · 218 code · 38 blank · 57 comment · 24 complexity · 8e0206317d066ff665ff7edbe16af4e1 MD5 · raw file

  1. // extensions: xls;xlsx;xlsm;xlsb;xlam
  2. //
  3. // TortoiseSVN Diff script for Excel files
  4. //
  5. // Copyright (C) 2004-2008 the TortoiseSVN team
  6. // This file is distributed under the same license as TortoiseSVN
  7. //
  8. // Last commit by:
  9. // $Author$
  10. // $Date$
  11. // $Rev$
  12. //
  13. // Authors:
  14. // Hiroki Najima <h.najima at gmail.com>, 2013
  15. // Michael Joras <michael@joras.net>, 2008
  16. // Suraj Barkale, 2006
  17. //
  18. // ----- configuration -----
  19. // Fast mode switch
  20. // Fast mode does not copy Worksheets but require opened base document at the same time.
  21. var bFastMode = false;
  22. // ----- constants -----
  23. var vbCritical = 0x10;
  24. var vbExclamation = 0x30;
  25. //var vbInformation = 0x40;
  26. var xlNone = -4142;
  27. var xlMaximized = -4137;
  28. var xlArrangeStyleHorizontal = -4128;
  29. var xlCellValue = 1;
  30. //var xlExpression = 2;
  31. //var xlEqual = 3;
  32. var xlNotEqual = 4;
  33. //var vOffice95 = 7;
  34. //var vOffice97 = 8;
  35. //var vOffice2000 = 9;
  36. //var vOffice2002 = 10;
  37. var vOffice2003 = 11;
  38. //var vOffice2007 = 12;
  39. //var vOffice2010 = 14;
  40. //var vOffice2013 = 15;
  41. // ----- main -----
  42. var aWarningMessages = Array();
  43. var objArgs = WScript.Arguments;
  44. if (objArgs.length < 2)
  45. {
  46. Abort("Usage: [CScript | WScript] diff-xls.js base.xls new.xls", "Invalid arguments");
  47. }
  48. var sBaseDoc = objArgs(0);
  49. var sNewDoc = objArgs(1);
  50. var objScript = new ActiveXObject("Scripting.FileSystemObject");
  51. if (objScript.GetBaseName(sBaseDoc) === objScript.GetBaseName(sNewDoc))
  52. {
  53. Abort("File '" + sBaseDoc + "' and '" + sNewDoc + "' is same file name.\nCannot compare the documents.", "Same file name");
  54. }
  55. if (!objScript.FileExists(sBaseDoc))
  56. {
  57. Abort("File '" + sBaseDoc + "' does not exist.\nCannot compare the documents.", "File not found");
  58. }
  59. if (!objScript.FileExists(sNewDoc))
  60. {
  61. Abort("File '" + sNewDoc + "' does not exist.\nCannot compare the documents.", "File not found");
  62. }
  63. sBaseDoc = objScript.GetAbsolutePathName(sBaseDoc);
  64. sNewDoc = objScript.GetAbsolutePathName(sNewDoc);
  65. objScript = null;
  66. var objExcelApp;
  67. try
  68. {
  69. objExcelApp = WScript.CreateObject("Excel.Application");
  70. }
  71. catch (e)
  72. {
  73. Abort("You must have Excel installed to perform this operation.", "Excel Instantiation Failed");
  74. }
  75. var fExcelVersion = parseInt(objExcelApp.Version, 10);
  76. // Open base Excel book
  77. var objBaseWorkbook;
  78. try
  79. {
  80. objBaseWorkbook = objExcelApp.Workbooks.Open(sBaseDoc, null, true);
  81. }
  82. catch (e)
  83. {
  84. Abort("Failed to open '" + sBaseDoc + "'\nIt might not be a valid Excel file.", "File open error");
  85. }
  86. // Open new Excel book
  87. var objNewWorkbook;
  88. try
  89. {
  90. objNewWorkbook = objExcelApp.Workbooks.Open(sNewDoc, null, true);
  91. }
  92. catch (e)
  93. {
  94. Abort("Failed to open '" + sNewDoc + "'\nIt might not be a valid Excel file.", "File open error");
  95. }
  96. // Show Excel window
  97. objExcelApp.Visible = true;
  98. // Arrange windows
  99. if (objBaseWorkbook.ProtectWindows || objNewWorkbook.ProtectWindows)
  100. {
  101. StoreWarning("Unable to arrange windows because one or both Workbooks are protected.");
  102. }
  103. else
  104. {
  105. // Make windows a compare side by side view
  106. if (fExcelVersion >= vOffice2003)
  107. {
  108. objExcelApp.Windows.CompareSideBySideWith(objExcelApp.Windows(2).Caption);
  109. }
  110. objExcelApp.Application.WindowState = xlMaximized;
  111. objExcelApp.Windows.Arrange(xlArrangeStyleHorizontal);
  112. }
  113. if (!bFastMode && objNewWorkbook.ProtectWindows)
  114. {
  115. StoreWarning("Fall back to fast mode because " + objNewWorkbook.Name + " is protected.");
  116. bFastMode = true;
  117. }
  118. // Create a special workbook for formula convertion.
  119. var objSpecialWorkbook = objExcelApp.Workbooks.Add;
  120. // Mark differences in sNewDoc red
  121. var length = objNewWorkbook.Worksheets.Count;
  122. for (var i = 1; i <= length; i++)
  123. {
  124. var objBaseWorksheet = objBaseWorkbook.Worksheets(i);
  125. var objNewWorksheet = objNewWorkbook.Worksheets(i);
  126. UnhideWorksheet(objBaseWorksheet);
  127. UnhideWorksheet(objNewWorksheet);
  128. if (!bFastMode)
  129. {
  130. objBaseWorkbook.Sheets(i).Copy(null, objNewWorkbook.Sheets(objNewWorkbook.Sheets.Count));
  131. var objDummyWorksheet = objNewWorkbook.Sheets(objNewWorkbook.Sheets.Count);
  132. objDummyWorksheet.Name = "Dummy_for_Comparison" + i;
  133. objDummyWorksheet.Visible = true;
  134. if (fExcelVersion >= vOffice2003)
  135. {
  136. objDummyWorksheet.Tab.ColorIndex = 16; // 16:Dark gray RGB(128,128,128)
  137. }
  138. }
  139. if (objNewWorksheet.ProtectContents)
  140. {
  141. StoreWarning("Unable to mark differences to " +
  142. ToAbsoluteReference(objNewWorksheet) +
  143. " because the Worksheet is protected.");
  144. }
  145. else
  146. {
  147. objNewWorksheet.Cells.FormatConditions.Delete();
  148. var sFormula;
  149. if (bFastMode)
  150. {
  151. sFormula = "=INDIRECT(\"" + ToAbsoluteReference(objBaseWorksheet) + "!\"&ADDRESS(ROW(),COLUMN()))";
  152. }
  153. else
  154. {
  155. sFormula = "=INDIRECT(\"Dummy_for_Comparison" + i + "!\"&ADDRESS(ROW(),COLUMN()))";
  156. }
  157. sFormula = convertFormula(sFormula);
  158. objNewWorksheet.Cells.FormatConditions.Add(xlCellValue, xlNotEqual, sFormula);
  159. objNewWorksheet.Cells.FormatConditions(1).Interior.ColorIndex = 3; // 3:Red RGB(128,0,0)
  160. }
  161. }
  162. // Close the special workbook quietly
  163. objSpecialWorkbook.Saved = true;
  164. objSpecialWorkbook.Close;
  165. // Activate first Worksheet
  166. objBaseWorkbook.Sheets(1).Activate();
  167. objNewWorkbook.Sheets(1).Activate();
  168. // Suppress save dialog if nothing changed
  169. objBaseWorkbook.Saved = true;
  170. objNewWorkbook.Saved = true;
  171. // Show warnings if exist
  172. ShowWarning();
  173. WScript.Quit(0);
  174. // ----- functions -----
  175. // Show Message Dialog
  176. // VBcript's MsgBox emulation
  177. function MsgBox(sMessage, iButtons, sTitle)
  178. {
  179. var objShell = new ActiveXObject("WScript.Shell");
  180. objShell.popup(sMessage, 0, sTitle, iButtons);
  181. }
  182. // Show an error message and quit script with cleanup Excel Application Object.
  183. function Abort(sMessage, sTitle)
  184. {
  185. MsgBox(sMessage, vbCritical, sTitle);
  186. if (objExcelApp)
  187. {
  188. objExcelApp.Quit();
  189. }
  190. WScript.Quit(1);
  191. }
  192. // Unhide the Worksheet if it is hidden.
  193. // This also sets color to the tab, if Office2003 or later.
  194. // - 46(Orange) : Hidden Worksheet
  195. // - xlNone(default) : Not hidden Worksheet
  196. function UnhideWorksheet(objWorksheet)
  197. {
  198. if (objWorksheet.Visible)
  199. {
  200. if (fExcelVersion >= vOffice2003)
  201. {
  202. if (objWorksheet.Tab.ColorIndex !== xlNone)
  203. {
  204. if (objWorksheet.Parent.ProtectStructure)
  205. {
  206. StoreWarning("Unable to set tab color to " +
  207. ToAbsoluteReference(objWorksheet) +
  208. " because the Workbook's structure is protected.");
  209. }
  210. else
  211. {
  212. objWorksheet.Tab.ColorIndex = xlNone;
  213. }
  214. }
  215. }
  216. }
  217. else
  218. {
  219. if (objWorksheet.Parent.ProtectStructure)
  220. {
  221. StoreWarning("Unable to unhide " +
  222. ToAbsoluteReference(objWorksheet) +
  223. " because the Workbook's structure is protected.");
  224. }
  225. else
  226. {
  227. objWorksheet.Visible = true;
  228. if (fExcelVersion >= vOffice2003)
  229. {
  230. objWorksheet.Tab.ColorIndex = 10; // 10:Green RGB(0,128,0)
  231. }
  232. }
  233. }
  234. }
  235. // Generate Absolute Reference Formula of Worksheet.
  236. function ToAbsoluteReference(objWorksheet)
  237. {
  238. return "[" + objWorksheet.Parent.Name + "]" + objWorksheet.Name;
  239. }
  240. // Convert a formula for workaround in some situation.
  241. // Actually I don't know what will be changed between sFormula and FormulaLocal.
  242. function convertFormula(sFormula)
  243. {
  244. var worksheet = objSpecialWorkbook.Sheets(1);
  245. var original_content = worksheet.Cells(1,1).Formula;
  246. worksheet.Cells(1,1).Formula = sFormula;
  247. sFormula = worksheet.Cells(1,1).FormulaLocal;
  248. worksheet.Cells(1,1).Formula = original_content;
  249. return sFormula;
  250. }
  251. // Accumulate a warning message.
  252. function StoreWarning(sMessage)
  253. {
  254. aWarningMessages[aWarningMessages.length] = sMessage;
  255. }
  256. // Show accumulated warning messages if exist.
  257. // To avoid make huge message dialog, this limits message count to show.
  258. function ShowWarning()
  259. {
  260. if (aWarningMessages.length === 0)
  261. {
  262. return;
  263. }
  264. var sMessage = "The following warnings occurred while processing.\n";
  265. for (var i = 0; i < aWarningMessages.length; i++)
  266. {
  267. if (i >= 10)
  268. {
  269. sMessage += "... And more " + (aWarningMessages.length - i) + " messages";
  270. break;
  271. }
  272. sMessage += "[" + (i + 1) + "] " + aWarningMessages[i] + "\n";
  273. }
  274. MsgBox(sMessage, vbExclamation, "Warning");
  275. }