Janne Jalkanen wrote:
Okay, I've finished writing the IndexPlugin and fired off a message
to Craig Russell regarding a JIRA account, though he's yet to respond
(time zone likely culprit). I'd thought I had one and was all set up
but it doesn't seem to recognize any of my email addresses.

Yeah, according to the svn-committers list you should have access to the SVN for both JSPWiki and xml-xindice...

Yes, but when I try to retrieve the password for 'altheim' I see the
message "No user with that username exists".

http://people.apache.org/~jim/committers.html

Yeah, understood. I note that I apparently don't have a signed CLA on
file -- thought I had faxed a copy before Christmas. If I need to fax
or send via post again, please let me know details. Thanks. I'm
guessing this is why I'm not able to log in.

If there's any rush I can forward a patch, or do what is probably a
better thing: get with the programme by submitting it against the
existing JIRA bug.

I guess there's no rush, but if you want to have a code review, you can always attach it as a patch.

I'm not in any particular rush but since I've got a bit of a window
here I might as well attach it. This is against svn's trunk.

Murray

...........................................................................
Murray Altheim <murray07 at altheim.com>                           ===  = =
http://www.altheim.com/murray/                                     = =  ===
SGML Grease Monkey, Banjo Player, Wantanabe Zen Monk               = =  = =

      Boundless wind and moon - the eye within eyes,
      Inexhaustible heaven and earth - the light beyond light,
      The willow dark, the flower bright - ten thousand houses,
      Knock at any door - there's one who will respond.
                                      -- The Blue Cliff Record
diff -Naur tronk/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java trunk/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java
--- tronk/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java	2008-04-15 10:29:32.000000000 +1200
+++ trunk/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java	2008-04-15 19:37:21.000000000 +1200
@@ -1,235 +1,527 @@
 /*
     JSPWiki - a JSP-based WikiWiki clone.
 
-    Copyright (C) 2002 Janne Jalkanen ([EMAIL PROTECTED])
-
-    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
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
  */
-package com.ecyrd.jspwiki.plugin;
-
-import java.io.StringWriter;
-import java.util.*;
 
-import org.apache.log4j.Logger;
-import org.apache.oro.text.GlobCompiler;
-import org.apache.oro.text.regex.*;
+package org.ceryle.wiki.plugin;
 
