/* Copyright (C) 2003-2012 JabRef contributors.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
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.JabRef;
import net.sf.jabref.JabRefPreferences;
import net.sf.jabref.SearchRuleSet;
import net.sf.jabref.Util;
import net.sf.jabref.specialfields.Priority;
import net.sf.jabref.specialfields.Rank;
import net.sf.jabref.specialfields.SpecialFieldValue;
import net.sf.jabref.specialfields.SpecialFieldsUtils;
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 ICON_COLUMN_PREFIX = "iconcol:";
// Values to gather iconImages for those columns
// These values are also used to put a heading into the table; see getColumnName(int)
public static final String[]
PDF = {"pdf", "ps"},
URL_ = {"url", "doi"},
CITESEER = {"citeseerurl"},
ARXIV = {"eprint"},
RANKING = {SpecialFieldsUtils.FIELDNAME_RANKING},
PRIORITY = {SpecialFieldsUtils.FIELDNAME_PRIORITY},
RELEVANCE = {SpecialFieldsUtils.FIELDNAME_RELEVANCE},
QUALITY = {SpecialFieldsUtils.FIELDNAME_QUALITY},
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;
}
/**
* @return the string that should be put in the column header
*/
public String getColumnName(int col) {
if (col == 0) {
return GUIGlobals.NUMBER_COL;
} else if (getIconTypeForColumn(col) != null) {
if (JabRef.jrf.prefs().getBoolean(JabRefPreferences.SHOWONELETTERHEADINGFORICONCOLUMNS)) {
return getIconTypeForColumn(col)[0].substring(0,1).toUpperCase();
} else {
return null;
}
}
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]);
}
/**
* Get the column title, or a string identifying the column if it is an icon
* column without a title.
* @param col The column number
* @return the String identifying the column
*/
public String getColumnType(int col) {
String name = getColumnName(col);
if (name != null)
return name;
String[] icon = getIconTypeForColumn(col);
if ((icon != null) && (icon.length > 0)) {
return ICON_COLUMN_PREFIX+icon[0];
}
return null;
}
/**
* 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;
}
/**
* Checks, if the Column (int col) is a Ranking-Column
* @param col Column Number
* @return Is Ranking-Column or not?
*/
public boolean isRankingColumn(int col) {
if (iconCols.get(col) != null) {
if (iconCols.get(col)[0] == RANKING[0]){
return true;
}
}
return false;
}
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));
// Handle priority column special
// Extra handling because the icon depends on a FieldValue
} else if (iconType[hasField].equals(PRIORITY[0])) {
SpecialFieldValue prio = Priority.getInstance().parse(be.getField(SpecialFieldsUtils.FIELDNAME_PRIORITY));
if (prio != null) {
// prio might be null if fieldvalue is an invalid value, therefore we check for != null
o = prio.createLabel();
}
// Handle ranking column special
// Extra handling because the icon depends on a FieldValue
} else if (iconType[hasField].equals(RANKING[0])) {
SpecialFieldValue rank = Rank.getInstance().parse(be.getField(SpecialFieldsUtils.FIELDNAME_RANKING));
if (rank != null) {
o = rank.createLabel();
}
} 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;
// Add special Icon Columns
if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SPECIALFIELDSENABLED)) {
if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_RANKING))
iconCols.put(coln++, RANKING);
if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_RELEVANCE))
iconCols.put(coln++, RELEVANCE);
if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_QUALITY))
iconCols.put(coln++, QUALITY);
if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_PRIORITY))
iconCols.put(coln++, PRIORITY);
}
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("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;
}
}
}