Java tutorial
/* Copyright (C) 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.io.File; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import com.jgoodies.forms.factories.Borders; import net.sf.jabref.*; import net.sf.jabref.external.ExternalFileType; import net.sf.jabref.imports.HTMLConverter; import net.sf.jabref.imports.CaseKeeper; import net.sf.jabref.imports.UnitFormatter; import net.sf.jabref.undo.NamedCompound; import net.sf.jabref.undo.UndoableFieldChange; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import net.sf.jabref.util.DOIUtil; import net.sf.jabref.util.FileUtil; import net.sf.jabref.util.MonthUtil; import net.sf.jabref.util.Util; public class CleanUpAction extends AbstractWorker { private final Logger logger = Logger.getLogger(CleanUpAction.class.getName()); private final static String AKS_AUTO_NAMING_PDFS_AGAIN = "AskAutoNamingPDFsAgain"; private final static String CLEANUP_DOI = "CleanUpDOI"; private final static String CLEANUP_MONTH = "CleanUpMonth"; private final static String CLEANUP_PAGENUMBERS = "CleanUpPageNumbers"; private final static String CLEANUP_MAKEPATHSRELATIVE = "CleanUpMakePathsRelative"; private final static String CLEANUP_RENAMEPDF = "CleanUpRenamePDF"; private final static String CLEANUP_RENAMEPDF_ONLYRELATIVE_PATHS = "CleanUpRenamePDFonlyRelativePaths"; private final static String CLEANUP_UPGRADE_EXTERNAL_LINKS = "CleanUpUpgradeExternalLinks"; private final static String CLEANUP_SUPERSCRIPTS = "CleanUpSuperscripts"; private final static String CLEANUP_HTML = "CleanUpHTML"; private final static String CLEANUP_CASE = "CleanUpCase"; private final static String CLEANUP_LATEX = "CleanUpLaTeX"; private final static String CLEANUP_UNITS = "CleanUpUnits"; private final static String CLEANUP_UNICODE = "CleanUpUnicode"; private final static String CLEANUP_CONVERTTOBIBLATEX = "CleanUpConvertToBiblatex"; public static void putDefaults(HashMap<String, Object> defaults) { defaults.put(CleanUpAction.AKS_AUTO_NAMING_PDFS_AGAIN, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_SUPERSCRIPTS, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_DOI, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_MONTH, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_PAGENUMBERS, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_MAKEPATHSRELATIVE, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_RENAMEPDF, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_RENAMEPDF_ONLYRELATIVE_PATHS, Boolean.FALSE); defaults.put(CleanUpAction.CLEANUP_UPGRADE_EXTERNAL_LINKS, Boolean.FALSE); defaults.put(CleanUpAction.CLEANUP_MAKEPATHSRELATIVE, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_HTML, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_CASE, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_LATEX, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_UNITS, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_UNICODE, Boolean.TRUE); defaults.put(CleanUpAction.CLEANUP_CONVERTTOBIBLATEX, Boolean.FALSE); } private JCheckBox cleanUpSuperscrips; private JCheckBox cleanUpDOI; private JCheckBox cleanUpMonth; private JCheckBox cleanUpPageNumbers; private JCheckBox cleanUpMakePathsRelative; private JCheckBox cleanUpRenamePDF; private JCheckBox cleanUpRenamePDFonlyRelativePaths; private JCheckBox cleanUpUpgradeExternalLinks; private JCheckBox cleanUpHTML; private JCheckBox cleanUpCase; private JCheckBox cleanUpLaTeX; private JCheckBox cleanUpUnits; private JCheckBox cleanUpUnicode; private JCheckBox cleanUpBiblatex; private JPanel optionsPanel = new JPanel(); private final BasePanel panel; private final JabRefFrame frame; // global variable to count unsuccessful renames private int unsuccesfullRenames = 0; public CleanUpAction(BasePanel panel) { this.panel = panel; this.frame = panel.frame(); initOptionsPanel(); } private void initOptionsPanel() { cleanUpSuperscrips = new JCheckBox(Globals.lang("Convert 1st, 2nd, ... to real superscripts")); cleanUpDOI = new JCheckBox( Globals.lang("Move DOIs from note and URL field to DOI field and remove http prefix")); cleanUpMonth = new JCheckBox(Globals.lang("Format content of month field to #mon#")); cleanUpPageNumbers = new JCheckBox(Globals.lang("Ensure that page ranges are of the form num1--num2")); cleanUpMakePathsRelative = new JCheckBox(Globals.lang("Make paths of linked files relative (if possible)")); cleanUpRenamePDF = new JCheckBox(Globals.lang("Rename PDFs to given file name format pattern")); cleanUpRenamePDF.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { cleanUpRenamePDFonlyRelativePaths.setEnabled(cleanUpRenamePDF.isSelected()); } }); cleanUpRenamePDFonlyRelativePaths = new JCheckBox(Globals.lang("Rename only PDFs having a relative path")); cleanUpUpgradeExternalLinks = new JCheckBox( Globals.lang("Upgrade external PDF/PS links to use the '%0' field.", GUIGlobals.FILE_FIELD)); cleanUpHTML = new JCheckBox(Globals.lang("Run HTML converter on title")); cleanUpCase = new JCheckBox(Globals.lang("Run filter on title keeping the case of selected words")); cleanUpLaTeX = new JCheckBox( Globals.lang("Remove unneccessary $, {, and } and move adjacent numbers into equations")); cleanUpUnits = new JCheckBox( Globals.lang("Add brackets and replace separators with their non-breaking version for units")); cleanUpUnicode = new JCheckBox(Globals.lang("Run Unicode converter on title, author(s), and abstract")); cleanUpBiblatex = new JCheckBox(Globals.lang( "Convert to BibLatex format (for example, move the value of the 'journal' field to 'journaltitle')")); optionsPanel = new JPanel(); retrieveSettings(); FormLayout layout = new FormLayout("left:15dlu,pref:grow", "pref, pref, pref, pref, pref, pref, pref, pref, pref, pref, pref, pref, pref, pref, pref"); DefaultFormBuilder builder = new DefaultFormBuilder(layout, optionsPanel); builder.border(Borders.DIALOG); CellConstraints cc = new CellConstraints(); builder.add(cleanUpHTML, cc.xyw(1, 1, 2)); builder.add(cleanUpUnicode, cc.xyw(1, 2, 2)); builder.add(cleanUpCase, cc.xyw(1, 3, 2)); builder.add(cleanUpLaTeX, cc.xyw(1, 4, 2)); builder.add(cleanUpUnits, cc.xyw(1, 5, 2)); builder.add(cleanUpSuperscrips, cc.xyw(1, 6, 2)); builder.add(cleanUpDOI, cc.xyw(1, 7, 2)); builder.add(cleanUpMonth, cc.xyw(1, 8, 2)); builder.add(cleanUpPageNumbers, cc.xyw(1, 9, 2)); builder.add(cleanUpUpgradeExternalLinks, cc.xyw(1, 10, 2)); builder.add(cleanUpMakePathsRelative, cc.xyw(1, 11, 2)); builder.add(cleanUpRenamePDF, cc.xyw(1, 12, 2)); String currentPattern = Globals.lang("File name format pattern").concat(": ") .concat(Globals.prefs.get(ImportSettingsTab.PREF_IMPORT_FILENAMEPATTERN)); builder.add(new JLabel(currentPattern), cc.xyw(2, 13, 1)); builder.add(cleanUpRenamePDFonlyRelativePaths, cc.xyw(2, 14, 1)); builder.add(cleanUpBiblatex, cc.xyw(1, 15, 2)); } private void retrieveSettings() { cleanUpSuperscrips.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_SUPERSCRIPTS)); cleanUpDOI.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_DOI)); cleanUpMonth.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_MONTH)); cleanUpPageNumbers.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_PAGENUMBERS)); cleanUpMakePathsRelative.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_MAKEPATHSRELATIVE)); cleanUpRenamePDF.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_RENAMEPDF)); cleanUpRenamePDFonlyRelativePaths .setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_RENAMEPDF_ONLYRELATIVE_PATHS)); cleanUpRenamePDFonlyRelativePaths.setEnabled(cleanUpRenamePDF.isSelected()); cleanUpUpgradeExternalLinks .setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_UPGRADE_EXTERNAL_LINKS)); cleanUpHTML.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_HTML)); cleanUpCase.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_CASE)); cleanUpLaTeX.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_LATEX)); cleanUpUnits.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_UNITS)); cleanUpUnicode.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_UNICODE)); cleanUpBiblatex.setSelected(Globals.prefs.getBoolean(CleanUpAction.CLEANUP_CONVERTTOBIBLATEX)); } private void storeSettings() { Globals.prefs.putBoolean(CleanUpAction.CLEANUP_SUPERSCRIPTS, cleanUpSuperscrips.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_DOI, cleanUpDOI.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_MONTH, cleanUpMonth.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_PAGENUMBERS, cleanUpPageNumbers.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_MAKEPATHSRELATIVE, cleanUpMakePathsRelative.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_RENAMEPDF, cleanUpRenamePDF.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_RENAMEPDF_ONLYRELATIVE_PATHS, cleanUpRenamePDFonlyRelativePaths.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_UPGRADE_EXTERNAL_LINKS, cleanUpUpgradeExternalLinks.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_HTML, cleanUpHTML.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_CASE, cleanUpCase.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_LATEX, cleanUpLaTeX.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_UNITS, cleanUpUnits.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_UNICODE, cleanUpUnicode.isSelected()); Globals.prefs.putBoolean(CleanUpAction.CLEANUP_CONVERTTOBIBLATEX, cleanUpBiblatex.isSelected()); } private int showCleanUpDialog() { String dialogTitle = Globals.lang("Cleanup entries"); Object[] messages = { Globals.lang("What would you like to clean up?"), optionsPanel }; return JOptionPane.showConfirmDialog(frame, messages, dialogTitle, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); } private boolean cancelled; private int modifiedEntriesCount; int numSelected; @Override public void init() { cancelled = false; modifiedEntriesCount = 0; int numSelected = panel.getSelectedEntries().length; if (numSelected == 0) { // None selected. Inform the user to select entries first. JOptionPane.showMessageDialog(frame, Globals.lang("First select entries to clean up."), Globals.lang("Cleanup entry"), JOptionPane.INFORMATION_MESSAGE); cancelled = true; return; } frame.block(); panel.output(Globals.lang("Doing a cleanup for %0 entries...", Integer.toString(numSelected))); } @Override public void run() { if (cancelled) { return; } int choice = showCleanUpDialog(); if (choice != JOptionPane.OK_OPTION) { cancelled = true; return; } storeSettings(); boolean choiceCleanUpSuperscripts = cleanUpSuperscrips.isSelected(), choiceCleanUpDOI = cleanUpDOI.isSelected(), choiceCleanUpMonth = cleanUpMonth.isSelected(), choiceCleanUpPageNumbers = cleanUpPageNumbers.isSelected(), choiceCleanUpUpgradeExternalLinks = cleanUpUpgradeExternalLinks.isSelected(), choiceMakePathsRelative = cleanUpMakePathsRelative.isSelected(), choiceRenamePDF = cleanUpRenamePDF.isSelected(), choiceConvertHTML = cleanUpHTML.isSelected(), choiceConvertCase = cleanUpCase.isSelected(), choiceConvertLaTeX = cleanUpLaTeX.isSelected(), choiceConvertUnits = cleanUpUnits.isSelected(), choiceConvertUnicode = cleanUpUnicode.isSelected(), choiceConvertToBiblatex = cleanUpBiblatex.isSelected(); if (choiceRenamePDF && Globals.prefs.getBoolean(CleanUpAction.AKS_AUTO_NAMING_PDFS_AGAIN)) { CheckBoxMessage cbm = new CheckBoxMessage( Globals.lang("Auto-generating PDF-Names does not support undo. Continue?"), Globals.lang("Disable this confirmation dialog"), false); int answer = JOptionPane.showConfirmDialog(frame, cbm, Globals.lang("Autogenerate PDF Names"), JOptionPane.YES_NO_OPTION); if (cbm.isSelected()) { Globals.prefs.putBoolean(CleanUpAction.AKS_AUTO_NAMING_PDFS_AGAIN, false); } if (answer == JOptionPane.NO_OPTION) { cancelled = true; return; } } // first upgrade the external links // we have to use it separately as the Utils function generates a separate Named Compound if (choiceCleanUpUpgradeExternalLinks) { NamedCompound ce = Util.upgradePdfPsToFile(Arrays.asList(panel.getSelectedEntries()), new String[] { "pdf", "ps" }); if (ce.hasEdits()) { panel.undoManager.addEdit(ce); panel.markBaseChanged(); panel.updateEntryEditorIfShowing(); panel.output(Globals.lang("Upgraded links.")); } } for (BibtexEntry entry : panel.getSelectedEntries()) { // undo granularity is on entry level NamedCompound ce = new NamedCompound(Globals.lang("Cleanup entry")); if (choiceCleanUpSuperscripts) { doCleanUpSuperscripts(entry, ce); } if (choiceCleanUpDOI) { doCleanUpDOI(entry, ce); } if (choiceCleanUpMonth) { doCleanUpMonth(entry, ce); } if (choiceCleanUpPageNumbers) { doCleanUpPageNumbers(entry, ce); } fixWrongFileEntries(entry, ce); if (choiceMakePathsRelative) { doMakePathsRelative(entry, ce); } if (choiceRenamePDF) { doRenamePDFs(entry, ce); } if (choiceConvertHTML) { doConvertHTML(entry, ce); } if (choiceConvertUnits) { doConvertUnits(entry, ce); } if (choiceConvertCase) { doConvertCase(entry, ce); } if (choiceConvertLaTeX) { doConvertLaTeX(entry, ce); } if (choiceConvertUnicode) { doConvertUnicode(entry, ce); } if (choiceConvertToBiblatex) { doConvertToBiblatex(entry, ce); } ce.end(); if (ce.hasEdits()) { modifiedEntriesCount++; panel.undoManager.addEdit(ce); } } } @Override public void update() { if (cancelled) { frame.unblock(); return; } if (unsuccesfullRenames > 0) { //Rename failed for at least one entry JOptionPane.showMessageDialog(frame, Globals.lang("File rename failed for") + " " + unsuccesfullRenames + " " + Globals.lang("entries") + ".", Globals.lang("Autogenerate PDF Names"), JOptionPane.INFORMATION_MESSAGE); } if (modifiedEntriesCount > 0) { panel.updateEntryEditorIfShowing(); panel.markBaseChanged(); } String message; switch (modifiedEntriesCount) { case 0: message = Globals.lang("No entry needed a clean up"); break; case 1: message = Globals.lang("One entry needed a clean up"); break; default: message = Globals.lang("%0 entries needed a clean up", Integer.toString(modifiedEntriesCount)); break; } panel.output(message); frame.unblock(); } /** * Converts the text in 1st, 2nd, ... to real superscripts by wrapping in \textsuperscript{st}, ... */ private void doCleanUpSuperscripts(BibtexEntry entry, NamedCompound ce) { final String field = "booktitle"; String oldValue = entry.getField(field); if (oldValue == null) { return; } String newValue = oldValue.replaceAll(" (\\d+)(st|nd|rd|th) ", " $1\\\\textsuperscript{$2} "); if (!oldValue.equals(newValue)) { entry.setField(field, newValue); ce.addEdit(new UndoableFieldChange(entry, field, oldValue, newValue)); } } /** * Removes the http://... for each DOI * Moves DOIs from URL and NOTE filed to DOI field * @param ce */ private void doCleanUpDOI(BibtexEntry bes, NamedCompound ce) { // fields to check String[] fields = { "note", "url", "ee" }; // First check if the DOI Field is empty if (bes.getField("doi") != null) { String doiFieldValue = bes.getField("doi"); if (DOIUtil.checkForDOIwithHTTPprefix(doiFieldValue)) { String newValue = DOIUtil.getDOI(doiFieldValue); ce.addEdit(new UndoableFieldChange(bes, "doi", doiFieldValue, newValue)); bes.setField("doi", newValue); } if (DOIUtil.checkForPlainDOI(doiFieldValue)) { // DOI field seems to contain DOI // cleanup note, url, ee field // we do NOT copy values to the DOI field as the DOI field contains a DOI! for (String field : fields) { if (DOIUtil.checkForPlainDOI(bes.getField(field))) { DOIUtil.removeDOIfromBibtexEntryField(bes, field, ce); } } } } else { // As the DOI field is empty we now check if note, url, or ee field contains a DOI for (String field : fields) { if (DOIUtil.checkForPlainDOI(bes.getField(field))) { // update DOI String oldValue = bes.getField("doi"); String newValue = DOIUtil.getDOI(bes.getField(field)); ce.addEdit(new UndoableFieldChange(bes, "doi", oldValue, newValue)); bes.setField("doi", newValue); DOIUtil.removeDOIfromBibtexEntryField(bes, field, ce); } } } } private void doCleanUpMonth(BibtexEntry entry, NamedCompound ce) { // implementation based on patch 3470076 by Mathias Walter String oldValue = entry.getField("month"); if (oldValue == null) { return; } String newValue = oldValue; MonthUtil.Month month = MonthUtil.getMonth(oldValue); if (month.isValid()) { newValue = month.bibtexFormat; } if (!oldValue.equals(newValue)) { entry.setField("month", newValue); ce.addEdit(new UndoableFieldChange(entry, "month", oldValue, newValue)); } } private void doCleanUpPageNumbers(BibtexEntry entry, NamedCompound ce) { String oldValue = entry.getField("pages"); if (oldValue == null) { return; } String newValue = oldValue.replaceAll(" *(\\d+) *- *(\\d+) *", "$1--$2"); if (!oldValue.equals(newValue)) { entry.setField("pages", newValue); ce.addEdit(new UndoableFieldChange(entry, "pages", oldValue, newValue)); } } private void fixWrongFileEntries(BibtexEntry entry, NamedCompound ce) { String oldValue = entry.getField(GUIGlobals.FILE_FIELD); if (oldValue == null) { return; } FileListTableModel flModel = new FileListTableModel(); flModel.setContent(oldValue); if (flModel.getRowCount() == 0) { return; } boolean changed = false; for (int i = 0; i < flModel.getRowCount(); i++) { FileListEntry flEntry = flModel.getEntry(i); String link = flEntry.getLink(); String description = flEntry.getDescription(); if (link.equals("") && (!description.equals(""))) { // link and description seem to be switched, quickly fix that flEntry.setLink(flEntry.getDescription()); flEntry.setDescription(""); changed = true; } } if (changed) { String newValue = flModel.getStringRepresentation(); assert (!oldValue.equals(newValue)); entry.setField(GUIGlobals.FILE_FIELD, newValue); ce.addEdit(new UndoableFieldChange(entry, GUIGlobals.FILE_FIELD, oldValue, newValue)); } } private void doMakePathsRelative(BibtexEntry entry, NamedCompound ce) { String oldValue = entry.getField(GUIGlobals.FILE_FIELD); if (oldValue == null) { return; } FileListTableModel flModel = new FileListTableModel(); flModel.setContent(oldValue); if (flModel.getRowCount() == 0) { return; } boolean changed = false; for (int i = 0; i < flModel.getRowCount(); i++) { FileListEntry flEntry = flModel.getEntry(i); String oldFileName = flEntry.getLink(); String newFileName = FileUtil.shortenFileName(new File(oldFileName), panel.metaData().getFileDirectory(GUIGlobals.FILE_FIELD)).toString(); if (!oldFileName.equals(newFileName)) { flEntry.setLink(newFileName); changed = true; } } if (changed) { String newValue = flModel.getStringRepresentation(); assert (!oldValue.equals(newValue)); entry.setField(GUIGlobals.FILE_FIELD, newValue); ce.addEdit(new UndoableFieldChange(entry, GUIGlobals.FILE_FIELD, oldValue, newValue)); } } private void doRenamePDFs(BibtexEntry entry, NamedCompound ce) { //Extract the path String oldValue = entry.getField(GUIGlobals.FILE_FIELD); if (oldValue == null) { return; } FileListTableModel flModel = new FileListTableModel(); flModel.setContent(oldValue); if (flModel.getRowCount() == 0) { return; } boolean changed = false; for (int i = 0; i < flModel.getRowCount(); i++) { String realOldFilename = flModel.getEntry(i).getLink(); if (cleanUpRenamePDFonlyRelativePaths.isSelected() && (new File(realOldFilename).isAbsolute())) { continue; } String newFilename = Util.getLinkedFileName(panel.database(), entry); //String oldFilename = bes.getField(GUIGlobals.FILE_FIELD); // would have to be stored for undoing purposes //Add extension to newFilename newFilename = newFilename + "." + flModel.getEntry(i).getType().getExtension(); //get new Filename with path //Create new Path based on old Path and new filename File expandedOldFile = FileUtil.expandFilename(realOldFilename, panel.metaData().getFileDirectory(GUIGlobals.FILE_FIELD)); if (expandedOldFile.getParent() == null) { // something went wrong. Just skipt his entry continue; } String newPath = expandedOldFile.getParent().concat(System.getProperty("file.separator")) .concat(newFilename); if (new File(newPath).exists()) { // we do not overwrite files // TODO: we could check here if the newPath file is linked with the current entry. And if not, we could add a link continue; } //do rename boolean renameSuccesfull = FileUtil.renameFile(expandedOldFile.toString(), newPath); if (renameSuccesfull) { changed = true; //Change the path for this entry String description = flModel.getEntry(i).getDescription(); ExternalFileType type = flModel.getEntry(i).getType(); flModel.removeEntry(i); // we cannot use "newPath" to generate a FileListEntry as newPath is absolute, but we want to keep relative paths whenever possible File parent = (new File(realOldFilename)).getParentFile(); String newFileEntryFileName; if (parent == null) { newFileEntryFileName = newFilename; } else { newFileEntryFileName = parent.toString().concat(System.getProperty("file.separator")) .concat(newFilename); } flModel.addEntry(i, new FileListEntry(description, newFileEntryFileName, type)); } else { unsuccesfullRenames++; } } if (changed) { String newValue = flModel.getStringRepresentation(); assert (!oldValue.equals(newValue)); entry.setField(GUIGlobals.FILE_FIELD, newValue); //we put an undo of the field content here //the file is not being renamed back, which leads to inconsostencies //if we put a null undo object here, the change by "doMakePathsRelative" would overwrite the field value nevertheless. ce.addEdit(new UndoableFieldChange(entry, GUIGlobals.FILE_FIELD, oldValue, newValue)); } } /** * Converts HTML code to LaTeX code */ private void doConvertHTML(BibtexEntry entry, NamedCompound ce) { final String field = "title"; String oldValue = entry.getField(field); if (oldValue == null) { return; } final HTMLConverter htmlConverter = new HTMLConverter(); String newValue = htmlConverter.format(oldValue); if (!oldValue.equals(newValue)) { entry.setField(field, newValue); ce.addEdit(new UndoableFieldChange(entry, field, oldValue, newValue)); } } /** * Converts Unicode characters to LaTeX code */ private void doConvertUnicode(BibtexEntry entry, NamedCompound ce) { final String[] fields = { "title", "author", "abstract" }; for (String field : fields) { String oldValue = entry.getField(field); if (oldValue == null) { return; } final HTMLConverter htmlConverter = new HTMLConverter(); String newValue = htmlConverter.formatUnicode(oldValue); if (!oldValue.equals(newValue)) { entry.setField(field, newValue); ce.addEdit(new UndoableFieldChange(entry, field, oldValue, newValue)); } } } /** * Adds curly brackets {} around keywords */ private void doConvertCase(BibtexEntry entry, NamedCompound ce) { final String field = "title"; String oldValue = entry.getField(field); if (oldValue == null) { return; } final CaseKeeper caseKeeper = new CaseKeeper(); String newValue = caseKeeper.format(oldValue); if (!oldValue.equals(newValue)) { entry.setField(field, newValue); ce.addEdit(new UndoableFieldChange(entry, field, oldValue, newValue)); } } private void doConvertUnits(BibtexEntry entry, NamedCompound ce) { final String field = "title"; String oldValue = entry.getField(field); if (oldValue == null) { return; } final UnitFormatter unitFormatter = new UnitFormatter(); String newValue = unitFormatter.format(oldValue); if (!oldValue.equals(newValue)) { entry.setField(field, newValue); ce.addEdit(new UndoableFieldChange(entry, field, oldValue, newValue)); } } private void doConvertLaTeX(BibtexEntry entry, NamedCompound ce) { final String field = "title"; String oldValue = entry.getField(field); if (oldValue == null) { return; } String newValue = oldValue; // Remove redundant $, {, and }, but not if the } is part of a command argument: \mbox{-}{GPS} should not be adjusted newValue = newValue.replace("$$", "") .replaceAll("(?<!\\\\[\\p{Alpha}]{0,100}\\{[^\\}]{0,100})\\}([-/ ]?)\\{", "$1"); // Move numbers, +, -, /, and brackets into equations // System.err.println(newValue); newValue = newValue.replaceAll("(([^$]|\\\\\\$)*)\\$", "$1@@"); // Replace $, but not \$ with @@ // System.err.println(newValue); newValue = newValue.replaceAll("([^@]*)@@([^@]*)@@", "$1\\$$2@@"); // Replace every other @@ with $ // System.err.println(newValue); //newValue = newValue.replaceAll("([0-9\\(\\.]+) \\$","\\$$1\\\\ "); // Move numbers followed by a space left of $ inside the equation, e.g., 0.35 $\mu$m // System.err.println(newValue); newValue = newValue.replaceAll("([0-9\\(\\.]+[ ]?[-+/]?[ ]?)\\$", "\\$$1"); // Move numbers, possibly with operators +, -, or /, left of $ into the equation // System.err.println(newValue); newValue = newValue.replaceAll("@@([ ]?[-+/]?[ ]?[0-9\\)\\.]+)", " $1@@"); // Move numbers right of @@ into the equation // System.err.println(newValue); newValue = newValue.replace("@@", "$"); // Replace all @@ with $ // System.err.println(newValue); newValue = newValue.replace(" ", " "); // Clean up newValue = newValue.replace("$$", ""); newValue = newValue.replace(" )$", ")$"); if (!oldValue.equals(newValue)) { entry.setField(field, newValue); ce.addEdit(new UndoableFieldChange(entry, field, oldValue, newValue)); } } /** * Converts to BibLatex format */ private void doConvertToBiblatex(BibtexEntry entry, NamedCompound ce) { for (Map.Entry<String, String> alias : BibtexEntry.FieldAliasesOldToNew.entrySet()) { String oldFieldName = alias.getKey(); String newFieldName = alias.getValue(); String oldValue = entry.getField(oldFieldName); String newValue = entry.getField(newFieldName); if ((oldValue != null) && (oldValue.length() > 0) && (newValue == null)) { // There is content in the old field and no value in the new, so just copy entry.setField(newFieldName, oldValue); ce.addEdit(new UndoableFieldChange(entry, newFieldName, null, oldValue)); entry.setField(oldFieldName, null); ce.addEdit(new UndoableFieldChange(entry, oldFieldName, oldValue, null)); } } // Dates: create date out of year and month, save it and delete old fields if ((entry.getField("date") == null) || (entry.getField("date").length() == 0)) { String newDate = entry.getFieldOrAlias("date"); String oldYear = entry.getField("year"); String oldMonth = entry.getField("month"); entry.setField("date", newDate); entry.setField("year", null); entry.setField("month", null); ce.addEdit(new UndoableFieldChange(entry, "date", null, newDate)); ce.addEdit(new UndoableFieldChange(entry, "year", oldYear, null)); ce.addEdit(new UndoableFieldChange(entry, "month", oldMonth, null)); } } }