[jsword-svn] r1350 - in trunk: bibledesktop/src/main/java/org/crosswire/bibledesktop/book common/src/main/java/org/crosswire/common/diff common-swing/src/main/java/org/crosswire/common/config/swing jsword/src/main/java/org/crosswire/jsword/book jsword/src/main/java/org/crosswire/jsword/book/basic
dmsmith at www.crosswire.org
dmsmith at www.crosswire.org
Fri May 25 08:31:58 MST 2007
Author: dmsmith
Date: 2007-05-25 08:31:57 -0700 (Fri, 25 May 2007)
New Revision: 1350
Added:
trunk/common/src/main/java/org/crosswire/common/diff/Distance.java
trunk/jsword/src/main/java/org/crosswire/jsword/book/BookComparators.java
Modified:
trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksComboBoxModel.java
trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksListModel.java
trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/DisplaySelectPane.java
trunk/common-swing/src/main/java/org/crosswire/common/config/swing/OptionsField.java
trunk/jsword/src/main/java/org/crosswire/jsword/book/Book.java
trunk/jsword/src/main/java/org/crosswire/jsword/book/DefaultBook.java
trunk/jsword/src/main/java/org/crosswire/jsword/book/basic/AbstractBook.java
Log:
Added the ability to find the edit distance between two strings.
Added the ability to find a book by an inexact match.
Added the ability to sort a book list in different ways.
Modified: trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksComboBoxModel.java
===================================================================
--- trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksComboBoxModel.java 2007-05-24 21:01:53 UTC (rev 1349)
+++ trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksComboBoxModel.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -23,6 +23,7 @@
import java.io.IOException;
import java.io.ObjectInputStream;
+import java.util.Comparator;
import javax.swing.ComboBoxModel;
@@ -45,7 +46,7 @@
*/
public BooksComboBoxModel()
{
- this(null);
+ this(null, null);
}
/**
@@ -53,7 +54,14 @@
*/
public BooksComboBoxModel(BookFilter filter)
{
- super(filter);
+ this(filter, null);
+ }
+ /**
+ * Basic Constructor
+ */
+ public BooksComboBoxModel(BookFilter filter, Comparator comparator)
+ {
+ super(filter, comparator);
postCacheData();
Modified: trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksListModel.java
===================================================================
--- trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksListModel.java 2007-05-24 21:01:53 UTC (rev 1349)
+++ trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/BooksListModel.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -25,6 +25,7 @@
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import javax.swing.AbstractListModel;
@@ -55,7 +56,7 @@
*/
public BooksListModel()
{
- this(null);
+ this(null, null);
}
/**
@@ -63,16 +64,25 @@
*/
public BooksListModel(BookFilter filter)
{
- this(filter, Books.installed());
+ this(filter, Books.installed(), null);
}
/**
- * Basic constructor
+ * Basic constructor, redefining ordering.
*/
- public BooksListModel(BookFilter filter, BookList bookList)
+ public BooksListModel(BookFilter filter, Comparator comp)
{
+ this(filter, Books.installed(), comp);
+ }
+
+ /**
+ * Basic constructor for a filtered list of books, ordered as requested.
+ */
+ public BooksListModel(BookFilter filter, BookList bookList, Comparator comparator)
+ {
this.filter = filter;
this.bookList = bookList;
+ this.comparator = comparator;
cacheData();
}
@@ -159,7 +169,7 @@
{
books = new ArrayList();
books.addAll(bookList.getBooks(filter));
- Collections.sort(books);
+ Collections.sort(books, comparator);
}
/**
@@ -239,6 +249,11 @@
protected List books;
/**
+ * The sort algorithm to use.
+ */
+ protected Comparator comparator;
+
+ /**
* The log stream
*/
private static final Logger log = Logger.getLogger(BooksListModel.class);
Modified: trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/DisplaySelectPane.java
===================================================================
--- trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/DisplaySelectPane.java 2007-05-24 21:01:53 UTC (rev 1349)
+++ trunk/bibledesktop/src/main/java/org/crosswire/bibledesktop/book/DisplaySelectPane.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -54,6 +54,7 @@
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.BookComparators;
import org.crosswire.jsword.book.BookException;
import org.crosswire.jsword.book.BookFilters;
import org.crosswire.jsword.index.IndexStatus;
@@ -106,7 +107,7 @@
};
// search() and version() rely on this returning only Books indexed by verses
- mdlBible = new BooksComboBoxModel(BookFilters.getBibles());
+ mdlBible = new BooksComboBoxModel(BookFilters.getBibles(), BookComparators.getInitialComparator());
JComboBox cboBible = new JComboBox(mdlBible);
cboBible.setPrototypeDisplayValue(" "); //$NON-NLS-1$
selected = mdlBible.getSelectedBook();
Added: trunk/common/src/main/java/org/crosswire/common/diff/Distance.java
===================================================================
--- trunk/common/src/main/java/org/crosswire/common/diff/Distance.java (rev 0)
+++ trunk/common/src/main/java/org/crosswire/common/diff/Distance.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -0,0 +1,116 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. 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.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2007
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: org.eclipse.jdt.ui.prefs 1178 2006-11-06 12:48:02Z dmsmith $
+ */
+
+package org.crosswire.common.diff;
+
+/**
+ * Compute the distance between 2 strings. The larger the number the greater the distance.
+ *
+ * @see gnu.lgpl.License for license details.<br>
+ * The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public class Distance
+{
+ /**
+ * Compute the LevenshteinDistance between two strings.
+ * See <a href="http://www.merriampark.com/ldjava.htm">www.merriampark.com/ldjava.htm</a> for original implementation.
+ * @param source the baseline text
+ * @param target the changed text
+ * @return the distance
+ */
+ public static int getLevenshteinDistance (String source, String target)
+ {
+ if (source == null || target == null)
+ {
+ throw new IllegalArgumentException("Strings must not be null"); //$NON-NLS-1$
+ }
+
+ /*
+ The difference between this impl. and the previous is that, rather
+ than creating and retaining a matrix of size s.length()+1 by t.length()+1,
+ we maintain two single-dimensional arrays of length s.length()+1. The first, d,
+ is the 'current working' distance array that maintains the newest distance cost
+ counts as we iterate through the characters of String s. Each time we increment
+ the index of String t we are comparing, d is copied to p, the second int[]. Doing so
+ allows us to retain the previous cost counts as required by the algorithm (taking
+ the minimum of the cost count to the left, up one, and diagonally up and to the left
+ of the current cost count being calculated). (Note that the arrays aren't really
+ copied anymore, just switched...this is clearly much better than cloning an array
+ or doing a System.arraycopy() each time through the outer loop.)
+
+ Effectively, the difference between the two implementations is this one does not
+ cause an out of memory condition when calculating the LD over two very large strings.
+ */
+
+ int sourceLength = source.length(); // length of source
+ int targetLength = target.length(); // length of target
+
+ if (sourceLength == 0)
+ {
+ return targetLength;
+ }
+ else if (targetLength == 0)
+ {
+ return sourceLength;
+ }
+
+ int prevDist[] = new int[sourceLength + 1]; //'previous' cost array, horizontally
+ int dist[] = new int[sourceLength + 1]; // cost array, horizontally
+ int swap[]; //placeholder to assist in swapping prevDist and dist
+
+ // indexes into strings source and target
+ int i; // iterates through source
+ int j; // iterates through target
+
+ char targetJ; // jth character of t
+
+ int cost;
+
+ for (i = 0; i <= sourceLength; i++)
+ {
+ prevDist[i] = i;
+ }
+
+ for (j = 1; j <= targetLength; j++)
+ {
+ targetJ = target.charAt(j - 1);
+ dist[0] = j;
+
+ for (i = 1; i <= sourceLength; i++)
+ {
+ cost = source.charAt(i - 1) == targetJ ? 0 : 1;
+ // minimum of cell to the left + 1, to the top + 1, diagonally left and up +cost
+ dist[i] = Math.min(Math.min(dist[i - 1] + 1, prevDist[i] + 1), prevDist[i - 1] + cost);
+ }
+
+ // copy current distance counts to 'previous row' distance counts
+ swap = prevDist;
+ prevDist = dist;
+ dist = swap;
+ }
+
+ // our last action in the above loop was to switch d and p, so p now
+ // actually has the most recent cost counts
+ return prevDist[sourceLength];
+ }
+}
Property changes on: trunk/common/src/main/java/org/crosswire/common/diff/Distance.java
___________________________________________________________________
Name: svn:kewords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Modified: trunk/common-swing/src/main/java/org/crosswire/common/config/swing/OptionsField.java
===================================================================
--- trunk/common-swing/src/main/java/org/crosswire/common/config/swing/OptionsField.java 2007-05-24 21:01:53 UTC (rev 1349)
+++ trunk/common-swing/src/main/java/org/crosswire/common/config/swing/OptionsField.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -29,6 +29,7 @@
import org.crosswire.common.config.Choice;
import org.crosswire.common.config.MultipleChoice;
+import org.crosswire.common.diff.Distance;
import org.crosswire.common.util.Logger;
/**
@@ -103,6 +104,7 @@
{
if (list != null && list.length > 0)
{
+ int distance = value.length();
for (int i = 0; i < list.length; i++)
{
if (value.equals(list[i]))
@@ -110,9 +112,28 @@
combo.setSelectedItem(list[i]);
return;
}
+ distance = Math.max(distance, list[i].length());
}
- combo.setSelectedItem(list[0]);
+ // We didn't find an exact match so look for the closest one.
+ distance++; // A number larger than the length of any of the strings in question.
+ int bestMatch = 0;
+ for (int i = 0; i < list.length; i++)
+ {
+ int newDistance = Distance.getLevenshteinDistance(value, list[i]);
+ if (distance > newDistance)
+ {
+ bestMatch = i;
+ distance = newDistance;
+ }
+ }
+
+ combo.setSelectedItem(list[bestMatch]);
+ if (bestMatch > 0)
+ {
+ log.warn("Checked for options without finding exact match: '" + value + "'. Best match is: " + combo.getSelectedItem()); //$NON-NLS-1$//$NON-NLS-2$
+ return;
+ }
}
log.warn("Checked for options without finding: '" + value + "'. Defaulting to first option: " + combo.getSelectedItem()); //$NON-NLS-1$//$NON-NLS-2$
Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/Book.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/Book.java 2007-05-24 21:01:53 UTC (rev 1349)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/Book.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -185,6 +185,15 @@
String getFullName();
/**
+ * Return the likelihood that we have a match.
+ * This allows for calling the book different things
+ * and still be found.
+ * @param name
+ * @return true if we have a match.
+ */
+ boolean match(String name);
+
+ /**
* Indicate whether this book is supported by JSword.
* Since the expectation is that all books are supported,
* abstract implementations should return true and let
Added: trunk/jsword/src/main/java/org/crosswire/jsword/book/BookComparators.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/BookComparators.java (rev 0)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/BookComparators.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -0,0 +1,79 @@
+/**
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. 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.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2005
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id$
+ */
+package org.crosswire.jsword.book;
+
+import java.util.Comparator;
+
+import org.crosswire.common.util.Logger;
+
+/**
+ * Provides different ways to sort Books.
+ *
+ * @see gnu.lgpl.License for license details.
+ * The copyright to this program is held by it's authors.
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ */
+public final class BookComparators
+{
+ /**
+ * Ensure we cant be created
+ */
+ private BookComparators()
+ {
+ }
+
+ /**
+ * Order by default Book ordering
+ */
+ public static Comparator getDefault()
+ {
+ return new Comparator()
+ {
+ public int compare(Object o1, Object o2)
+ {
+ return ((Book)o1).compareTo(o2);
+ }
+
+ };
+ }
+
+ /**
+ * Order by Initials.
+ */
+ public static Comparator getInitialComparator()
+ {
+ return new Comparator()
+ {
+ public int compare(Object o1, Object o2)
+ {
+ Book b1 = (Book) o1;
+ Book b2 = (Book) o2;
+ return b1.getInitials().compareTo(b2.getInitials());
+ }
+ };
+ }
+
+ /**
+ * The log stream
+ */
+ static final Logger log = Logger.getLogger(BookComparators.class);
+}
Property changes on: trunk/jsword/src/main/java/org/crosswire/jsword/book/BookComparators.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/DefaultBook.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/DefaultBook.java 2007-05-24 21:01:53 UTC (rev 1349)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/DefaultBook.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -135,7 +135,7 @@
while (iter.hasNext())
{
Book aBook = (Book) iter.next();
- if (name.equals(aBook.getFullName()))
+ if (aBook.match(name))
{
setDefault(aBook);
return;
Modified: trunk/jsword/src/main/java/org/crosswire/jsword/book/basic/AbstractBook.java
===================================================================
--- trunk/jsword/src/main/java/org/crosswire/jsword/book/basic/AbstractBook.java 2007-05-24 21:01:53 UTC (rev 1349)
+++ trunk/jsword/src/main/java/org/crosswire/jsword/book/basic/AbstractBook.java 2007-05-25 15:31:57 UTC (rev 1350)
@@ -149,6 +149,66 @@
}
/* (non-Javadoc)
+ * @see org.crosswire.jsword.book.Book#match(java.lang.String)
+ */
+ public boolean match(String name)
+ {
+ if (name == null)
+ {
+ return false;
+ }
+ if (name.equals(getInitials()))
+ {
+ return true;
+ }
+ if (name.equals(getName()))
+ {
+ return true;
+ }
+ if (name.equals(getFullName()))
+ {
+ return true;
+ }
+ if (name.equals(toString()))
+ {
+ return true;
+ }
+ if (name.equalsIgnoreCase(getInitials()))
+ {
+ return true;
+ }
+ if (name.equalsIgnoreCase(getName()))
+ {
+ return true;
+ }
+ if (name.equalsIgnoreCase(getFullName()))
+ {
+ return true;
+ }
+ if (name.equalsIgnoreCase(toString()))
+ {
+ return true;
+ }
+ if (name.startsWith(getInitials()))
+ {
+ return true;
+ }
+ if (name.startsWith(getName()))
+ {
+ return true;
+ }
+ if (name.startsWith(getFullName()))
+ {
+ return true;
+ }
+ if (name.startsWith(toString()))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
* @see org.crosswire.jsword.book.BookMetaData#getIndexStatus()
*/
public IndexStatus getIndexStatus()
More information about the jsword-svn
mailing list