improvements to Doc.java, corresponding fixes to the reference
[org.ibex.core.git] / src / org / ibex / util / Doc.java
index 70ef527..9770a99 100644 (file)
@@ -2,6 +2,7 @@
 // FEATURE:   <code type="c++"/>          -- syntax highlighting
 // FEATURE:   <code linenumbers="true"/>  -- LaTeX moreverb package can help
 // FIXME: nest TextNodes within each other for bold+italic
+// FEATURE: property tree
 
 package org.ibex.util;
 import java.util.*;
@@ -9,7 +10,8 @@ import java.io.*;
 import org.ibex.util.*;
 
 public class Doc extends XML {
-
+    
+    public static boolean slides = false;
     Root root = null;
     int skip = 0;
     Vec nodeStack = new Vec();
@@ -20,6 +22,7 @@ public class Doc extends XML {
     public Doc() { }
 
     public static void main(String[] s) throws Exception {
+        if (s.length > 0 && "slides".equals(s[0])) slides = true;
         Doc d = new Doc();
         Reader r = new InputStreamReader(System.in);
         int len = 0;
@@ -41,6 +44,14 @@ public class Doc extends XML {
 
     public void startElement(Element e) throws Exn {
         if (preStart != -1) return;
+
+        Node target = (Node)nodeStack.lastElement();
+        if (target == null) target = (Node)victim;
+        if (target != null) {
+            if (pending.length() > 0) target.addText(pending);
+            pending = "";
+        }
+
         String name = e.getLocalName();
         Node newGuy = null;
         if (name.equals("ibex-doc")) {            newGuy = new Root(e);
@@ -52,11 +63,9 @@ public class Doc extends XML {
         } else if (name.equals("pre")) {          preStart = getGlobalOffset();
 
         } else if (name.equals("definition")) {   newGuy = new Definition(e);
+        } else if (name.equals("math")) {         newGuy = new Math(e);
         } else if (name.equals("property")) {     newGuy = new Property(e);
 
-        } else if (name.equals("b")) {            newGuy = new B();
-        } else if (name.equals("i")) {            newGuy = new I();
-        } else if (name.equals("t")) {            newGuy = new T();
         } else if (name.equals("link")) {         newGuy = new Link(e);
         } else if (name.equals("image")) {        newGuy = new Image(e);
 
@@ -71,22 +80,33 @@ public class Doc extends XML {
         }
     }
 
+    static Object victim = null;
+
     public void whitespace(char[] ch, int start, int length) throws Exn, IOException { characters(ch, start, length); }
     public void endElement(Element e) throws Exn, IOException {
+
+        Node target = (Node)nodeStack.lastElement();
+        if (target == null) target = (Node)victim;
         if (preStart != -1) {
             if (!e.getLocalName().equals("pre")) return;
-            ((Node)nodeStack.lastElement()).addChild(new PRE(preStart, getGlobalOffset()));
+            target.addChild(new PRE(preStart, getGlobalOffset()));
             preStart = -1;
         } else if (skip > 0) {
             skip--;
             return;
         } else {
+            if (target != null) {
+                if (pending.length() > 0) target.addText(pending);
+                pending = "";
+            }
+            if (nodeStack.lastElement() instanceof Section) victim = nodeStack.lastElement();
             nodeStack.setSize(nodeStack.size() - 1);
         }
     }
+
     public void characters(char[] ch, int start, int length) throws Exn, IOException {
         if (preStart != -1) return;
-        ((Node)nodeStack.lastElement()).addText(new String(ch, start, length));
+        pending += new String(ch, start, length);
     }
 
     abstract class Node {
@@ -96,20 +116,22 @@ public class Doc extends XML {
         public abstract void dumpLatex(StringBuffer sb);
         final String fixLatex(String s) {
             if (s == null) return "";
-            s = s.replaceAll("\\$", "\\\\\\$ ");
-            s = s.replaceAll("\\\\([^\\$])", "\\$\\\\backslash\\$\\1");
+            s = s.replaceAll("\\\\", "\\$\\\\backslash\\$");
+            s = s.replaceAll("\\$", "\\\\\\$");
+            s = s.replaceAll("\\\\\\$\\\\backslash\\\\\\$", "\\$\\\\backslash\\$");
+            s = s.replaceAll("\\{", "\\\\{");
+            s = s.replaceAll("\\}", "\\\\}");
+            s = s.replaceAll("\\*\\*([^\n]+?)\\*\\*", "{\\\\it{$1}}");
+            s = s.replaceAll("__([^\n]+?)__", "{\\\\textbf{$1}}");
+            s = s.replaceAll("\\[\\[([^\n]+?)\\]\\]", "{\\\\texttt{$1}}");
             s = s.replaceAll("LaTeX", "\\\\LaTeX");
             s = s.replaceAll("\\%", "\\\\% ");
             s = s.replaceAll("#", "\\\\#");
-            s = s.replaceAll("\\{", "\\\\{");
-            s = s.replaceAll("\\}", "\\\\}");
             s = s.replaceAll("\\&", "\\\\&");
             s = s.replaceAll("\\~", "\\\\~");
             s = s.replaceAll("_", "\\\\_");
-            if (!(this instanceof T)) {
-                s = s.replaceAll(" \"", " ``");
-                s = s.replaceAll("\"", "''");
-            }
+            s = s.replaceAll(" \"", " ``");
+            s = s.replaceAll("\"", "''");
             return s;
         }
     }
@@ -126,8 +148,38 @@ public class Doc extends XML {
 
     class Image extends EmptyNode {
         public String url;
-        public Image(XML.Element e) { url = e.getAttrVal("url"); }
-        public void dumpLatex(StringBuffer sb) { sb.append("\\hyperimage{" + url + "}"); }
+        public String caption;
+        public String width;
+        public String align;
+        public Image(XML.Element e) {
+            url = e.getAttrVal("url"); caption = e.getAttrVal("caption"); width = e.getAttrVal("width");
+            align = e.getAttrVal("align");
+        }
+        public void dumpLatex(StringBuffer sb) {
+            if (url.endsWith(".pdf")) {
+                if (width == null) {
+                    sb.append("\\begin{figure}[H]\n");
+                    sb.append("\\begin{center}\n");
+                    sb.append("\\epsfig{file="+url.substring(0, url.length() - 4)+",width=\\textwidth}\n");
+                    if (caption != null)
+                        sb.append("\\caption{"+fixLatex(caption)+"}\n");
+                    sb.append("\\end{center}\n");
+                    sb.append("\\end{figure}\n");
+                } else {
+                    if ("left".equals(align)) {
+                        sb.append("\\begin{wrapfigure}{l}{"+width+"}\n");
+                    } else {
+                        sb.append("\\begin{wrapfigure}{r}{"+width+"}\n");
+                    }
+                    sb.append("\\epsfig{file="+url.substring(0, url.length() - 4)+",width="+width+"}%\n");
+                    if (caption != null)
+                        sb.append("\\caption{"+fixLatex(caption)+"}\n");
+                    sb.append("\\end{wrapfigure}\n");
+                }
+            } else {
+                sb.append("\\hyperimage{" + url + "}");
+            }
+        }
     }
 
     class Heading extends EmptyNode {
@@ -154,7 +206,7 @@ public class Doc extends XML {
 
     /** Nodes which contain only text; they split themselves if anything else is added */
     class TextNode extends Node implements Cloneable {
-        protected String mytext = "";
+        public String mytext = "";
         private boolean canAcceptMoreText = true;
         public void dumpLatex(StringBuffer sb) { sb.append(fixLatex(mytext)); }
         public void addChild(Node o) { canAcceptMoreText = false; parent.addChild(o); }
@@ -167,53 +219,47 @@ public class Doc extends XML {
                 mytext = split[0];
                 parent.addChild(new ParagraphBreak());
                 o = "";
-                for(int i=1; i<split.length; i++) o += split[i];
+                for(int i=1; i<split.length; i++) o += split[i] + "\n\n";
             }
             try {
                 TextNode clone = (TextNode)clone();
                 clone.mytext = "";
                 clone.canAcceptMoreText = true;
-                clone.addText(o);
                 parent.addChild(clone);
+                clone.addText(o);
             } catch (CloneNotSupportedException cnse) {
                 throw new RuntimeException(cnse);
             }
         }
     }
 
-    class T extends TextNode {
-        public void dumpLatex(StringBuffer sb) {
-            sb.append("{\\texttt{");
-            super.dumpLatex(sb);
-            sb.append("}}");
-        } }
-    class B extends TextNode {
-        public void dumpLatex(StringBuffer sb) {sb.append("{\\textbf{"); super.dumpLatex(sb); sb.append("}}");}}
-    class I extends TextNode {
-        public void dumpLatex(StringBuffer sb) {sb.append("{\\it{"); super.dumpLatex(sb); sb.append("}}");}}
     class Link extends TextNode {
         public String url;
         public String section;
         public String appendix;
         public String text;
         public Link(XML.Element e) {
-            url = e.getAttrVal("url");
-            text = e.getAttrVal("text");
-            appendix = e.getAttrVal("appendix");
-            section = e.getAttrVal("section");
+            url = e.getAttrVal("url");            if ("".equals(url)) url = null;
+            appendix = e.getAttrVal("appendix");  if ("".equals(appendix)) appendix = null;
+            section = e.getAttrVal("section");    if ("".equals(section)) section = null;
+            text = e.getAttrVal("text");          if ("".equals(url)) text = null;
+            if (text == null) text = url;
+            if (text == null) text = section;
+            if (text == null) text = appendix;
         }
         public void dumpLatex(StringBuffer sb) {
             // FIXME: dotted underline for section/appendix, solid underline for url
             String text = fixLatex(this.text);
             if (text == null) text = "\\tt " + (url != null ? url : section != null ? section : appendix);
             if (url != null) {             sb.append("\\href{" + url + "}{\\uline{" + text + "}} ");
-            } else if (section != null) {  sb.append("\\hyperlink{" + section + "}{\\uwave{" + text + "}} ");
-            } else if (appendix != null) { sb.append("\\hyperlink{" + appendix + "}{\\uwave{" + text + "}} ");
+            } else if (section != null) {  sb.append("\\hyperlink{" + section + "}{" + text + "} ");
+            } else if (appendix != null) { sb.append("\\hyperlink{" + appendix + "}{" + text + "} ");
             }
         }
     }
 
     class PRE extends TextNode {
+        int gobble = 0;
         public PRE(int start, int end) {
             while(Character.isWhitespace(buffer[start])) start++;
             while(buffer[start] != '\n') start--;
@@ -224,9 +270,20 @@ public class Doc extends XML {
                 end++;
             }
             mytext = new String(buffer, start, end - start);
+            gobble = 9999;
+            int i = 0;
+            while(true) {
+                int start2 = i;
+                while(i<mytext.length() && mytext.charAt(i) == ' ') i++;
+                if (i==mytext.length()) break;
+                gobble = java.lang.Math.min(gobble, i - start2);
+                i = mytext.indexOf('\n', i);
+                if (i == -1) break;
+                i++;
+            }
         }
         public void dumpLatex(StringBuffer sb) {
-            sb.append("\n\n\\begin{Verbatim}[fontfamily=courier,fontsize=\\footnotesize,frame=single,rulecolor=\\color{CodeBorder},resetmargins=true]\n");
+            sb.append("\n\n\\begin{Verbatim}[fontfamily=courier,fontsize=\\tiny,frame=single,rulecolor=\\color{CodeBorder},resetmargins=true,gobble="+gobble+"]\n");
             sb.append(mytext);
             sb.append("\\end{Verbatim}\n\n");
         }
@@ -270,7 +327,7 @@ public class Doc extends XML {
             while(Character.isSpace(s.charAt(0))) s = s.substring(1);
             String fname = fixLatex(name);
             type = type == null || type.equals("") ? "" : "({\\it{" + fixLatex(type) + "}})";
-            if (name.trim().length() > 13) {
+            if (name.trim().length() > 13 && name.trim().indexOf(' ') == -1) {
                 sb.append("\n\n{\\color{CodeBorder}\\hspace{-2cm}\\dotfill\\\\\\color{black}}");
                 sb.append("\\marginpar{\\raggedleft{\\texttt{\\textbf{\\footnotesize{"+fname+"}}}}\\\\"+type+" }");
                 sb.append("\\\\");
@@ -282,7 +339,10 @@ public class Doc extends XML {
                 sb.append(s.substring(s.indexOf(' ')));
             }
             if (default_ != null) {
-                sb.append("\\\\{\\it default: }{\\texttt{" + fixLatex(default_) + "}}\n\n");
+                String fd = fixLatex(default_);
+                fd = fd.replaceAll(" ``", " \"");
+                fd = fd.replaceAll("''", "\"");
+                sb.append("\\\\{\\it default: }{\\texttt{" + fd + "}}\n\n");
             } else {
                 sb.append("\n\n");
             }
@@ -303,21 +363,52 @@ public class Doc extends XML {
         }
     }
 
+    class Math extends ParagraphNode {
+        String tex = "";
+        public Math(XML.Element e) { tex = e.getAttrVal("tex"); if (tex == null) tex = ""; }
+        public void addText(String s) { tex += s; }
+        public void dumpLatex(StringBuffer sb) { sb.append("\n\n$$\n" + tex.replaceAll("\n", " ") + "\n$$\n\n"); }
+    }
+
     class Section extends ParagraphNode {
         String name;
-        public Section(XML.Element e) { name = e.getAttrVal("title"); }
+        public Section(XML.Element e) {
+            name = e.getAttrVal("title");
+            if (slides) super.addChild(new List());
+        }
+        public void addText(String s) {
+            if (slides) ((List)children.elementAt(0)).addText(s);
+            else super.addText(s);
+        }
+        public void addChild(Node n) {
+            /*            if (slides) ((List)children.elementAt(0)).addChild(n);
+                          else*/ super.addChild(n);
+        }
         public void dumpLatex(StringBuffer sb) {
             String secs = "";
             String base = "section";
+            int count = 0;
+            String pile = "";
             for(Node n = parent; n != null; n = n.parent)
                 if (n instanceof Section || n instanceof Appendix) {
                     base = "section";
                     secs += "sub";
+                    for (int i=0; i<count; i++) pile += "\\hspace{1cm}";
+                    pile += ((Section)n).name + "\\\\\n";
+                    count++;
                 }
-            if (secs.length() == 0)
-                sb.append("\\newpage\n\n");
-            sb.append("\n\n\\hypertarget{" + name + "}{\\" + secs + base + "{" + name + "}}\n\n");
-            super.dumpLatex(sb);
+            if (slides) {
+                sb.append(pile);
+                sb.append("\n\n\\begin{slide}\n");
+                sb.append("\\slideheading{"+fixLatex(name)+"}\n");
+                super.dumpLatex(sb);
+                sb.append("\n\n\\end{slide}\n");
+            } else {
+                if (secs.length() == 0)
+                    sb.append("\\newpage\n\n");
+                sb.append("\n\n\\hypertarget{" + name + "}{\\" + secs + base + "{" + name + "}}\n\n");
+                super.dumpLatex(sb);
+            }
         }
     }
 
@@ -332,32 +423,75 @@ public class Doc extends XML {
     }
 
     class List extends ParagraphNode {
-        Node textnode = null;
+        TextNode textnode = null;
         public List() { }
+        public void addChild(Node n) {
+            if (n != textnode) textnode = null;
+            super.addChild(n);
+        }
         public void addText(String s) {
             if (!(children.lastElement() == textnode) || (textnode == null && children.lastElement() == null))
                 addChild(textnode = new TextNode());
-            ((TextNode)children.lastElement()).addText(s);
+            s = s.replaceAll("\n( +)\\- ", "\n\n$1 ");
+            textnode.addText(s);
         }
-        public void dumpLatex(StringBuffer sb) {
-            sb.append("\n\\begin{itemize}%\n");
+        public int indentof(String s) {
+            for(int i=0; i<s.length(); i++)
+                if (!Character.isWhitespace(s.charAt(i)))
+                    return i;
+            return s.length();
+        }
+        public void dumpLatex(StringBuffer sb0) {
+            StringBuffer sb = new StringBuffer();
+            boolean began = false;
             boolean unusedItem = false;
+            List spawn = null;
+            int indentation = -1;
             for(int i=0; i<children.size(); i++) {
                 Object kid = children.elementAt(i);
-                if (kid instanceof ParagraphBreak || kid instanceof List) unusedItem = false;
+                if (kid instanceof ParagraphBreak) { unusedItem = false; continue; }
+                if (kid instanceof List) unusedItem = true;
+                String txt = null;
                 if (kid instanceof String) {
                     if (kid.toString().trim().length() == 0) continue;
-                    if (!unusedItem) { unusedItem = true; sb.append("\n\n\\item\n"); }
-                    sb.append(children.elementAt(i));
+                    txt = (String)children.elementAt(i);
+                } else if (kid instanceof TextNode) {
+                    if (((TextNode)kid).mytext.trim().length() == 0) continue;
+                    txt = ((TextNode)kid).mytext;
                 } else {
-                    if (kid instanceof TextNode) {
-                        if (((TextNode)kid).mytext.trim().length() == 0) continue;
-                        if (!unusedItem) { unusedItem = true; sb.append("\n\n\\item\n"); }
+                    if (spawn != null) {
+                        spawn.dumpLatex(sb);
+                        unusedItem = false;
+                        spawn = null;
                     }
                     ((Node)kid).dumpLatex(sb);
+                    continue;
+                }
+                if (txt.trim().length() == 0) continue;
+                if (indentation == -1) indentation = indentof(txt);
+                if (indentof(txt) > indentation) {
+                    if (spawn == null) spawn = new List();
+                    spawn.addText(txt);
+                    spawn.addChild(new ParagraphBreak());
+                    continue;
+                }
+                if (spawn != null) {
+                    spawn.dumpLatex(sb);
+                    unusedItem = false;
+                    spawn = null;
                 }
+                if (!unusedItem) { unusedItem = true; sb.append("\n\n\\item\n"); }
+                sb.append(fixLatex(txt));
+            }
+            if (spawn != null) {
+                spawn.dumpLatex(sb);
+                spawn = null;
+            }
+            if (sb.toString().replaceAll("\\[.+\\]", "").trim().length() > 0) {
+                sb0.append("\n\\begin{itemize}\n");
+                sb0.append(sb.toString());
+                sb0.append("\n\\end{itemize}\n");
             }
-            sb.append("\n\\end{itemize}%\n");
         }
     }
 
@@ -373,63 +507,190 @@ public class Doc extends XML {
             email = e.getAttrVal("email");
             subtitle = e.getAttrVal("subtitle");
         }
+        public void addText(String s) {
+            if (victim != null) ((Node)victim).addText(s);
+        }
+        public void addChild(Node n) {
+            if (!(n instanceof Section))
+                ((Section)victim).addChild(n);
+            else
+                super.addChild(n);
+        }
         public void dumpLatex(StringBuffer sb) {
-            sb.append("\\documentclass{article}\n");
-            sb.append("\\def\\ninept{\\def\\baselinestretch{.95}\\let\\normalsize\\small\\normalsize}\n");
-            sb.append("\\ninept\n");
-            sb.append("\\usepackage{color}\n");
-            sb.append("\\definecolor{CodeBorder}{rgb}{0.6,0.6,0.6}\n");
-            sb.append("\\definecolor{CodeBackground}{rgb}{0.93,0.93,0.93}\n");
-            sb.append("\\usepackage{graphicx}\n");
-            sb.append("\\usepackage{courier}\n");
-            sb.append("\\usepackage{fancyvrb}\n");
-            sb.append("\\usepackage{fvrb-ex}\n");
-            sb.append("\\usepackage{bold-extra}\n");
-            sb.append("\\usepackage{ulem}\n");
-            sb.append("\\usepackage{appendix}\n");
-            sb.append("\\usepackage{amssymb,amsmath,epsfig,alltt}\n");
-            sb.append("\\sloppy\n");
-            sb.append("\\usepackage{palatino}\n");
-            sb.append("\\usepackage{sectsty}\n");
-            sb.append("\\allsectionsfont{\\sffamily}\n");
-            sb.append("\\sectionfont{\\color{black}\\leftskip=-2cm\\hrulefill\\\\\\sffamily\\bfseries\\raggedleft\\vspace{1cm}}\n");
-            sb.append("\\subsectionfont{\\color{black}\\dotfill\\\\\\sffamily\\raggedright\\hspace{-4cm}}\n");
-            sb.append("\\newdimen\\sectskip\n");
-            sb.append("\\newdimen\\subsectskip\n");
-            sb.append("\\newdimen\\saveskip\n");
-            sb.append("\\saveskip=\\leftskip\n");
-            sb.append("\\sectskip=-2cm\n");
-            sb.append("\\subsectskip=0cm\n");
-            sb.append("\\let\\oldsection\\section\n");
-            sb.append("\\let\\oldsubsection\\subsection\n");
-            sb.append("\\def\\subsection#1{\\leftskip=\\sectskip\\oldsubsection{#1}\\leftskip=0cm}\n");
-            sb.append("\\usepackage{parskip}\n");
-            sb.append("\\usepackage{tabularx}\n");
-            sb.append("\\usepackage{alltt}\n");
-            sb.append("\\usepackage[pdftex,colorlinks=true,urlcolor=blue,linkcolor=blue,bookmarks=true]{hyperref}\n");
-            // FIXME: pdfauthor, pdftitle, pdfsubject, pdfkeywords?
-            sb.append("\n");
-            sb.append("\\begin{document}\n");
-            sb.append("\\reversemarginpar\n");
-            sb.append("\n");
-            sb.append("\\title{\\textbf{\\textsf{\n");
-            sb.append(title);
-            if (subtitle != null) sb.append("\\\\{\\large " + subtitle + "}\n");
-            sb.append("}}}\n");
-            if (author != null) {
-                sb.append("\\author{\n");
-                sb.append(author);
-                if (email != null) sb.append("\\\\{\\tt " + email + "}\n");
-                sb.append("}\n");
+            if (slides) {
+                sb.append("\\documentclass[letter]{seminar}\n");
+                sb.append("\\usepackage{calc}               % Simple computations with LaTeX variables\n");
+                sb.append("\\usepackage[hang]{caption2}     % Improved captions\n");
+                sb.append("\\usepackage{fancybox}           % To have several backgrounds\n");
+                sb.append("                                % (must be loaded before `fancyvrb')\n");
+                sb.append("\\usepackage{fancyhdr}           % Headers and footers definitions\n");
+                sb.append("\\usepackage{fancyvrb}           % Fancy verbatim environments\n");
+                sb.append("\\usepackage{wrapfig}\n");
+                sb.append("\\usepackage{float}\n");
+                sb.append("\\usepackage{amsmath}\n");
+                sb.append("\\usepackage{amssymb}\n");
+                sb.append("\\usepackage{pdftricks}\n");
+                sb.append("\\begin{psinputs}\n");
+                sb.append("  \\usepackage{pstcol}             % PSTricks with the standard color package\n");
+                sb.append("                                  % (before `graphicx' for the \\scalebox macro)\n");
+                sb.append("  \\usepackage{graphicx}           % Standard graphics package\n");
+                sb.append("  \\usepackage{multido}            % General loop macro\n");
+                sb.append("  \\usepackage{pifont}             % Ding symbols (mainly for lists)\n");
+                sb.append("  \\usepackage{pst-fr3d}           % PSTricks 3D framed boxes\n");
+                sb.append("  \\usepackage{pst-grad}           % PSTricks gradient mode\n");
+                sb.append("  \\usepackage{pst-node}           % PSTricks nodes\n");
+                sb.append("  \\usepackage{pst-slpe}           % Improved PSTricks gradients\n");
+                sb.append("\\end{psinputs}\n");
+                sb.append("\\usepackage{color}\n");
+                sb.append("\\definecolor{CodeBorder}{rgb}{0.6,0.6,0.6}\n");
+                sb.append("\\definecolor{CodeBackground}{rgb}{0.93,0.93,0.93}\n");
+                sb.append("\\usepackage{graphicx}\n");
+                sb.append("\\usepackage{courier}\n");
+                sb.append("\\usepackage{fancyvrb}\n");
+                sb.append("\\usepackage{float}\n");
+                sb.append("\\usepackage{fvrb-ex}\n");
+                sb.append("\\usepackage{bold-extra}\n");
+                sb.append("\\usepackage{ulem}\n");
+                sb.append("\\usepackage{amssymb,amsmath,epsfig,alltt}\n");
+                sb.append("\\usepackage{semcolor}           % Seminar colored slides\n");
+                sb.append("\\usepackage{semhelv}            % Seminar helvetica fonts\n");
+                sb.append("\\usepackage{semlayer}           % Seminar overlays\n");
+                sb.append("\\usepackage{slidesec}           % Seminar sections and list of slides\n");
+                sb.append("\\usepackage{url}                % Convenient URL typesetting\n");
+                sb.append("\\usepackage[pdftex,letterpaper,pdffitwindow=true,colorlinks=true,pdfpagemode=UseNone,\n");
+                sb.append("            bookmarks=true]{hyperref} % Hyperlinks for PDF versions\n");
+                sb.append("\\usepackage{hcolor}\n");
+                sb.append("\\slidepagestyle{fancy}\n");
+                sb.append("\n");
+                sb.append("\\slidesmag{4}     % Set magnification of slide\n");
+                sb.append("\\def\\SeminarPaperWidth{\\paperwidth / 2}\n");
+                sb.append("\\def\\SeminarPaperHeight{\\paperheight / 2}\n");
+                sb.append("\\slideframe{none} % No default frame\n");
+                sb.append("\n");
+                sb.append("  \n");
+                sb.append("\n");
+                sb.append("  % General size parameters\n");
+                sb.append("\\renewcommand{\\slideparindent}{5mm}\n");
+                sb.append("\\raggedslides[0mm]\n");
+                sb.append("%  \\renewcommand{\\slidetopmargin}{15.5mm}\n");
+                sb.append("%  \\renewcommand{\\slidebottommargin}{13mm}\n");
+                sb.append("%  \\renewcommand{\\slideleftmargin}{4mm}\n");
+                sb.append("%  \\renewcommand{\\sliderightmargin}{4mm}\n");
+                sb.append("  % To adjust the frame length to the header and footer ones\n");
+                sb.append("%  \\autoslidemarginstrue\n");
+                sb.append("  % We suppress the header and footer `fancyhdr' rules\n");
+                sb.append("\\fancyhf{} % Clear all fields\n");
+                sb.append("\\renewcommand{\\headrule}{}\n");
+                sb.append("\\renewcommand{\\footrule}{}\n");
+                sb.append("\n");
+                sb.append("%  \\usepackage{nohyperref}       % To deactivate the `hyperref' features\n");
+                sb.append("%  \\overlaysfalse                % To suppress overlays\n");
+                sb.append("%  \\def\\special@paper{}% Needed to avoid `hyperref' to collapse with ``dvips''\n");
+                sb.append("\\newslideframe{IMAGE}{%\n");
+                sb.append("  \\boxput{\\rput(0,0){%\n");
+                sb.append("      \\includegraphics[width=\\SeminarPaperHeight,height=\\SeminarPaperWidth]{background.pdf}}}{#1}}\n");
+                sb.append("\\slideframe*{IMAGE}\n");
+                sb.append("%\\renewcommand{\\slideleftmargin}{3cm}\n");
+                sb.append("%\\addtolength{\\slidewidth}{-\\slideleftmargin}\n");
+                sb.append("\\RequirePackage[T1]{fontenc}\n");
+                sb.append("\\RequirePackage{textcomp}\n");
+                sb.append("\\renewcommand{\\rmdefault}{trebuchet}\n");
+                sb.append("\\renewcommand{\\slidefonts}{%\n");
+                sb.append("  \\renewcommand{\\rmdefault}{trebuchet}%\n");
+                sb.append("  \\renewcommand{\\ttdefault}{courier}}%\n");
+                sb.append("  \\newcommand{\\ParagraphTitle}[2][black]{%\n");
+                sb.append("  \\noindent\\psshadowbox[fillstyle=solid,fillcolor=#1]{\\large{#2}}}\n");
+                sb.append("  \\newcommand{\\CenteredParagraphTitle}[2][black]{%\n");
+                sb.append("  \\centerline{\\psshadowbox[fillstyle=solid,fillcolor=#1]{\\large{#2}}}}\n");
+                sb.append("  \\renewcommand{\\makeslideheading}[1]{%\n");
+                sb.append("  \\CenteredParagraphTitle[black]{%\n");
+                sb.append("    \\textcolor{black}{\\huge\\textbf{#1}}}}\n");
+                sb.append("  \\renewcommand{\\makeslidesubheading}[1]{%\n");
+                sb.append("    \\CenteredParagraphTitle{\\Large\\theslidesubsection{} -- #1}}\n");
+                sb.append("  \\renewenvironment{dinglist}[2][black]\n");
+                sb.append("  {\\begin{list}{\\ding{#2}}{}}{\\end{list}}\n");
+                sb.append("  \\newcommand{\\DingListSymbolA}{43}\n");
+                sb.append("  \\newcommand{\\DingListSymbolB}{243}\n");
+                sb.append("  \\newcommand{\\DingListSymbolC}{224}\n");
+                sb.append("  \\newcommand{\\DingListSymbolD}{219}\n");
+                sb.append("  \\newcommand{\\eqbox}[2][0.6]{%\n");
+                sb.append("  \\centerline{\\psshadowbox[fillstyle=solid,fillcolor=gray]{%\n");
+                sb.append("  \\parbox{#1\\hsize}{%\n");
+                sb.append("      \\[\n");
+                sb.append("        \\textcolor{black} {#2}\n");
+                sb.append("      \\]}}}}\n");
+                sb.append("\\begin{document}\n");
+                sb.append("\\begin{slide}\n");
+                sb.append("\\begin{center}\n");
+                sb.append("\\ParagraphTitle{\\bf \\Large "+title+"}\n");
+                sb.append("\\vspace{5mm} \\\n");
+                sb.append("\\textit{\\large "+subtitle+"} \\\\\n");
+                sb.append("\\vspace{5mm} \\\n");
+                sb.append("\\textit{"+author+"} \\\n");
+                sb.append("\\end{center}\n");
+                sb.append("\\end{slide}\n\n");
+                super.dumpLatex(sb);
+                sb.append("\\end{document}");
+            } else {
+                sb.append("\\documentclass{article}\n");
+                sb.append("\\def\\ninept{\\def\\baselinestretch{.95}\\let\\normalsize\\small\\normalsize}\n");
+                sb.append("\\ninept\n");
+                sb.append("\\usepackage{color}\n");
+                sb.append("\\definecolor{CodeBorder}{rgb}{0.6,0.6,0.6}\n");
+                sb.append("\\definecolor{CodeBackground}{rgb}{0.93,0.93,0.93}\n");
+                sb.append("\\usepackage{graphicx}\n");
+                sb.append("\\usepackage{courier}\n");
+                sb.append("\\usepackage{fancyvrb}\n");
+                sb.append("\\usepackage{float}\n");
+                sb.append("\\usepackage{wrapfig}\n");
+                sb.append("\\usepackage{fvrb-ex}\n");
+                sb.append("\\usepackage{bold-extra}\n");
+                sb.append("\\usepackage{ulem}\n");
+                sb.append("\\usepackage{amssymb,amsmath,epsfig,alltt}\n");
+                sb.append("\\sloppy\n");
+                sb.append("\\usepackage{palatino}\n");
+                sb.append("\\usepackage{sectsty}\n");
+                sb.append("\\allsectionsfont{\\sffamily}\n");
+                sb.append("\\sectionfont{\\color{black}\\leftskip=-2cm");
+                sb.append("\\hrulefill\\\\\\sffamily\\bfseries\\raggedleft\\vspace{1cm}}\n");
+                sb.append("\\subsectionfont{\\color{black}\\dotfill\\\\\\sffamily\\raggedright\\hspace{-4cm}}\n");
+                sb.append("\\newdimen\\sectskip\n");
+                sb.append("\\newdimen\\subsectskip\n");
+                sb.append("\\newdimen\\saveskip\n");
+                sb.append("\\saveskip=\\leftskip\n");
+                sb.append("\\sectskip=-2cm\n");
+                sb.append("\\subsectskip=0cm\n");
+                sb.append("\\let\\oldsection\\section\n");
+                sb.append("\\let\\oldsubsection\\subsection\n");
+                sb.append("\\def\\subsection#1{\\leftskip=\\sectskip\\oldsubsection{#1}\\leftskip=0cm}\n");
+                sb.append("\\usepackage{parskip}\n");
+                sb.append("\\usepackage{tabularx}\n");
+                sb.append("\\usepackage{alltt}\n");
+                sb.append("\\usepackage[pdftex,colorlinks=true,urlcolor=blue,linkcolor=blue,bookmarks=true]{hyperref}\n");
+                // FIXME: pdfauthor, pdftitle, pdfsubject, pdfkeywords?
+                sb.append("\n");
+                sb.append("\\begin{document}\n");
+                sb.append("\\reversemarginpar\n");
+                sb.append("\n");
+                sb.append("\\title{\\textbf{\\textsf{\n");
+                sb.append(title);
+                if (subtitle != null) sb.append("\\\\{\\large " + subtitle + "}\n");
+                sb.append("}}}\n");
+                if (author != null) {
+                    sb.append("\\author{\n");
+                    sb.append(author);
+                    if (email != null) sb.append("\\\\{\\tt " + email + "}\n");
+                    sb.append("}\n");
+                }
+                sb.append("\n");
+                sb.append("\\maketitle\n");
+                sb.append("\\clearpage\n");
+                sb.append("\\tableofcontents\n");
+                sb.append("\\clearpage\n");
+                sb.append("\\onecolumn\n");
+                super.dumpLatex(sb);
+                sb.append("\\end{document}");
             }
-            sb.append("\n");
-            sb.append("\\maketitle\n");
-            sb.append("\\clearpage\n");
-            sb.append("\\tableofcontents\n");
-            sb.append("\\clearpage\n");
-            sb.append("\\onecolumn\n");
-            super.dumpLatex(sb);
-            sb.append("\\end{document}");
         }
     }
 }