You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/02/13 06:54:24 UTC

svn commit: r627255 [23/41] - in /incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src: ./ com/ com/ecyrd/ com/ecyrd/jspwiki/ com/ecyrd/jspwiki/action/ com/ecyrd/jspwiki/attachment/ com/ecyrd/jspwiki/auth/ com/ecyrd/jspwiki/auth/acl/ com/ecyrd/jspwiki...

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/CreoleToJSPWikiTranslator.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/CreoleToJSPWikiTranslator.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/CreoleToJSPWikiTranslator.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/CreoleToJSPWikiTranslator.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,538 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-2002 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.parser;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <p>Translates Creole markp to JSPWiki markup. Simple translator uses regular expressions.
+ * See http://www.wikicreole.org for the WikiCreole spec.</p>
+ *
+ * <p>This translator can be configured through properties defined in
+ * jspwiki.properties starting with "creole.*". See the
+ * jspwiki.properties file for an explanation of the properties</p>
+ *
+ * <p><b>WARNING</b>: This is an experimental feature, and known to be
+ * broken.  Use at your own risk.</o>
+ *
+ * @author Steffen Schramm
+ * @author Hanno Eichelberger
+ * @author Christoph Sauer
+ *
+ * @see <a href="http://www.wikicreole.org/">Wiki Creole Spec</a>
+ */
+public class CreoleToJSPWikiTranslator
+{
+
+    // These variables are expanded so that admins
+    // can display information about the current installed
+    // pagefilter
+    //
+    // The syntax is the same as a wiki var. Unlike a wiki
+    // war though, the CreoleTranslator itself
+    //
+    // [{$creolepagefilter.version}]
+    // [{$creolepagefilter.creoleversion}]
+    // [{$creolepagefilter.linebreak}] -> bloglike/wikilike
+
+    public static String VAR_VERSION = "1.0.3";
+
+    public static String VAR_CREOLE_VERSION = "1.0";
+
+    public static String VAR_LINEBREAK_BLOGLIKE = "bloglike";
+
+    public static String VAR_LINEBREAK_C2LIKE = "c2like";
+
+    private static final String CREOLE_BOLD = "\\*\\*((?s:.)*?)(\\*\\*|(\n\n|\r\r|\r\n\r\n))";
+
+    private static final String JSPWIKI_BOLD = "__$1__$3";
+
+    private static final String CREOLE_ITALIC = "//((?s:.)*?)(//|(\n\n|\r\r|\r\n\r\n))";
+
+    private static final String JSPWIKI_ITALIC = "''$1''$3";
+
+    private static final String CREOLE_SIMPLELINK = "\\[\\[([^\\]]*?)\\]\\]";
+
+    private static final String JSPWIKI_SIMPLELINK = "[$1]";
+
+    private static final String CREOLE_LINK = "\\[\\[([^\\]]*?)\\|([^\\[\\]]*?)\\]\\]";
+
+    private static final String JSPWIKI_LINK = "[$2|$1]";
+
+    private static final String CREOLE_HEADER_0 = "(\n|\r|\r\n|^)=([^=\\r\\n]*)={0,2}";
+
+    private static final String JSPWIKI_HEADER_0 = "$1!!!$2";
+
+    private static final String CREOLE_HEADER_1 = "(\n|\r|\r\n|^)==([^=\\r\\n]*)={0,2}";
+
+    private static final String JSPWIKI_HEADER_1 = "$1!!!$2";
+
+    private static final String CREOLE_HEADER_2 = "(\n|\r|\r\n|^)===([^=\\r\\n]*)={0,3}";
+
+    private static final String JSPWIKI_HEADER_2 = "$1!!$2";
+
+    private static final String CREOLE_HEADER_3 = "(\n|\r|\r\n|^)====([^=\\r\\n]*)={0,4}";
+
+    private static final String JSPWIKI_HEADER_3 = "$1!$2";
+
+    private static final String CREOLE_HEADER_4 = "(\n|\r|\r\n|^)=====([^=\\r\\n]*)={0,5}";
+
+    private static final String JSPWIKI_HEADER_4 = "$1__$2__";
+
+    private static final String CREOLE_SIMPLEIMAGE = "\\{\\{([^\\}]*?)\\}\\}";
+
+    private static final String JSPWIKI_SIMPLEIMAGE = "[{Image src='$1'}]";
+
+    private static final String CREOLE_IMAGE = "\\{\\{([^\\}]*?)\\|([^\\}]*?)\\}\\}";
+
+    private static final String JSPWIKI_IMAGE = "[{Image src='$1' caption='$2'}]";
+
+    private static final String CREOLE_IMAGE_LINK = "\\[\\[(.*?)\\|\\{\\{(.*?)\\}\\}\\]\\]";
+
+    private static final String JSPWIKI_IMAGE_LINK = "[{Image src='$2' link='$1'}]";
+
+    private static final String CREOLE_IMAGE_LINK_DESC = "\\[\\[(.*?)\\|\\{\\{(.*?)\\|(.*?)\\}\\}\\]\\]";
+
+    private static final String JSPWIKI_IMAGE_LINK_DESC = "[{Image src='$2' link='$1' caption='$3'}]";
+
+    private static final String PREFORMATTED_PROTECTED = "\\Q{{{\\E.*?\\Q}}}\\E";
+
+    //private static final String CREOLE_LINEBREAKS = "([^\\s\\\\])(\r\n|\r|\n)+(?=[^\\s\\*#])";
+
+    //private static final String JSPWIKI_LINEBREAKS = "$1\\\\\\\\$2";
+
+    private static final String CREOLE_TABLE = "(\n|\r|\r\n|^)(\\|[^\n\r]*)\\|(\\t| )*(\n|\r|\r\n|$)";
+
+    private static final String CREOLE_PLUGIN = "\\<\\<((?s:.)*?)\\>\\>";
+
+    private static final String JSPWIKI_PLUGIN = "[{$1}]";
+
+    private static final String WWW_URL = "(\\[\\[)\\s*(www\\..*?)(\\]\\])";
+
+    private static final String HTTP_URL = "$1http://$2$3";
+
+    private static final String CREOLE_IMAGE_X = "\\{\\{(.*?)((\\|)(.*?)){0,1}((\\|)(.*?)){0,1}\\}\\}";
+
+    private static final String JSPWIKI_IMAGE_X = "[{\u2016 src='$1' caption='$4' \u2015}]";
+
+    private static final String CREOLE_LINK_IMAG_X = "\\[\\[(.*?)\\|\\{\\{(.*?)((\\|)(.*?)){0,1}((\\|)(.*?)){0,1}\\}\\}\\]\\]";
+
+    private static final String JSPWIKI_LINK_IMAGE_X = "[{\u2016 src='$2' link='$1' caption='$5' \u2015}]";
+
+    private static final String JSPWIKI_TABLE = "$1$2$4";
+
+    /* TODO Is it possible to use just protect :// ? */
+    private static final String URL_PROTECTED = "http://|ftp://|https://";
+
+    private static final String TABLE_HEADER_PROTECTED = "((\n|\r|\r\n|^)(\\|.*?)(\n|\r|\r\n|$))";
+
+    private static final String SIGNATURE = "--~~~";
+
+    private static final String SIGNATURE_AND_DATE = "--~~~~";
+
+    private static final String DEFAULT_DATEFORMAT = "yyyy-MM-dd";
+
+    private static final String ESCAPE_PROTECTED = "~(\\*\\*|~|//|-|#|\\{\\{|}}|\\\\|~\\[~~[|]]|----|=|\\|)";
+
+    private static Map          c_protectionMap = new HashMap();
+
+    private        ArrayList    m_hashList = new ArrayList();
+
+    public String translateSignature(Properties wikiProps, final String content, String username)
+    {
+
+        String dateFormat = wikiProps.getProperty("creole.dateFormat");
+
+        if (dateFormat == null)
+        {
+            dateFormat = DEFAULT_DATEFORMAT;
+        }
+
+        SimpleDateFormat df = null;
+        try
+        {
+            df = new SimpleDateFormat(dateFormat);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            df = new SimpleDateFormat(DEFAULT_DATEFORMAT);
+        }
+
+        String result = content;
+        result = protectMarkup(result, PREFORMATTED_PROTECTED, "", "");
+        result = protectMarkup(result, URL_PROTECTED, "", "");
+
+        Calendar cal = Calendar.getInstance();
+        result = translateElement(result, SIGNATURE_AND_DATE, "-- [[" + username + "]], " + df.format(cal.getTime()));
+        result = translateElement(result, SIGNATURE, "-- [[" + username + "]]");
+        result = unprotectMarkup(result, false);
+        return result;
+    }
+
+    /** Translates Creole markup to JSPWiki markup */
+    public String translate(Properties wikiProps, final String content)
+    {
+        boolean blogLineBreaks = false;
+        /*
+        // BROKEN, breaks on different platforms.
+        String tmp = wikiProps.getProperty("creole.blogLineBreaks");
+        if (tmp != null)
+        {
+            if (tmp.trim().equals("true"))
+                blogLineBreaks = true;
+        }
+        */
+        String imagePlugin = wikiProps.getProperty("creole.imagePlugin.name");
+
+        String result = content;
+        //
+        // Breaks on OSX.  It is never a good idea to tamper with the linebreaks.  JSPWiki always
+        // stores linebreaks as \r\n, regardless of the platform.
+        //result = result.replace("\r\n", "\n");
+        //result = result.replace("\r", "\n");
+
+        /* Now protect the rest */
+        result = protectMarkup(result);
+        result = translateLists(result, "*", "-", "Nothing");
+        result = translateElement(result, CREOLE_BOLD, JSPWIKI_BOLD);
+        result = translateElement(result, CREOLE_ITALIC, JSPWIKI_ITALIC);
+        result = translateElement(result, WWW_URL, HTTP_URL);
+
+        if (imagePlugin != null && !imagePlugin.equals(""))
+        {
+            result = this.replaceImageArea(wikiProps, result, CREOLE_LINK_IMAG_X, JSPWIKI_LINK_IMAGE_X, 6, imagePlugin);
+            result = this.replaceImageArea(wikiProps, result, CREOLE_IMAGE_X, JSPWIKI_IMAGE_X, 5, imagePlugin);
+        }
+        result = translateElement(result, CREOLE_IMAGE_LINK_DESC, JSPWIKI_IMAGE_LINK_DESC);
+        result = translateElement(result, CREOLE_IMAGE_LINK, JSPWIKI_IMAGE_LINK);
+        result = translateElement(result, CREOLE_LINK, JSPWIKI_LINK);
+        result = translateElement(result, CREOLE_SIMPLELINK, JSPWIKI_SIMPLELINK);
+        result = translateElement(result, CREOLE_HEADER_4, JSPWIKI_HEADER_4);
+        result = translateElement(result, CREOLE_HEADER_3, JSPWIKI_HEADER_3);
+        result = translateElement(result, CREOLE_HEADER_2, JSPWIKI_HEADER_2);
+        result = translateElement(result, CREOLE_HEADER_1, JSPWIKI_HEADER_1);
+        result = translateElement(result, CREOLE_HEADER_0, JSPWIKI_HEADER_0);
+        result = translateElement(result, CREOLE_IMAGE, JSPWIKI_IMAGE);
+        result = translateLists(result, "-", "*", "#");
+        result = translateElement(result, CREOLE_SIMPLEIMAGE, JSPWIKI_SIMPLEIMAGE);
+        result = translateElement(result, CREOLE_TABLE, JSPWIKI_TABLE);
+        result = replaceArea(result, TABLE_HEADER_PROTECTED, "\\|=([^\\|]*)=|\\|=([^\\|]*)", "||$1$2");
+
+        /*
+        if (blogLineBreaks)
+        {
+            result = translateElement(result, CREOLE_LINEBREAKS, JSPWIKI_LINEBREAKS);
+        }
+        */
+        result = unprotectMarkup(result, true);
+
+        result = translateVariables(result, blogLineBreaks);
+        //result = result.replace("\n", System.getProperty("line.separator"));
+        return result;
+    }
+
+    /** Translates lists. */
+    private static String translateLists(String content, String sourceSymbol, String targetSymbol, String sourceSymbol2)
+    {
+        String[] lines = content.split("\n");
+        StringBuffer result = new StringBuffer();
+        int counter = 0;
+        int inList = -1;
+        for (int i = 0; i < lines.length; i++)
+        {
+            String line = lines[i];
+            String actSourceSymbol = "";
+            while ((line.startsWith(sourceSymbol) || line.startsWith(sourceSymbol2))
+                   && (actSourceSymbol.equals("") || line.substring(0, 1).equals(actSourceSymbol)))
+            {
+                actSourceSymbol = line.substring(0, 1);
+                line = line.substring(1, line.length());
+                counter++;
+            }
+            if ((inList == -1 && counter != 1) || (inList != -1 && inList + 1 < counter))
+            {
+                for (int c = 0; c < counter; c++)
+                {
+                    result.append(actSourceSymbol);
+                }
+                inList = -1;
+            }
+            else
+            {
+                for (int c = 0; c < counter; c++)
+                {
+                    if (actSourceSymbol.equals(sourceSymbol2))
+                    {
+                        result.append(sourceSymbol2);
+                    }
+                    else
+                    {
+                        result.append(targetSymbol);
+                    }
+                }
+                inList = counter;
+            }
+            result.append(line);
+            if (i < lines.length - 1)
+            {
+                result.append("\n");
+            }
+            counter = 0;
+        }
+        return result.toString();
+    }
+
+    private String translateVariables(String result, boolean blogLineBreaks)
+    {
+        result = result.replace("[{$creolepagefilter.version}]", VAR_VERSION);
+        result = result.replace("[{$creolepagefilter.creoleversion}]", VAR_CREOLE_VERSION);
+        String linebreaks = blogLineBreaks ? VAR_LINEBREAK_BLOGLIKE : VAR_LINEBREAK_C2LIKE;
+        result = result.replace("[{$creolepagefilter.linebreak}]", linebreaks);
+        return result;
+    }
+
+    /**
+     * Undoes the protection. This is done by replacing the md5 hashes by the
+     * original markup.
+     *
+     * @see #protectMarkup(String)
+     */
+    private String unprotectMarkup(String content,boolean replacePlugins)
+    {
+        Object[] it = this.m_hashList.toArray();
+
+        for (int i = it.length - 1; i >= 0; i--)
+        {
+            String hash = (String) it[i];
+            String protectedMarkup = (String) c_protectionMap.get(hash);
+            content = content.replace(hash, protectedMarkup);
+            if ((protectedMarkup.length() < 3 || (protectedMarkup.length() > 2 &&
+                !protectedMarkup.substring(0, 3).equals("{{{")))&&replacePlugins)
+                content = translateElement(content, CREOLE_PLUGIN, JSPWIKI_PLUGIN);
+
+        }
+        return content;
+    }
+
+    /**
+     * Protects markup that should not be processed. For now this includes:
+     * <ul>
+     * <li>Preformatted sections, they should be ignored</li>
+     * </li>
+     * <li>Protocol strings like <code>http://</code>, they cause problems
+     * because of the <code>//</code> which is interpreted as italic</li>
+     * </ul>
+     * This protection is a simple method to keep the regular expressions for
+     * the other markup simple. Internally the protection is done by replacing
+     * the protected markup with the the md5 hash of the markup.
+     *
+     * @param content
+     * @return
+     */
+    private String protectMarkup(String content)
+    {
+        c_protectionMap.clear();
+        this.m_hashList = new ArrayList();
+        content = protectMarkup(content, PREFORMATTED_PROTECTED, "", "");
+        content = protectMarkup(content, URL_PROTECTED, "", "");
+        content = protectMarkup(content, ESCAPE_PROTECTED, "", "");
+        content = protectMarkup(content, CREOLE_PLUGIN, "", "");
+
+        // content = protectMarkup(content, LINE_PROTECTED);
+        // content = protectMarkup(content, SIGNATURE_PROTECTED);
+        return content;
+    }
+
+    private ArrayList readPlaceholderProperties(Properties wikiProps)
+    {
+        Set keySet = wikiProps.keySet();
+        Object[] keys = keySet.toArray();
+        ArrayList result = new ArrayList();
+
+        for (int i = 0; i < keys.length; i++)
+        {
+            String key = keys[i] + "";
+            String value = wikiProps.getProperty(keys[i] + "");
+            if ((key).indexOf("creole.imagePlugin.para.%") > -1)
+            {
+                String[] pair = new String[2];
+                pair[0] = key.replaceAll("creole.imagePlugin.para.%", "");
+                pair[1] = value;
+                result.add(pair);
+            }
+        }
+        return result;
+    }
+
+    private String replaceImageArea(Properties wikiProps, String content, String markupRegex, String replaceContent, int groupPos,
+                                    String imagePlugin)
+    {
+        Matcher matcher = Pattern.compile(markupRegex, Pattern.MULTILINE | Pattern.DOTALL).matcher(content);
+        String contentCopy = content;
+
+        ArrayList plProperties = readPlaceholderProperties(wikiProps);
+
+        while (matcher.find())
+        {
+            String protectedMarkup = matcher.group(0);
+            String paramsField = matcher.group(groupPos);
+            String paramsString = "";
+
+            if (paramsField != null)
+            {
+                String[] params = paramsField.split(",");
+
+                for (int i = 0; i < params.length; i++)
+                {
+                    String param = params[i].replaceAll("\\||\\s", "").toUpperCase();
+
+                    // Replace placeholder params
+                    for (int j = 0; j < plProperties.size(); j++)
+                    {
+                        String[] pair = (String[]) plProperties.get(j);
+                        String key = pair[0];
+                        String value = pair[1];
+                        String code = param.replaceAll("(?i)([0-9]+)" + key, value + "<check>" + "$1" + "</check>");
+                        code = code.replaceAll("(.*?)%(.*?)<check>(.*?)</check>", "$1$3$2");
+                        if (!code.equals(param))
+                            paramsString += code;
+                    }
+
+                    // Check if it is a number
+                    try
+                    {
+                        Integer.parseInt(param);
+                        paramsString += " width='" + param + "px'";
+                    }
+                    catch (Exception e)
+                    {
+
+                        if (wikiProps.getProperty("creole.imagePlugin.para." + param) != null)
+                            paramsString += " "
+                                            + wikiProps.getProperty("creole.imagePlugin.para." + param)
+                                                .replaceAll("^(\"|')(.*)(\"|')$", "$2");
+                    }
+                }
+            }
+            String temp = protectedMarkup;
+
+            protectedMarkup = translateElement(protectedMarkup, markupRegex, replaceContent);
+            protectedMarkup = protectedMarkup.replaceAll("\u2015", paramsString);
+            protectedMarkup = protectedMarkup.replaceAll("\u2016", imagePlugin);
+            protectedMarkup = protectedMarkup.replaceAll("caption=''", "");
+            protectedMarkup = protectedMarkup.replaceAll("\\s+", " ");
+
+            int pos = contentCopy.indexOf(temp);
+            contentCopy = contentCopy.substring(0, pos) + protectedMarkup
+                          + contentCopy.substring(pos + temp.length(), contentCopy.length());
+        }
+        return contentCopy;
+    }
+
+    private String replaceArea(String content, String markupRegex, String replaceSource, String replaceTarget)
+    {
+        Matcher matcher = Pattern.compile(markupRegex, Pattern.MULTILINE | Pattern.DOTALL).matcher(content);
+        String contentCopy = content;
+
+        while (matcher.find())
+        {
+            String protectedMarkup = matcher.group(0);
+            String temp = protectedMarkup;
+            protectedMarkup = protectedMarkup.replaceAll(replaceSource, replaceTarget);
+            int pos = contentCopy.indexOf(temp);
+            contentCopy = contentCopy.substring(0, pos) + protectedMarkup
+                          + contentCopy.substring(pos + temp.length(), contentCopy.length());
+        }
+        return contentCopy;
+    }
+
+    /**
+     * Protects a specific markup
+     *
+     * @see #protectMarkup(String)
+     */
+    private String protectMarkup(String content, String markupRegex, String replaceSource, String replaceTarget)
+    {
+        Matcher matcher = Pattern.compile(markupRegex, Pattern.MULTILINE | Pattern.DOTALL).matcher(content);
+        StringBuffer result = new StringBuffer();
+        while (matcher.find())
+        {
+            String protectedMarkup = matcher.group();
+            protectedMarkup = protectedMarkup.replaceAll(replaceSource, replaceTarget);
+            try
+            {
+                MessageDigest digest = MessageDigest.getInstance("MD5");
+                digest.reset();
+                digest.update(protectedMarkup.getBytes("UTF-8"));
+                String hash = bytesToHash(digest.digest());
+                matcher.appendReplacement(result, hash);
+                c_protectionMap.put(hash, protectedMarkup);
+                this.m_hashList.add(hash);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                // FIXME: Should log properly
+                e.printStackTrace();
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                // FIXME: Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        matcher.appendTail(result);
+        return result.toString();
+    }
+
+    private String bytesToHash(byte[] b)
+    {
+        String hash = "";
+        for (int i = 0; i < b.length; i++)
+        {
+            hash += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
+        }
+        return hash;
+    }
+
+    private String translateElement(String content, String fromMarkup, String toMarkup)
+    {
+        Matcher matcher = Pattern.compile(fromMarkup, Pattern.MULTILINE).matcher(content);
+        StringBuffer result = new StringBuffer();
+
+        while (matcher.find())
+        {
+            matcher.appendReplacement(result, toMarkup);
+        }
+        matcher.appendTail(result);
+        return result.toString();
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/Heading.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/Heading.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/Heading.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/Heading.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,39 @@
+/*
+  JSPWiki - a JSP-based WikiWiki clone.
+
+  Copyright (C) 2001-2006 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package com.ecyrd.jspwiki.parser;
+
+/**
+ *  This class is used to store the headings in a manner which
+ *  allow the building of a Table Of Contents.
+ *
+ *  @since 2.4
+ *  @author Janne Jalkanen
+ */
+public class Heading
+{
+    public static final int HEADING_SMALL  = 1;
+    public static final int HEADING_MEDIUM = 2;
+    public static final int HEADING_LARGE  = 3;
+
+    public int    m_level;
+    public String m_titleText;
+    public String m_titleAnchor;
+    public String m_titleSection;
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/HeadingListener.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/HeadingListener.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/HeadingListener.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/parser/HeadingListener.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,33 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2004 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.parser;
+
+import com.ecyrd.jspwiki.WikiContext;
+
+/**
+ *  Provides a listener interface for headings
+ */
+public interface HeadingListener
+{
+    /**
+     *  Is called whenever a heading is encountered in the stream.
+     */
+    public void headingAdded( WikiContext context, Heading hd );
+}