[sword-cvs] r46 - in trunk/app/src/org/crosswire/common: . swing
util
Apache
apache at crosswire.org
Sun Sep 19 05:32:10 MST 2004
Author:
Date: 2004-09-19 05:32:10 -0700 (Sun, 19 Sep 2004)
New Revision: 46
Added:
trunk/app/src/org/crosswire/common/swing/RowColumns.java
trunk/app/src/org/crosswire/common/swing/RowTable.java
trunk/app/src/org/crosswire/common/swing/RowTableModel.java
trunk/app/src/org/crosswire/common/swing/SortRenderer.java
trunk/app/src/org/crosswire/common/util/
trunk/app/src/org/crosswire/common/util/CWClassLoader.java
trunk/app/src/org/crosswire/common/util/CallContext.java
trunk/app/src/org/crosswire/common/util/CallContext.jbx
trunk/app/src/org/crosswire/common/util/ResourceUtil.java
trunk/app/src/org/crosswire/common/util/RowProcessor.java
trunk/app/src/org/crosswire/common/util/TabbedFileReader.java
Removed:
trunk/app/src/org/crosswire/common/CWClassLoader.java
trunk/app/src/org/crosswire/common/CallContext.java
trunk/app/src/org/crosswire/common/CallContext.jbx
trunk/app/src/org/crosswire/common/ResourceUtil.java
Log:
added more utility classes
Deleted: trunk/app/src/org/crosswire/common/CWClassLoader.java
===================================================================
--- trunk/app/src/org/crosswire/common/CWClassLoader.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/CWClassLoader.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -1,377 +0,0 @@
-package org.crosswire.common;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * CWClassLoader extends the regular class loader by using looking
- * in more places. This is needed so that ResourceBundle can find
- * resources that are not held in the same package as the class.
- *
- * <p><table border='1' cellPadding='3' cellSpacing='0'>
- * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
- *
- * Distribution Licence:<br />
- * JSword is free software; you can redistribute it
- * and/or modify it under the terms of the GNU General Public License,
- * version 2 as published by the Free Software Foundation.<br />
- * 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
- * General Public License for more details.<br />
- * The License is available on the internet
- * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA<br />
- * The copyright to this program is held by it's authors.
- * </font></td></tr></table>
- * @see gnu.gpl.Licence
- * @author DM Smith [dmsmith555 at yahoo dot com]
- * @version $Id: CWClassLoader.java,v 1.4 2004/08/16 22:07:35 joe Exp $
- */
-public class CWClassLoader extends ClassLoader
-{
- /**
- * Creates a class loader that finds resources
- * for the supplied class that may not be in the class' package.
- * You can use this within base classes by passing getClass()
- * to load resources for a derived class.
- * @param resourceOwner is the owner of the resource
- */
- public CWClassLoader(Class resourceOwner)
- {
- owner = resourceOwner;
- }
-
- /**
- * Creates a class loader that finds resources
- * for the calling class that may not be in the class' package.
- * Use this only within classes that are directly looking up their resources.
- */
- public CWClassLoader()
- {
- owner = CallContext.instance().getCallingClass();
- }
-
- /* (non-Javadoc)
- * @see java.lang.ClassLoader#findResource(java.lang.String)
- */
- public URL findResource(String search)
- {
- URL resource = null;
- if (search == null || search.length() == 0)
- {
- return resource;
- }
-
- // First look for it with an absolute path
- // This allows developer overrides
- if (search.charAt(0) != '/')
- {
- resource = findResource('/' + search);
- }
-
- if (resource == null)
- {
- // Look for it in the class's package.
- String newsearch = adjustPackageSearch(search);
- if (!search.equals(newsearch))
- {
- resource = findResource(newsearch);
- }
- }
-
- // Sometimes it comes in with '/' inside of it.
- // So look for it as a file with '.' in the name
- // This is the form that will find files in the resource.jar
- if (resource == null)
- {
- // Look for it in the class's package.
- String newsearch = adjustPathSearch(search);
- if (!search.equals(newsearch))
- {
- resource = findResource(newsearch);
- }
- }
-
- // See if it can be found in the home directory
- if (resource == null)
- {
- resource = CWClassLoader.findHomeResource(search);
- }
-
- // See if it can be found by its own class.
- if (resource == null)
- {
- resource = owner.getResource(search);
- }
-
- // Try the appropriate class loader
- if (resource == null)
- {
- resource = getClassLoader().getResource(search);
- }
-
- // Try the bootstrap and the system loader
- if (resource == null)
- {
- resource = ClassLoader.getSystemResource(search);
- }
-
- // For good measure let the super class try to find it.
- if (resource == null)
- {
- resource = super.findResource(search);
- }
-
- return resource;
- }
-
- /**
- * Prefix the search with a package prefix, if not already.
- * Skip a leading '/' if present.
- */
- private String adjustPackageSearch(String search)
- {
- // If it has embedded '/' there is nothing to do.
- if (search.indexOf('/', 1) == -1)
- {
- String className = owner.getName();
- String pkgPrefix = className.substring(0, className.lastIndexOf('.') + 1);
-
- if (search.charAt(0) == '/')
- {
- String part = search.substring(1);
- if (!part.startsWith(pkgPrefix))
- {
- search = '/' + pkgPrefix + part;
- }
- }
- else
- {
- if (!search.startsWith(pkgPrefix))
- {
- search = pkgPrefix + search;
- }
- }
- }
-
- return search;
- }
-
- /**
- * Change all but a leading '/' to '.'
- */
- private String adjustPathSearch(String search)
- {
- if (search.indexOf('/', 1) != -1)
- {
- // Change all but a leading '/' to '.'
- if (search.charAt(0) == '/')
- {
- search = '/' + search.substring(1).replace('/', '.');
- }
- else
- {
- search = search.replace('/', '.');
- }
- }
- return search;
- }
-
- /**
- *
- */
- public ClassLoader getClassLoader()
- {
- // Choose the child loader as it will use the parent if need be
- // If they are not related then choose the context loader
- ClassLoader loader = pickLoader(Thread.currentThread().getContextClassLoader(), owner.getClassLoader());
- return pickLoader(loader, ClassLoader.getSystemClassLoader());
- }
-
- /**
- * Returns 'true' if 'loader2' is a delegation child of 'loader1' [or if
- * 'loader1'=='loader2']. Of course, this works only for classloaders that
- * set their parent pointers correctly. 'null' is interpreted as the
- * primordial loader [i.e., everybody's parent].
- */
- private static ClassLoader pickLoader(final ClassLoader loader1, final ClassLoader loader2)
- {
- ClassLoader loader = loader2;
- if (loader1 != loader2)
- {
- loader = loader1;
- if (loader1 == null)
- {
- loader = loader2;
- }
- else
- {
- // Is loader2 a descendant of loader1?
- // It is if we can walk up to the top and find it.
- for (ClassLoader curloader = loader2; curloader != null; curloader = curloader.getParent())
- {
- if (curloader == loader1)
- {
- loader = loader2;
- break;
- }
- }
- }
- }
- return loader;
- }
-
- /**
- * If the application has set the home, it will return
- * the application's home directory, otherwise it returns null.
- * @return Returns the home.
- */
- public static synchronized URL getHome()
- {
- try
- {
- if (home != null)
- {
-
- return new URL(home.getProtocol(), home.getHost(), home.getPort(), home.getFile());
- }
- }
- catch (MalformedURLException e)
- {
- assert false;
- }
- return home;
- }
-
- /**
- * Establish the applications home directory from where
- * additional resources can be found. URL is expected to
- * end with the directory name, not '/'.
- * @param newhome The home to set.
- */
- public static synchronized void setHome(URL newhome)
- {
- home = newhome;
- }
-
- /**
- * Look for the resource in the home directory
- * @param search must be non-null, non-empty
- */
- public static URL findHomeResource(String search)
- {
- URL reply = null;
-
- URL override = getHomeResource(search);
-
- // Look at the application's home first to allow overrides
- if (override != null)
- {
- // Make sure the file exists and can be read
- File f = new File(override.getFile());
- if (f.canRead())
- {
- reply = override;
- }
- }
-
- return reply;
- }
-
- /**
- * Compute an URL for the resource in the home directory
- * @param search must be non-null, non-empty
- */
- public static URL getHomeResource(String search)
- {
- URL reply = null;
-
- URL homeURL = getHome();
-
- // Look at the application's home first to allow overrides
- if (homeURL != null)
- {
- reply = lengthenURL(homeURL, search);
- }
-
- return reply;
- }
-
- /**
- * Utility to add a string to the end of a URL.
- * @param orig The URL to strip
- * @param extra The text to add to the end of the URL
- * @return The stripped URL
- */
- public static URL lengthenURL(URL orig, String extra)
- {
- try
- {
- char firstChar = extra.charAt(extra.length() - 1);
- if (isSeparator(firstChar))
- {
- extra = extra.substring(1);
- }
-
- if (orig.getProtocol().equals(PROTOCOL_FILE))
- {
- String file = orig.toExternalForm();
- char lastChar = file.charAt(file.length() - 1);
- if (isSeparator(lastChar))
- {
- return new URL(orig.getProtocol(),
- orig.getHost(),
- orig.getPort(),
- orig.getFile() + extra);
- }
- else
- {
- return new URL(orig.getProtocol(),
- orig.getHost(),
- orig.getPort(),
- orig.getFile() + File.separator + extra);
- }
- }
- else
- {
- return new URL(orig.getProtocol(),
- orig.getHost(),
- orig.getPort(),
- orig.getFile() + SEPARATOR + extra);
- }
- }
- catch (MalformedURLException ex)
- {
- assert false : ex;
- return null;
- }
- }
-
- private static boolean isSeparator(char c)
- {
- return c == '/' || c == '\\';
- }
-
- /**
- * Constant for the file: protocol
- */
- public static final String PROTOCOL_FILE = "file"; //$NON-NLS-1$
-
- /**
- * URL separator
- */
- public static final String SEPARATOR = "/"; //$NON-NLS-1$
-
- /**
- * The class to which the resources belong
- */
- private Class owner;
-
- /**
- * Notion of a project's home from where additional resources can be found.
- */
- private static URL home = null;
-}
Deleted: trunk/app/src/org/crosswire/common/CallContext.java
===================================================================
--- trunk/app/src/org/crosswire/common/CallContext.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/CallContext.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -1,91 +0,0 @@
-package org.crosswire.common;
-
-/**
- * This singleton class provides a way for a method to determine
- * which class called it.
- * <p>
- * It has been tested to work in command line and WebStart environments.
- *
- * <p><table border='1' cellPadding='3' cellSpacing='0'>
- * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
- *
- * Distribution Licence:<br />
- * JSword is free software; you can redistribute it
- * and/or modify it under the terms of the GNU General Public License,
- * version 2 as published by the Free Software Foundation.<br />
- * 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
- * General Public License for more details.<br />
- * The License is available on the internet
- * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA<br />
- * The copyright to this program is held by it's authors.
- * </font></td></tr></table>
- * @see gnu.gpl.Licence
- * @author DM Smith [ dmsmith555 at yahoo dot com]
- * @version $Id: CallContext.java,v 1.1 2004/04/20 21:16:06 joe Exp $
- */
-public class CallContext extends SecurityManager
-{
- /**
- * Prevent instansiation
- */
- private CallContext()
- {
- }
-
- /**
- * Singleton accessor
- */
- public static CallContext instance()
- {
- if (resolver == null)
- {
- resolver = new CallContext();
- }
-
- return resolver;
- }
-
- /*
- * (non-Javadoc)
- * @see java.lang.SecurityManager#getClassContext()
- */
- protected Class[] getClassContext()
- {
- return super.getClassContext();
- }
-
- /**
- * When called from a method it will return the class
- * calling that method.
- */
- public Class getCallingClass()
- {
- return getCallingClass(1); // add 1 for this method
- }
-
- /**
- * When called from a method it will return the i-th class
- * calling that method, up the call chain.
- * If used with a -1 it will return the class making the call
- * -2 and -3 will return this class
- * @throws ArrayIndexOutOfBoundsException if the index is not valid
- */
- public Class getCallingClass(int i)
- {
- return resolver.getClassContext()[CALL_CONTEXT_OFFSET + i];
- }
-
- // may need to change if this class is redesigned
- /**
- * Offset needed to represent the caller of the method
- * that called this method.
- *
- */
- private static final int CALL_CONTEXT_OFFSET = 3;
-
- private static CallContext resolver;
-}
Deleted: trunk/app/src/org/crosswire/common/CallContext.jbx
===================================================================
--- trunk/app/src/org/crosswire/common/CallContext.jbx 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/CallContext.jbx 2004-09-19 12:32:10 UTC (rev 46)
@@ -1,8 +0,0 @@
-[PropertyInfo]
-callingClass,Class,false,false, , ,true,<default>
-resolver,CallContext,false,false, , ,false,<default>
-[IconNames]
-
-
-
-
Deleted: trunk/app/src/org/crosswire/common/ResourceUtil.java
===================================================================
--- trunk/app/src/org/crosswire/common/ResourceUtil.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/ResourceUtil.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -1,71 +0,0 @@
-package org.crosswire.common;
-
-import java.net.URL;
-import java.util.MissingResourceException;
-
-/**
- * Better implemenetations of the getResource methods with less ambiguity and
- * that are less dependent on the specific classloader situation.
- *
- * <p><table border='1' cellPadding='3' cellSpacing='0'>
- * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
- *
- * Distribution Licence:<br />
- * JSword is free software; you can redistribute it
- * and/or modify it under the terms of the GNU General Public License,
- * version 2 as published by the Free Software Foundation.<br />
- * 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
- * General Public License for more details.<br />
- * The License is available on the internet
- * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA<br />
- * The copyright to this program is held by it's authors.
- * </font></td></tr></table>
- * @see gnu.gpl.Licence
- * @author Joe Walker [joe at eireneh dot com]
- * @author DM Smith [ dmsmith555 at yahoo dot com ]
- * @version $Id: ResourceUtil.java,v 1.5 2004/08/16 22:07:35 joe Exp $
- */
-public class ResourceUtil
-{
- /**
- * Prevent Instansiation
- */
- private ResourceUtil()
- {
- }
-
- /**
- * Generic resource URL fetcher. One way or the other we'll find it!
- * Either as a relative or an absolute reference.
- * @param search The name of the resource (without a leading /) to find
- * @return The requested resource
- * @throws MissingResourceException if the resource can not be found
- */
- public static URL getResource(String search) throws MissingResourceException
- {
- return getResource(CallContext.instance().getCallingClass(), search);
- }
-
- /**
- * Generic resource URL fetcher. One way or the other we'll find it!
- * Either as a relative or an absolute reference.
- * @param clazz The resource to find
- * @return The requested resource
- * @throws MissingResourceException if the resource can not be found
- */
- public static URL getResource(Class clazz, String resourceName) throws MissingResourceException
- {
- URL resource = new CWClassLoader(clazz).findResource(resourceName);
-
- if (resource == null)
- {
- throw new MissingResourceException("Can't find resource", clazz.getName(), resourceName);
- }
-
- return resource;
- }
-}
Added: trunk/app/src/org/crosswire/common/swing/RowColumns.java
===================================================================
--- trunk/app/src/org/crosswire/common/swing/RowColumns.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/swing/RowColumns.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,175 @@
+/*
+ * Distribution Licence:
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 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 General Public License for more details.
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/gpl.html,
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * The copyright to this program is held by it's authors
+ * Copyright: 2004
+ */
+package org.crosswire.common.swing;
+
+import javax.swing.table.DefaultTableColumnModel;
+
+/**
+ * Defines the prototypes needed to display a RowTable.
+ * Also defines some column indexed concrete methods to access
+ * the prototypes.
+ *
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ */
+public abstract class RowColumns extends DefaultTableColumnModel
+{
+
+ /**
+ * Method getHeaders gets the headers for all the columns
+ * @return String[] of table headers.
+ */
+ public abstract String[] getHeaders();
+
+ /**
+ * Method getHeaderToolTips gets the tooltips
+ * for the headers for all the columns
+ * @return String[] of table header's tooltips.
+ */
+ public abstract String[] getHeaderToolTips();
+
+ /**
+ * Method getCharacterWidths gets the widths of all the columns,
+ * expressed in Standard Width Characters.
+ * @return int[] of widths in standard characters
+ */
+ public abstract int[] getCharacterWidths();
+
+ /**
+ * Method getFixedWidths gives whether a column is not
+ * resizable (true) or resizable (false)
+ * @return boolean[] of whether a column is fixed
+ */
+ public abstract boolean[] getFixedWidths();
+
+ /**
+ * Method getClasses indicates the type of the data in a column
+ * @return Class[] of data types of the columns
+ */
+ public abstract Class[] getClasses();
+
+ /**
+ * Method getSortKeys returns the primary (array of size 1) or
+ * composite key (size > 1) used for default sorting and
+ * for secondary sorting.
+ * @return int[] of the order of columns participating in sort.
+ */
+ public abstract int[] getSortKeys();
+
+ /**
+ * Method getValueAt gets the contents of a cell from a row.
+ * @param row the row
+ * @param columnIndex int
+ * @return Object The content of a cell from a row
+ */
+ public abstract Object getValueAt(Object row, int columnIndex);
+
+ /**
+ * Method getTableName provides the string for a Titled Border.
+ * @return String the table name
+ */
+ public abstract String getTableName();
+
+ /**
+ * Method getCount is the number of columns in the table.
+ * @return int the number of columns in the table.
+ */
+ public int getCount()
+ {
+ return getHeaders().length;
+ }
+
+ /**
+ * Method getClass gets the class of a given column
+ * @param columnIndex int
+ * @return Class of the given column
+ */
+ public Class getClass(int columnIndex)
+ {
+ final Class[] classes = getClasses();
+ if (classes != null && columnIndex < classes.length)
+ {
+ return classes[columnIndex];
+ }
+ return null;
+ }
+
+ /**
+ * Method getName gets the header for the given column
+ * @param columnIndex int
+ * @return String the header name of the given column
+ */
+ public String getName(int columnIndex)
+ {
+ final String[] headers = getHeaders();
+ if (headers != null && columnIndex < headers.length)
+ {
+ return headers[columnIndex];
+ }
+ return null;
+ }
+
+ /**
+ * Method getClass gets the class of a given column
+ * @param columnIndex int
+ * @return Class of the given column
+ */
+ public String getHeaderToolTip(int columnIndex)
+ {
+ final String[] tooltips = getHeaderToolTips();
+ if (tooltips != null && columnIndex < tooltips.length)
+ {
+ return tooltips[columnIndex];
+ }
+ return null;
+ }
+
+ /**
+ * Method isFixedWidth indicates whether a column is fixed
+ * @param columnIndex int
+ * @return boolean, true if the column cannot be resized
+ */
+ public boolean isFixedWidth(int columnIndex)
+ {
+ final boolean[] fixedWidths = getFixedWidths();
+ if (fixedWidths != null && columnIndex < fixedWidths.length)
+ {
+ return fixedWidths[columnIndex];
+ }
+ return false;
+ }
+
+ /**
+ * Method getCharacterWidth gets the width of the column,
+ * expressed in Standard Characters
+ * @param columnIndex int
+ * @return int the number of characters wide the column is to be.
+ */
+ public int getCharacterWidth(int columnIndex)
+ {
+ final int[] characterWidths = getCharacterWidths();
+ if (characterWidths != null && columnIndex < characterWidths.length)
+ {
+ return characterWidths[columnIndex];
+ }
+ return 0;
+ }
+
+}
\ No newline at end of file
Added: trunk/app/src/org/crosswire/common/swing/RowTable.java
===================================================================
--- trunk/app/src/org/crosswire/common/swing/RowTable.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/swing/RowTable.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,316 @@
+/*
+ * Distribution Licence:
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 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 General Public License for more details.
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/gpl.html,
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * The copyright to this program is held by it's authors
+ * Copyright: 2004
+ */
+package org.crosswire.common.swing;
+import java.awt.Component;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+
+/**
+ * Presents a table of items to a user in a table.
+ *
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ */
+public class RowTable extends JTable
+{
+ /**
+ * Field ONE_STANDARD_CHARACTER
+ */
+ private static final String ONE_STANDARD_CHARACTER = "M"; //$NON-NLS-1$
+ /**
+ * Field TWO_STANDARD_CHARACTERS
+ */
+ private static final String TWO_STANDARD_CHARACTERS = "MM"; //$NON-NLS-1$
+ /**
+ * Field PADDING
+ */
+ private static final int PADDING = 3;
+
+ /**
+ * Constructor for RowTable
+ * @param aList
+ * @param columns
+ */
+ public RowTable(List aList, RowColumns columns)
+ {
+ super(new RowTableModel(aList, columns));
+ setSortRenderer();
+
+ // Don't display vertical lines in table
+ // getColumnModel().setColumnMargin(0);
+
+ setColumnWidths(columns.getCharacterWidths(), columns.getFixedWidths());
+
+ getTableHeader().addMouseListener(new MouseAdapter()
+ {
+ public void mouseClicked(MouseEvent e)
+ {
+ sort(getColumnModel().getColumnIndexAtX(e.getX()));
+ }
+ });
+ }
+
+ /**
+ * Save the selection so it can be restored after sorting.
+ * @param aTable
+ * @return List
+ */
+ private List saveSelection(JTable aTable)
+ {
+ final ListSelectionModel lsm = aTable.getSelectionModel();
+ final RowTableModel tm = (RowTableModel) aTable.getModel();
+ final int first = lsm.getMinSelectionIndex();
+ final int last = lsm.getMaxSelectionIndex();
+ final List objs = new ArrayList();
+ if (first != -1)
+ {
+ for (int i = first; i <= last; i++)
+ {
+ if (lsm.isSelectedIndex(i))
+ {
+ objs.add(tm.getRow(i));
+ }
+ }
+ }
+ return objs;
+ }
+
+ /**
+ * load the selections
+ * @param aTable JTable
+ * @param objs List
+ */
+ private void loadSelection(JTable aTable, List objs)
+ {
+ final ListSelectionModel lsm = aTable.getSelectionModel();
+ final RowTableModel tm = (RowTableModel) aTable.getModel();
+ // reset the selection
+ Object obj = null;
+ int where = -1;
+ for (int i = 0; i < objs.size(); i++)
+ {
+ obj = objs.get(i);
+ where = tm.getRow(obj);
+ if (where != -1)
+ {
+ lsm.addSelectionInterval(where, where);
+ }
+ }
+ scrollToVisible(aTable);
+ }
+
+ /**
+ * Method scrollToVisible
+ * @param aTable JTable
+ */
+ private void scrollToVisible(JTable aTable)
+ {
+ final ListSelectionModel lsm = aTable.getSelectionModel();
+ final int first = lsm.getMinSelectionIndex();
+ final int last = lsm.getMaxSelectionIndex();
+ if (first != -1)
+ {
+ final Rectangle bounds = getRowBounds(aTable, first, last);
+ if (isVerticallyVisible(aTable, bounds) == false)
+ {
+ // Is SwingUtilities.invokeLater needed ???
+ aTable.scrollRectToVisible(bounds);
+ }
+ }
+ }
+
+ /**
+ * Method selectRow
+ * @param row int
+ */
+ public void selectRow(int row)
+ {
+ final ListSelectionModel lsm = getSelectionModel();
+ lsm.clearSelection();
+ lsm.setSelectionInterval(row, row);
+ scrollToVisible(this);
+ }
+
+ /**
+ * Method getRowBounds
+ * @param table JTable
+ * @param first int
+ * @param last int
+ * @return Rectangle
+ */
+ private Rectangle getRowBounds(JTable table, int first, int last)
+ {
+ Rectangle result = table.getCellRect(first, -1, true);
+ result = result.union(table.getCellRect(last, -1, true));
+ final Insets insets = table.getInsets();
+ result.x = insets.left;
+ result.width = table.getWidth() - insets.left - insets.right;
+ return result;
+ }
+
+ /**
+ * Method isVerticallyVisible
+ * @param aTable JTable
+ * @param r Rectangle
+ * @return boolean
+ */
+ private boolean isVerticallyVisible(JTable aTable, Rectangle r)
+ {
+ final Rectangle visible = aTable.getVisibleRect();
+ return visible.y <= r.y && visible.y + visible.height >= r.y + r.height;
+ }
+
+ /**
+ * Method setColumnWidths
+ * @param widths int[]
+ * @param fixed boolean[]
+ */
+ private void setColumnWidths(int[] widths, boolean[] fixed)
+ {
+ final int mWidth = getStandardCharacterWidth();
+ final TableColumnModel tcm = getColumnModel();
+ // The << 1 accounts for two margins
+ // The + PADDING accounts for an extra pixel on either side
+ // and an extra pixel for between the columns
+ // that the text needs to not display ...
+ final int margins = (tcm.getColumnMargin() << 1) + PADDING;
+ TableColumn tc = null;
+ int width = -1;
+ for (int i = 0; i < widths.length; i++)
+ {
+ tc = tcm.getColumn(i);
+ width = widths[i] * mWidth + margins;
+ if (fixed[i])
+ {
+ tc.setMinWidth(width);
+ tc.setMaxWidth(width);
+ }
+ else
+ {
+ tc.setPreferredWidth(width);
+ }
+ }
+ }
+
+ /**
+ * Method setSortRenderer
+ */
+ private void setSortRenderer()
+ {
+ final TableCellRenderer sortRenderer = new SortRenderer((RowTableModel) getModel());
+ // TableCellRenderer rowRenderer = new RowRenderer();
+ final TableColumnModel model = getColumnModel();
+ final int colCount = model.getColumnCount();
+ TableColumn tc = null;
+ for (int i = 0; i < colCount; i++)
+ {
+ tc = model.getColumn(i);
+ tc.setHeaderRenderer(sortRenderer);
+ }
+ }
+
+ /**
+ * Size each column to something reasonable
+ * We do this by getting the width of the letter 'M"
+ * from the default Table Header Renderer
+ * and set the preferred width of the column
+ * as the width of some number of 'M's.
+ * @return int
+ */
+ private int getStandardCharacterWidth()
+ {
+ // The preferredSize of the component is more than just the character
+ // So we remove the extra determining the delta
+ // between one and two chars
+ final JTableHeader th = getTableHeader();
+ final TableCellRenderer renderer = th.getDefaultRenderer();
+ Component comp = renderer.getTableCellRendererComponent(this, ONE_STANDARD_CHARACTER, false, false, 0, 0);
+ final int oneStandardCharacterWidth = comp.getPreferredSize().width;
+ comp = renderer.getTableCellRendererComponent(this, TWO_STANDARD_CHARACTERS, false, false, 0, 0);
+ final int twoStandardCharactersWidth = comp.getPreferredSize().width;
+ return twoStandardCharactersWidth - oneStandardCharacterWidth;
+ }
+
+ /**
+ * Method addListSelectionListener
+ * @param listener ListSelectionListener
+ */
+ public void addListSelectionListener(ListSelectionListener listener)
+ {
+ getSelectionModel().addListSelectionListener(listener);
+ }
+
+ /**
+ * Method getPreferredHeight
+ * @param numRows int
+ * @return int
+ */
+ public int getPreferredHeight(int numRows)
+ {
+ int newHeight = getRowHeight() * numRows;
+ // The following may be needed for Java 1.4
+ // newHeight += table.getIntercellSpacing().height * (numRows + 1);
+ newHeight += getTableHeader().getPreferredSize().height;
+ final Insets insets = getInsets();
+ newHeight += insets.top + insets.bottom;
+ return newHeight;
+ }
+
+ /**
+ * Method sort
+ * @param col int
+ */
+ public void sort(int col)
+ {
+ if (col != -1)
+ {
+ final TableColumnModel tcm = getColumnModel();
+ final TableColumn tc = tcm.getColumn(col);
+ final SortRenderer renderer = (SortRenderer) tc.getHeaderRenderer();
+ renderer.setPressedColumn(tc);
+ }
+ final List objs = saveSelection(this);
+ getSelectionModel().clearSelection();
+ ((RowTableModel) getModel()).sort(convertColumnIndexToModel(col));
+ loadSelection(this, objs);
+ }
+
+ public void reset()
+ {
+ final RowTableModel stm = (RowTableModel) getModel();
+ final ListSelectionModel lsm = getSelectionModel();
+ getSelectionModel().clearSelection();
+ lsm.clearSelection();
+ stm.reset();
+ }
+
+}
\ No newline at end of file
Added: trunk/app/src/org/crosswire/common/swing/RowTableModel.java
===================================================================
--- trunk/app/src/org/crosswire/common/swing/RowTableModel.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/swing/RowTableModel.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,345 @@
+/*
+ * Distribution Licence:
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 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 General Public License for more details.
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/gpl.html,
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * The copyright to this program is held by it's authors
+ * Copyright: 2004
+ */
+package org.crosswire.common.swing;
+
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+
+/**
+ * The RowTableModel defines the "model" behaviour for
+ * a RowTable.
+ *
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ */
+public class RowTableModel extends AbstractTableModel
+{
+ /**
+ * Field list contains the objects that can be worked upon
+ */
+ private List list;
+
+ /**
+ * Field columnModel provides the definition of the structure
+ * of the table
+ */
+ private RowColumns rowColumnModel;
+
+ /**
+ * Field indexes provides a look-aside for the sorted view of the
+ * table to the row list.
+ */
+ private int[] indexes;
+
+ /**
+ * Field keys provides the primary or composite key of the table.
+ * It is a local optimization of columnModel.getSortKeys().
+ */
+ private int[] keys;
+ /**
+ * Field sortColumn indicates the column that was last sorted upon.
+ * It is initialized the first value in keys, if present otherwise -1
+ */
+ private int sortColumn;
+
+ /**
+ * Builds a RowTable model for the provided (non-null) row list,
+ * using the provided row column definition.
+ * @param aList List
+ * @param aColumnModel RowColumns
+ */
+ public RowTableModel(List aList, RowColumns aRowColumnModel)
+ {
+ super();
+ list = aList;
+ rowColumnModel = aRowColumnModel;
+ keys = rowColumnModel.getSortKeys();
+ sortColumn = keys[0];
+ allocate();
+ }
+
+ /**
+ * Method getRowCount returns the number of rows in the list.
+ * @return int
+ * @see javax.swing.table.TableModel#getRowCount()
+ */
+ public int getRowCount()
+ {
+ return (list == null) ? 0 : list.size();
+ }
+
+ /**
+ * Method getColumnCount returns the number of columns in the table
+ * @return int
+ * @see javax.swing.table.TableModel#getColumnCount()
+ */
+ public int getColumnCount()
+ {
+ return rowColumnModel.getCount();
+ }
+
+ /**
+ * Method getValueAt returns the contents of a cell.
+ * @param row int
+ * @param column int
+ * @return Object
+ * @see javax.swing.table.TableModel#getValueAt(int, int)
+ */
+ public Object getValueAt(int row, int column)
+ {
+ return getCellValue(indexes[row], column);
+ }
+
+ /**
+ * Method getCellValue Translates from a row index to a row object
+ * and asks it for the appropriate cell value
+ * @param rowIndex int
+ * @param columnIndex int
+ * @return Object
+ */
+ private Object getCellValue(int rowIndex, int columnIndex)
+ {
+ final Object obj = list.get(rowIndex);
+ return rowColumnModel.getValueAt(obj, columnIndex);
+ }
+
+ /**
+ * Method getColumnClass returns the class of the column
+ * @param columnIndex int
+ * @return Class
+ * @see javax.swing.table.TableModel#getColumnClass(int)
+ */
+ public Class getColumnClass(int columnIndex)
+ {
+ return rowColumnModel.getClass(columnIndex);
+ }
+
+ /**
+ * Method getHeaderToolTip returns the tooltip for the header of the column
+ * @param columnIndex int
+ * @return String
+ */
+ public String getHeaderToolTip(int columnIndex)
+ {
+ return rowColumnModel.getHeaderToolTip(columnIndex);
+ }
+
+ /**
+ * Method getColumnName returns the header name for the column
+ * @param columnIndex int
+ * @return String
+ * @see javax.swing.table.TableModel#getColumnName(int)
+ */
+ public String getColumnName(int columnIndex)
+ {
+ return rowColumnModel.getName(columnIndex);
+ }
+
+ /**
+ * Method addRow adds a row to the table.
+ * @param obj the row to add
+ */
+ public void addRow(Object obj)
+ {
+ list.add(obj);
+ allocate();
+ final int visibleRow = getRow(obj);
+ fireTableRowsInserted(visibleRow, visibleRow);
+ }
+
+ /**
+ * Method getRow retrieves a row from the table
+ * @param rowIndex int
+ * @return the row
+ */
+ public Object getRow(int rowIndex)
+ {
+ return list.get(indexes[rowIndex]);
+ }
+
+ /**
+ * Method getRow finds the visible row index for a given row
+ * @param obj the row
+ * @return int
+ */
+ public int getRow(Object obj)
+ {
+ for (int i = 0; i < indexes.length; i++)
+ {
+ if (getRow(i).equals(obj))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Method removeRow removes a row from the model
+ * and causes the display to update itself appropriately
+ * @param obj the row to remove
+ */
+ public void removeRow(Object obj)
+ {
+ final int dataIndex = list.indexOf(obj);
+ final int visibleIndex = getRow(obj);
+ list.remove(dataIndex);
+ fireTableRowsDeleted(visibleIndex, visibleIndex);
+ allocate();
+ }
+
+ /**
+ * Method updateRow causes the display to update itself appropriately.
+ * Methods on rows are actually used to update the row
+ * @param obj the row
+ */
+ public void updateRow(Object obj)
+ {
+ final int visibleIndex = getRow(obj);
+ fireTableRowsUpdated(visibleIndex, visibleIndex);
+ }
+
+ public void reset()
+ {
+ allocate();
+ fireTableDataChanged();
+ }
+
+ public void clear()
+ {
+ list.clear();
+ allocate();
+ fireTableDataChanged();
+ }
+
+ // Bubble Sort!!! Replace if performance is an issue.
+ /**
+ * Method sort
+ * @param column int
+ */
+ public void sort(int modelIndex)
+ {
+ if (modelIndex != -1)
+ {
+ sortColumn = modelIndex;
+ }
+ final int rowCount = getRowCount();
+ boolean changed = false;
+ for (int i = 0; i < rowCount; i++)
+ {
+ for (int j = i + 1; j < rowCount; j++)
+ {
+ if (compareKeys(indexes[i], indexes[j], sortColumn) < 0)
+ {
+ swap(i, j);
+ changed = true;
+ }
+ }
+ }
+ if (changed)
+ {
+ fireTableRowsUpdated(0, getRowCount());
+ }
+ }
+
+ /**
+ * Method swap
+ * @param i int
+ * @param j int
+ */
+ private void swap(int i, int j)
+ {
+ final int tmp = indexes[i];
+ indexes[i] = indexes[j];
+ indexes[j] = tmp;
+ }
+
+ /**
+ * Method compareKeys
+ * @param i int
+ * @param j int
+ * @param column int
+ * @return int
+ */
+ private int compareKeys(int i, int j, int column)
+ {
+ int cmp = compare(i, j, column);
+ if (keys != null)
+ {
+ for (int k = 0; cmp == 0 && k < keys.length; k++)
+ {
+ if (k != column)
+ {
+ cmp = compare(i, j, keys[k]);
+ }
+ }
+ }
+ return cmp;
+ }
+
+ /**
+ * Method compare
+ * @param i int
+ * @param j int
+ * @param column int
+ * @return int
+ */
+ public int compare(int i, int j, int column)
+ {
+ final Object io = getCellValue(i, column);
+ final Object jo = getCellValue(j, column);
+ int cmp = 0;
+ if (io.getClass().equals(jo.getClass()) && io instanceof Comparable)
+ {
+ cmp = ((Comparable) jo).compareTo(io);
+ }
+ else if (io instanceof Boolean)
+ {
+ cmp = io.toString().compareTo(jo.toString());
+ }
+ else
+ {
+ cmp = jo.toString().compareTo(io.toString());
+ }
+
+ return (cmp < 0) ? -1 : ((cmp > 0) ? 1 : 0);
+ }
+
+ /**
+ * Method allocate
+ */
+ private void allocate()
+ {
+ final int rowCount = getRowCount();
+ if (indexes == null || indexes.length != rowCount)
+ {
+ final int[] newData = new int[rowCount];
+ for (int i = 0; i < rowCount; i++)
+ {
+ newData[i] = i;
+ }
+ indexes = newData;
+ // Do the default or last sort
+ sort(-1);
+ }
+ }
+
+}
\ No newline at end of file
Added: trunk/app/src/org/crosswire/common/swing/SortRenderer.java
===================================================================
--- trunk/app/src/org/crosswire/common/swing/SortRenderer.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/swing/SortRenderer.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,113 @@
+/*
+ * Distribution Licence:
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 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 General Public License for more details.
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/gpl.html,
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * The copyright to this program is held by it's authors
+ * Copyright: 2004
+ */
+package org.crosswire.common.swing;
+
+import java.awt.Component;
+import java.awt.Font;
+
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumn;
+
+/**
+ * A SortRenderer indicates the column that is sorted by italizing it.
+ *
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ */
+public class SortRenderer extends DefaultTableCellRenderer {
+
+ /**
+ * Field pressedColumn
+ */
+ private TableColumn pressedColumn;
+ /**
+ * Field model
+ */
+ private RowTableModel model;
+
+ /**
+ * Constructor for SortRenderer
+ * @param stm SegmentTableModel
+ */
+ public SortRenderer(RowTableModel stm) {
+ model = stm;
+ pressedColumn = null;
+ setHorizontalAlignment(SwingConstants.CENTER);
+ }
+
+ /**
+ * Method getTableCellRendererComponent
+ * @param table JTable
+ * @param value Object
+ * @param isSelected boolean
+ * @param hasFocus boolean
+ * @param row int
+ * @param column int
+ * @return Component
+ */
+ public Component getTableCellRendererComponent(
+ JTable table,
+ Object value,
+ boolean isSelected,
+ boolean hasFocus,
+ int row,
+ int column) {
+ if (table != null) {
+ setToolTipText(model.getHeaderToolTip(column));
+ final JTableHeader header = table.getTableHeader();
+ final TableColumn tableColumn = table.getColumnModel().getColumn(column);
+ if (header != null) {
+ setForeground(header.getForeground());
+ setBackground(header.getBackground());
+ final Font headerFont = header.getFont();
+ if (tableColumn == pressedColumn) {
+ setFont(headerFont.deriveFont(Font.ITALIC));
+ } else {
+ setFont(headerFont);
+ }
+ }
+ }
+
+ setText((value == null) ? "" : value.toString()); //$NON-NLS-1$
+ setBorder(UIManager.getBorder("TableHeader.cellBorder")); //$NON-NLS-1$
+ return this;
+ }
+
+ /**
+ * Method getPressedColumn
+ * @return the table column
+ */
+ public TableColumn getPressedColumn() {
+ return pressedColumn;
+ }
+
+ /**
+ * Method setPressedColumn
+ * @param tc the table column
+ */
+ public void setPressedColumn(TableColumn tc) {
+ pressedColumn = tc;
+ }
+
+}
\ No newline at end of file
Copied: trunk/app/src/org/crosswire/common/util/CWClassLoader.java (from rev 43, trunk/app/src/org/crosswire/common/CWClassLoader.java)
===================================================================
--- trunk/app/src/org/crosswire/common/CWClassLoader.java 2004-09-17 06:21:12 UTC (rev 43)
+++ trunk/app/src/org/crosswire/common/util/CWClassLoader.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,377 @@
+package org.crosswire.common.util;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * CWClassLoader extends the regular class loader by using looking
+ * in more places. This is needed so that ResourceBundle can find
+ * resources that are not held in the same package as the class.
+ *
+ * <p><table border='1' cellPadding='3' cellSpacing='0'>
+ * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
+ *
+ * Distribution Licence:<br />
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.<br />
+ * 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
+ * General Public License for more details.<br />
+ * The License is available on the internet
+ * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA<br />
+ * The copyright to this program is held by it's authors.
+ * </font></td></tr></table>
+ * @see gnu.gpl.Licence
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ * @version $Id: CWClassLoader.java,v 1.4 2004/08/16 22:07:35 joe Exp $
+ */
+public class CWClassLoader extends ClassLoader
+{
+ /**
+ * Creates a class loader that finds resources
+ * for the supplied class that may not be in the class' package.
+ * You can use this within base classes by passing getClass()
+ * to load resources for a derived class.
+ * @param resourceOwner is the owner of the resource
+ */
+ public CWClassLoader(Class resourceOwner)
+ {
+ owner = resourceOwner;
+ }
+
+ /**
+ * Creates a class loader that finds resources
+ * for the calling class that may not be in the class' package.
+ * Use this only within classes that are directly looking up their resources.
+ */
+ public CWClassLoader()
+ {
+ owner = CallContext.instance().getCallingClass();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.ClassLoader#findResource(java.lang.String)
+ */
+ public URL findResource(String search)
+ {
+ URL resource = null;
+ if (search == null || search.length() == 0)
+ {
+ return resource;
+ }
+
+ // First look for it with an absolute path
+ // This allows developer overrides
+ if (search.charAt(0) != '/')
+ {
+ resource = findResource('/' + search);
+ }
+
+ if (resource == null)
+ {
+ // Look for it in the class's package.
+ String newsearch = adjustPackageSearch(search);
+ if (!search.equals(newsearch))
+ {
+ resource = findResource(newsearch);
+ }
+ }
+
+ // Sometimes it comes in with '/' inside of it.
+ // So look for it as a file with '.' in the name
+ // This is the form that will find files in the resource.jar
+ if (resource == null)
+ {
+ // Look for it in the class's package.
+ String newsearch = adjustPathSearch(search);
+ if (!search.equals(newsearch))
+ {
+ resource = findResource(newsearch);
+ }
+ }
+
+ // See if it can be found in the home directory
+ if (resource == null)
+ {
+ resource = CWClassLoader.findHomeResource(search);
+ }
+
+ // See if it can be found by its own class.
+ if (resource == null)
+ {
+ resource = owner.getResource(search);
+ }
+
+ // Try the appropriate class loader
+ if (resource == null)
+ {
+ resource = getClassLoader().getResource(search);
+ }
+
+ // Try the bootstrap and the system loader
+ if (resource == null)
+ {
+ resource = ClassLoader.getSystemResource(search);
+ }
+
+ // For good measure let the super class try to find it.
+ if (resource == null)
+ {
+ resource = super.findResource(search);
+ }
+
+ return resource;
+ }
+
+ /**
+ * Prefix the search with a package prefix, if not already.
+ * Skip a leading '/' if present.
+ */
+ private String adjustPackageSearch(String search)
+ {
+ // If it has embedded '/' there is nothing to do.
+ if (search.indexOf('/', 1) == -1)
+ {
+ String className = owner.getName();
+ String pkgPrefix = className.substring(0, className.lastIndexOf('.') + 1);
+
+ if (search.charAt(0) == '/')
+ {
+ String part = search.substring(1);
+ if (!part.startsWith(pkgPrefix))
+ {
+ search = '/' + pkgPrefix + part;
+ }
+ }
+ else
+ {
+ if (!search.startsWith(pkgPrefix))
+ {
+ search = pkgPrefix + search;
+ }
+ }
+ }
+
+ return search;
+ }
+
+ /**
+ * Change all but a leading '/' to '.'
+ */
+ private String adjustPathSearch(String search)
+ {
+ if (search.indexOf('/', 1) != -1)
+ {
+ // Change all but a leading '/' to '.'
+ if (search.charAt(0) == '/')
+ {
+ search = '/' + search.substring(1).replace('/', '.');
+ }
+ else
+ {
+ search = search.replace('/', '.');
+ }
+ }
+ return search;
+ }
+
+ /**
+ *
+ */
+ public ClassLoader getClassLoader()
+ {
+ // Choose the child loader as it will use the parent if need be
+ // If they are not related then choose the context loader
+ ClassLoader loader = pickLoader(Thread.currentThread().getContextClassLoader(), owner.getClassLoader());
+ return pickLoader(loader, ClassLoader.getSystemClassLoader());
+ }
+
+ /**
+ * Returns 'true' if 'loader2' is a delegation child of 'loader1' [or if
+ * 'loader1'=='loader2']. Of course, this works only for classloaders that
+ * set their parent pointers correctly. 'null' is interpreted as the
+ * primordial loader [i.e., everybody's parent].
+ */
+ private static ClassLoader pickLoader(final ClassLoader loader1, final ClassLoader loader2)
+ {
+ ClassLoader loader = loader2;
+ if (loader1 != loader2)
+ {
+ loader = loader1;
+ if (loader1 == null)
+ {
+ loader = loader2;
+ }
+ else
+ {
+ // Is loader2 a descendant of loader1?
+ // It is if we can walk up to the top and find it.
+ for (ClassLoader curloader = loader2; curloader != null; curloader = curloader.getParent())
+ {
+ if (curloader == loader1)
+ {
+ loader = loader2;
+ break;
+ }
+ }
+ }
+ }
+ return loader;
+ }
+
+ /**
+ * If the application has set the home, it will return
+ * the application's home directory, otherwise it returns null.
+ * @return Returns the home.
+ */
+ public static synchronized URL getHome()
+ {
+ try
+ {
+ if (home != null)
+ {
+
+ return new URL(home.getProtocol(), home.getHost(), home.getPort(), home.getFile());
+ }
+ }
+ catch (MalformedURLException e)
+ {
+ assert false;
+ }
+ return home;
+ }
+
+ /**
+ * Establish the applications home directory from where
+ * additional resources can be found. URL is expected to
+ * end with the directory name, not '/'.
+ * @param newhome The home to set.
+ */
+ public static synchronized void setHome(URL newhome)
+ {
+ home = newhome;
+ }
+
+ /**
+ * Look for the resource in the home directory
+ * @param search must be non-null, non-empty
+ */
+ public static URL findHomeResource(String search)
+ {
+ URL reply = null;
+
+ URL override = getHomeResource(search);
+
+ // Look at the application's home first to allow overrides
+ if (override != null)
+ {
+ // Make sure the file exists and can be read
+ File f = new File(override.getFile());
+ if (f.canRead())
+ {
+ reply = override;
+ }
+ }
+
+ return reply;
+ }
+
+ /**
+ * Compute an URL for the resource in the home directory
+ * @param search must be non-null, non-empty
+ */
+ public static URL getHomeResource(String search)
+ {
+ URL reply = null;
+
+ URL homeURL = getHome();
+
+ // Look at the application's home first to allow overrides
+ if (homeURL != null)
+ {
+ reply = lengthenURL(homeURL, search);
+ }
+
+ return reply;
+ }
+
+ /**
+ * Utility to add a string to the end of a URL.
+ * @param orig The URL to strip
+ * @param extra The text to add to the end of the URL
+ * @return The stripped URL
+ */
+ public static URL lengthenURL(URL orig, String extra)
+ {
+ try
+ {
+ char firstChar = extra.charAt(extra.length() - 1);
+ if (isSeparator(firstChar))
+ {
+ extra = extra.substring(1);
+ }
+
+ if (orig.getProtocol().equals(PROTOCOL_FILE))
+ {
+ String file = orig.toExternalForm();
+ char lastChar = file.charAt(file.length() - 1);
+ if (isSeparator(lastChar))
+ {
+ return new URL(orig.getProtocol(),
+ orig.getHost(),
+ orig.getPort(),
+ orig.getFile() + extra);
+ }
+ else
+ {
+ return new URL(orig.getProtocol(),
+ orig.getHost(),
+ orig.getPort(),
+ orig.getFile() + File.separator + extra);
+ }
+ }
+ else
+ {
+ return new URL(orig.getProtocol(),
+ orig.getHost(),
+ orig.getPort(),
+ orig.getFile() + SEPARATOR + extra);
+ }
+ }
+ catch (MalformedURLException ex)
+ {
+ assert false : ex;
+ return null;
+ }
+ }
+
+ private static boolean isSeparator(char c)
+ {
+ return c == '/' || c == '\\';
+ }
+
+ /**
+ * Constant for the file: protocol
+ */
+ public static final String PROTOCOL_FILE = "file"; //$NON-NLS-1$
+
+ /**
+ * URL separator
+ */
+ public static final String SEPARATOR = "/"; //$NON-NLS-1$
+
+ /**
+ * The class to which the resources belong
+ */
+ private Class owner;
+
+ /**
+ * Notion of a project's home from where additional resources can be found.
+ */
+ private static URL home = null;
+}
Copied: trunk/app/src/org/crosswire/common/util/CallContext.java (from rev 43, trunk/app/src/org/crosswire/common/CallContext.java)
===================================================================
--- trunk/app/src/org/crosswire/common/CallContext.java 2004-09-17 06:21:12 UTC (rev 43)
+++ trunk/app/src/org/crosswire/common/util/CallContext.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,91 @@
+package org.crosswire.common.util;
+
+/**
+ * This singleton class provides a way for a method to determine
+ * which class called it.
+ * <p>
+ * It has been tested to work in command line and WebStart environments.
+ *
+ * <p><table border='1' cellPadding='3' cellSpacing='0'>
+ * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
+ *
+ * Distribution Licence:<br />
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.<br />
+ * 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
+ * General Public License for more details.<br />
+ * The License is available on the internet
+ * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA<br />
+ * The copyright to this program is held by it's authors.
+ * </font></td></tr></table>
+ * @see gnu.gpl.Licence
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ * @version $Id: CallContext.java,v 1.1 2004/04/20 21:16:06 joe Exp $
+ */
+public class CallContext extends SecurityManager
+{
+ /**
+ * Prevent instansiation
+ */
+ private CallContext()
+ {
+ }
+
+ /**
+ * Singleton accessor
+ */
+ public static CallContext instance()
+ {
+ if (resolver == null)
+ {
+ resolver = new CallContext();
+ }
+
+ return resolver;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.SecurityManager#getClassContext()
+ */
+ protected Class[] getClassContext()
+ {
+ return super.getClassContext();
+ }
+
+ /**
+ * When called from a method it will return the class
+ * calling that method.
+ */
+ public Class getCallingClass()
+ {
+ return getCallingClass(1); // add 1 for this method
+ }
+
+ /**
+ * When called from a method it will return the i-th class
+ * calling that method, up the call chain.
+ * If used with a -1 it will return the class making the call
+ * -2 and -3 will return this class
+ * @throws ArrayIndexOutOfBoundsException if the index is not valid
+ */
+ public Class getCallingClass(int i)
+ {
+ return resolver.getClassContext()[CALL_CONTEXT_OFFSET + i];
+ }
+
+ // may need to change if this class is redesigned
+ /**
+ * Offset needed to represent the caller of the method
+ * that called this method.
+ *
+ */
+ private static final int CALL_CONTEXT_OFFSET = 3;
+
+ private static CallContext resolver;
+}
Copied: trunk/app/src/org/crosswire/common/util/CallContext.jbx (from rev 43, trunk/app/src/org/crosswire/common/CallContext.jbx)
Copied: trunk/app/src/org/crosswire/common/util/ResourceUtil.java (from rev 43, trunk/app/src/org/crosswire/common/ResourceUtil.java)
===================================================================
--- trunk/app/src/org/crosswire/common/ResourceUtil.java 2004-09-17 06:21:12 UTC (rev 43)
+++ trunk/app/src/org/crosswire/common/util/ResourceUtil.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,71 @@
+package org.crosswire.common.util;
+
+import java.net.URL;
+import java.util.MissingResourceException;
+
+/**
+ * Better implemenetations of the getResource methods with less ambiguity and
+ * that are less dependent on the specific classloader situation.
+ *
+ * <p><table border='1' cellPadding='3' cellSpacing='0'>
+ * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
+ *
+ * Distribution Licence:<br />
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.<br />
+ * 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
+ * General Public License for more details.<br />
+ * The License is available on the internet
+ * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA<br />
+ * The copyright to this program is held by it's authors.
+ * </font></td></tr></table>
+ * @see gnu.gpl.Licence
+ * @author Joe Walker [joe at eireneh dot com]
+ * @author DM Smith [ dmsmith555 at yahoo dot com ]
+ * @version $Id: ResourceUtil.java,v 1.5 2004/08/16 22:07:35 joe Exp $
+ */
+public class ResourceUtil
+{
+ /**
+ * Prevent Instansiation
+ */
+ private ResourceUtil()
+ {
+ }
+
+ /**
+ * Generic resource URL fetcher. One way or the other we'll find it!
+ * Either as a relative or an absolute reference.
+ * @param search The name of the resource (without a leading /) to find
+ * @return The requested resource
+ * @throws MissingResourceException if the resource can not be found
+ */
+ public static URL getResource(String search) throws MissingResourceException
+ {
+ return getResource(CallContext.instance().getCallingClass(), search);
+ }
+
+ /**
+ * Generic resource URL fetcher. One way or the other we'll find it!
+ * Either as a relative or an absolute reference.
+ * @param clazz The resource to find
+ * @return The requested resource
+ * @throws MissingResourceException if the resource can not be found
+ */
+ public static URL getResource(Class clazz, String resourceName) throws MissingResourceException
+ {
+ URL resource = new CWClassLoader(clazz).findResource(resourceName);
+
+ if (resource == null)
+ {
+ throw new MissingResourceException("Can't find resource", clazz.getName(), resourceName);
+ }
+
+ return resource;
+ }
+}
Added: trunk/app/src/org/crosswire/common/util/RowProcessor.java
===================================================================
--- trunk/app/src/org/crosswire/common/util/RowProcessor.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/util/RowProcessor.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,36 @@
+package org.crosswire.common.util;
+
+/**
+ * A RowProcessor processes a single row consisting of an array of objects.
+ *
+ * <p><table border='1' cellPadding='3' cellSpacing='0'>
+ * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
+ *
+ * Distribution Licence:<br />
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.<br />
+ * 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
+ * General Public License for more details.<br />
+ * The License is available on the internet
+ * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA<br />
+ * The copyright to this program is held by it's authors.
+ * </font></td></tr></table>
+ * @see gnu.gpl.Licence
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ * @version $Id$
+ */
+public interface RowProcessor
+{
+
+ /**
+ * Process a row of Objects making up a line.
+ * @param row the row to handle
+ */
+ public void process(Object[] row);
+
+}
\ No newline at end of file
Added: trunk/app/src/org/crosswire/common/util/TabbedFileReader.java
===================================================================
--- trunk/app/src/org/crosswire/common/util/TabbedFileReader.java 2004-09-19 12:30:52 UTC (rev 45)
+++ trunk/app/src/org/crosswire/common/util/TabbedFileReader.java 2004-09-19 12:32:10 UTC (rev 46)
@@ -0,0 +1,89 @@
+package org.crosswire.common.util;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+import org.crosswire.common.ResourceUtil;
+
+/**
+ * A TabbedFileReader reads a file consisting of lines with
+ * tab separated columns.
+ *
+ * <p><table border='1' cellPadding='3' cellSpacing='0'>
+ * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
+ *
+ * Distribution Licence:<br />
+ * JSword is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License,
+ * version 2 as published by the Free Software Foundation.<br />
+ * 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
+ * General Public License for more details.<br />
+ * The License is available on the internet
+ * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA<br />
+ * The copyright to this program is held by it's authors.
+ * </font></td></tr></table>
+ * @see gnu.gpl.Licence
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ * @version $Id$
+ */
+public class TabbedFileReader
+{
+ /**
+ * Process all the lines in the file.
+ * @param fileName java.lang.String
+ * @param columns int
+ * @param lp lineProcessor
+ * @throws IOException
+ */
+ static public void read(String fileName, int columns, RowProcessor lp) throws IOException
+ {
+ InputStream inputStream = null;
+ try
+ {
+ URL fileURL = ResourceUtil.getResource(fileName);
+ inputStream = new FileInputStream(fileURL.getFile());
+ }
+ catch (Exception ex1)
+ {
+ inputStream = new FileInputStream(fileName);
+ }
+
+ // open the file
+ BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+
+ Object row[] = new Object[columns];
+
+ // read the file a line at a time and send it to the
+ // processor for processing
+ String line = null;
+ while ((line = in.readLine()) != null)
+ {
+ // Split it on tabs
+ int previousLoc = 0;
+ int lastColumn = columns - 1;
+ for (int col = 0; col < lastColumn; col++)
+ {
+ int loc = line.indexOf('\t', previousLoc);
+ if (loc == -1)
+ {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ row[col] = line.substring(previousLoc, loc);
+ previousLoc = (loc + 1);
+ }
+ row[lastColumn] = line.substring(previousLoc);
+ lp.process(row);
+ }
+ // close the file
+ in.close();
+ }
+
+}
\ No newline at end of file
More information about the sword-cvs
mailing list