ba148aa9cb434375cdf72d23d2eac54ada31d007
[TortoiseGit.git] / contrib / diff-scripts / diff-xls.js
blobba148aa9cb434375cdf72d23d2eac54ada31d007
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$
13 // Authors:
14 // Hiroki Najima <h.najima at gmail.com>, 2013
15 // Michael Joras <michael@joras.net>, 2008
16 // Suraj Barkale, 2006
19 // ----- configuration -----
20 // Fast mode switch
21 // Fast mode does not copy Worksheets but require opened base document at the same time.
22 var bFastMode = false;
24 // ----- constants -----
25 var vbCritical = 0x10;
26 var vbExclamation = 0x30;
27 //var vbInformation = 0x40;
29 var xlNone = -4142;
30 var xlMaximized = -4137;
31 var xlArrangeStyleHorizontal = -4128;
32 var xlCellValue = 1;
33 //var xlExpression = 2;
34 //var xlEqual = 3;
35 var xlNotEqual = 4;
37 //var vOffice95 = 7;
38 //var vOffice97 = 8;
39 //var vOffice2000 = 9;
40 //var vOffice2002 = 10;
41 var vOffice2003 = 11;
42 //var vOffice2007 = 12;
43 //var vOffice2010 = 14;
44 //var vOffice2013 = 15;
46 // ----- main -----
48 var aWarningMessages = Array();
50 var objArgs = WScript.Arguments;
51 if (objArgs.length < 2)
53     Abort("Usage: [CScript | WScript] diff-xls.js base.xls new.xls", "Invalid arguments");
56 var sBaseDoc = objArgs(0);
57 var sNewDoc = objArgs(1);
59 var objScript = new ActiveXObject("Scripting.FileSystemObject");
61 if (objScript.GetBaseName(sBaseDoc) === objScript.GetBaseName(sNewDoc))
63     Abort("File '" + sBaseDoc + "' and '" + sNewDoc + "' is same file name.\nCannot compare the documents.", "Same file name");
66 if (!objScript.FileExists(sBaseDoc))
68     Abort("File '" + sBaseDoc + "' does not exist.\nCannot compare the documents.", "File not found");
71 if (!objScript.FileExists(sNewDoc))
73     Abort("File '" + sNewDoc + "' does not exist.\nCannot compare the documents.", "File not found");
76 sBaseDoc = objScript.GetAbsolutePathName(sBaseDoc);
77 sNewDoc = objScript.GetAbsolutePathName(sNewDoc);
78 objScript = null;
80 var objExcelApp;
81 try
83     objExcelApp = WScript.CreateObject("Excel.Application");
85 catch (e)
87     Abort("You must have Excel installed to perform this operation.", "Excel Instantiation Failed");
89 var fExcelVersion = parseInt(objExcelApp.Version);
91 // Open base Excel book
92 var objBaseWorkbook;
93 try
95     objBaseWorkbook = objExcelApp.Workbooks.Open(sBaseDoc, null, true);
97 catch (e)
99     Abort("Failed to open '" + sBaseDoc + "'\nIt might not be a valid Excel file.", "File open error");
102 // Open new Excel book
103 var objNewWorkbook;
106     objNewWorkbook = objExcelApp.Workbooks.Open(sNewDoc, null, true);
108 catch (e)
110     Abort("Failed to open '" + sNewDoc + "'\nIt might not be a valid Excel file.", "File open error");
113 // Show Excel window
114 objExcelApp.Visible = true;
116 // Arrange windows
117 if (objBaseWorkbook.ProtectWindows || objNewWorkbook.ProtectWindows)
119     StoreWarning("Unable to arrange windows because one or both workbooks are protected.");
121 else
123     // Make windows a compare side by side view
124     if (fExcelVersion >= vOffice2003)
125     {
126         objExcelApp.Windows.CompareSideBySideWith(objExcelApp.Windows(2).Caption);
127     }
128     objExcelApp.Application.WindowState = xlMaximized;
129     objExcelApp.Windows.Arrange(xlArrangeStyleHorizontal);
132 if (!bFastMode && objNewWorkbook.ProtectWindows)
134     StoreWarning("Fallback to fast mode bacause " + objNewWorkbook.Name + " is protected.");
135     bFastMode = true;
138 // Mark differences in sNewDoc red
139 var length = objNewWorkbook.Worksheets.Count;
140 for (var i = 1; i <= length; i++)
142     var objBaseWorksheet = objBaseWorkbook.Worksheets(i);
143     var objNewWorksheet = objNewWorkbook.Worksheets(i);
145     UnhideWorksheet(objBaseWorksheet);
146     UnhideWorksheet(objNewWorksheet);
148     if (!bFastMode)
149     {
150         objBaseWorkbook.Sheets(i).Copy(null, objNewWorkbook.Sheets(objNewWorkbook.Sheets.Count));
151         var objDummyWorksheet = objNewWorkbook.Sheets(objNewWorkbook.Sheets.Count);
152         objDummyWorksheet.Name = "Dummy_for_Comparison" + i;
153         objDummyWorksheet.Visible = true;
154         if (fExcelVersion >= vOffice2003)
155         {
156             objDummyWorksheet.Tab.ColorIndex = 16;  // 16:Dark gray RGB(128,128,128)
157         }
158     }
160     if (objNewWorksheet.ProtectContents)
161     {
162         StoreWarning("Unable to mark differences to " +
163             ToAbsoluteReference(objNewWorksheet) +
164             " because the Worksheet is protected.");
165     }
166     else
167     {
168         objNewWorksheet.Cells.FormatConditions.Delete();
169         var sFormula;
170         if (bFastMode)
171         {
172             sFormula = "=INDIRECT(\"" + ToAbsoluteReference(objBaseWorksheet) + "!\"&ADDRESS(ROW(),COLUMN()))";
173         }
174         else
175         {
176             sFormula = "=INDIRECT(\"Dummy_for_Comparison" + i + "!\"&ADDRESS(ROW(),COLUMN()))";
177         }
178         objNewWorksheet.Cells.FormatConditions.Add(xlCellValue, xlNotEqual, sFormula);
179         objNewWorksheet.Cells.FormatConditions(1).Interior.ColorIndex = 3;  // 3:Red RGB(128,0,0)
180     }
184 // Activate first Worksheet
185 objBaseWorkbook.Sheets(1).Activate();
186 objNewWorkbook.Sheets(1).Activate();
188 // Suppress save dialog if nothing changed
189 objBaseWorkbook.Saved = true;
190 objNewWorkbook.Saved = true;
192 // Show warnings if exist
193 ShowWarning();
195 WScript.Quit(0);
198 // ----- functions -----
200 // Show Message Dialog
201 // VBcript's MsgBox emulation
202 function MsgBox(sMessage, iButtons, sTitle)
204     var objShell = new ActiveXObject("WScript.Shell");
205     objShell.popup(sMessage, 0, sTitle, iButtons);
208 // Show an error message and quit script with cleanup Excel Application Object.
209 function Abort(sMessage, sTitle)
211     MsgBox(sMessage, vbCritical, sTitle);
212     if (objExcelApp)
213     {
214         objExcelApp.Quit();
215     }
216     WScript.Quit(1);
219 // Unhide the Worksheet if it is hidden.
220 // This also sets color to the tab, if Office2003 or later.
221 //  - 46(Orange)      : Hidden Worksheet
222 //  - xlNone(default) : Not hidden Worksheet
223 function UnhideWorksheet(objWorksheet)
225     if (objWorksheet.Visible)
226     {
227         if (fExcelVersion >= vOffice2003)
228         {
229             if (objWorksheet.Tab.ColorIndex !== xlNone)
230             {
231                 if (objWorksheet.Parent.ProtectStructure)
232                 {
233                     StoreWarning("Unable to set tab color to " +
234                         ToAbsoluteReference(objWorksheet) +
235                         " because the Workbook's structure is protected.");
236                 }
237                 else
238                 {
239                     objWorksheet.Tab.ColorIndex = xlNone;
240                 }
241             }
242         }
243     }
244     else
245     {
246         if (objWorksheet.Parent.ProtectStructure)
247         {
248             StoreWarning("Unable to unhide " +
249                 ToAbsoluteReference(objWorksheet) +
250                 " because the Workbook's structure is protected.");
251         }
252         else
253         {
254             objWorksheet.Visible = true;
255             if (fExcelVersion >= vOffice2003)
256             {
257                 objWorksheet.Tab.ColorIndex = 10;   // 10:Green RGB(0,128,0)
258             }
259         }
260     }
263 // Generate Absolute Reference Formula of Worksheet.
264 function ToAbsoluteReference(objWorksheet)
266     return "[" + objWorksheet.Parent.Name + "]" + objWorksheet.Name;
269 // Accumulate a warning message.
270 function StoreWarning(sMessage)
272     aWarningMessages[aWarningMessages.length] = sMessage;
275 // Show accumulated warning messages if exist.
276 // To avoid make huge message dialog, this limits message count to show.
277 function ShowWarning()
279     if (aWarningMessages.length === 0)
280     {
281         return;
282     }
283     var sMessage = "The following warnings occurred while processing.\n";
284     for (var i = 0; i < aWarningMessages.length; i++)
285     {
286         if (i >= 10)
287         {
288             sMessage += "... And more " + (aWarningMessages.length - i) + " messages";
289             break;
290         }
291         sMessage += "[" + (i + 1) + "] " + aWarningMessages[i] + "\n";
292     }
293     MsgBox(sMessage, vbExclamation, "Warning");