1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package convwatch;
25 
26 import convwatch.GraphicalTestArguments;
27 import convwatch.OfficePrint;
28 import convwatch.ConvWatchCancelException;
29 import convwatch.FileHelper;
30 import java.io.File;
31 
32 import helper.URLHelper;
33 import com.sun.star.lang.XComponent;
34 import com.sun.star.frame.XStorable;
35 import com.sun.star.beans.PropertyValue;
36 import com.sun.star.lang.XServiceInfo;
37 import com.sun.star.uno.UnoRuntime;
38 
39 public class GraphicalDifferenceCheck
40 {
41     private static void showVersion()
42         {
43             // DEBUG only
44             if (FileHelper.isDebugEnabled())
45             {
46                 GlobalLogWriter.get().println("");
47                 GlobalLogWriter.get().println("+##############################+");
48                 GlobalLogWriter.get().println("##### THIS IS CONVWATCH    #####");
49                 GlobalLogWriter.get().println("##### Debug Version 1.0015 #####");
50                 GlobalLogWriter.get().println("+##############################+");
51                 GlobalLogWriter.get().println("");
52             }
53         }
54 
55     /**
56      * Creates references form documents used by the graphical difference check
57      *
58      * @param _sInputPath       the original document path
59      * @param _sReferencePath   the directory where the document will print as file or export as pdf.
60      *
61      * @throws  ConvWatchException if there are problems, see message
62      *
63      * Stops rest, if one creation of reference fails.
64      */
65     public static void createReferences(String _sInputPath, String _sReferencePath, GraphicalTestArguments _aGTA) throws ConvWatchException
66         {
67 //!
68 //            System.out.println("createReferences() InputPath: " + _sInputPath + " refpath: " + _sReferencePath);
69             showVersion();
70             File aInputPath = new File(_sInputPath);
71 
72 //            System.out.println("Inputpath in file: " + aInputPath.getAbsolutePath());
73 //!
74 //             if (aInputPath.exists())
75 //             {
76 //                 System.out.println("Inputpath exists");
77 //             }
78 //             else
79 //             {
80 //                 System.out.println("Inputpath doesn't exists");
81 //                 return;
82 //             }
83 
84             if (aInputPath.isDirectory())
85             {
86                 String fs = System.getProperty("file.separator");
87 
88                 String sRemovePath = aInputPath.getAbsolutePath();
89                 // a whole directory
90 
91                 Object[] aList = DirectoryHelper.traverse(_sInputPath, FileHelper.getFileFilter(), _aGTA.includeSubDirectories());
92                 for (int i=0;i<aList.length;i++)
93                 {
94                     String sEntry = (String)aList[i];
95                     String sNewReferencePath = _sReferencePath + fs + FileHelper.removeFirstDirectorysAndBasenameFrom(sEntry, _sInputPath);
96                     createOneReferenceFile(sEntry, sNewReferencePath, _aGTA);
97                 }
98             }
99             else
100             {
101 //!
102                 // System.out.println("No directory.");
103                 createOneReferenceFile(_sInputPath, _sReferencePath, _aGTA);
104             }
105         }
106 
107 
108     /**
109      * Creates a reference for a single document used by the graphical difference check
110      *
111      * @param _sInputFile       the original document
112      * @param _sReferencePath   the directory where the document will print as file or export as pdf.
113      *
114      * @throws  ConvWatchException if the are problems, see containing message
115      */
116     public static boolean createOneReferenceFile(String _sInputFile, String _sReferencePath, GraphicalTestArguments _aGTA) throws ConvWatchException
117         {
118             showVersion();
119             if (_aGTA != null)
120             {
121                 _aGTA.setInputFile(_sInputFile);
122             }
123             return OfficePrint.buildReference(_aGTA, _sReferencePath, _sInputFile);
124         }
125 
126     /**
127      * Check if a reference exist
128      *
129      * @param _sInputFile       the original document
130      * @param _sReferencePath   the directory where the document will print as file or export as pdf.
131      */
132     public static boolean isReferenceExists(String _sInputFile, String _sReferencePath, GraphicalTestArguments _aGTA)
133         {
134             return OfficePrint.isReferenceExists(_aGTA, _sReferencePath, _sInputFile);
135         }
136 
137 
138     /**
139      * Used for the comparance of graphical differences.
140      * Method compares one document (_sInputFile) with an older document of the same name in the provided directory (_sReferencePath).
141      *
142      * @param _sInputPath       the original document path
143      * @param _sOutputPath      path where the same directory structure of the given input path will create. All the result documents
144      *                          needed very much disk space (up to 10MB per page).
145      *                          The path _sOutputPath must be writeable.
146      * @param _sReferencePath   the directory where the document will print as file or export as pdf.
147      * @param _aGTA             Helper class for lot of parameter to control the office.
148      *
149      * Disadvantage: stops rest if one test file has a problem.
150      */
151     public static boolean check(String _sInputPath, String _sOutputPath, String _sReferencePath, GraphicalTestArguments _aGTA ) throws ConvWatchException
152         {
153             return check(_sInputPath, _sOutputPath, _sReferencePath, null, _aGTA);
154         }
155 
156     /**
157      * Used for the comparance of graphical differences.
158      * Method compares one document (_sInputFile) with an older document of the same name in the provided directory (_sReferencePath).
159      *
160      * @param _sInputPath       the original document path
161      * @param _sReferencePath   the directory where the document will print as file or export as pdf.
162      * @param _sOutputPath      path where the same directory structure of the given input path will create. All the result documents
163      *                          needed very much disk space (up to 10MB per page).
164      *                          The path _sOutputPath must be writeable.
165      * @param _sDiffPath        Path to older differences.
166      * @param _aGTA             Helper class for lot of parameter to control the office.
167      *
168      *
169      * Stops all, if one creation of reference fails
170      */
171     public static boolean check(String _sInputPath, String _sOutputPath, String _sReferencePath, String _sDiffPath, GraphicalTestArguments _aGTA ) throws ConvWatchException
172         {
173             showVersion();
174 
175             boolean bOk = true;
176 
177             File aInputPath = new File(_sInputPath);
178             if (aInputPath.isDirectory())
179             {
180                 String fs = System.getProperty("file.separator");
181                 // a whole directory
182                 Object[] aList = DirectoryHelper.traverse(_sInputPath, FileHelper.getFileFilter(), _aGTA.includeSubDirectories());
183                 if (aList.length != 0)
184                 {
185                     for (int i=0;i<aList.length;i++)
186                     {
187                         String sEntry = (String)aList[i];
188                         String sNewSubDir = FileHelper.removeFirstDirectorysAndBasenameFrom(sEntry, _sInputPath);
189                         String sNewReferencePath = _sReferencePath;
190                         String sNewOutputPath = _sOutputPath;
191                         String sNewDiffPath = _sDiffPath;
192                         if (sNewSubDir.length() > 0)
193                         {
194                             if (sNewReferencePath != null)
195                             {
196                                 sNewReferencePath = sNewReferencePath + fs + sNewSubDir;
197                             }
198 
199                             sNewOutputPath = sNewOutputPath + fs + sNewSubDir;
200                             if (sNewDiffPath != null)
201                             {
202                                 sNewDiffPath = sNewDiffPath + fs + sNewSubDir;
203                             }
204                         }
205                         bOk &= checkOneFile(sEntry, sNewOutputPath, sNewReferencePath, sNewDiffPath, _aGTA);
206                     }
207                 }
208             }
209             else
210             {
211                 bOk = /* GraphicalDifferenceCheck.*/ checkOneFile(_sInputPath, _sOutputPath, _sReferencePath, _sDiffPath, _aGTA);
212             }
213             return bOk;
214         }
215 
216     /**
217      * Used for the comparance of graphical differences.
218      * Method compares one document (_sInputFile) with an older document of the same name in the provided directory (_sReferencePath).
219      *
220      * The path _sOutputPath must be writeable
221      */
222     public static boolean checkOneFile(String _sInputFile, String _sOutputPath, String _sReferencePath, GraphicalTestArguments _aGTA)  throws ConvWatchException
223     {
224         return checkOneFile( _sInputFile, _sOutputPath, _sReferencePath, null, _aGTA);
225     }
226 
227 
228     /**
229      * Used for the comparance of graphical differences.
230      * Method compares one document (_sInputFile) with an older document of the same name in the provided directory (_sReferencePath).
231      *
232      * For scenarios, where a difference is known and further changes are of interest, differences itself can be compared.
233      * This functionality is provided by the difference path parameter (_sDiffPath). If set, the difference of the current comparance (between input and reference),
234      * will be compared with the (same named) difference document from a earlier comparance.
235      *
236      * The path _sOutputPath must be writeable
237      */
238     public static boolean checkOneFile(String _sInputFile, String _sOutputPath, String _sReferencePath, String _sDiffPath, GraphicalTestArguments _aGTA ) throws ConvWatchException
239         {
240             showVersion();
241             if (_aGTA != null)
242             {
243                 _aGTA.setInputFile(_sInputFile);
244             }
245 
246             boolean bOk = false;
247             if (_sDiffPath != null)
248             {
249                 // check with an old diff
250                 bOk = convwatch.ConvWatch.checkDiffDiff(_aGTA, _sOutputPath, _sInputFile, _sReferencePath, _sDiffPath);
251             }
252             else
253             {
254                 // one file
255                 bOk = convwatch.ConvWatch.check(_aGTA, _sOutputPath, _sInputFile, _sReferencePath);
256             }
257             return bOk;
258         }
259 
260     /**
261      * Instead of providing a saved document for graphical comparance a StarOffice xComponent
262      * will be saved and afterwards compared.
263      *
264      * @param xComponent        the test document to be compared as StarOffice component
265      * @param _sOutputPath      Path where test results are supposed to been saved. The path _sOutputPath must be writeable.
266      *                          These documents need sufficient disk space (up to 10MB per page).
267      *                          A directory structure will be created, which is a mirrored from input path.
268      *
269      * @param _resultDocName    Name by which the xComponent shall be saved as OpenOffice.org XML document.
270      *                          If provided without suffix, the suffix will be derived from the export filter.
271      * @param _sReferencePath   the directory where the document will print as file or export as pdf.
272      * @param _aGTA             Helper class for lot of parameter to control the office.
273      */
274     public static boolean checkOneFile(XComponent xComponent, String _sOutputPath, String _resultDocName, String _sReferencePath, GraphicalTestArguments _aGTA ) throws ConvWatchException
275         {
276             showVersion();
277 
278             // one file
279             String sInputFile;
280             sInputFile = createInputFile(xComponent, _sOutputPath, _resultDocName);
281             sInputFile = FileHelper.getSystemPathFromFileURL(sInputFile);
282             return convwatch.ConvWatch.check(_aGTA, _sOutputPath, sInputFile, _sReferencePath);
283         }
284 
285 
286 // LLA: old!     /**
287 // LLA: old!      * Returns 'true' if a reference document on the specific output path exists.
288 // LLA: old!      * The name of the document is corresponding to the input document, which can be
289 // LLA: old!      * provided by a single name or path.
290 // LLA: old!      *
291 // LLA: old!      * @param inputPath       the original document name (possibly including path)
292 // LLA: old!      * @param referencePath   the directory where the reference document will be stored
293 // LLA: old!
294 // LLA: old!      */
295 // LLA: old!     public static boolean isReferencExistent(String inputDocumentPath, String referencePath)
296 // LLA: old!     {
297 // LLA: old! 		// isolate the document name
298 // LLA: old!         if(inputDocumentPath.indexOf(File.separator) != -1)
299 // LLA: old!             inputDocumentPath = inputDocumentPath.substring(inputDocumentPath.lastIndexOf(File.separator) + 1, inputDocumentPath.length());
300 // LLA: old!
301 // LLA: old! 		// exchange any arbitray suffix against the refence suffix (.prn)
302 // LLA: old!         if(inputDocumentPath.indexOf('.') != -1)
303 // LLA: old!             inputDocumentPath = inputDocumentPath.substring(0, inputDocumentPath.lastIndexOf('.'));
304 // LLA: old!         inputDocumentPath = inputDocumentPath + ".prn";
305 // LLA: old! System.out.println("GraphicalDifference CheckReferenceDocument: " + inputDocumentPath);
306 // LLA: old!
307 // LLA: old!         File refFile = new File(referencePath + inputDocumentPath);
308 // LLA: old!         if(refFile.exists()){
309 // LLA: old!             return true;
310 // LLA: old!         }else
311 // LLA: old!             return false;
312 // LLA: old! 	}
313 
314 
315     private static String createInputFile(XComponent xComponent, String _sOutputPath, String resultDocName)
316         throws ConvWatchCancelException
317     {
318 
319         // find the adequate XML StarOffice output filter to save the document and adequate suffix
320         StringBuffer suffix = new StringBuffer();
321         String exportFilter = getXMLOutputFilterforXComponent(xComponent, suffix);
322         if(resultDocName == null)
323             resultDocName = "OOoTestDocument";
324         if(resultDocName.indexOf('.') == -1)
325             resultDocName = suffix.insert(0, resultDocName).toString();
326 
327         // create a result URL for storing the office document
328         String resultURL = URLHelper.getFileURLFromSystemPath(ensureEndingFileSep(_sOutputPath) + resultDocName);
329 
330         XStorable xStorable = null;
331         xStorable  = (com.sun.star.frame.XStorable)UnoRuntime.queryInterface(com.sun.star.frame.XStorable.class, xComponent);
332         if(xStorable == null)
333         {
334             throw new ConvWatchCancelException("com.sun.star.frame.XStorable could not be instantiated from the office.");
335         }
336 
337         PropertyValue pvFilterName = new PropertyValue("FilterName", -1, exportFilter, com.sun.star.beans.PropertyState.getDefault());
338         PropertyValue pvOverwrite = new PropertyValue("Overwrite", -1, new Boolean(true), com.sun.star.beans.PropertyState.getDefault());
339 
340         try
341         {
342             xStorable.storeAsURL(resultURL, new PropertyValue[]{pvFilterName, pvOverwrite});
343         }
344         catch (com.sun.star.io.IOException e)
345         {
346             // wrap IOException
347             throw new ConvWatchCancelException("Wrap IOException caught, " + e.getMessage());
348         }
349 
350         GlobalLogWriter.get().println("Saving XComponent as " + resultURL);
351 
352         return resultURL;
353     }
354 
355 
356     private static String getXMLOutputFilterforXComponent(XComponent xComponent, StringBuffer suffix){
357         XServiceInfo xSI = (XServiceInfo) UnoRuntime.queryInterface(XServiceInfo.class, xComponent);
358         if (xSI.supportsService("com.sun.star.text.TextDocument")){
359             resetBuffer(suffix, ".sxw");
360             return "swriter: StarOffice XML (Writer)";
361         }else if (xSI.supportsService("com.sun.star.sheet.SpreadsheetDocument")){
362             resetBuffer(suffix, ".sxc");
363             return "scalc: StarOffice XML (Calc)";
364         }else if (xSI.supportsService("com.sun.star.presentation.PresentationDocument")){
365             resetBuffer(suffix, ".sxi");
366             return "simpress: StarOffice XML (Impress)";
367         }else if(xSI.supportsService("com.sun.star.drawing.DrawingDocument")){
368             resetBuffer(suffix, ".sxd");
369             return "sdraw: StarOffice XML (Draw)";
370         }else if (xSI.supportsService("com.sun.star.formula.FormulaProperties")){
371             resetBuffer(suffix, ".sxm");
372             return "smath: StarOffice XML (Math)";
373         }
374         return null;
375     }
376 
377     private static StringBuffer resetBuffer(StringBuffer sb, String suffix)
378         {
379             if(sb != null)
380             {
381                 sb.replace(0, sb.length(), suffix);
382             }
383             return sb;
384         }
385 
386     private static String ensureEndingFileSep(String s)
387         {
388 	    if(s != null && !s.equals("") && !s.endsWith(File.separator))
389             {
390             	s = s.trim() + File.separator;
391             }
392             else
393             {
394                 if(s == null)
395                 {
396                     s = "";
397                 }
398             }
399 
400 	    return s;
401 	}
402 
403 
404 }
405