package net.sf.jabref.gui;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Vector;
import net.sf.jabref.AuthorList;
import net.sf.jabref.BasePanel;
import net.sf.jabref.BibtexEntry;
import net.sf.jabref.BibtexFields;
import net.sf.jabref.GUIGlobals;
import net.sf.jabref.Globals;
import net.sf.jabref.SearchRuleSet;
import net.sf.jabref.Util;
import ca.odell.glazedlists.gui.TableFormat;
import ca.odell.glazedlists.matchers.Matcher;
/**
* Class defining the contents and column headers of the main table.
*/
public class MainTableFormat implements TableFormat<BibtexEntry> {
// Character separating field names that are to be used in sequence as
// fallbacks for a single column (e.g. "author/editor" to use editor where
// author is not set):
public static final String COL_DEFINITION_FIELD_SEPARATOR = "/";
public static final String[]
PDF = {"pdf", "ps"}
,
URL_ = {"url", "doi"}
,
CITESEER = {"citeseerurl"},
ARXIV = {"eprint"},
FILE = {GUIGlobals.FILE_FIELD};
BasePanel panel;
private String[][] columns; // Contains the current column names.
public int padleft = -1; // padleft indicates how many columns (starting from left) are
// special columns (number column or icon column).
private HashMap<Integer, String[]> iconCols = new HashMap<Integer, String[]>();
int[][] nameCols = null;
boolean namesAsIs, abbr_names, namesNatbib, namesFf, namesLf, namesLastOnly, showShort;
public MainTableFormat(BasePanel panel) {
this.panel = panel;
}
public int getColumnCount() {
return padleft + columns.length;
}
public String getColumnName(int col) {
if (col == 0) {
return GUIGlobals.NUMBER_COL;
} else if (getIconTypeForColumn(col) != null) {
return "";
}
else // try to find an alternative fieldname (for display)
{
String[] fld = columns[col - padleft];
StringBuilder sb = new StringBuilder();
for (int i=0; i<fld.length; i++) {
if (i > 0)
sb.append('/');
String disName = BibtexFields.getFieldDisplayName(fld[i]);
if (disName != null)
sb.append(disName);
else
sb.append(Util.nCase(fld[i]));
}
return sb.toString();
/*String disName = BibtexFields.getFieldDisplayName(columns[col - padleft]) ;
if ( disName != null)
{
return disName ;
} */
}
//return Util.nCase(columns[col - padleft]);
}
/**
* This method returns a string array indicating the types of icons to be displayed in the given column.
* It returns null if the column is not an icon column, and thereby also serves to identify icon
* columns.
*/
public String[] getIconTypeForColumn(int col) {
Object o = iconCols.get(new Integer(col));
if (o != null)
return (String[]) o;
else
return null;
}
/**
* Finds the column index for the given column name.
* @param colName The column name
* @return The column index if any, or -1 if no column has that name.
*/
public int getColumnIndex(String colName) {
for (int i=0; i<columns.length; i++) {
// TODO: is the following line correct with [0] ?
if (columns[i][0].equalsIgnoreCase(colName))
return i+padleft;
}
return -1;
}
public Object getColumnValue(BibtexEntry be, int col) {
Object o = null;
String[] iconType = getIconTypeForColumn(col); // If non-null, indicates an icon column's type.
if (col == 0) {
o = "#";// + (row + 1);
}
else if (iconType != null) {
int hasField = -1;
for (int i = iconType.length - 1; i >= 0; i--)
if (hasField(be, iconType[i]))
hasField = i;
if (hasField < 0)
return null;
// Ok, so we are going to display an icon. Find out which one, and return it:
if (iconType[hasField].equals(GUIGlobals.FILE_FIELD)) {
o = FileListTableModel.getFirstLabel(be.getField(GUIGlobals.FILE_FIELD));
} else
o = GUIGlobals.getTableIcon(iconType[hasField]);
} else {
String[] fld = columns[col - padleft];
// Go through the fields until we find one with content:
int j = 0;
for (int i = 0; i < fld.length; i++) {
if (fld[i].equals(GUIGlobals.TYPE_HEADER))
o = be.getType().getName();
else
o = be.getField(fld[i]);
if (o != null) {
j = i;
break;
}
}
for (int i = 0; i < nameCols.length; i++) {
if ((col - padleft == nameCols[i][0]) && (nameCols[i][1] == j)) {
return formatName(o);
}
}
}
return o;
}
/**
* Format a name field for the table, according to user preferences.
* @param o The contents of the name field.
* @return The formatted name field.
*/
public Object formatName(Object o) {
if (o == null) {
return null;
}
if (namesAsIs) return o;
if (namesNatbib) o = AuthorList.fixAuthor_Natbib((String) o);
else if (namesLastOnly) o = AuthorList.fixAuthor_lastNameOnlyCommas((String) o, false);
else if (namesFf) o = AuthorList.fixAuthor_firstNameFirstCommas((String) o, abbr_names, false);
else if (namesLf) o = AuthorList.fixAuthor_lastNameFirstCommas((String) o, abbr_names, false);
return o;
}
public boolean hasField(BibtexEntry be, String field) {
// Returns true iff the entry has a nonzero value in its
// 'search' field.
return ((be != null) && (be.getField(field) != null));
}
public void updateTableFormat() {
// Read table columns from prefs:
String[] colSettings = Globals.prefs.getStringArray("columnNames");
columns = new String[colSettings.length][];
for (int i=0; i<colSettings.length; i++) {
String[] fields = colSettings[i].split(COL_DEFINITION_FIELD_SEPARATOR);
columns[i] = new String[fields.length];
for (int j = 0; j < fields.length; j++) {
columns[i][j] = fields[j];
}
}
// Read name format options:
showShort = Globals.prefs.getBoolean("showShort"); //MK:
namesNatbib = Globals.prefs.getBoolean("namesNatbib"); //MK:
namesLastOnly = Globals.prefs.getBoolean("namesLastOnly");
namesAsIs = Globals.prefs.getBoolean("namesAsIs");
abbr_names = Globals.prefs.getBoolean("abbrAuthorNames"); //MK:
namesFf = Globals.prefs.getBoolean("namesFf");
namesLf = !(namesAsIs || namesFf || namesNatbib || namesLastOnly); // None of the above.
// Set the icon columns, indicating the number of special columns to the left.
// We add those that are enabled in preferences.
iconCols.clear();
int coln = 1;
if (Globals.prefs.getBoolean("fileColumn"))
iconCols.put(coln++, FILE);
if (Globals.prefs.getBoolean("pdfColumn"))
iconCols.put(coln++, PDF);
if (Globals.prefs.getBoolean("urlColumn"))
iconCols.put(coln++, URL_);
if (Globals.prefs.getBoolean("citeseerColumn"))
iconCols.put(coln++, CITESEER);
if (Globals.prefs.getBoolean("arxivColumn"))
iconCols.put(coln++, ARXIV);
// Add 1 to the number of icon columns to get padleft.
padleft = 1 + iconCols.size();
// Set up the int[][] nameCols, to mark which columns should be
// treated as lists of names. This is to provide a correct presentation
// of names as efficiently as possible.
// Each subarray contains the column number (before padding) and the
// subfield number in case a column has fallback fields.
Vector<int[]> tmp = new Vector<int[]>(2, 1);
for (int i = 0; i < columns.length; i++) {
for (int j = 0; j < columns[i].length; j++) {
if (columns[i][j].equals("author")
|| columns[i][j].equals("editor")) {
tmp.add(new int[] {i, j});
}
}
}
nameCols = new int[tmp.size()][];
for (int i = 0; i < nameCols.length; i++) {
nameCols[i] = tmp.elementAt(i);
}
}
public boolean isIconColumn(int col) {
return (getIconTypeForColumn(col) != null);
}
static class NoSearchMatcher implements Matcher<BibtexEntry> {
public boolean matches(BibtexEntry object) {
return true;
}
}
static class SearchMatcher implements Matcher<BibtexEntry> {
private SearchRuleSet ruleSet;
private Hashtable<String, String> searchOptions;
public SearchMatcher(SearchRuleSet ruleSet, Hashtable<String, String> searchOptions) {
this.ruleSet = ruleSet;
this.searchOptions = searchOptions;
}
public boolean matches(BibtexEntry entry) {
int result = ruleSet.applyRule(searchOptions, entry);
return result > 0;
}
}
}