-import com.ecyrd.jspwiki.*;
-import com.ecyrd.jspwiki.providers.ProviderException;
+import  com.ecyrd.jspwiki.ReferenceManager;
+import  com.ecyrd.jspwiki.TextUtil;
+import  com.ecyrd.jspwiki.WikiContext;
+import  com.ecyrd.jspwiki.WikiEngine;
+import  com.ecyrd.jspwiki.plugin.PluginException;
+import  com.ecyrd.jspwiki.plugin.PluginManager;
+import  com.ecyrd.jspwiki.plugin.WikiPlugin;
+import  com.ecyrd.jspwiki.providers.ProviderException;
+
+import  org.apache.log4j.Logger;
+
+import  java.text.Collator;
+import  java.util.Comparator;
+import  java.util.Iterator;
+import  java.util.Locale;
+import  java.util.Map;
+import  java.util.MissingResourceException;
+import  java.util.SortedSet;
+import  java.util.StringTokenizer;
+import  java.util.TreeSet;
+import  java.util.regex.*;
 
 /**
- *  Builds an index of all pages.
- *  <P>Parameters</P>
- *  <UL>
- *    <LI>itemsPerLine: How many items should be allowed per line before break.
- *    If set to zero (the default), will not write breaks.
- *    <LI>include: Include only these pages.
- *    <LI>exclude: Exclude with this pattern.
- *  </UL>
+ *  This IndexPlugin is a CeryleWikiPlugin reworking of the original JSPWiki
+ *  IndexPlugin. This was developed when the JSPWiki project moved to Apache
+ *  and IP permissions could not be obtained for the original plugin.
+ *  Changes include:
+ *  <ul>
+ *    <li>improved (Collator-based) locale-dependent sorting </li>
+ *    <li>ability to include and exclude pages based on multiple
+ *        (whitespace-delimited) regular expression (regex) patterns </li>
+ *    <li>include/exclude matching based on Java's regex rather than ORO
+ *        (one less dependency) </li>
+ *    <li>locale can be set for sorting (in absence of a parameter, uses
+ *        Unicode UTF-8 order) </li>
+ *    <li>produces valid XHTML markup </li>
+ *  </ul>
+ *
+ *  <h4>Parameters</h4>
+ *  <ul>
+ *    <li><b>exclude</b> = <i>'regex regex'</i>.
+ *      one or more regular expressions (separated by whitespace) to match
+ *      pages that should be excluded from the generated index.
+ *    </li>
+ *    <li><b>include</b> = <i>'regex regex'</i>.
+ *      one or more regular expressions (separated by whitespace) to match
+ *      pages that should be included in the generated index.
+ *    </li>
+ *    <li><b>itemsPerLine</b> = <i>'int'</i>.
+ *      the number of page names to display per line of the generated index
+ *    </li>
+ *    <li><b>locale</b> = <i>'lang'</i> | <i>'lang_COUNTRY'</i>.
+ *      provides a locale for sorting page names. This can be specified as
+ *      either a two character lowercase ISO-639 language code (e.g., "en"
+ *      for English) , or a two character language code followed by a two
+ *      character uppercase ISO 3166 country code, separated by an underscore
+ *      character (e.g., "en_NZ" for New Zealand English). If this parameter
+ *      is not included the plugin will not use the default (environment)
+ *      locale, it will resort to Java's native Unicode (UTF-8) String sort
+ *      method, which may be faster but does not sort according to any natural
+ *      language sort order, just the Unicode glyph ordering. To use the
+ *      default Locale of the server environment, specify an empty string
+ *      parameter.
+ *    </li>
+ *    <li><b>debug</b> = <i>'true' | 'false'</i>.
+ *      When true, displays debugging level information. Defaults to false.
+ *    </li>
+ *  </ul>
+ *  <p>
+ *    All parameters are optional. If both <tt>include</tt> and <tt>exclude</tt>
+ *    are specified, the former acts as a filter on the results of the latter.
+ *  </p>
+ *
+ *  <h4>Notes</h4>
+ *  <ul>
+ *    <li>
+ *      If no locale is specified [EMAIL PROTECTED] java.lang.String#CompareTo(Object)} is
+ *      used for sorting, which sorts using the Unicode glyph order. If your
+ *      wiki uses page names beginning with non-ASCII characters and you want
+ *      a more sensible sort order a Locale should be specified.
+ *    </li>
+ *    <li>
+ *      This uses [EMAIL PROTECTED] com.ecyrd.jspwiki.ReferenceManager#findCreated()} rather
+ *      than [EMAIL PROTECTED] com.ecyrd.jspwiki.PageManager#getAllPages()} as the source of
+ *      its page list, which as according to the documentation is significantly
+ *      faster (as it incurs no disk access) but may not represent the actual
+ *      contents of the wiki, especially during startup. Because of the performance
+ *      issues of this plugin in production environments speed was considered more
+ *      important than an initial plugin display problem during startup.
+ *    </li>
+ *  </ul>
  *
- *  @author Alain Ravet
- *  @author Janne Jalkanen
- *  @since 1.9.9
+ *  @author Murray Altheim
+ *  @since 2.6.x
  */
 public class IndexPlugin implements WikiPlugin
 {
-    protected static final Logger log = Logger.getLogger(IndexPlugin.class);
+    private static Logger log = Logger.getLogger(IndexPlugin.class);
 
-    public  static final String INITIALS_COLOR                  = "red" ;
-    private static final int    DEFAULT_ITEMS_PER_LINE          = 0     ;
+    /** The name of the <tt>debug</tt> parameter. */
+    public static final String PARAM_DEBUG          = "debug";
 
-    private static final String PARAM_ITEMS_PER_LINE            = "itemsPerLine";
-    private static final String PARAM_INCLUDE                   = "include";
-    private static final String PARAM_EXCLUDE                   = "exclude";
-
-    private int                 m_currentNofPagesOnLine         = 0;
-    private int                 m_itemsPerLine;
-    protected String            m_previousPageFirstLetter       = "";
-    protected StringWriter      m_bodyPart      =   new StringWriter();
-    protected StringWriter      m_headerPart    =   new StringWriter();
-    private Pattern             m_includePattern;
-    private Pattern             m_excludePattern;
-
-
-    public String execute( WikiContext wikiContext , Map params )
-        throws PluginException
-    {
-        //
-        //  Parse arguments and create patterns.
-        //
-        PatternCompiler compiler = new GlobCompiler();
-        m_itemsPerLine = TextUtil.parseIntParameter( (String) params.get(PARAM_ITEMS_PER_LINE),
-                                                     DEFAULT_ITEMS_PER_LINE );
-        try
-        {
-            String ptrn = (String) params.get(PARAM_INCLUDE);
-            if( ptrn == null ) ptrn = "*";
-            m_includePattern = compiler.compile(ptrn);
+    /** The name of the <tt>exclude</tt> parameter. */
+    public static final String PARAM_EXCLUDE        = "exclude";
 
-            ptrn = (String) params.get(PARAM_EXCLUDE);
-            if( ptrn == null ) ptrn = "";
-            m_excludePattern = compiler.compile(ptrn);
-        }
-        catch( MalformedPatternException e )
-        {
-            throw new PluginException("Illegal pattern detected."); // FIXME, make a proper error.
-        }
+    /** The name of the <tt>include</tt> parameter. */
+    public static final String PARAM_INCLUDE        = "include";
 
-        //
-        //  Get pages, then sort.
-        //
+    /** The name of the <tt>itemsPerLine</tt> parameter. */
+    public static final String PARAM_ITEMS_PER_LINE = "itemsPerLine";
 
-        final Collection        allPages      = getAllPagesSortedByName( wikiContext );
+    /** The name of the <tt>locale</tt> parameter. */
+    public static final String PARAM_LOCALE         = "locale";
 
-        //
-        //  Build the page.
-        //
-        buildIndexPageHeaderAndBody( wikiContext, allPages );
+    /** The character used as a delimiter between page names in
+     *  the generated list. The default is a comma. */
+    public static char DELIM = ',';
 
-        StringBuffer res = new StringBuffer();
+    /**
+     *  When true, locale specifications are checked for availability of associated
+     *  resources, throwing a MissingResourceException if the locale specification
+     *  is invalid or resources for the specified locale are unavailable.
+     *  There is a performance hit for performing this check so you may wish to
+     *  skip it if the check is unnecessary for your application. The default value
+     *  is true.
+     */
+    public static boolean CHECK_LOCALE_AVAILABILITY = true;
 
-        res.append( "<div class=\"index\">\n" );
-        res.append( "<div class=\"header\">\n" );
-        res.append( m_headerPart.toString() );
-        res.append( "</div>\n" );
-        res.append( "<div class=\"body\">\n" );
-        res.append( m_bodyPart.toString() );
-        res.append( "</div>\n</div>\n" );
+    /**
+     *  When true and no locale is specified (i.e., when simple sorting is active),
+     *  comparisons are made using lowercased page names. This uses the Java
+     *  [EMAIL PROTECTED] java.lang.String#toLowerCase()} method. If a Locale has been
+     *  specified (i.e., a Collator is being used) this flag has no effect.
+     */
+    public static boolean LOWERCASE_SORT = true;
 
-        return res.toString();
-    }
+    private static final int DEFAULT_ITEMS_PER_LINE = 0;
+    private Pattern[] m_pattern_include = null,
+                      m_pattern_exclude = null;
+    private Matcher[] m_matcher_include = null,
+                      m_matcher_exclude = null;
+    private Locale m_locale           = null;
+    private Collator m_collator       = null;
+    private int m_maxItemsPerLine;
+    private StringBuilder m_body      = new StringBuilder();
+    private StringBuilder m_header    = new StringBuilder();
+    private boolean m_debug           = false;
 
+    // ............
 
-    private void buildIndexPageHeaderAndBody( WikiContext context,
-                                              final Collection allPages )
+
+    public String execute( WikiContext context, Map params ) throws PluginException
     {
-        PatternMatcher matcher = new Perl5Matcher();
+        StringBuffer out = new StringBuffer();
+
+        // get parameters ..................................................
+        m_debug              = TextUtil.isPositive((String)params.get(PARAM_DEBUG));
+        m_maxItemsPerLine    = TextUtil.parseIntParameter((String)params.get(PARAM_ITEMS_PER_LINE),
+                                   DEFAULT_ITEMS_PER_LINE);
+        String param_exclude = (String)params.get(PARAM_EXCLUDE);
+        String param_include = (String)params.get(PARAM_INCLUDE);
+        String param_locale  = (String)params.get(PARAM_LOCALE);
 
-        for( Iterator i = allPages.iterator (); i.hasNext ();)
+        // process parameters ..............................................
+
+        try
         {
-            WikiPage curPage = (WikiPage) i.next();
+            // 'include' regex ...................
+            setIncludePatterns(param_include);
 
-            if( matcher.matches( curPage.getName(), m_includePattern ) )
-            {
-                if( !matcher.matches( curPage.getName(), m_excludePattern ) )
-                {
-                    ++m_currentNofPagesOnLine;
+            // 'exclude' regex ...................
+            setExcludePatterns(param_exclude);
 
-                    String    pageNameFirstLetter           = curPage.getName().substring(0,1).toUpperCase();
-                    boolean   sameFirstLetterAsPreviousPage = m_previousPageFirstLetter.equals(pageNameFirstLetter);
+            // locale ............................
+            setLocale(param_locale);
 
-                    if( !sameFirstLetterAsPreviousPage )
-                    {
-                        addLetterToIndexHeader( pageNameFirstLetter );
-                        addLetterHeaderWithLine( pageNameFirstLetter );
+            // build index .....................................................
+
+            // get a sorted Set of all page names
+            SortedSet pages = new TreeSet( m_collator != null
+                    ? m_collator
+                    : new PageSorter() );
+            final ReferenceManager refMgr = context.getEngine().getReferenceManager();
+            if ( refMgr != null ) {
+                pages.addAll( refMgr.findCreated() );
+            }
 
-                        m_currentNofPagesOnLine   = 1;
-                        m_previousPageFirstLetter = pageNameFirstLetter;
-                    }
+            buildIndex(context,pages);
+
+            // generate XHTML output ...........................................
 
-                    addPageToIndex( context, curPage );
-                    breakLineIfTooLong();
+            out.append( "<div class=\"index\">\n" );
+            if ( m_debug ) // I18N?
+            {
+                params.remove(PluginManager.PARAM_BODY);
+                params.remove(PluginManager.PARAM_BOUNDS);
+                params.remove(PluginManager.PARAM_CMDLINE);
+                out.append( "<div class=\"debug\">\n" );
+                out.append( "<h4>" );
+                out.append( "Parameters:" );
+                out.append( "</h4>\n" );
+                out.append( "<p>\n" );
+                for ( int i = 0; i < m_matcher_exclude.length; i++ )
+                {
+                    out.append( "<b>exclude</b>: "
+                            + ( m_pattern_exclude[i] != null
+                                ? m_pattern_exclude[i].pattern() : "not specified" ) + "<br />\n" );
+                }
+                for ( int i = 0; i < m_matcher_include.length; i++ )
+                {
+                    out.append( "<b>include</b>: "
+                            + ( m_pattern_include[i] != null
+                                ? m_pattern_include[i].pattern() : "not specified" ) + "<br />\n" );
                 }
+                out.append( "<b>locale</b>: "
+                        + ( m_locale != null ? m_locale.toString() : "not specified" ) + "<br />\n" );
+                out.append( "<b>items per line</b>: "
+                        + m_maxItemsPerLine + ( params.get(PARAM_ITEMS_PER_LINE) != null
+                            ? "" : " (default)" ) + "\n" );
+                out.append( "</p>\n" );
+                out.append( "</div>\n" );
             }
-        } // for
+
+            // write header
+            out.append( "<div class=\"header\">\n" );
+            out.append( m_header.toString() );
+            out.append( "\n</div>\n" );
+
+            // write body
+            out.append( "<div class=\"body\">\n" );
+            out.append( m_body.toString() );
+            out.append( "\n</div>\n" );
+
+            out.append( "</div>\n" );
+
+        }
+        catch ( PatternSyntaxException pse ) // from 'include' or 'exclude' parameter
+        {
+            log.error( " invalid regular expression in IndexPlugin:  " + pse.getMessage() ); // I18N
+            out.setLength(0);
+            out.append( "<div class=\"error\">\n" );
+            out.append( "invalid regular expression in IndexPlugin:  " + pse.getMessage() ); // I18N
+            out.append( "</div>\n" );
+        }
+        catch ( MissingResourceException mre )
+        {
+            log.error( " bad locale specification in IndexPlugin '"
+                    + param_locale+"': " + mre.getMessage() ); // I18N
+            out.setLength(0);
+            out.append( "<div class=\"error\">\n" );
+            out.append( "bad locale specification in IndexPlugin '"
+                    + param_locale+"': " + mre.getMessage() ); // I18N
+            out.append( "</div>\n" );
+        }
+        catch ( Exception e )
+        {
+            log.error( e.getClass().getName() + " thrown by IndexPlugin: " + e.getMessage() ); // I18N
+            out.setLength(0);
+            out.append( "<div class=\"error\">\n" );
+            out.append( e.getClass().getName() + " thrown by IndexPlugin: " + e.getMessage() ); // I18N
+            out.append( "</div>\n" );
+        }
+        return out.toString();
     }
 
 
     /**
-     *  Gets all pages, then sorts them.
+     *  Generates an index based on the provided list of page names, with
+     *  all other factors provided by method variable parameters.
      */
-    static Collection getAllPagesSortedByName( WikiContext wikiContext )
+    private void buildIndex( WikiContext context, final SortedSet pagenames )
     {
-        final WikiEngine engine = wikiContext.getEngine();
+        String prevFirstLetter = "";
+        int itemsOnLine = 0;
+        m_body.append("         ");
 
-        final PageManager pageManager = engine.getPageManager();
-        if( pageManager == null )
-            return null;
+        for ( Iterator it = pagenames.iterator (); it.hasNext (); )
+        {
+            String pagename = (String)it.next();
 
-        Collection result = new TreeSet( new Comparator() {
-            public int compare( Object o1, Object o2 )
-            {
-                if( o1 == null || o2 == null ) return 0;
+            boolean include = true;
+            boolean exclude = false;
+
+            // filter inclusions, then exclusions
+            if ( includePage( pagename ) ) {
+                if ( !excludePage( pagename ) ) {
 
-                WikiPage page1 = (WikiPage)o1;
-                WikiPage page2 = (WikiPage)o2;
+                    ++itemsOnLine;
 
-                return page1.getName().compareTo( page2.getName() );
+                    String firstLetter = pagename.substring(0,1).toUpperCase();
+
+                    if ( !prevFirstLetter.equals(firstLetter) ) // if not same first letter as prev page
+                    {
+                        // add letter to index header
+                        if ( !prevFirstLetter.equals("") )
+                        {
+                            m_header.append( " - " );
+                        }
+                        m_header.append( "<a href=\"#" );
+                        m_header.append( firstLetter );
+                        m_header.append( "\">" );
+                        m_header.append( firstLetter );
+                        m_header.append( "</a> " );
+
+                        // REMOVE_TRAILING_DELIM at end of previous section
+                        if ( m_body.charAt(m_body.length()-8) == DELIM ) {
+                            m_body.setCharAt(m_body.length()-8,' ');
+                        }
+                        // add letter header with line
+                        m_body.append( "\n<br /><br /><span class=\"section\">" );
+                        m_body.append( "<a id=\"" );
+                        m_body.append( firstLetter );
+                        m_body.append( "\">" );
+                        m_body.append( firstLetter );
+                        m_body.append( "</a></span><hr />\n" );
+
+                        itemsOnLine = 1;
+
+                        prevFirstLetter = firstLetter;
+                    }
+
+                    // add page to index
+                //  if ( m_maxItemsPerLine == 0 || itemsOnLine >= 2 )
+                    if ( itemsOnLine >= 2 )
+                    {
+                        m_body.append( ",&nbsp;\n" );
+                    }
+                    m_body.append( "<a href=\"" );
+                    m_body.append( context.getURL( WikiContext.VIEW, pagename ) );
+                    m_body.append( "\">" );
+                    m_body.append( context.getEngine().beautifyTitleNoBreak( pagename ) );
+                    m_body.append( "</a>" );
+
+                    // break line if too long
+                    if ( m_maxItemsPerLine == itemsOnLine )
+                    {
+                        m_body.append( DELIM ); // see REMOVE_TRAILING_DELIM above
+                        m_body.append( "<br />\n" ); // 7 char length
+                        itemsOnLine = 0;
+                    }
+                }
             }
-        });
+        }
+    }
 
-        try
+
+    // regex ...................................................................
+
+
+    /**
+     *  Sets the array of 'exclude' Patterns and Matchers by parsing
+     *  <tt>regexs</tt> as one or more whitespace-delimited regular
+     *  expressions.
+     */
+    private void setExcludePatterns( String regexs )
+    {
+        if ( regexs != null )
         {
-            Collection allPages = pageManager.getAllPages();
-            result.addAll( allPages );
+            StringTokenizer st = new StringTokenizer(regexs);
+            m_pattern_exclude = new Pattern[st.countTokens()];
+            m_matcher_exclude = new Matcher[st.countTokens()];
+            for ( int i = 0 ; st.hasMoreTokens(); i++ )
+            {
+                String regex = st.nextToken();
+                m_pattern_exclude[i] = Pattern.compile(regex);
+                m_matcher_exclude[i] = m_pattern_exclude[i].matcher("");
+            }
         }
-        catch( ProviderException e )
+    }
+
+
+    /**
+     *  Sets the array of 'include' Patterns and Matchers by parsing
+     *  <tt>regexs</tt> as one or more whitespace-delimited regular
+     *  expressions.
+     */
+    private void setIncludePatterns( String regexs )
+    {
+        if ( regexs != null )
         {
-            log.fatal("PageProvider is unable to list pages: ", e);
+            StringTokenizer st = new StringTokenizer(regexs);
+            m_pattern_include = new Pattern[st.countTokens()];
+            m_matcher_include = new Matcher[st.countTokens()];
+            for ( int i = 0 ; st.hasMoreTokens(); i++ )
+            {
+                String regex = st.nextToken();
+                m_pattern_include[i] = Pattern.compile(regex);
+                m_matcher_include[i] = m_pattern_include[i].matcher("");
+            }
         }
-
-        return result;
     }
 
 
-    private void addLetterToIndexHeader( final String firstLetter )
+    /**
+     *  Returns true if the wiki page with name <tt>pagename</tt> matches
+     *  any of the 'exclude' page parameters.
+     */
+    private boolean excludePage( String pagename )
     {
-        final boolean noLetterYetInTheIndex = ! "".equals(m_previousPageFirstLetter);
-
-        if( noLetterYetInTheIndex )
+        if ( m_matcher_exclude == null ) return true;
+        for ( int i = 0; i < m_matcher_exclude.length; i++ )
         {
-            m_headerPart.write(" - " );
+            m_matcher_exclude[i].reset(pagename);
+            if ( m_matcher_exclude[i].matches() ) return true;
         }
-
-        m_headerPart.write("<a href=\"#"  + firstLetter + "\">" + firstLetter + "</a>" );
+        return false;
     }
 
 
-    private void addLetterHeaderWithLine( final String firstLetter )
+    /**
+     *  Returns true if the wiki page with name <tt>pagename</tt> matches
+     *  any of the 'include' page parameters.
+     */
+    private boolean includePage( String pagename )
     {
-        m_bodyPart.write("\n<br /><br />" +
-                         "<span class=\"section\">"+
-                         "<a name=\"" + firstLetter + "\">"+
-                         firstLetter+"</a></span>" +
-                         "<hr />\n" );
+        if ( m_matcher_include == null ) return true;
+        for ( int i = 0; i < m_matcher_include.length; i++ )
+        {
+            m_matcher_include[i].reset(pagename);
+            if ( m_matcher_include[i].matches() ) return true;
+        }
+        return false;
     }
 
-    protected void addPageToIndex( WikiContext context, WikiPage curPage )
-    {
-        final boolean notFirstPageOnLine = 2 <= m_currentNofPagesOnLine;
 
-        if( notFirstPageOnLine )
+    // sorting .................................................................
+
+
+    /**
+     *  A simple page sorter based on comparing the page names using the
+     *  Java native [EMAIL PROTECTED] java.lang.String#compareTo(Object)} method.
+     */
+    private class PageSorter implements Comparator
+    {
+        public int compare( Object o1, Object o2 )
         {
-            m_bodyPart.write(",&nbsp; ");
+            if ( o1 == null || o2 == null ) return 0;
+            String pagename1 = (String)o1;
+            String pagename2 = (String)o2;
+            return LOWERCASE_SORT
+                    ? pagename1.toLowerCase().compareTo(pagename2.toLowerCase())
+                    : pagename1.compareTo(pagename2);
         }
-
-        m_bodyPart.write("<a href=\""+
-                         context.getURL(WikiContext.VIEW, curPage.getName())+"\">"+
-                         context.getEngine().beautifyTitleNoBreak(curPage.getName())+
-                         "</a>");
     }
 
-    protected void breakLineIfTooLong()
-    {
-        final boolean limitReached = m_itemsPerLine == m_currentNofPagesOnLine;
 
-        if( limitReached )
+    /**
+     *  Sets the Locale for the given locale specification, creating an
+     *  associated Collator to be used for sorting.
+     *
+     * @param locale  the Locale specification, e.g., "en" or "en_US". A null
+     *                parameter sets no locale; an empty string uses the default
+     *                locale. The underscore character can be used as a
+     *                delimiter between ISO 639 language (lowercase) and ISO
+     *                3166 (uppercase) country codes.
+     * @see #CHECK_LOCALE_AVAILABILITY
+     * @throws java.util.MissingResourceException  if the locale specification
+     *                is invalid or the resources for the specified Locale are
+     *                unavailable.
+     */
+    protected void setLocale( String locale )
+    {
+        if ( locale != null )
         {
-            m_bodyPart.write( "<br />\n" );
-            m_currentNofPagesOnLine = 0;
+            int underscore = locale.indexOf('_');
+            if ( locale.trim().length() == 0 )
+            {
+                m_locale = Locale.getDefault(); // use default locale
+            }
+            else if ( underscore == -1 )
+            {
+                m_locale = new Locale(locale);
+            }
+            else
+            {
+                m_locale = new Locale(locale.substring(0,underscore),
+                        locale.substring(underscore+1));
+            }
+            if ( CHECK_LOCALE_AVAILABILITY )
+            {
+                Locale[] locales = Collator.getAvailableLocales();
+                for ( int i = 0; i < locales.length; i++ )
+                {
+                    if ( ((Locale)locales[i]).equals(m_locale) )
+                    {
+                        m_collator = Collator.getInstance(m_locale);
+                        return;
+                    }
+                }
+                // not found
+                m_locale = null;
+                throw new MissingResourceException(
+                        "locale specification invalid, unknown or resources unavailable.", // I18N
+                        m_locale.getClass().getName(), locale );
+            }
+            else
+            {
+                m_collator = Collator.getInstance(m_locale);
+            }
         }
     }
 
-}
+
+} // end org.ceryle.wiki.plugin.IndexPlugin

Reply via email to