[jsword-svn]
bibledesktop/java/main/org/crosswire/bibledesktop/book s
jswordcvs at crosswire.org
jswordcvs at crosswire.org
Fri Apr 1 10:10:16 MST 2005
Update of /cvs/jsword/bibledesktop/java/main/org/crosswire/bibledesktop/book
In directory www.crosswire.org:/tmp/cvs-serv5440/java/main/org/crosswire/bibledesktop/book
Modified Files:
Msg.properties DisplaySelectPane.java AdvancedSearchPane.java
Msg.java BibleViewPane.java
Log Message:
Improved ranking, bible display and fixed a few bugs.
Index: DisplaySelectPane.java
===================================================================
RCS file: /cvs/jsword/bibledesktop/java/main/org/crosswire/bibledesktop/book/DisplaySelectPane.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -C2 -d -r1.28 -r1.29
*** DisplaySelectPane.java 25 Mar 2005 04:02:49 -0000 1.28
--- DisplaySelectPane.java 1 Apr 2005 17:10:14 -0000 1.29
***************
*** 16,21 ****
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
- import java.util.ArrayList;
- import java.util.List;
import javax.swing.BorderFactory;
--- 16,19 ----
***************
*** 28,31 ****
--- 26,30 ----
import javax.swing.JPanel;
import javax.swing.JTextField;
+ import javax.swing.event.EventListenerList;
import org.crosswire.bibledesktop.book.install.IndexResolver;
***************
*** 35,48 ****
import org.crosswire.common.swing.GuiUtil;
import org.crosswire.common.swing.QuickHelpDialog;
import org.crosswire.common.util.Reporter;
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookFilters;
import org.crosswire.jsword.book.IndexStatus;
import org.crosswire.jsword.book.search.parse.IndexSearcher;
import org.crosswire.jsword.book.search.parse.PhraseParamWord;
import org.crosswire.jsword.passage.Key;
! import org.crosswire.jsword.passage.NoSuchVerseException;
import org.crosswire.jsword.passage.PassageTally;
import org.crosswire.jsword.passage.RestrictionType;
/**
--- 34,52 ----
import org.crosswire.common.swing.GuiUtil;
import org.crosswire.common.swing.QuickHelpDialog;
+ import org.crosswire.common.swing.desktop.event.TitleChangedEvent;
+ import org.crosswire.common.swing.desktop.event.TitleChangedListener;
import org.crosswire.common.util.Reporter;
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookFilters;
import org.crosswire.jsword.book.IndexStatus;
+ import org.crosswire.jsword.book.search.basic.DefaultSearchModifier;
+ import org.crosswire.jsword.book.search.basic.DefaultSearchRequest;
import org.crosswire.jsword.book.search.parse.IndexSearcher;
import org.crosswire.jsword.book.search.parse.PhraseParamWord;
import org.crosswire.jsword.passage.Key;
! import org.crosswire.jsword.passage.NoSuchKeyException;
import org.crosswire.jsword.passage.PassageTally;
import org.crosswire.jsword.passage.RestrictionType;
+ import org.crosswire.jsword.passage.RocketPassage;
/**
***************
*** 85,88 ****
--- 89,94 ----
private void initialize()
{
+ listeners = new EventListenerList();
+
advanced = new AdvancedSearchPane();
***************
*** 99,102 ****
--- 105,109 ----
selected.addPropertyChangeListener(pcl);
cboBible.setToolTipText(selected.toString());
+ key = selected.createEmptyKeyList();
}
else
***************
*** 105,108 ****
--- 112,118 ----
// So make the combo box a reasonable size.
cboBible.setPrototypeDisplayValue(" "); //$NON-NLS-1$
+ // Should always get a key from book, unless we need a PassageTally
+ // But here we don't have a book yet.
+ key = new RocketPassage();
}
cboBible.setRenderer(new BookListCellRenderer());
***************
*** 205,209 ****
public Book getBook()
{
! return mdlBible.getSelectedBook();
}
--- 215,219 ----
public Book getBook()
{
! return selected;
}
***************
*** 213,227 ****
public void clear()
{
! if (isClear())
! {
! return;
! }
!
! txtKey.setText(""); //$NON-NLS-1$
! txtSearch.setText(""); //$NON-NLS-1$
!
! title = Msg.UNTITLED.toString(new Integer(base++));
!
! updateDisplay();
}
--- 223,228 ----
public void clear()
{
! setKey(selected == null ? new RocketPassage() : selected.createEmptyKeyList());
! setTitle(CLEAR);
}
***************
*** 263,268 ****
public void doPassageAction()
{
! setTitle(txtKey.getText());
! updateDisplay();
}
--- 264,273 ----
public void doPassageAction()
{
! setKey(txtKey.getText());
! if (!key.isEmpty())
! {
! txtSearch.setText(""); //$NON-NLS-1$
! setTitle(PASSAGE);
! }
}
***************
*** 272,277 ****
public void doSearchAction()
{
! Book book = mdlBible.getSelectedBook();
! if (book == null)
{
noBookInstalled();
--- 277,281 ----
public void doSearchAction()
{
! if (selected == null)
{
noBookInstalled();
***************
*** 282,287 ****
{
String param = txtSearch.getText();
! if (chkMatch.isSelected())
{
String quote = IndexSearcher.getPreferredSyntax(PhraseParamWord.class);
--- 286,298 ----
{
String param = txtSearch.getText();
+ if (param == null || param.length() == 0)
+ {
+ return;
+ }
! // We may want to do ranking for more than just
! // "match"
! boolean rank = chkMatch.isSelected();
! if (rank)
{
String quote = IndexSearcher.getPreferredSyntax(PhraseParamWord.class);
***************
*** 289,315 ****
}
! Key key = book.find(param);
// we get PassageTallys for best match searches
! if (key instanceof PassageTally)
{
! if (chkMatch.isSelected())
! {
! PassageTally tally = (PassageTally) key;
! tally.setOrdering(PassageTally.ORDER_TALLY);
! // TODO: Make the number of ranges in a tally be an option.
! tally.trimRanges(20, RestrictionType.NONE);
! }
! else
! {
! // If match is not selected then show the entire result
! Key newKey = book.createEmptyKeyList();
! newKey.addAll(key);
! }
}
! txtKey.setText(key.getName());
! setTitle(param);
! updateDisplay();
}
catch (Exception ex)
--- 300,325 ----
}
! DefaultSearchModifier modifier = new DefaultSearchModifier();
! modifier.setRanked(rank);
!
! Key results = selected.find(new DefaultSearchRequest(param, modifier));
// we get PassageTallys for best match searches
! if (results instanceof PassageTally || rank)
{
! PassageTally tally = (PassageTally) results;
! tally.setOrdering(PassageTally.ORDER_TALLY);
! tally.trimRanges(getNumRankedVerses(), RestrictionType.NONE);
}
! if (results.isEmpty())
! {
! Reporter.informUser(this, Msg.NO_HITS, new Object[] { param });
! }
! else
! {
! setTitle(SEARCH);
! setKey(results);
! }
}
catch (Exception ex)
***************
*** 369,374 ****
private void updateDisplay()
{
! Book book = mdlBible.getSelectedBook();
! if (book == null)
{
noBookInstalled();
--- 379,383 ----
private void updateDisplay()
{
! if (selected == null)
{
noBookInstalled();
***************
*** 376,401 ****
}
! try
! {
! Key key = book.getKey(txtKey.getText());
! fireCommandMade(new DisplaySelectEvent(this, key, book));
}
! catch (NoSuchVerseException ex)
{
! JOptionPane.showMessageDialog(this, ex.getMessage(), Msg.BAD_VERSE.toString(), JOptionPane.ERROR_MESSAGE);
}
! catch (Exception ex)
{
! Reporter.informUser(this, ex);
}
}
! /**
! * Accessor for the default name
! */
! public String getTitle()
{
! return title;
}
--- 385,443 ----
}
! fireCommandMade(new DisplaySelectEvent(this, key, selected));
! }
! /**
! * Accessor for the default name
! */
! public String getTitle()
! {
! return title;
! }
!
! public void setKey(String newKey)
! {
! if (selected == null)
! {
! noBookInstalled();
! return;
}
!
! try
{
! setKey(selected.getKey(newKey));
}
! catch (NoSuchKeyException e)
{
! Reporter.informUser(this, e);
}
}
! public void setKey(Key newKey)
{
! if (newKey == null || newKey.isEmpty())
! {
! if (!key.isEmpty())
! {
! key = selected.createEmptyKeyList();
! txtKey.setText(""); //$NON-NLS-1$
! txtSearch.setText(""); //$NON-NLS-1$
!
! updateDisplay();
! setTitle(CLEAR);
! }
! }
! else if (!newKey.equals(key))
! {
! key = newKey;
! String text = key.getName();
! txtKey.setText(text);
! updateDisplay();
! if (isClear())
! {
! setTitle(PASSAGE);
! txtSearch.setText(""); //$NON-NLS-1$
! }
! }
}
***************
*** 403,423 ****
* Sets the default name
*/
! public void setTitle(String title)
{
! this.title = title;
}
/**
! * Sets the default name
*/
! public void setText(String text)
{
! String currentText = txtKey.getText();
! if (!currentText.equals(text))
! {
! txtKey.setText(text);
! setTitle(text);
! updateDisplay();
! }
}
--- 445,481 ----
* Sets the default name
*/
! // public void setTitle(String title)
! // {
! // this.title = title;
! // }
!
! // /**
! // * Sets the default name
! // */
! // public void setText(String text)
! // {
! // String currentText = txtKey.getText();
! // if (!currentText.equals(text))
! // {
! // txtKey.setText(text);
! // setTitle(text);
! // updateDisplay();
! // }
! // }
! //
! /**
! * @return Returns the numRankedVerses.
! */
! public static int getNumRankedVerses()
{
! return numRankedVerses;
}
/**
! * @param newNumRankedVerses The numRankedVerses to set.
*/
! public static void setNumRankedVerses(int newNumRankedVerses)
{
! numRankedVerses = newNumRankedVerses;
}
***************
*** 445,457 ****
}
! try
! {
! Key key = selected.getKey(txtKey.getText());
! fireVersionChanged(new DisplaySelectEvent(this, key, selected));
}
! catch (Exception ex)
{
! Reporter.informUser(this, ex);
}
}
--- 503,533 ----
}
! fireVersionChanged(new DisplaySelectEvent(this, key, selected));
! }
! private void setTitle(int newMode)
! {
! mode = newMode;
! switch (mode)
! {
! case CLEAR:
! title = Msg.UNTITLED.toString(new Integer(base++));
! break;
! case PASSAGE:
! title = key.getName();
! break;
! case SEARCH:
! title = txtSearch.getText();
! break;
! default:
! assert false;
}
! if (title.length() == 0)
{
! setTitle(CLEAR);
! }
! else
! {
! fireTitleChanged(new TitleChangedEvent(this, title));
}
}
***************
*** 523,562 ****
public void keyChanged(KeyChangeEvent ev)
{
! String text = ev.getKey().getName();
! setText(text);
}
/**
! * Add a command listener
*/
! public synchronized void addCommandListener(DisplaySelectListener li)
{
! List temp = new ArrayList(2);
! if (listeners != null)
! {
! temp.addAll(listeners);
! }
! if (!temp.contains(li))
{
! temp.add(li);
! listeners = temp;
}
}
/**
! * Remove a command listener
*/
! public synchronized void removeCommandListener(DisplaySelectListener li)
{
! if (listeners != null && listeners.contains(li))
! {
! List temp = new ArrayList();
! temp.addAll(listeners);
! temp.remove(li);
! listeners = temp;
! }
}
--- 599,655 ----
public void keyChanged(KeyChangeEvent ev)
{
! setKey(ev.getKey());
}
/**
! * Add a TitleChangedEvent listener
*/
! public synchronized void addTitleChangedListener(TitleChangedListener li)
{
! listeners.add(TitleChangedListener.class, li);
! }
! /**
! * Remove a TitleChangedEvent listener
! */
! public synchronized void removeTitleChangedListener(TitleChangedListener li)
! {
! listeners.remove(TitleChangedListener.class, li);
! }
! /**
! * Listen for changes to the title
! * @param ev the event to throw
! */
! protected void fireTitleChanged(TitleChangedEvent ev)
! {
! // Guaranteed to return a non-null array
! Object[] contents = listeners.getListenerList();
!
! // Process the listeners last to first, notifying
! // those that are interested in this event
! for (int i = contents.length - 2; i >= 0; i -= 2)
{
! if (contents[i] == TitleChangedListener.class)
! {
! ((TitleChangedListener) contents[i + 1]).titleChanged(ev);
! }
}
}
/**
! * Add a DisplaySelectEvent listener
*/
! public synchronized void addCommandListener(DisplaySelectListener li)
{
! listeners.add(DisplaySelectListener.class, li);
! }
! /**
! * Remove a DisplaySelectEvent listener
! */
! public synchronized void removeCommandListener(DisplaySelectListener li)
! {
! listeners.remove(DisplaySelectListener.class, li);
}
***************
*** 566,575 ****
protected void fireCommandMade(DisplaySelectEvent ev)
{
! if (listeners != null)
{
! for (int i = 0; i < listeners.size(); i++)
{
! DisplaySelectListener li = (DisplaySelectListener) listeners.get(i);
! li.passageSelected(ev);
}
}
--- 659,672 ----
protected void fireCommandMade(DisplaySelectEvent ev)
{
! // Guaranteed to return a non-null array
! Object[] contents = listeners.getListenerList();
!
! // Process the listeners last to first, notifying
! // those that are interested in this event
! for (int i = contents.length - 2; i >= 0; i -= 2)
{
! if (contents[i] == DisplaySelectListener.class)
{
! ((DisplaySelectListener) contents[i + 1]).passageSelected(ev);
}
}
***************
*** 581,590 ****
protected void fireVersionChanged(DisplaySelectEvent ev)
{
! if (listeners != null)
{
! int count = listeners.size();
! for (int i = 0; i < count; i++)
{
! ((DisplaySelectListener) listeners.get(i)).bookChosen(ev);
}
}
--- 678,691 ----
protected void fireVersionChanged(DisplaySelectEvent ev)
{
! // Guaranteed to return a non-null array
! Object[] contents = listeners.getListenerList();
!
! // Process the listeners last to first, notifying
! // those that are interested in this event
! for (int i = contents.length - 2; i >= 0; i -= 2)
{
! if (contents[i] == DisplaySelectListener.class)
{
! ((DisplaySelectListener) contents[i + 1]).bookChosen(ev);
}
}
***************
*** 613,618 ****
private String title;
- private transient List listeners;
-
private QuickHelpDialog dlgHelp;
--- 714,717 ----
***************
*** 637,640 ****
--- 736,762 ----
/**
+ * The current state of the display: SEARCH, PASSAGE, CLEAR
+ */
+ private int mode;
+ private static final int CLEAR = 0;
+ private static final int PASSAGE = 1;
+ private static final int SEARCH = 2;
+
+ /**
+ * The current passage.
+ */
+ private Key key;
+
+ /**
+ * Who is interested in things this DisplaySelectPane does
+ */
+ private EventListenerList listeners;
+
+ /**
+ * How may hits to show when the search results are ranked.
+ */
+ private static int numRankedVerses = 20;
+
+ /**
* Serialization ID
*/
Index: BibleViewPane.java
===================================================================
RCS file: /cvs/jsword/bibledesktop/java/main/org/crosswire/bibledesktop/book/BibleViewPane.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** BibleViewPane.java 24 Jan 2005 23:24:19 -0000 1.12
--- BibleViewPane.java 1 Apr 2005 17:10:14 -0000 1.13
***************
*** 8,17 ****
import java.io.Reader;
import java.io.Writer;
- import java.util.ArrayList;
- import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;
--- 8,16 ----
import java.io.Reader;
import java.io.Writer;
import javax.swing.BorderFactory;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
+ import javax.swing.event.EventListenerList;
import javax.swing.filechooser.FileFilter;
***************
*** 56,60 ****
* @version $Id$
*/
! public class BibleViewPane extends JPanel implements Titleable, Clearable
{
/**
--- 55,59 ----
* @version $Id$
*/
! public class BibleViewPane extends JPanel implements Titleable, Clearable, TitleChangedListener
{
/**
***************
*** 63,66 ****
--- 62,66 ----
public BibleViewPane()
{
+ listeners = new EventListenerList();
pnlSelect = new DisplaySelectPane();
KeySidebar sidebar = new KeySidebar(pnlSelect.getBook());
***************
*** 69,72 ****
--- 69,73 ----
sidebar.addKeyChangeListener(pnlSelect);
pnlSelect.addCommandListener(sidebar);
+ pnlSelect.addTitleChangedListener(this);
pnlPassg.addKeyChangeListener(sidebar);
init();
***************
*** 271,280 ****
public void setKey(Key key)
{
- pnlSelect.setTitle(key.getName());
pnlPassg.setBookData(pnlSelect.getBook(), key);
! if (saved == null)
! {
! fireTitleChanged(new TitleChangedEvent(BibleViewPane.this, getTitle()));
! }
}
--- 272,280 ----
public void setKey(Key key)
{
pnlPassg.setBookData(pnlSelect.getBook(), key);
! // if (saved == null)
! // {
! // fireTitleChanged(new TitleChangedEvent(BibleViewPane.this, getTitle()));
! // }
}
***************
*** 295,369 ****
}
- // /**
- // * Add a listener when someone clicks on a browser 'link'
- // */
- // public void addHyperlinkListener(HyperlinkListener li)
- // {
- // pnlPassg.addHyperlinkListener(li);
- // }
- //
- // /**
- // * Remove a listener when someone clicks on a browser 'link'
- // */
- // public void removeHyperlinkListener(HyperlinkListener li)
- // {
- // pnlPassg.removeHyperlinkListener(li);
- // }
-
/**
! * Add a listener to the list
*/
public synchronized void addTitleChangedListener(TitleChangedListener li)
{
! List temp = new ArrayList();
! if (listeners == null)
! {
! temp.add(li);
! listeners = temp;
! }
! else
! {
! temp.addAll(listeners);
!
! if (!temp.contains(li))
! {
! temp.add(li);
! listeners = temp;
! }
! }
}
/**
! * Remove a listener from the list
*/
public synchronized void removeTitleChangedListener(TitleChangedListener li)
{
! if (listeners != null && listeners.contains(li))
! {
! List temp = new ArrayList();
! temp.addAll(listeners);
! temp.remove(li);
! listeners = temp;
! }
}
/**
! * Inform the listeners that a title has changed
*/
protected void fireTitleChanged(TitleChangedEvent ev)
{
! if (listeners != null)
{
! List temp = listeners;
! int count = temp.size();
! for (int i = 0; i < count; i++)
{
! ((TitleChangedListener) temp.get(i)).titleChanged(ev);
}
}
}
protected File saved;
! private transient List listeners;
private DisplaySelectPane pnlSelect;
protected SplitBookDataDisplay pnlPassg;
--- 295,347 ----
}
/**
! * Add a TitleChangedEvent listener
*/
public synchronized void addTitleChangedListener(TitleChangedListener li)
{
! listeners.add(TitleChangedListener.class, li);
}
/**
! * Remove a TitleChangedEvent listener
*/
public synchronized void removeTitleChangedListener(TitleChangedListener li)
{
! listeners.remove(TitleChangedListener.class, li);
}
/**
! * Listen for changes to the title
! * @param ev the event to throw
*/
protected void fireTitleChanged(TitleChangedEvent ev)
{
! // Guaranteed to return a non-null array
! Object[] contents = listeners.getListenerList();
!
! // Process the listeners last to first, notifying
! // those that are interested in this event
! for (int i = contents.length - 2; i >= 0; i -= 2)
{
! if (contents[i] == TitleChangedListener.class)
{
! ((TitleChangedListener) contents[i + 1]).titleChanged(ev);
}
}
}
+ /* (non-Javadoc)
+ * @see org.crosswire.common.swing.desktop.event.TitleChangedListener#titleChanged(org.crosswire.common.swing.desktop.event.TitleChangedEvent)
+ */
+ public void titleChanged(TitleChangedEvent ev)
+ {
+ if (saved == null)
+ {
+ fireTitleChanged(new TitleChangedEvent(BibleViewPane.this, getTitle()));
+ }
+ }
+
protected File saved;
! private transient EventListenerList listeners;
private DisplaySelectPane pnlSelect;
protected SplitBookDataDisplay pnlPassg;
Index: Msg.properties
===================================================================
RCS file: /cvs/jsword/bibledesktop/java/main/org/crosswire/bibledesktop/book/Msg.properties,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** Msg.properties 15 Feb 2005 02:08:59 -0000 1.12
--- Msg.properties 1 Apr 2005 17:10:14 -0000 1.13
***************
*** 24,27 ****
--- 24,28 ----
DisplaySelectPane.Clear=Untitled
DisplaySelectPane.Untitled=Untitled {0}
+ DisplaySelectPane.NoHits=Could not find verses with: {0}
DisplaySelectPane.HelpTitle=Search Quick Help
DisplaySelectPane.HelpText=<html><b>Search Tips.</b><br\>\
Index: AdvancedSearchPane.java
===================================================================
RCS file: /cvs/jsword/bibledesktop/java/main/org/crosswire/bibledesktop/book/AdvancedSearchPane.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** AdvancedSearchPane.java 6 Mar 2005 20:21:36 -0000 1.3
--- AdvancedSearchPane.java 1 Apr 2005 17:10:14 -0000 1.4
***************
*** 33,38 ****
import org.crosswire.common.swing.ActionFactory;
import org.crosswire.common.swing.GuiUtil;
- import org.crosswire.common.swing.LookAndFeelUtil;
- import org.crosswire.common.util.Logger;
import org.crosswire.common.util.StringUtil;
import org.crosswire.jsword.book.search.parse.IndexSearcher;
--- 33,36 ----
***************
*** 512,526 ****
}
! /**
! * Quick test method
! */
! public static void main(String[] args)
! {
! LookAndFeelUtil.initialize();
! AdvancedSearchPane adv = new AdvancedSearchPane();
! String reply = adv.showInDialog(null, "Advanced Search", true, "test"); //$NON-NLS-1$ //$NON-NLS-2$
! log.debug(reply);
! System.exit(0);
! }
/*
--- 510,525 ----
}
! // /**
! // * Temporary driver.
! // * @param args The command line arguments
! // */
! // public static void main(String[] args)
! // {
! // LookAndFeelUtil.initialize();
! // AdvancedSearchPane adv = new AdvancedSearchPane();
! // String reply = adv.showInDialog(null, "Advanced Search", true, "test"); //$NON-NLS-1$ //$NON-NLS-2$
! // log.debug(reply);
! // System.exit(0);
! // }
/*
***************
*** 615,622 ****
private JScrollPane scrSummary;
! /**
! * The log stream
! */
! private static final Logger log = Logger.getLogger(AdvancedSearchPane.class);
/**
--- 614,621 ----
private JScrollPane scrSummary;
! // /**
! // * The log stream
! // */
! // private static final Logger log = Logger.getLogger(AdvancedSearchPane.class);
/**
Index: Msg.java
===================================================================
RCS file: /cvs/jsword/bibledesktop/java/main/org/crosswire/bibledesktop/book/Msg.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** Msg.java 15 Feb 2005 02:08:59 -0000 1.14
--- Msg.java 1 Apr 2005 17:10:14 -0000 1.15
***************
*** 48,51 ****
--- 48,52 ----
static final Msg CLEAR = new Msg("DisplaySelectPane.Clear"); //$NON-NLS-1$
static final Msg UNTITLED = new Msg("DisplaySelectPane.Untitled"); //$NON-NLS-1$
+ static final Msg NO_HITS = new Msg("DisplaySelectPane.NoHits"); //$NON-NLS-1$
static final Msg ADVANCED_TITLE = new Msg("DisplaySelectPane.AdvancedTitle"); //$NON-NLS-1$
static final Msg HELP_TEXT = new Msg("DisplaySelectPane.HelpText"); //$NON-NLS-1$
More information about the jsword-svn
mailing list