package net.sf.jabref; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; /** * This class is used to represent customized entry types. * */ public class CustomEntryType extends BibtexEntryType { private String name; private String[] req, opt; private String[][] reqSets = null; // Sets of either-or required fields, if any public CustomEntryType(String name_, String[] req_, String[] opt_) { name = name_; parseRequiredFields(req_); opt = opt_; } public CustomEntryType(String name_, String reqStr, String optStr) { name = name_; if (reqStr.length() == 0) req = new String[0]; else { parseRequiredFields(reqStr); } if (optStr.length() == 0) opt = new String[0]; else opt = optStr.split(";"); } protected void parseRequiredFields(String reqStr) { String[] parts = reqStr.split(";"); parseRequiredFields(parts); } protected void parseRequiredFields(String[] parts) { ArrayList<String> fields = new ArrayList<String>(); ArrayList<String[]> sets = new ArrayList<String[]>(); for (int i = 0; i < parts.length; i++) { String[] subParts = parts[i].split("/"); for (int j = 0; j < subParts.length; j++) { fields.add(subParts[j]); } // Check if we have either/or fields: if (subParts.length > 1) { sets.add(subParts); } } req = fields.toArray(new String[fields.size()]); if (sets.size() > 0) { reqSets = sets.toArray(new String[sets.size()][]); } } public String getName() { return name; } public String[] getOptionalFields() { return opt; } public String[] getRequiredFields() { return req; } public String[] getRequiredFieldsForCustomization() { return getRequiredFieldsString().split(";"); } // public boolean isTemporary public String describeRequiredFields() { StringBuffer sb = new StringBuffer(); for (int i=0; i<req.length; i++) { sb.append(req[i]); sb.append(((i<=req.length-1)&&(req.length>1))?", ":""); } return sb.toString(); } public String describeOptionalFields() { StringBuffer sb = new StringBuffer(); for (int i=0; i<opt.length; i++) { sb.append(opt[i]); sb.append(((i<=opt.length-1)&&(opt.length>1))?", ":""); } return sb.toString(); } /** * Check whether this entry's required fields are set, taking crossreferenced entries and * either-or fields into account: * @param entry The entry to check. * @param database The entry's database. * @return True if required fields are set, false otherwise. */ public boolean hasAllRequiredFields(BibtexEntry entry, BibtexDatabase database) { // First check if the bibtex key is set: if (entry.getField(BibtexFields.KEY_FIELD) == null) return false; // Then check other fields: boolean[] isSet = new boolean[req.length]; // First check for all fields, whether they are set here or in a crossref'd entry: for (int i=0; i<req.length; i++) isSet[i] = BibtexDatabase.getResolvedField(req[i], entry, database) != null; // Then go through all fields. If a field is not set, see if it is part of an either-or // set where another field is set. If not, return false: for (int i=0; i<req.length; i++) { if (!isSet[i]) { if (!isCoupledFieldSet(req[i], entry, database)) return false; } } // Passed all fields, so return true: return true; } protected boolean isCoupledFieldSet(String field, BibtexEntry entry, BibtexDatabase database) { if (reqSets == null) return false; for (int i=0; i<reqSets.length; i++) { boolean takesPart = false, oneSet = false; for (int j=0; j<reqSets[i].length; j++) { // If this is the field we're looking for, note that the field is part of the set: if (reqSets[i][j].equalsIgnoreCase(field)) takesPart = true; // If it is a different field, check if it is set: else if (BibtexDatabase.getResolvedField(reqSets[i][j], entry, database) != null) oneSet = true; } // Ths the field is part of the set, and at least one other field is set, return true: if (takesPart && oneSet) return true; } // No hits, so return false: return false; } /** * Get a String describing the required field set for this entry type. * @return Description of required field set for storage in preferences or bib file. */ public String getRequiredFieldsString() { StringBuilder sb = new StringBuilder(); int reqSetsPiv = 0; for (int i=0; i<req.length; i++) { if ((reqSets == null) || (reqSetsPiv == reqSets.length)) { sb.append(req[i]); } else if (req[i].equals(reqSets[reqSetsPiv][0])) { for (int j = 0; j < reqSets[reqSetsPiv].length; j++) { sb.append(reqSets[reqSetsPiv][j]); if (j < reqSets[reqSetsPiv].length-1) sb.append("/"); } // Skip next n-1 fields: i += reqSets[reqSetsPiv].length-1; reqSetsPiv++; } else sb.append(req[i]); if (i < req.length-1) sb.append(";"); } return sb.toString(); } public void save(Writer out) throws IOException { out.write("@comment{"); out.write(GUIGlobals.ENTRYTYPE_FLAG); out.write(getName()); out.write(": req["); out.write(getRequiredFieldsString()); /*StringBuffer sb = new StringBuffer(); for (int i=0; i<req.length; i++) { sb.append(req[i]); if (i<req.length-1) sb.append(";"); } out.write(sb.toString());*/ out.write("] opt["); StringBuilder sb = new StringBuilder(); for (int i=0; i<opt.length; i++) { sb.append(opt[i]); if (i<opt.length-1) sb.append(";"); } out.write(sb.toString()); out.write("]}"+Globals.NEWLINE); } public static CustomEntryType parseEntryType(String comment) { try { //if ((comment.length() < 9+GUIGlobals.ENTRYTYPE_FLAG.length()) // || comment //System.out.println(">"+comment+"<"); String rest; rest = comment.substring(GUIGlobals.ENTRYTYPE_FLAG.length()); int nPos = rest.indexOf(':'); String name = rest.substring(0, nPos); rest = rest.substring(nPos+2); int rPos = rest.indexOf(']'); if (rPos < 4) throw new IndexOutOfBoundsException(); String reqFields = rest.substring(4, rPos); //System.out.println(name+"\nr '"+reqFields+"'"); int oPos = rest.indexOf(']', rPos+1); String optFields = rest.substring(rPos+6, oPos); //System.out.println("o '"+optFields+"'"); return new CustomEntryType(name, reqFields, optFields); } catch (IndexOutOfBoundsException ex) { Globals.logger("Ill-formed entrytype comment in BibTeX file."); return null; } } }