Java tutorial
/* Copyright (C) 2003-2015 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.exporter.layout; import java.io.File; import java.nio.charset.Charset; import java.util.*; import java.util.regex.Pattern; import net.sf.jabref.gui.search.MatchesHighlighter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import net.sf.jabref.*; import net.sf.jabref.exporter.layout.format.NameFormatter; import net.sf.jabref.exporter.layout.format.NotFoundFormatter; import net.sf.jabref.gui.preftabs.NameFormatterTab; import net.sf.jabref.model.database.BibDatabase; import net.sf.jabref.model.entry.BibEntry; import net.sf.jabref.util.Util; class LayoutEntry { private LayoutFormatter[] option; // Formatter to be run after other formatters: private LayoutFormatter postFormatter; private String text; private LayoutEntry[] layoutEntries; private final int type; private final String classPrefix; private List<String> invalidFormatter; private static final Log LOGGER = LogFactory.getLog(LayoutEntry.class); public LayoutEntry(StringInt si, final String classPrefix_) { type = si.i; classPrefix = classPrefix_; if (type == LayoutHelper.IS_LAYOUT_TEXT) { text = si.s; } else if (type == LayoutHelper.IS_SIMPLE_FIELD) { text = si.s.trim(); } else if ((type == LayoutHelper.IS_FIELD_START) || (type == LayoutHelper.IS_FIELD_END)) { // Do nothing } else if (type == LayoutHelper.IS_OPTION_FIELD) { Vector<String> v = new Vector<>(); WSITools.tokenize(v, si.s, "\n"); if (v.size() == 1) { text = v.get(0); } else { text = v.get(0).trim(); option = LayoutEntry.getOptionalLayout(v.get(1), classPrefix); // See if there was an undefined formatter: for (LayoutFormatter anOption : option) { if (anOption instanceof NotFoundFormatter) { String notFound = ((NotFoundFormatter) anOption).getNotFound(); if (invalidFormatter == null) { invalidFormatter = new ArrayList<>(); } invalidFormatter.add(notFound); } } } } } public LayoutEntry(Vector<StringInt> parsedEntries, final String classPrefix_, int layoutType) { classPrefix = classPrefix_; Vector<StringInt> blockEntries = null; Vector<LayoutEntry> tmpEntries = new Vector<>(); LayoutEntry le; String blockStart = parsedEntries.get(0).s; String blockEnd = parsedEntries.get(parsedEntries.size() - 1).s; if (!blockStart.equals(blockEnd)) { LOGGER.warn("Field start and end entry must be equal."); } type = layoutType; text = blockEnd; for (StringInt parsedEntry : parsedEntries.subList(1, parsedEntries.size() - 1)) { if ((parsedEntry.i == LayoutHelper.IS_LAYOUT_TEXT) || (parsedEntry.i == LayoutHelper.IS_SIMPLE_FIELD)) { // Do nothing } else if ((parsedEntry.i == LayoutHelper.IS_FIELD_START) || (parsedEntry.i == LayoutHelper.IS_GROUP_START)) { blockEntries = new Vector<>(); blockStart = parsedEntry.s; } else if ((parsedEntry.i == LayoutHelper.IS_FIELD_END) || (parsedEntry.i == LayoutHelper.IS_GROUP_END)) { if (blockStart.equals(parsedEntry.s)) { blockEntries.add(parsedEntry); if (parsedEntry.i == LayoutHelper.IS_GROUP_END) { le = new LayoutEntry(blockEntries, classPrefix, LayoutHelper.IS_GROUP_START); } else { le = new LayoutEntry(blockEntries, classPrefix, LayoutHelper.IS_FIELD_START); } tmpEntries.add(le); blockEntries = null; } else { LOGGER.warn("Nested field entries are not implemented !!!"); } } else if (parsedEntry.i == LayoutHelper.IS_OPTION_FIELD) { // Do nothing } if (blockEntries == null) { tmpEntries.add(new LayoutEntry(parsedEntry, classPrefix)); } else { blockEntries.add(parsedEntry); } } layoutEntries = new LayoutEntry[tmpEntries.size()]; for (int i = 0; i < tmpEntries.size(); i++) { layoutEntries[i] = tmpEntries.get(i); // Note if one of the entries has an invalid formatter: if (layoutEntries[i].isInvalidFormatter()) { if (invalidFormatter == null) { invalidFormatter = new ArrayList<>(1); } invalidFormatter.addAll(layoutEntries[i].getInvalidFormatters()); } } } public void setPostFormatter(LayoutFormatter formatter) { this.postFormatter = formatter; } private String doLayout(BibEntry bibtex, BibDatabase database) { return doLayout(bibtex, database, null); } public String doLayout(BibEntry bibtex, BibDatabase database, Optional<Pattern> highlightPattern) { switch (type) { case LayoutHelper.IS_LAYOUT_TEXT: return text; case LayoutHelper.IS_SIMPLE_FIELD: String value = BibDatabase.getResolvedField(text, bibtex, database); if (value == null) { value = ""; } // If a post formatter has been set, call it: if (postFormatter != null) { value = postFormatter.format(value); } return value; case LayoutHelper.IS_FIELD_START: case LayoutHelper.IS_GROUP_START: { String field; if (type == LayoutHelper.IS_GROUP_START) { field = BibDatabase.getResolvedField(text, bibtex, database); } else if (text.matches(".*(;|(\\&+)).*")) { // split the strings along &, && or ; for AND formatter String[] parts = text.split("\\s*(;|(\\&+))\\s*"); field = null; for (String part : parts) { field = BibDatabase.getResolvedField(part, bibtex, database); if (field == null) { break; } } } else { // split the strings along |, || for OR formatter String[] parts = text.split("\\s*(\\|+)\\s*"); field = null; for (String part : parts) { field = BibDatabase.getResolvedField(part, bibtex, database); if (field != null) { break; } } } if ((field == null) || ((type == LayoutHelper.IS_GROUP_START) && field.equalsIgnoreCase(LayoutHelper.getCurrentGroup()))) { return null; } else { if (type == LayoutHelper.IS_GROUP_START) { LayoutHelper.setCurrentGroup(field); } StringBuilder sb = new StringBuilder(100); String fieldText; boolean previousSkipped = false; for (int i = 0; i < layoutEntries.length; i++) { fieldText = layoutEntries[i].doLayout(bibtex, database); if (fieldText == null) { if ((i + 1) < layoutEntries.length) { if (layoutEntries[i + 1].doLayout(bibtex, database).trim().isEmpty()) { i++; previousSkipped = true; continue; } } } else { // if previous was skipped --> remove leading line // breaks if (previousSkipped) { int eol = 0; while ((eol < fieldText.length()) && ((fieldText.charAt(eol) == '\n') || (fieldText.charAt(eol) == '\r'))) { eol++; } if (eol < fieldText.length()) { sb.append(fieldText.substring(eol)); } } else { //System.out.println("ENTRY-BLOCK: " + //layoutEntries[i].doLayout(bibtex)); /* * if fieldText is not null and the bibtexentry is marked * as a searchhit, try to highlight the searched words * */ if (bibtex.isSearchHit()) { sb.append(MatchesHighlighter.highlightWordsWithHTML(fieldText, highlightPattern)); } else { sb.append(fieldText); } } } previousSkipped = false; } return sb.toString(); } } case LayoutHelper.IS_FIELD_END: case LayoutHelper.IS_GROUP_END: return ""; case LayoutHelper.IS_OPTION_FIELD: String fieldEntry; if ("bibtextype".equals(text)) { fieldEntry = bibtex.getType().getName(); } else { // changed section begin - arudert // resolve field (recognized by leading backslash) or text String field = text.startsWith("\\") ? BibDatabase.getResolvedField(text.substring(1), bibtex, database) : BibDatabase.getText(text, database); // changed section end - arudert if (field == null) { fieldEntry = ""; } else { fieldEntry = field; } } //System.out.println("OPTION: "+option); if (option != null) { for (LayoutFormatter anOption : option) { fieldEntry = anOption.format(fieldEntry); } } // If a post formatter has been set, call it: if (postFormatter != null) { fieldEntry = postFormatter.format(fieldEntry); } return fieldEntry; case LayoutHelper.IS_ENCODING_NAME: // Printing the encoding name is not supported in entry layouts, only // in begin/end layouts. This prevents breakage if some users depend // on a field called "encoding". We simply return this field instead: return BibDatabase.getResolvedField("encoding", bibtex, database); default: return ""; } } // added section - begin (arudert) /** * Do layout for general formatters (no bibtex-entry fields). * * @param database * Bibtex Database * @return */ public String doLayout(BibDatabase database, Charset encoding) { if (type == LayoutHelper.IS_LAYOUT_TEXT) { return text; } else if (type == LayoutHelper.IS_SIMPLE_FIELD) { throw new UnsupportedOperationException("bibtex entry fields not allowed in begin or end layout"); } else if ((type == LayoutHelper.IS_FIELD_START) || (type == LayoutHelper.IS_GROUP_START)) { throw new UnsupportedOperationException("field and group starts not allowed in begin or end layout"); } else if ((type == LayoutHelper.IS_FIELD_END) || (type == LayoutHelper.IS_GROUP_END)) { throw new UnsupportedOperationException("field and group ends not allowed in begin or end layout"); } else if (type == LayoutHelper.IS_OPTION_FIELD) { String field = BibDatabase.getText(text, database); if (option != null) { for (LayoutFormatter anOption : option) { field = anOption.format(field); } } // If a post formatter has been set, call it: if (postFormatter != null) { field = postFormatter.format(field); } return field; } else if (type == LayoutHelper.IS_ENCODING_NAME) { return encoding.displayName(); } else if (type == LayoutHelper.IS_FILENAME) { File f = Globals.prefs.databaseFile; return f == null ? "" : f.getName(); } else if (type == LayoutHelper.IS_FILEPATH) { File f = Globals.prefs.databaseFile; return f == null ? "" : f.getPath(); } return ""; } // added section - end (arudert) private static LayoutFormatter getLayoutFormatterByClassName(String className, String classPrefix) throws Exception { if (!className.isEmpty()) { try { try { return (LayoutFormatter) Class.forName(classPrefix + className).newInstance(); } catch (Throwable ex2) { return (LayoutFormatter) Class.forName(className).newInstance(); } } catch (ClassNotFoundException ex) { throw new Exception("Formatter not found: " + className); } catch (InstantiationException ex) { throw new Exception(className + " cannot be instantiated."); } catch (IllegalAccessException ex) { throw new Exception(className + " cannot be accessed."); } } return null; } /** * Return an array of LayoutFormatters found in the given formatterName * string (in order of appearance). * */ private static LayoutFormatter[] getOptionalLayout(String formatterName, String classPrefix) { ArrayList<String[]> formatterStrings = Util.parseMethodsCalls(formatterName); ArrayList<LayoutFormatter> results = new ArrayList<>(formatterStrings.size()); Map<String, String> userNameFormatter = NameFormatterTab.getNameFormatters(); for (String[] strings : formatterStrings) { String className = strings[0].trim(); // Check if this is a name formatter defined by this export filter: if (Globals.prefs.customExportNameFormatters != null) { String contents = Globals.prefs.customExportNameFormatters.get(className); if (contents != null) { NameFormatter nf = new NameFormatter(); nf.setParameter(contents); results.add(nf); continue; } } // Try to load from formatters in formatter folder try { LayoutFormatter f = LayoutEntry.getLayoutFormatterByClassName(className, classPrefix); // If this formatter accepts an argument, check if we have one, and // set it if so: if ((f instanceof ParamLayoutFormatter) && (strings.length >= 2)) { ((ParamLayoutFormatter) f).setArgument(strings[1]); } results.add(f); continue; } catch (Exception ignored) { // Ignored } // Then check whether this is a user defined formatter String formatterParameter = userNameFormatter.get(className); if (formatterParameter != null) { NameFormatter nf = new NameFormatter(); nf.setParameter(formatterParameter); results.add(nf); continue; } // If not found throw exception... //return new LayoutFormatter[] {new NotFoundFormatter(className)}; results.add(new NotFoundFormatter(className)); //throw new Exception(Globals.lang("Formatter not found") + ": "+ className); } return results.toArray(new LayoutFormatter[results.size()]); } public boolean isInvalidFormatter() { return invalidFormatter != null; } public List<String> getInvalidFormatters() { return invalidFormatter; } }