Add support to valign and nowrap features in <td> and <th> tags in help pages
[scilab.git] / scilab / modules / helptools / src / java / org / scilab / modules / helptools / HTMLDocbookTagConverter.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 package org.scilab.modules.helptools;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.net.URI;
21 import java.net.URISyntaxException;
22 import java.util.Date;
23 import java.util.Map;
24 import java.util.Stack;
25 import java.util.regex.Pattern;
26
27 import org.scilab.modules.commons.ScilabCommonsUtils;
28 import org.scilab.modules.helptools.XML.HTMLXMLCodeHandler;
29 import org.scilab.modules.helptools.XML.XMLLexer;
30 import org.scilab.modules.helptools.c.CLexer;
31 import org.scilab.modules.helptools.c.HTMLCCodeHandler;
32 import org.scilab.modules.helptools.external.HTMLMathMLHandler;
33 import org.scilab.modules.helptools.external.HTMLSVGHandler;
34 import org.scilab.modules.helptools.external.HTMLScilabHandler;
35 import org.scilab.modules.helptools.image.Image;
36 import org.scilab.modules.helptools.image.ImageConverter;
37 import org.scilab.modules.helptools.java.JavaLexer;
38 import org.scilab.modules.helptools.scilab.AbstractScilabCodeHandler;
39 import org.scilab.modules.helptools.scilab.HTMLScilabCodeHandler;
40 import org.scilab.modules.helptools.scilab.ScilabLexer;
41 import org.scilab.modules.localization.Messages;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44
45 /**
46  * Class to convert DocBook to HTML
47  * @author Calixte DENIZET
48  */
49 public class HTMLDocbookTagConverter extends DocbookTagConverter implements TemplateFiller {
50
51     public static enum GenerationType { WEB, JAVAHELP, CHM, HTML };
52
53     private static final String SCILAB_URI = "http://www.scilab.org";
54     private static final String LATEXBASENAME = "_LaTeX_";
55     private static final String VERSION = Messages.gettext("Version");
56     private static final String DESCRIPTION = Messages.gettext("Description");
57
58     private final StringBuilder buffer = new StringBuilder(8192);
59     private int latexCompt = 1;
60     private boolean hasExamples;
61     private int warnings;
62     private int nbFiles;
63
64     private final String imageDir;
65     protected String urlBase;
66     protected boolean linkToTheWeb;
67     protected final String outName;
68     protected String outImages;
69
70     protected final Map<String, String> mapId;
71     protected final Map<String, String> tocitem;
72     protected final HTMLDocbookLinkResolver.TreeId tree;
73     protected final Map<String, HTMLDocbookLinkResolver.TreeId> mapTreeId;
74     protected final Map<String, String> mapIdPurpose;
75     protected final Map<String, String> mapIdRefname;
76
77     protected final TemplateHandler templateHandler;
78
79     protected final ScilabLexer scilabLexer;
80     protected final XMLLexer xmlLexer;
81     protected final CLexer cLexer;
82     protected final JavaLexer javaLexer;
83
84     protected String bookTitle = "";
85     protected String partTitle = "";
86     protected String chapterTitle = "";
87     protected String sectionTitle = "";
88     protected String fileSubtitle = "";
89
90     protected String refpurpose = "";
91     protected String refname = "";
92     protected String version;
93     protected String appendToProgramListing;
94     protected String appendForExecToProgramListing;
95     protected String prependToProgramListing;
96     protected String currentId;
97     protected String indexFilename = "index" /*UUID.randomUUID().toString()*/ + ".html";
98     protected final String language;
99
100     protected final boolean isToolbox;
101     protected final Backend type;
102
103     /**
104      * Constructor
105      * @param inName the name of the input stream
106      * @param sciDocMain provide useful doc generation properties
107      * @param imgConvert the shared image converter for all generation
108      */
109     public HTMLDocbookTagConverter(String inName, SciDocMain sciDocMain, ImageConverter imgConvert) throws IOException, SAXException {
110         super(inName, imgConvert);
111
112         this.version = sciDocMain.getConf().getVersion();
113         this.imageDir = sciDocMain.getImagedir();
114         this.outName = sciDocMain.getOutputDirectory() + File.separator;
115         this.outImages = this.outName;
116
117         imgConvert.setDocbookTagConverter(this);
118         HTMLDocbookLinkResolver resolver = new HTMLDocbookLinkResolver(inName);
119
120         mapId = resolver.getMapId();
121         tocitem = resolver.getToc();
122         tree = resolver.getTree();
123         mapTreeId = resolver.getMapTreeId();
124         mapIdPurpose = resolver.getMapIdPurpose();
125         mapIdRefname = resolver.getMapIdRefname();
126
127         this.isToolbox = sciDocMain.isToolbox();
128         this.language = sciDocMain.getLanguage();
129         this.type = sciDocMain.getFormat();
130
131         if (isToolbox) {
132             urlBase = sciDocMain.getConf().getWebSiteURL() + language + "/";
133             linkToTheWeb = true;
134         } else {
135             urlBase = null;
136             linkToTheWeb = false;
137         }
138
139         if (isToolbox) {// we generate a toolbox's help
140             HTMLScilabCodeHandler.setLinkWriter(new AbstractScilabCodeHandler.LinkWriter() {
141                 public String getLink(String id) {
142                     if (id.length() > 0 && id.charAt(0) == '%') {
143                         id = id.replace("%", "percent");
144                     }
145                     String link = mapId.get(id);
146                     if (link == null) {
147                         return HTMLDocbookTagConverter.this.urlBase + id;
148                     } else {
149                         return link;
150                     }
151                 }
152             });
153         } else {// we generate Scilab's help
154             HTMLScilabCodeHandler.setLinkWriter(new AbstractScilabCodeHandler.LinkWriter() {
155                 public String getLink(String id) {
156                     if (id.length() > 0 && id.charAt(0) == '%') {
157                         id = id.replace("%", "percent");
158                     }
159                     return mapId.get(id);
160                 }
161             });
162         }
163
164         scilabLexer = new ScilabLexer(sciDocMain.getConf().getBuiltins(), sciDocMain.getConf().getMacros());
165         xmlLexer = new XMLLexer();
166         cLexer = new CLexer();
167         javaLexer = new JavaLexer();
168
169         final String template = sciDocMain.getConf().getTemplate(sciDocMain.getFormat().toString().toLowerCase());
170         File tpl = new File(template);
171         if (!tpl.isFile()) {
172             final String msg = "Could not find template document: " + template;
173             System.err.println(msg);
174             throw new RuntimeException();
175         }
176         templateHandler = new TemplateHandler(this, tpl, language);
177     }
178
179     public static boolean containsCJK(CharSequence seq) {
180         if (seq == null) {
181             return false;
182         }
183
184         for (int i = 0; i < seq.length(); i++) {
185             Character.UnicodeBlock block = Character.UnicodeBlock.of(seq.charAt(i));
186             if (block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
187                     || block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
188                     || block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
189                     || block == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS
190                     || block == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
191                     || block == Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT
192                     || block == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
193                     || block == Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS) {
194                 return true;
195             }
196         }
197
198         return false;
199     }
200
201     public static boolean containsCyrillic(CharSequence seq) {
202         if (seq == null) {
203             return false;
204         }
205
206         for (int i = 0; i < seq.length(); i++) {
207             Character.UnicodeBlock block = Character.UnicodeBlock.of(seq.charAt(i));
208             if (block == Character.UnicodeBlock.CYRILLIC || block == Character.UnicodeBlock.CYRILLIC_SUPPLEMENTARY) {
209                 return true;
210             }
211         }
212
213         return false;
214     }
215
216     /**
217      * Replace special chars
218      */
219     public static final String replaceEntity(final String str) {
220         return str.replaceAll("&", "&amp;").replaceAll("<", "&#0060;").replaceAll(">", "&#0062;").replaceAll("\"", "&#0034;").replaceAll("\'", "&#0039;");
221     }
222
223     /**
224      * Get the type of the generation
225      * @return the generation type
226      */
227     public final Backend getGenerationType() {
228         return type;
229     }
230
231     public String getLanguage() {
232         return language;
233     }
234
235     @Override
236     public void registerAllExternalXMLHandlers() {
237         super.registerAllExternalXMLHandlers();
238
239         registerExternalXMLHandler(new HTMLMathMLHandler(outImages, imageDir));
240         registerExternalXMLHandler(new HTMLSVGHandler(outImages, imageDir));
241         registerExternalXMLHandler(new HTMLScilabHandler(outImages, imageDir));
242     }
243
244     @Override
245     public void install() {
246         super.install();
247
248         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/scilab_code.css"), new File(outName + "/scilab_code.css"));
249         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/xml_code.css"), new File(outName + "/xml_code.css"));
250         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/c_code.css"), new File(outName + "/c_code.css"));
251         ScilabCommonsUtils.copyFile(new File(SCI + "/modules/helptools/data/css/style.css"), new File(outName + "/style.css"));
252     }
253
254     /**
255      * @return the buffer used
256      */
257     public StringBuilder getBuffer() {
258         return buffer;
259     }
260
261     /**
262      * @param tag the tag name
263      * @param contents the contents to enclose between opening and closing tags
264      */
265     public String encloseContents(final String tag, final String contents) {
266         buffer.setLength(0);
267         buffer.append("<");
268         buffer.append(tag);
269         buffer.append(">");
270         if (contents != null) {
271             buffer.append(contents);
272         }
273         buffer.append("</");
274         buffer.append(tag);
275         buffer.append(">");
276
277         return buffer.toString();
278     }
279
280     /**
281      * @param tag the tag name
282      * @param attrs the attributes {attr1, value1, attr2, value2, ...}
283      * @param contents the contents to enclose between opening and closing tags
284      */
285     public String encloseContents(final String tag, final String[] attrs, final String contents) {
286         buffer.setLength(0);
287         buffer.append("<");
288         buffer.append(tag);
289         if (attrs != null) {
290             for (int i = 0; i < attrs.length; i += 2) {
291                 if (attrs[i + 1] != null && !attrs[i + 1].isEmpty()) {
292                     buffer.append(" ");
293                     buffer.append(attrs[i]);
294                     buffer.append("=\"");
295                     buffer.append(attrs[i + 1]);
296                     buffer.append("\"");
297                 }
298             }
299         }
300
301         buffer.append(">");
302         if (contents != null) {
303             buffer.append(contents);
304         }
305         buffer.append("</");
306         buffer.append(tag);
307         buffer.append(">");
308
309         return buffer.toString();
310     }
311
312     /**
313      * @param tag the tag name
314      * @param clazz the css class name
315      * @param contents the contents to enclose between opening and closing tags
316      */
317     public String encloseContents(final String tag, final String clazz, final String contents) {
318         buffer.setLength(0);
319         buffer.append("<");
320         buffer.append(tag);
321         buffer.append(" class=\"");
322         buffer.append(clazz);
323         buffer.append("\">");
324         if (contents != null) {
325             buffer.append(contents);
326         }
327         buffer.append("</");
328         buffer.append(tag);
329         buffer.append(">");
330
331         return buffer.toString();
332     }
333
334     /**
335      * {@inheritDoc}
336      */
337     public boolean isEscapable(final String tagName, final String uri) {
338         return !"latex".equals(tagName) && !"screen".equals(tagName) && !"programlisting".equals(tagName) && !"code".equals(tagName) && !"synopsis".equals(tagName) && !(uri.equals(SCILAB_URI) && tagName.equals("image"));
339     }
340
341     /**
342      * {@inheritDoc}
343      */
344     public boolean isTrimable(final String tagName) {
345         return !"screen".equals(tagName) && !"programlisting".equals(tagName) && !"code".equals(tagName) && !"synopsis".equals(tagName);
346     }
347
348     /**
349      * @param fileName the file to create
350      * @param subtitle the subtitle of the file
351      * @param contents the contents of the file
352      */
353     public void createHTMLFile(final String id, final String fileName, final String subtitle, final String contents) {
354         if (!hasError) {
355             fileSubtitle = subtitle;
356             nbFiles++;
357             templateHandler.generateFileFromTemplate(outName + fileName, id, contents);
358         }
359     }
360
361
362
363     /**
364      * @param code the code to translate
365      * @param img image information
366      * @param fileName the filename
367      * @param attrs the attribute of the image
368      * @return the HTML code to insert the image
369      */
370     public String generateCode(Image img, String fileName, Map<String, String> attrs, final String tooltipString) {
371         String style = attrs.get("style");
372         String top = "";
373         boolean display = style != null && style.equals("display");
374
375         if (!display) {
376             top = "top:" + img.descent + "px;";
377         }
378
379         String alignAttr = attrs.get("align");
380         String align = "";
381         String div = "div";
382         if (alignAttr != null) {
383             align = " style=\'text-align:" + alignAttr + "\'";
384         } else if (display) {
385             align = " style=\'text-align:center\'";
386         } else {
387             div = "span";
388         }
389
390         return "<" + div + align + "><img src=\'" + fileName + "\' style=\'position:relative;" + top  + "width:" + img.width + "px;height:" + img.height + "px\'/></" + div + ">";
391     }
392
393     /**
394      * {@inheritDoc}
395      */
396     public String makeTitle(final String id) {
397         if (refname.length() > 0) {
398             return tocitem.get(id);
399         }
400
401         return "";
402     }
403
404     /**
405      * {@inheritDoc}
406      */
407     public String makeSubtitle(final String id) {
408         return fileSubtitle;
409     }
410
411     /**
412      * {@inheritDoc}
413      */
414     public String makePrevious(final String id) {
415         buffer.setLength(0);
416         buffer.append("<span class=\"previous\">");
417         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
418         if (leaf == null) {
419             return "";
420         }
421         HTMLDocbookLinkResolver.TreeId prev = leaf.getPrevious();
422         if (prev.parent != null) {
423             buffer.append("<a href=\"");
424             buffer.append(mapId.get(prev.id));
425             buffer.append("\">&lt;&lt; ");
426             buffer.append(tocitem.get(prev.id));
427             buffer.append("</a></span>\n");
428
429             return buffer.toString();
430         }
431
432         return "";
433     }
434
435     /**
436      * {@inheritDoc}
437      */
438     public String makePath(final String id) {
439         buffer.setLength(0);
440         buffer.append("<span class=\"path\">");
441         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
442         if (leaf == null) {
443             return "";
444         }
445         String str = tocitem.get(id);
446         leaf = leaf.parent;
447         while (leaf != null && !leaf.isRoot()) {
448             str = "<a href=\"" + mapId.get(leaf.id) + "\">" + tocitem.get(leaf.id) + "</a> &gt; " + str;
449             leaf = leaf.parent;
450         }
451
452         str = "<a href=\"" + indexFilename  + "\">" + bookTitle + "</a> &gt;&gt; " + str;
453         buffer.append(str);
454         buffer.append("</span>\n");
455
456         return buffer.toString();
457     }
458
459     /**
460      * {@inheritDoc}
461      */
462     public String makeTop(final String id) {
463         buffer.setLength(0);
464         buffer.append("<span class=\"top\">");
465         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
466         if (leaf == null) {
467             return "";
468         }
469
470         leaf = leaf.parent;
471         if (leaf != null) {
472             buffer.append("<a href=\"");
473             if (!leaf.isRoot()) {
474                 buffer.append(mapId.get(leaf.id));
475                 buffer.append("\">");
476                 buffer.append(tocitem.get(leaf.id));
477             } else {
478                 buffer.append(indexFilename);
479                 buffer.append("\">");
480                 buffer.append(bookTitle);
481             }
482             buffer.append("</a></span>\n");
483         } else {
484             return "";
485         }
486
487         return buffer.toString();
488     }
489
490     /**
491      * {@inheritDoc}
492      */
493     public String makeNext(final String id) {
494         buffer.setLength(0);
495         buffer.append("<span class=\"next\">");
496         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
497         if (leaf == null) {
498             return "";
499         }
500         HTMLDocbookLinkResolver.TreeId next = leaf.getNext();
501         if (next != null) {
502             buffer.append("<a href=\"");
503             buffer.append(mapId.get(next.id));
504             buffer.append("\">");
505             buffer.append(tocitem.get(next.id));
506             buffer.append(" &gt;&gt;</a></span>\n");
507
508             return buffer.toString();
509         }
510
511         return "";
512     }
513
514     /**
515      * {@inheritDoc}
516      */
517     public String makeStart(final String id) {
518         buffer.setLength(0);
519         buffer.append("<span class=\"start\">");
520         buffer.append("<a href=\"");
521         buffer.append(indexFilename);
522         buffer.append("\">");
523         buffer.append(bookTitle);
524         buffer.append("</a></span>\n");
525
526         return buffer.toString();
527     }
528
529     /**
530      * {@inheritDoc}
531      */
532     public String makeTocList(final String id) {
533         buffer.setLength(0);
534         HTMLDocbookLinkResolver.TreeId leaf = mapTreeId.get(id);
535         if (leaf == null) {
536             return "";
537         }
538
539         HTMLDocbookLinkResolver.TreeId parent = leaf.parent;
540         buffer.append("<ul class=\"toc\">\n");
541         String str = "";
542         while (parent != null && !parent.isRoot()) {
543             str = "<li class=\"parent\"><a href=\"" + mapId.get(parent.id) + "\">" + tocitem.get(parent.id) + "</a></li>\n" + str;
544             parent = parent.parent;
545         }
546         buffer.append("<li class=\"root\"><a href=\"");
547         buffer.append(indexFilename);
548         buffer.append("\">");
549         buffer.append(bookTitle);
550         buffer.append("</a></li>\n");
551         buffer.append(str);
552
553         parent = leaf.parent;
554
555         for (HTMLDocbookLinkResolver.TreeId c : parent.children) {
556             if (c == leaf) {
557                 buffer.append("<li class=\"list-active\"><a href=\"");
558             } else {
559                 buffer.append("<li><a href=\"");
560             }
561             buffer.append(mapId.get(c.id));
562             buffer.append("\">");
563             buffer.append(tocitem.get(c.id));
564             buffer.append("</a></li>\n");
565         }
566         buffer.append("</ul>\n");
567
568         return buffer.toString();
569     }
570
571     /**
572      * {@inheritDoc}
573      */
574     public String makeLastModified(final String id) {
575         buffer.setLength(0);
576         try {
577             buffer.append("<span class=\"lastmodified\">");
578             buffer.append(new Date(new File(new URI(currentFileName)).lastModified()).toString());
579             buffer.append("</span>\n");
580         } catch (URISyntaxException e) {
581             e.printStackTrace();
582         }
583         return buffer.toString();
584     }
585
586     /**
587      * {@inheritDoc}
588      */
589     public String makeGenerationDate(final String id) {
590         buffer.setLength(0);
591         buffer.append("<span class=\"generationdate\">");
592         buffer.append(new Date(System.currentTimeMillis()).toString());
593         buffer.append("</span>\n");
594
595         return buffer.toString();
596     }
597
598     /**
599      * {@inheritDoc}
600      */
601     public String makeVersion(final String id) {
602         buffer.setLength(0);
603         buffer.append("<span class=\"version\">");
604         buffer.append(version);
605         buffer.append("</span>\n");
606
607         return buffer.toString();
608     }
609
610     private boolean isLinkedImage() {
611         Stack<DocbookElement> stack = getStack();
612         return stack.size() >= 3 && stack.get(stack.size() - 3).getName().equals("link");
613     }
614
615     @Override
616     public String generateImageCode(String code, String fileName, Map<String, String> attrs) {
617         String alignAttr = attrs.get("align");
618         boolean addDiv = getGenerationType() != Backend.JAVAHELP || !isLinkedImage();
619         final StringBuilder buffer = new StringBuilder(128);
620         if (addDiv && alignAttr != null) {
621             buffer.append("<div style=\'text-align:").append(alignAttr).append("\'>");
622         }
623         buffer.append("<img src=\'").append(fileName).append("\'/>");
624         if (addDiv && alignAttr != null) {
625             buffer.append("</div>");
626         }
627
628         if (getGenerationType() == Backend.WEB) {
629             /* Prepare the code for the html inclusion */
630             code = convertCode(code);
631             /* Provide a tooltip */
632             return "<div rel='tooltip' title='" + code + "'>" + buffer.toString() + "</div>";
633         } else {
634             /* No tooltip in the javahelp browser ...
635              * too limited html capabilities */
636             return buffer.toString();
637         }
638     }
639
640     @Override
641     public String generateImageCode(Image img, String fileName, Map<String, String> attrs) {
642         String style = attrs.get("style");
643         String top = "";
644         boolean display = style != null && style.equals("display");
645
646         if (!display) {
647             top = "top:" + img.descent + "px;";
648         }
649
650         String alignAttr = attrs.get("align");
651         String align = "";
652         String div = "div";
653         if (alignAttr != null) {
654             align = " style=\'text-align:" + alignAttr + "\'";
655         } else if (display) {
656             align = " style=\'text-align:center\'";
657         } else {
658             div = "span";
659         }
660
661         if (getGenerationType() == Backend.JAVAHELP && isLinkedImage()) {
662             // Java HTML renderer is not good... so when  the image is linked, we remove the div
663             return "<img src=\'" + fileName + "\' style=\'position:relative;" + top  + "width:" + img.width + "px;height:" + img.height + "px\'/>>";
664         } else {
665             return "<" + div + align + "><img src=\'" + fileName + "\' style=\'position:relative;" + top  + "width:" + img.width + "px;height:" + img.height + "px\'/></" + div + ">";
666         }
667     }
668
669     @Override
670     public String generateImageCode(String fileName, Map<String, String> attrs) {
671         String alignAttr = attrs.get("align");
672         boolean addDiv = getGenerationType() != Backend.JAVAHELP || !isLinkedImage();
673         final StringBuilder buffer = new StringBuilder(128);
674         if (addDiv && alignAttr != null) {
675             buffer.append("<div style=\'text-align:").append(alignAttr).append("\'>");
676         }
677         buffer.append("<img src=\'").append(fileName).append("\'/>");
678         if (addDiv && alignAttr != null) {
679             buffer.append("</div>");
680         }
681
682         return buffer.toString();
683     }
684
685     public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
686         latexCompt = 1;
687         return super.resolveEntity(publicId, systemId);
688     }
689
690     /**
691      * Handle a refentry
692      * @param attributes the tag attributes
693      * @param contents the tag contents
694      * @return the HTML code
695      * @throws SAXEception if an error is encountered
696      */
697     public String handleRefentry(final Map<String, String> attributes, final String contents) throws SAXException {
698         String id = attributes.get("id");
699         if (id != null) {
700             currentId = id;
701         }
702         String fileName = mapId.get(currentId);
703         String needsExampleAttr = attributes.get("needs-examples");
704         createHTMLFile(currentId, fileName, refpurpose, contents);
705         if (!hasExamples && (needsExampleAttr == null || !needsExampleAttr.equals("no"))) {
706             warnings++;
707             //System.err.println("Warning (should be fixed): no example in " + currentFileName);
708         } else {
709             hasExamples = false;
710         }
711         String rp = encloseContents("span", "refentry-description", refpurpose);
712         String str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "refentry"}, refname) + " &#8212; " + rp);
713         refpurpose = "";
714         refname = "";
715         currentId = null;
716
717         return str;
718     }
719
720     /**
721      * Handle a section
722      * @param attributes the tag attributes
723      * @param contents the tag contents
724      * @return the HTML code
725      * @throws SAXEception if an error is encountered
726      */
727     public String handleSection(final Map<String, String> attributes, final String contents) throws SAXException {
728         String fileName = attributes.get("id") + ".html";
729         String str = encloseContents("ul", "list-refentry", contents);
730         String title = encloseContents("h3", "title-section", sectionTitle);
731         createHTMLFile(attributes.get("id"), fileName, sectionTitle, title + "\n" + str);
732
733         str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "section"}, sectionTitle) + "\n" + str);
734         sectionTitle = "";
735
736         return str;
737     }
738
739     /**
740      * Handle a book
741      * @param attributes the tag attributes
742      * @param contents the tag contents
743      * @return the HTML code
744      * @throws SAXEception if an error is encountered
745      */
746     public String handleBook(final Map<String, String> attributes, final String contents) throws SAXException {
747         String str = encloseContents("ul", "list-part", contents);
748         String btitle;
749         if (bookTitle.trim().equalsIgnoreCase("Scilab")) {
750             btitle = version;
751         } else {
752             btitle = bookTitle;
753         }
754         String title = encloseContents("h3", "book-title", btitle);
755         createHTMLFile("index", indexFilename, btitle, title + "\n" + str);
756
757         if (warnings != 0) {
758             System.err.println("Total files without example: " + warnings);
759             System.err.println("Total generated html files: " + nbFiles);
760         }
761
762         return encloseContents("li", encloseContents("a", new String[] {"href", indexFilename, "class", "part"}, bookTitle) + "\n" + str);
763     }
764
765     /**
766      * Handle a part
767      * @param attributes the tag attributes
768      * @param contents the tag contents
769      * @return the HTML code
770      * @throws SAXEception if an error is encountered
771      */
772     public String handlePart(final Map<String, String> attributes, final String contents) throws SAXException {
773         String fileName = attributes.get("id") + ".html";
774         String str = encloseContents("ul", "list-chapter", contents);
775         String title = encloseContents("h3", "title-part", partTitle);
776         createHTMLFile(attributes.get("id"), fileName, partTitle, title + "\n" + str);
777         str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "part"}, partTitle) + "\n" + str);
778         partTitle = "";
779
780         return str;
781     }
782
783     /**
784      * Handle a chapter
785      * @param attributes the tag attributes
786      * @param contents the tag contents
787      * @return the HTML code
788      * @throws SAXEception if an error is encountered
789      */
790     public String handleChapter(final Map<String, String> attributes, final String contents) throws SAXException {
791         String fileName = attributes.get("id") + ".html";
792         String str = encloseContents("ul", "list-refentry", contents);
793         String title = encloseContents("h3", "title-chapter", chapterTitle);
794         createHTMLFile(attributes.get("id"), fileName, chapterTitle, title + "\n" + str);
795
796         str = encloseContents("li", encloseContents("a", new String[] {"href", fileName, "class", "chapter"}, chapterTitle) + "\n" + str);
797         chapterTitle = "";
798
799         return str;
800     }
801
802     // partiellement merdique car le style de title depend du noeud pere.
803     /**
804      * Handle a title
805      * @param attributes the tag attributes
806      * @param contents the tag contents
807      * @return the HTML code
808      * @throws SAXEception if an error is encountered
809      */
810     public String handleTitle(final Map<String, String> attributes, final String contents) throws SAXException {
811         String clazz = "title";
812         String parent = getParentTagName();
813         if (parent.equals("chapter")) {
814             chapterTitle = contents;
815         } else if (parent.equals("part")) {
816             partTitle = contents;
817         } else if (parent.equals("info")) {
818             bookTitle = contents;
819         } else if (parent.equals("section")) {
820             sectionTitle = contents;
821         } else if (parent.equals("refsection") && Pattern.matches("^[ \\t]*ex[ea]mpl[eo].*", contents.toLowerCase())) {
822             hasExamples = true;
823             return encloseContents("h3", clazz, contents);
824         } else if (parent.equals("refsect1")) {
825             return encloseContents("h3", clazz, contents);
826         } else if (parent.equals("refsect2")) {
827             return encloseContents("h4", clazz, contents);
828         } else if (parent.equals("refsect3")) {
829             return encloseContents("h5", clazz, contents);
830         } else {
831             return encloseContents("h3", clazz, contents);
832         }
833
834         return null;
835     }
836
837     /**
838      * Handle a para
839      * @param attributes the tag attributes
840      * @param contents the tag contents
841      * @return the HTML code
842      * @throws SAXEception if an error is encountered
843      */
844     public String handlePara(final Map<String, String> attributes, final String contents) throws SAXException {
845         return encloseContents("p", "para", contents);
846     }
847
848     /**
849      * Handle a literal
850      * @param attributes the tag attributes
851      * @param contents the tag contents
852      * @return the HTML code
853      * @throws SAXEception if an error is encountered
854      */
855     public String handleLiteral(final Map<String, String> attributes, final String contents) throws SAXException {
856         return encloseContents("code", "literal", contents);
857     }
858
859     /**
860      * Handle a literallayout
861      * @param attributes the tag attributes
862      * @param contents the tag contents
863      * @return the HTML code
864      * @throws SAXEception if an error is encountered
865      */
866     public String handleLiterallayout(final Map<String, String> attributes, final String contents) throws SAXException {
867
868         //replace \n by <br>
869         String s = contents.replace("\n", "<BR>");
870         //replace spaces by &nbsp;
871         s = s.replace(" ", "&nbsp;");
872
873         return encloseContents("code", "literallayout", s);
874     }
875
876     /**
877      * Handle a varname
878      * @param attributes the tag attributes
879      * @param contents the tag contents
880      * @return the HTML code
881      * @throws SAXEception if an error is encountered
882      */
883     public String handleVarname(final Map<String, String> attributes, final String contents) throws SAXException {
884         return encloseContents("code", "varname", contents);
885     }
886
887     /**
888      * Handle a command
889      * @param attributes the tag attributes
890      * @param contents the tag contents
891      * @return the HTML code
892      * @throws SAXEception if an error is encountered
893      */
894     public String handleCommand(final Map<String, String> attributes, final String contents) throws SAXException {
895         return encloseContents("code", "command", contents);
896     }
897
898     /**
899      * Handle a code
900      * @param attributes the tag attributes
901      * @param contents the tag contents
902      * @return the HTML code
903      * @throws SAXEception if an error is encountered
904      */
905     public String handleCode(final Map<String, String> attributes, final String contents) throws SAXException {
906         return encloseContents("code", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));//encloseContents("code", "code", contents);
907     }
908
909     /**
910      * Handle a function
911      * @param attributes the tag attributes
912      * @param contents the tag contents
913      * @return the HTML code
914      * @throws SAXEception if an error is encountered
915      */
916     public String handleFunction(final Map<String, String> attributes, final String contents) throws SAXException {
917         return encloseContents("code", "function", contents);
918     }
919
920     /**
921      * Handle a constant
922      * @param attributes the tag attributes
923      * @param contents the tag contents
924      * @return the HTML code
925      * @throws SAXEception if an error is encountered
926      */
927     public String handleConstant(final Map<String, String> attributes, final String contents) throws SAXException {
928         return encloseContents("code", "constant", contents);
929     }
930
931     /**
932      * Handle an option
933      * @param attributes the tag attributes
934      * @param contents the tag contents
935      * @return the HTML code
936      * @throws SAXEception if an error is encountered
937      */
938     public String handleOption(final Map<String, String> attributes, final String contents) throws SAXException {
939         return encloseContents("code", "option", contents);
940     }
941
942     /**
943      * Handle a refnamediv
944      * @param attributes the tag attributes
945      * @param contents the tag contents
946      * @return the HTML code
947      * @throws SAXEception if an error is encountered
948      */
949     public String handleRefnamediv(final Map<String, String> attributes, final String contents) throws SAXException {
950         String id = attributes.get("id");
951         if (id != null) {
952             currentId = id;
953         }
954
955         return encloseContents("div", "refnamediv", contents);
956     }
957
958     /**
959      * Handle a refname
960      * @param attributes the tag attributes
961      * @param contents the tag contents
962      * @return the HTML code
963      * @throws SAXEception if an error is encountered
964      */
965     public String handleRefname(final Map<String, String> attributes, final String contents) throws SAXException {
966         refname = contents;
967         return encloseContents("h1", "refname", contents);
968     }
969
970     /**
971      * Handle a refpurpose
972      * @param attributes the tag attributes
973      * @param contents the tag contents
974      * @return the HTML code
975      * @throws SAXEception if an error is encountered
976      */
977     public String handleRefpurpose(final Map<String, String> attributes, final String contents) throws SAXException {
978         refpurpose = contents;
979         return encloseContents("p", "refpurpose", contents);
980     }
981
982     /**
983      * Handle a refsynopsisdiv
984      * @param attributes the tag attributes
985      * @param contents the tag contents
986      * @return the HTML code
987      * @throws SAXEception if an error is encountered
988      */
989     public String handleRefsynopsisdiv(final Map<String, String> attributes, final String contents) throws SAXException {
990         String id = attributes.get("id");
991         if (id != null) {
992             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsynopsisdiv", contents);
993         } else {
994             return encloseContents("div", "refsynopsisdiv", contents);
995         }
996     }
997
998     /**
999      * Handle a synopsis
1000      * @param attributes the tag attributes
1001      * @param contents the tag contents
1002      * @return the HTML code
1003      * @throws SAXEception if an error is encountered
1004      */
1005     public String handleSynopsis(final Map<String, String> attributes, final String contents) throws SAXException {
1006         String id = attributes.get("id");
1007         String str = encloseContents("div", "synopsis", encloseContents("pre", SynopsisLexer.convert(refname, contents)));
1008         if (id != null) {
1009             return "<a name=\"" + id + "\"></a>" + str;
1010         } else {
1011             return str;
1012         }
1013     }
1014
1015     /**
1016      * Handle a info
1017      * @param attributes the tag attributes
1018      * @param contents the tag contents
1019      * @return the HTML code
1020      * @throws SAXEception if an error is encountered
1021      */
1022     public String handleInfo(final Map<String, String> attributes, final String contents) throws SAXException {
1023         String id = attributes.get("id");
1024         if (id != null) {
1025             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "info", contents);
1026         } else {
1027             return encloseContents("div", "info", contents);
1028         }
1029     }
1030
1031     /**
1032      * Handle a refsection
1033      * @param attributes the tag attributes
1034      * @param contents the tag contents
1035      * @return the HTML code
1036      * @throws SAXEception if an error is encountered
1037      */
1038     public String handleRefsection(final Map<String, String> attributes, final String contents) throws SAXException {
1039         String id = attributes.get("id");
1040         if (id != null) {
1041             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsection", contents);
1042         } else {
1043             return encloseContents("div", "refsection", contents);
1044         }
1045     }
1046
1047     /**
1048      * Handle a refsect1
1049      * @param attributes the tag attributes
1050      * @param contents the tag contents
1051      * @return the HTML code
1052      * @throws SAXEception if an error is encountered
1053      */
1054     public String handleRefsect1(final Map<String, String> attributes, final String contents) throws SAXException {
1055         String id = attributes.get("id");
1056         if (id != null) {
1057             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsect1", contents);
1058         } else {
1059             return encloseContents("div", "refsect1", contents);
1060         }
1061     }
1062
1063     /**
1064      * Handle a refsect2
1065      * @param attributes the tag attributes
1066      * @param contents the tag contents
1067      * @return the HTML code
1068      * @throws SAXEception if an error is encountered
1069      */
1070     public String handleRefsect2(final Map<String, String> attributes, final String contents) throws SAXException {
1071         String id = attributes.get("id");
1072         if (id != null) {
1073             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsect2", contents);
1074         } else {
1075             return encloseContents("div", "refsect2", contents);
1076         }
1077     }
1078
1079     /**
1080      * Handle a refsect3
1081      * @param attributes the tag attributes
1082      * @param contents the tag contents
1083      * @return the HTML code
1084      * @throws SAXEception if an error is encountered
1085      */
1086     public String handleRefsect3(final Map<String, String> attributes, final String contents) throws SAXException {
1087         String id = attributes.get("id");
1088         if (id != null) {
1089             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "refsect3", contents);
1090         } else {
1091             return encloseContents("div", "refsect3", contents);
1092         }
1093     }
1094
1095     /**
1096      * Handle an anchor
1097      * @param attributes the tag attributes
1098      * @param contents the tag contents
1099      * @return the HTML code
1100      * @throws SAXEception if an error is encountered
1101      */
1102     public String handleAnchor(final Map<String, String> attributes, final String contents) throws SAXException {
1103         String id = attributes.get("id");
1104         if (id != null) {
1105             return "<a name=\"" + id + "\">" + contents + "</a>";
1106         } else {
1107             return contents;
1108         }
1109     }
1110
1111     /**
1112      * Handle a progamlisting
1113      * @param attributes the tag attributes
1114      * @param contents the tag contents
1115      * @return the HTML code
1116      * @throws SAXEception if an error is encountered
1117      */
1118     public String handleProgramlisting(final Map<String, String> attributes, final String contents) throws SAXException {
1119         String id = attributes.get("id");
1120         String role = attributes.get("role");
1121         String str;
1122         if (role == null) {
1123             String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1124             if (prependToProgramListing != null) {
1125                 code = prependToProgramListing + code;
1126             }
1127             if (appendToProgramListing != null) {
1128                 code += appendToProgramListing;
1129             }
1130             str = encloseContents("div", "programlisting", code);
1131         } else {
1132             if (role.equals("xml")) {
1133                 str = encloseContents("div", "programlisting", encloseContents("pre", "xmlcode", xmlLexer.convert(HTMLXMLCodeHandler.getInstance(), contents)));
1134             } else if (role.equals("c") || role.equals("cpp") || role.equals("code_gateway")) {
1135                 hasExamples = true;
1136                 str = encloseContents("div", "programlisting", encloseContents("pre", "ccode", cLexer.convert(HTMLCCodeHandler.getInstance(), contents)));
1137             } else if (role.equals("java")) {
1138                 hasExamples = true;
1139                 str = encloseContents("div", "programlisting", encloseContents("pre", "ccode", javaLexer.convert(HTMLCCodeHandler.getInstance(), contents)));
1140             } else if (role.equals("exec")) {
1141                 String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1142                 if (prependToProgramListing != null) {
1143                     code = prependToProgramListing + code;
1144                 }
1145                 if (appendForExecToProgramListing != null) {
1146                     code += appendForExecToProgramListing;
1147                 }
1148                 str = encloseContents("div", "programlisting", code);
1149             } else if (role.equals("no-scilab-exec")) {
1150                 hasExamples = true;
1151                 String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1152                 str = encloseContents("div", "programlisting", code);
1153             } else {
1154                 String code = encloseContents("pre", "scilabcode", scilabLexer.convert(HTMLScilabCodeHandler.getInstance(refname, currentFileName), contents));
1155                 if (prependToProgramListing != null) {
1156                     code = prependToProgramListing + code;
1157                 }
1158                 if (appendToProgramListing != null) {
1159                     code += appendToProgramListing;
1160                 }
1161                 str = encloseContents("div", "programlisting", code);
1162             }
1163         }
1164         if (id != null) {
1165             return "<a name=\"" + id + "\"></a>" + str;
1166         } else {
1167             return str;
1168         }
1169     }
1170
1171     /**
1172      * Handle a screen
1173      * @param attributes the tag attributes
1174      * @param contents the tag contents
1175      * @return the HTML code
1176      * @throws SAXEception if an error is encountered
1177      */
1178     public String handleScreen(final Map<String, String> attributes, final String contents) throws SAXException {
1179         String id = attributes.get("id");
1180         String str = encloseContents("div", "screen", encloseContents("pre", contents));
1181         if (id != null) {
1182             return "<a name=\"" + id + "\"></a>" + str;
1183         } else {
1184             return str;
1185         }
1186     }
1187
1188     /**
1189      * Handle a pubdate
1190      * @param attributes the tag attributes
1191      * @param contents the tag contents
1192      * @return the HTML code
1193      * @throws SAXEception if an error is encountered
1194      */
1195     public String handlePubdate(final Map<String, String> attributes, final String contents) throws SAXException {
1196         return null;
1197     }
1198
1199     /**
1200      * Handle a simplelist
1201      * @param attributes the tag attributes
1202      * @param contents the tag contents
1203      * @return the HTML code
1204      * @throws SAXEception if an error is encountered
1205      */
1206     public String handleSimplelist(final Map<String, String> attributes, final String contents) throws SAXException {
1207         String style = "itemizedlist";
1208
1209         return encloseContents("ul", style, contents);
1210     }
1211
1212     /**
1213      * Handle a member
1214      * @param attributes the tag attributes
1215      * @param contents the tag contents
1216      * @return the HTML code
1217      * @throws SAXEception if an error is encountered
1218      */
1219     public String handleMember(final Map<String, String> attributes, final String contents) throws SAXException {
1220         return encloseContents("li", "member", contents);
1221     }
1222
1223     /**
1224      * Handle a link
1225      * @param attributes the tag attributes
1226      * @param contents the tag contents
1227      * @return the HTML code
1228      * @throws SAXEception if an error is encountered
1229      */
1230     public String handleLink(final Map<String, String> attributes, final String contents) throws SAXException {
1231         String link = attributes.get("linkend");
1232         if (link == null) {
1233             throw new SAXException("No linkend attribute in tag link");
1234         }
1235
1236         String type = attributes.get("type");
1237         String id;
1238         if (type != null && type.equals("scilab")) {
1239             if (this.type == Backend.JAVAHELP || this.type == Backend.HTML) {
1240                 id = resolvScilabLink(link);
1241             } else {
1242                 return contents;
1243             }
1244         } else if (type != null && type.equals("remote")) {
1245             id = makeRemoteLink(link);
1246         } else {
1247             id = mapId.get(link);
1248         }
1249
1250         if (id == null) {
1251             if (isToolbox) {
1252                 if (this.type == Backend.HTML) {
1253                     id = urlBase + link;
1254                     if (linkToTheWeb) {
1255                         id += ".html";
1256                     }
1257                 }
1258                 if (this.type == Backend.JAVAHELP) {
1259                     id = urlBase + link;
1260                 }
1261             } else {
1262                 warnings++;
1263                 System.err.println("Warning (should be fixed): invalid internal link to " + link + " in " + currentFileName + "\nat line " + locator.getLineNumber());
1264                 return null;
1265             }
1266         }
1267
1268         Stack<DocbookElement> stack = getStack();
1269         String refnameTarget = mapIdRefname.get(link);
1270         String str;
1271         if (contents != null && !contents.isEmpty()) {
1272             str = contents;
1273         } else {
1274             str = refnameTarget;
1275         }
1276
1277         if (str == null) {
1278             warnings++;
1279             System.err.println("Warning (should be fixed): empty link (no text will be printed) to " + link + " in " + currentFileName + "\nat line " + locator.getLineNumber());
1280         }
1281
1282         String href = encloseContents("a", new String[] {"href", id, "class", "link"}, str);
1283
1284         int s = stack.size();
1285         if (s >= 3) {
1286             DocbookElement elem = stack.get(s - 3);
1287             if (elem.getName().equals("refsection")) {
1288                 String role = elem.getAttributes().get("role");
1289                 if (role != null && role.equals("see also")) {
1290                     String purpose = mapIdPurpose.get(link);
1291                     if (purpose != null) {
1292                         return href + " &#8212; " + purpose;
1293                     } else {
1294                         return href;
1295                     }
1296                 }
1297             }
1298         }
1299
1300         return href;
1301     }
1302
1303     /**
1304      * Rewrite a link when its type is "scilab"
1305      * @param link the link
1306      * @return the modified link with protocol scilab:// for example
1307      */
1308     protected String resolvScilabLink(String link) {
1309         int pos = link.indexOf("/");
1310         if (pos == -1) {
1311             return null;
1312         }
1313
1314         String first = link.substring(0, pos);
1315         String second = link.substring(pos + 1);
1316         String[] toks = first.split("\\.");
1317         if (toks == null || toks.length != 2) {
1318             return null;
1319         }
1320
1321         if (!linkToTheWeb) {
1322             return urlBase + link;
1323         } else {
1324             if (toks[0].equals("scilab") && toks[1].equals("help")) {
1325                 return urlBase + second + ".html";
1326             } else {
1327                 return "#";
1328             }
1329         }
1330     }
1331
1332     /**
1333      * Make a remote link
1334      * @param link the link
1335      * @return the good link
1336      */
1337     protected String makeRemoteLink(String link) {
1338         return link;
1339     }
1340
1341     /**
1342      * Handle an ulink
1343      * @param attributes the tag attributes
1344      * @param contents the tag contents
1345      * @return the HTML code
1346      * @throws SAXEception if an error is encountered
1347      */
1348     public String handleUlink(final Map<String, String> attributes, final String contents) throws SAXException {
1349         String link = attributes.get("url");
1350         if (link == null) {
1351             throw new SAXException("No url attribute in tag ulink");
1352         }
1353
1354         return encloseContents("a", new String[] {"href", link, "class", "ulink"}, contents);
1355     }
1356
1357     /**
1358      * Handle a xref
1359      * @param attributes the tag attributes
1360      * @param contents the tag contents
1361      * @return the HTML code
1362      * @throws SAXEception if an error is encountered
1363      */
1364     public String handleXref(final Map<String, String> attributes, final String contents) throws SAXException {
1365         String link = attributes.get("linkend");
1366         if (link == null) {
1367             throw new SAXException("No linkend attribute in tag link");
1368         }
1369
1370         String id = mapId.get(link);
1371         if (id == null) {
1372             warnings++;
1373             System.err.println("Warning (should be fixed): invalid internal link to " + link + " in " + currentFileName + "\nat line " + locator.getLineNumber());
1374             return null;
1375         }
1376
1377         return encloseContents("a", new String[] {"href", id, "class", "xref"}, contents);
1378     }
1379
1380     /**
1381      * Handle a latex (not really a docbook tag...)
1382      * @param attributes the tag attributes
1383      * @param contents the tag contents
1384      * @return the HTML code
1385      * @throws SAXEception if an error is encountered
1386      */
1387     public String handleLatex(final Map<String, String> attributes, final String contents) throws SAXException {
1388         boolean isLocalized = "true".equals(attributes.get("localized"));
1389         File f;
1390         if (isLocalized) {
1391             f = new File(outImages + "/" + imageDir, LATEXBASENAME + currentBaseName + "_" + language + "_" + (latexCompt++) + ".png");
1392         } else {
1393             if ("ru_RU".equals(language) && HTMLDocbookTagConverter.containsCyrillic(contents)) {
1394                 System.err.println("Warning: LaTeX code in " + getCurrentFileName() + " contains cyrillic character. The tag <latex> should contain the attribute scilab:localized=\"true\"");
1395             } else if ("ja_JP".equals(language) && HTMLDocbookTagConverter.containsCJK(contents)) {
1396                 System.err.println("Warning: LaTeX code in " + getCurrentFileName() + " contains CJK character. The tag <latex> should contain the attribute scilab:localized=\"true\"");
1397             }
1398             f = new File(outImages + "/" + imageDir, LATEXBASENAME + currentBaseName + "_" + (latexCompt++) + ".png");
1399         }
1400
1401         String parent = getParentTagName();
1402         if (parent.equals("para") && !attributes.containsKey("style")) {
1403             attributes.put("style", "text");
1404         }
1405         String fs = attributes.get("fontsize");
1406         if (fs == null) {
1407             attributes.put("fontsize", "16");
1408         }
1409
1410         return getImageConverter().getImageByCode(currentFileName, contents, attributes, "image/latex", f, imageDir + "/" + f.getName(), getBaseImagePath(), locator.getLineNumber(), language, isLocalized);
1411     }
1412
1413     /**
1414      * Handle a term
1415      * @param attributes the tag attributes
1416      * @param contents the tag contents
1417      * @return the HTML code
1418      * @throws SAXEception if an error is encountered
1419      */
1420     public String handleTerm(final Map<String, String> attributes, final String contents) throws SAXException {
1421         String id = attributes.get("id");
1422         if (id != null) {
1423             return "<a name=\"" + id + "\"></a>" + encloseContents("span", "term", contents);
1424         } else {
1425             return encloseContents("span", "term", contents);
1426         }
1427     }
1428
1429     /**
1430      * Handle a listitem
1431      * @param attributes the tag attributes
1432      * @param contents the tag contents
1433      * @return the HTML code
1434      * @throws SAXEception if an error is encountered
1435      */
1436     public String handleListitem(final Map<String, String> attributes, final String contents) throws SAXException {
1437         String parent = getParentTagName();
1438         if (parent.equals("varlistentry")) {
1439             return encloseContents("dd", contents);
1440         }
1441         return encloseContents("li", contents);
1442     }
1443
1444     /**
1445      * Handle a varlistentry
1446      * @param attributes the tag attributes
1447      * @param contents the tag contents
1448      * @return the HTML code
1449      * @throws SAXEception if an error is encountered
1450      */
1451     public String handleVarlistentry(final Map<String, String> attributes, final String contents) throws SAXException {
1452         return encloseContents("dt", contents);
1453     }
1454
1455     /**
1456      * Handle a variablelist
1457      * @param attributes the tag attributes
1458      * @param contents the tag contents
1459      * @return the HTML code
1460      * @throws SAXEception if an error is encountered
1461      */
1462     public String handleVariablelist(final Map<String, String> attributes, final String contents) throws SAXException {
1463         return encloseContents("dl", contents);
1464     }
1465
1466     /**
1467      * Handle an itemizedlist
1468      * @param attributes the tag attributes
1469      * @param contents the tag contents
1470      * @return the HTML code
1471      * @throws SAXEception if an error is encountered
1472      */
1473     public String handleItemizedlist(final Map<String, String> attributes, final String contents) throws SAXException {
1474         String id = attributes.get("id");
1475         if (id != null) {
1476             return "<a name=\"" + id + "\"></a>" + encloseContents("ul", "itemizedlist", contents);
1477         } else {
1478             return encloseContents("ul", "itemizedlist", contents);
1479         }
1480     }
1481
1482     /**
1483      * Handle an emphasis
1484      * @param attributes the tag attributes
1485      * @param contents the tag contents
1486      * @return the HTML code
1487      * @throws SAXEception if an error is encountered
1488      */
1489     public String handleEmphasis(final Map<String, String> attributes, final String contents) throws SAXException {
1490         String role = attributes.get("role");
1491         if (role != null) {
1492             if (role.equals("bold")) {
1493                 return encloseContents("b", contents);
1494             }
1495             if (role.equals("italic")) {
1496                 return encloseContents("i", contents);
1497             }
1498         }
1499
1500         return encloseContents("em", contents);
1501     }
1502
1503     /**
1504      * Handle a tr
1505      * @param attributes the tag attributes
1506      * @param contents the tag contents
1507      * @return the HTML code
1508      * @throws SAXEception if an error is encountered
1509      */
1510     public String handleTr(final Map<String, String> attributes, final String contents) throws SAXException {
1511         String bgcolor = attributes.get("bgcolor");
1512
1513         return encloseContents("tr", new String[] {"bgcolor", bgcolor}, contents);
1514     }
1515
1516     /**
1517      * Handle a td
1518      * @param attributes the tag attributes
1519      * @param contents the tag contents
1520      * @return the HTML code
1521      * @throws SAXEception if an error is encountered
1522      */
1523     public String handleTd(final Map<String, String> attributes, final String contents) throws SAXException {
1524         String align   = attributes.get("align");
1525         String valign  = attributes.get("valign");
1526         String bgcolor = attributes.get("bgcolor");
1527         String colspan = attributes.get("colspan");
1528         String rowspan = attributes.get("rowspan");
1529         String style   = attributes.get("style");   /*  for style="white-space:nowrap" */
1530
1531         return encloseContents("td", new String[] {"align", align, "valign", valign, "bgcolor", bgcolor, "colspan", colspan, "rowspan", rowspan, "style", style}, contents);
1532     }
1533
1534     /**
1535      * Handle an informaltable
1536      * @param attributes the tag attributes
1537      * @param contents the tag contents
1538      * @return the HTML code
1539      * @throws SAXEception if an error is encountered
1540      */
1541     public String handleInformaltable(final Map<String, String> attributes, final String contents) throws SAXException {
1542         String id = attributes.get("id");
1543         String border = attributes.get("border");
1544         String cellpadding = attributes.get("cellpadding");
1545         String width = attributes.get("width");
1546         if (id != null) {
1547             return "<a name=\"" + id + "\"></a>" + encloseContents("table", new String[] {"class", "informaltable", "border", border, "cellpadding", cellpadding, "width", width}, contents);
1548         } else {
1549             return encloseContents("table", new String[] {"class", "informaltable", "border", border, "cellpadding", cellpadding, "width", width}, contents);
1550         }
1551     }
1552
1553     /**
1554      * Handle an imagedata
1555      * @param attributes the tag attributes
1556      * @param contents the tag contents
1557      * @return the HTML code
1558      * @throws SAXEception if an error is encountered
1559      */
1560     public String handleImagedata(final Map<String, String> attributes, final String contents) throws SAXException {
1561         String fileref = attributes.get("fileref");
1562         if (fileref == null) {
1563             if (contents == null || contents.length() == 0) {
1564                 throw new SAXException("No fileref attribute or no data in tag imagedata");
1565             }
1566
1567             return contents;
1568         }
1569
1570         try {
1571             String path = new File(new URI(currentFileName)).getParent();
1572             File file = ImageConverter.imageExists(path, fileref);
1573             if (file != null) {
1574                 throw new SAXException("The given fileref is not on an existing image file:\n" + fileref + " [" + file + "]");
1575             }
1576
1577             return getImageConverter().getImageByFile(attributes, path, fileref, outImages, imageDir, getBaseImagePath());
1578         }  catch (URISyntaxException e) {
1579             System.err.println(e);
1580         }
1581
1582         return null;
1583     }
1584
1585     /**
1586      * Handle an imageobject
1587      * @param attributes the tag attributes
1588      * @param contents the tag contents
1589      * @return the HTML code
1590      * @throws SAXEception if an error is encountered
1591      */
1592     public String handleImageobject(final Map<String, String> attributes, final String contents) throws SAXException {
1593         return contents;
1594     }
1595
1596     /**
1597      * Handle an textobject (as an alternative to imageobject)
1598      * @param attributes the tag attributes
1599      * @param contents the tag contents
1600      * @return the HTML code
1601      * @throws SAXEception if an error is encountered
1602      */
1603     public String handleTextobject(final Map<String, String> attributes, final String contents) throws SAXException {
1604         return "<!-- " + contents + " -->";
1605     }
1606
1607     /**
1608      * Handle an inlinemediaobject
1609      * @param attributes the tag attributes
1610      * @param contents the tag contents
1611      * @return the HTML code
1612      * @throws SAXEception if an error is encountered
1613      */
1614     public String handleInlinemediaobject(final Map<String, String> attributes, final String contents) throws SAXException {
1615         return encloseContents("span", contents);
1616     }
1617
1618     /**
1619      * Handle a screenshot
1620      * @param attributes the tag attributes
1621      * @param contents the tag contents
1622      * @return the HTML code
1623      * @throws SAXEception if an error is encountered
1624      */
1625     public String handleScreenshot(final Map<String, String> attributes, final String contents) throws SAXException {
1626         String id = attributes.get("id");
1627         if (id != null) {
1628             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "screenshot", contents);
1629         } else {
1630             return encloseContents("div", "screenshot", contents);
1631         }
1632     }
1633
1634     /**
1635      * Handle a mediaobject
1636      * @param attributes the tag attributes
1637      * @param contents the tag contents
1638      * @return the HTML code
1639      * @throws SAXEception if an error is encountered
1640      */
1641     public String handleMediaobject(final Map<String, String> attributes, final String contents) throws SAXException {
1642         String id = attributes.get("id");
1643         String c = contents.replaceFirst("top:([0-9]+)px;", "");
1644         if (id != null) {
1645             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "mediaobject", c);
1646         } else {
1647             return encloseContents("div", "mediaobject", c);
1648         }
1649     }
1650
1651     /**
1652      * Handle an informalequation
1653      * @param attributes the tag attributes
1654      * @param contents the tag contents
1655      * @return the HTML code
1656      * @throws SAXEception if an error is encountered
1657      */
1658     public String handleInformalequation(final Map<String, String> attributes, final String contents) throws SAXException {
1659         String id = attributes.get("id");
1660         if (id != null) {
1661             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "informalequation", contents);
1662         } else {
1663             return encloseContents("div", "informalequation", contents);
1664         }
1665     }
1666
1667     /**
1668      * Handle an orderedlist
1669      * @param attributes the tag attributes
1670      * @param contents the tag contents
1671      * @return the HTML code
1672      * @throws SAXEception if an error is encountered
1673      */
1674     public String handleOrderedlist(final Map<String, String> attributes, final String contents) throws SAXException {
1675         String numeration = "1";
1676         String numAttr = attributes.get("numeration");
1677         if (numAttr != null) {
1678             if (numAttr.equals("loweralpha")) {
1679                 numeration = "a";
1680             } else if (numAttr.equals("upperalpha")) {
1681                 numeration = "A";
1682             } else if (numAttr.equals("lowerroman")) {
1683                 numeration = "i";
1684             } else if (numAttr.equals("upperroman")) {
1685                 numeration = "I";
1686             }
1687         }
1688
1689         String id = attributes.get("id");
1690         if (id != null) {
1691             return "<a name=\"" + id + "\"></a>" + encloseContents("ol", new String[] {"type", numeration}, contents);
1692         } else {
1693             return encloseContents("ol", new String[] {"type", numeration}, contents);
1694         }
1695     }
1696
1697     /**
1698      * Handle a subscript
1699      * @param attributes the tag attributes
1700      * @param contents the tag contents
1701      * @return the HTML code
1702      * @throws SAXEception if an error is encountered
1703      */
1704     public String handleSubscript(final Map<String, String> attributes, final String contents) throws SAXException {
1705         return encloseContents("sub", contents);
1706     }
1707
1708     /**
1709      * Handle a superscript
1710      * @param attributes the tag attributes
1711      * @param contents the tag contents
1712      * @return the HTML code
1713      * @throws SAXEception if an error is encountered
1714      */
1715     public String handleSuperscript(final Map<String, String> attributes, final String contents) throws SAXException {
1716         return encloseContents("sup", contents);
1717     }
1718
1719     /**
1720      * Handle a replaceable
1721      * @param attributes the tag attributes
1722      * @param contents the tag contents
1723      * @return the HTML code
1724      * @throws SAXEception if an error is encountered
1725      */
1726     public String handleReplaceable(final Map<String, String> attributes, final String contents) throws SAXException {
1727         return encloseContents("span", "replaceable", contents);
1728     }
1729
1730     /**
1731      * Handle a question
1732      * @param attributes the tag attributes
1733      * @param contents the tag contents
1734      * @return the HTML code
1735      * @throws SAXEception if an error is encountered
1736      */
1737     public String handleQuestion(final Map<String, String> attributes, final String contents) throws SAXException {
1738         return encloseContents("dt", encloseContents("strong", contents));
1739     }
1740
1741     /**
1742      * Handle an answer
1743      * @param attributes the tag attributes
1744      * @param contents the tag contents
1745      * @return the HTML code
1746      * @throws SAXEception if an error is encountered
1747      */
1748     public String handleAnswer(final Map<String, String> attributes, final String contents) throws SAXException {
1749         return encloseContents("dd", contents);
1750     }
1751
1752     /**
1753      * Handle a qandaentry
1754      * @param attributes the tag attributes
1755      * @param contents the tag contents
1756      * @return the HTML code
1757      * @throws SAXEception if an error is encountered
1758      */
1759     public String handleQandaentry(final Map<String, String> attributes, final String contents) throws SAXException {
1760         return encloseContents("dl", contents);
1761     }
1762
1763     /**
1764      * Handle a qandaset
1765      * @param attributes the tag attributes
1766      * @param contents the tag contents
1767      * @return the HTML code
1768      * @throws SAXEception if an error is encountered
1769      */
1770     public String handleQandaset(final Map<String, String> attributes, final String contents) throws SAXException {
1771         return encloseContents("div", "qandaset", contents);
1772     }
1773
1774     /**
1775      * Handle a caption
1776      * @param attributes the tag attributes
1777      * @param contents the tag contents
1778      * @return the HTML code
1779      * @throws SAXEception if an error is encountered
1780      */
1781     public String handleCaption(final Map<String, String> attributes, final String contents) throws SAXException {
1782         return encloseContents("caption", encloseContents("b", contents));
1783     }
1784
1785     /**
1786      * Handle a tbody
1787      * @param attributes the tag attributes
1788      * @param contents the tag contents
1789      * @return the HTML code
1790      * @throws SAXEception if an error is encountered
1791      */
1792     public String handleTbody(final Map<String, String> attributes, final String contents) throws SAXException {
1793         return encloseContents("tbody", "tbody", contents);
1794     }
1795
1796     /**
1797      * Handle a table
1798      * @param attributes the tag attributes
1799      * @param contents the tag contents
1800      * @return the HTML code
1801      * @throws SAXEception if an error is encountered
1802      */
1803     public String handleTable(final Map<String, String> attributes, final String contents) throws SAXException {
1804         String id = attributes.get("id");
1805         String bgcolor = attributes.get("bgcolor");
1806         String border = attributes.get("border");
1807         String cellpadding = attributes.get("cellpadding");
1808
1809         if (id != null) {
1810             return "<a name=\"" + id + "\"></a>" + encloseContents("table", new String[] {"class", "doctable", "bgcolor", bgcolor, "border", border, "cellpadding", cellpadding}, contents);
1811         } else {
1812             return encloseContents("table", new String[] {"class", "doctable", "bgcolor", bgcolor, "border", border, "cellpadding", cellpadding}, contents);
1813         }
1814     }
1815
1816     /**
1817      * Handle a surname
1818      * @param attributes the tag attributes
1819      * @param contents the tag contents
1820      * @return the HTML code
1821      * @throws SAXEception if an error is encountered
1822      */
1823     public String handleSurname(final Map<String, String> attributes, final String contents) throws SAXException {
1824         return encloseContents("span", "surname", contents);
1825     }
1826
1827     /**
1828      * Handle a firstname
1829      * @param attributes the tag attributes
1830      * @param contents the tag contents
1831      * @return the HTML code
1832      * @throws SAXEception if an error is encountered
1833      */
1834     public String handleFirstname(final Map<String, String> attributes, final String contents) throws SAXException {
1835         return encloseContents("span", "firstname", contents);
1836     }
1837
1838     /**
1839      * Handle a bibliomset
1840      * @param attributes the tag attributes
1841      * @param contents the tag contents
1842      * @return the HTML code
1843      * @throws SAXEception if an error is encountered
1844      */
1845     public String handleBibliomset(final Map<String, String> attributes, final String contents) throws SAXException {
1846         String id = attributes.get("id");
1847         if (id != null) {
1848             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "bibliomset", contents);
1849         } else {
1850             return encloseContents("div", "bibliomset", contents);
1851         }
1852     }
1853
1854     /**
1855      * Handle a bibliomixed
1856      * @param attributes the tag attributes
1857      * @param contents the tag contents
1858      * @return the HTML code
1859      * @throws SAXEception if an error is encountered
1860      */
1861     public String handleBibliomixed(final Map<String, String> attributes, final String contents) throws SAXException {
1862         String id = attributes.get("id");
1863         if (id != null) {
1864             return "<a name=\"" + id + "\"></a>" + encloseContents("div", "bibliomixed", contents);
1865         } else {
1866             return encloseContents("div", "bibliomixed", contents);
1867         }
1868     }
1869
1870     /**
1871      * Handle a th
1872      * @param attributes the tag attributes
1873      * @param contents the tag contents
1874      * @return the HTML code
1875      * @throws SAXEception if an error is encountered
1876      */
1877     public String handleTh(final Map<String, String> attributes, final String contents) throws SAXException {
1878         String align = attributes.get("align");
1879         String valign = attributes.get("valign");
1880         String style   = attributes.get("style");   /*  for style="white-space:nowrap" */
1881
1882         return encloseContents("th", new String[] {"align", align, "valign", valign, "style", style}, contents);
1883     }
1884
1885     /**
1886      * Handle a revhistory
1887      * @param attributes the tag attributes
1888      * @param contents the tag contents
1889      * @return the HTML code
1890      * @throws SAXEception if an error is encountered
1891      */
1892     public String handleRevhistory(final Map<String, String> attributes, final String contents) throws SAXException {
1893         String id = attributes.get("id");
1894         String str = "<table class=\"revhistory\"><tr class=\"title\"><td>" + VERSION + "</td><td>" + DESCRIPTION + "</td></tr>" + contents + "</table>";
1895         if (id != null) {
1896             return "<a name=\"" + id + "\"></a>" + str;
1897         } else {
1898             return str;
1899         }
1900     }
1901
1902     /**
1903      * Handle a revision
1904      * @param attributes the tag attributes
1905      * @param contents the tag contents
1906      * @return the HTML code
1907      * @throws SAXEception if an error is encountered
1908      */
1909     public String handleRevision(final Map<String, String> attributes, final String contents) throws SAXException {
1910         return encloseContents("tr", contents);
1911     }
1912
1913     /**
1914      * Handle a revnumber
1915      * @param attributes the tag attributes
1916      * @param contents the tag contents
1917      * @return the HTML code
1918      * @throws SAXEception if an error is encountered
1919      */
1920     public String handleRevnumber(final Map<String, String> attributes, final String contents) throws SAXException {
1921         return encloseContents("td", "revnumber", contents);
1922     }
1923
1924     /**
1925      * Handle a revremark
1926      * @param attributes the tag attributes
1927      * @param contents the tag contents
1928      * @return the HTML code
1929      * @throws SAXEception if an error is encountered
1930      */
1931     public String handleRevremark(final Map<String, String> attributes, final String contents) throws SAXException {
1932         return encloseContents("td", "revremark", contents);
1933     }
1934
1935     /**
1936      * Handle a revdescription
1937      * @param attributes the tag attributes
1938      * @param contents the tag contents
1939      * @return the HTML code
1940      * @throws SAXEception if an error is encountered
1941      */
1942     public String handleRevdescription(final Map<String, String> attributes, final String contents) throws SAXException {
1943         return encloseContents("td", "revdescription", contents);
1944     }
1945
1946     /**
1947      * Handle a note
1948      * @param attributes the tag attributes
1949      * @param contents the tag contents
1950      * @return the HTML code
1951      * @throws SAXEception if an error is encountered
1952      */
1953     public String handleNote(final Map<String, String> attributes, final String contents) throws SAXException {
1954         String id = attributes.get("id");
1955         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabNote.png\"/></td><td valign=\"top\">" + encloseContents("div", "note", contents) + "</td></tr></table>";
1956         if (id != null) {
1957             return "<a name=\"" + id + "\"></a>" + code;
1958         } else {
1959             return code;
1960         }
1961     }
1962
1963     /**
1964      * Handle a warning
1965      * @param attributes the tag attributes
1966      * @param contents the tag contents
1967      * @return the HTML code
1968      * @throws SAXEception if an error is encountered
1969      */
1970     public String handleWarning(final Map<String, String> attributes, final String contents) throws SAXException {
1971         String id = attributes.get("id");
1972         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabWarning.png\"/></td><td valign=\"top\">" + encloseContents("div", "warning", contents) + "</td></tr></table>";
1973         if (id != null) {
1974             return "<a name=\"" + id + "\"></a>" + code;
1975         } else {
1976             return code;
1977         }
1978     }
1979
1980     /**
1981      * Handle a caution
1982      * @param attributes the tag attributes
1983      * @param contents the tag contents
1984      * @return the HTML code
1985      * @throws SAXEception if an error is encountered
1986      */
1987     public String handleCaution(final Map<String, String> attributes, final String contents) throws SAXException {
1988         String id = attributes.get("id");
1989         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabCaution.png\"/></td><td valign=\"top\">" + encloseContents("div", "caution", contents) + "</td></tr></table>";
1990         if (id != null) {
1991             return "<a name=\"" + id + "\"></a>" + code;
1992         } else {
1993             return code;
1994         }
1995     }
1996
1997     /**
1998      * Handle a tip
1999      * @param attributes the tag attributes
2000      * @param contents the tag contents
2001      * @return the HTML code
2002      * @throws SAXEception if an error is encountered
2003      */
2004     public String handleTip(final Map<String, String> attributes, final String contents) throws SAXException {
2005         String id = attributes.get("id");
2006         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabTip.png\"/></td><td valign=\"top\">" + encloseContents("div", "tip", contents) + "</td></tr></table>";
2007         if (id != null) {
2008             return "<a name=\"" + id + "\"></a>" + code;
2009         } else {
2010             return code;
2011         }
2012     }
2013
2014     /**
2015      * Handle a important
2016      * @param attributes the tag attributes
2017      * @param contents the tag contents
2018      * @return the HTML code
2019      * @throws SAXEception if an error is encountered
2020      */
2021     public String handleImportant(final Map<String, String> attributes, final String contents) throws SAXException {
2022         String id = attributes.get("id");
2023         String code = "<table><tr><td valign=\"top\"><img src=\"" + getBaseImagePath() + "ScilabImportant.png\"/></td><td valign=\"top\">" + encloseContents("div", "important", contents) + "</td></tr></table>";
2024         if (id != null) {
2025             return "<a name=\"" + id + "\"></a>" + code;
2026         } else {
2027             return code;
2028         }
2029     }
2030
2031     private static final String convertCode(String code) {
2032         if (code == null || code.length() == 0) {
2033             return "";
2034         }
2035
2036         StringBuffer buffer = new StringBuffer(2 * code.length());
2037         int start = 0;
2038         int end = code.length() - 1;
2039         char c = code.charAt(0);
2040
2041         // first we trim
2042         while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
2043             if (start < end) {
2044                 c = code.charAt(++start);
2045             } else {
2046                 break;
2047             }
2048         }
2049         c = code.charAt(end);
2050         while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
2051             if (end > 0) {
2052                 c = code.charAt(--end);
2053             } else {
2054                 break;
2055             }
2056         }
2057
2058         // replace chars by their html entities equivalent
2059         for (int j = start; j <= end; j++) {
2060             c = code.charAt(j);
2061             switch (c) {
2062                 case '&':
2063                     buffer.append("&amp;");
2064                     break;
2065                 case '<':
2066                     buffer.append("&lt;");
2067                     break;
2068                 case '>':
2069                     buffer.append("&gt;");
2070                     break;
2071                 case '\n':
2072                     buffer.append("<br />");
2073                     break;
2074                 case '\'':
2075                     buffer.append("&#039;");
2076                     break;
2077                 case '\"':
2078                     buffer.append("&quot;");
2079                     break;
2080                 default:
2081                     buffer.append(c);
2082             }
2083         }
2084
2085         return buffer.toString();
2086     }
2087 }