package org.jabref.gui; import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Locale; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; import org.jabref.Globals; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; /** * Dialog for replacing strings. */ class ReplaceStringDialog extends JabRefDialog { private final JTextField fieldsField = new JTextField("", 30); private final JTextField fromField = new JTextField("", 30); private final JTextField toField = new JTextField("", 30); private final JCheckBox selOnly = new JCheckBox(Localization.lang("Limit to selected entries"), false); private final JRadioButton allFi = new JRadioButton(Localization.lang("All fields"), true); private final JRadioButton field = new JRadioButton(Localization.lang("Limit to fields") + ":", false); private boolean okPressed; private String[] fieldStrings; private String fromString; private String toString; public ReplaceStringDialog(JabRefFrame parent) { super(parent, Localization.lang("Replace string"), true, ReplaceStringDialog.class); ButtonGroup bg = new ButtonGroup(); bg.add(allFi); bg.add(field); ActionListener okListener = e -> { fromString = fromField.getText(); toString = toField.getText(); if ("".equals(fromString)) { return; } okPressed = true; fieldStrings = fieldsField.getText().toLowerCase(Locale.ROOT).split(";"); dispose(); }; JButton ok = new JButton(Localization.lang("OK")); ok.addActionListener(okListener); toField.addActionListener(okListener); fieldsField.addActionListener(okListener); AbstractAction cancelAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { dispose(); } }; JButton cancel = new JButton(Localization.lang("Cancel")); cancel.addActionListener(cancelAction); // Key bindings: JPanel settings = new JPanel(); ActionMap am = settings.getActionMap(); InputMap im = settings.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); am.put("close", cancelAction); // Layout starts here. GridBagLayout gbl = new GridBagLayout(); settings.setLayout(gbl); JPanel opt = new JPanel(); opt.setLayout(gbl); JPanel main = new JPanel(); main.setLayout(gbl); settings.setBorder(BorderFactory.createTitledBorder (BorderFactory.createEtchedBorder(), Localization.lang("Replace string"))); main.setBorder(BorderFactory.createTitledBorder (BorderFactory.createEtchedBorder(), Localization.lang("Strings"))); // Settings panel: GridBagConstraints con = new GridBagConstraints(); con.fill = GridBagConstraints.HORIZONTAL; con.gridwidth = 2; con.weightx = 0; con.anchor = GridBagConstraints.WEST; con.gridy = 0; con.gridx = 0; con.insets = new Insets(3, 5, 3, 5); gbl.setConstraints(selOnly, con); settings.add(selOnly); con.gridy = 1; con.insets = new Insets(13, 5, 3, 5); gbl.setConstraints(allFi, con); settings.add(allFi); con.gridwidth = 1; con.gridy = 2; con.gridx = 0; con.insets = new Insets(3, 5, 3, 5); gbl.setConstraints(field, con); settings.add(field); con.gridx = 1; con.weightx = 1; gbl.setConstraints(fieldsField, con); settings.add(fieldsField); con.weightx = 0; con.gridx = 0; con.gridy = 0; JLabel fl = new JLabel(Localization.lang("Search for") + ":"); gbl.setConstraints(fl, con); main.add(fl); con.gridy = 1; JLabel tl = new JLabel(Localization.lang("Replace with") + ":"); gbl.setConstraints(tl, con); main.add(tl); con.weightx = 1; con.gridx = 1; con.gridy = 0; gbl.setConstraints(fromField, con); main.add(fromField); con.gridy = 1; gbl.setConstraints(toField, con); main.add(toField); // Option buttons: con.gridx = GridBagConstraints.RELATIVE; con.gridy = GridBagConstraints.RELATIVE; con.weightx = 1; con.gridwidth = 1; con.anchor = GridBagConstraints.EAST; con.fill = GridBagConstraints.NONE; gbl.setConstraints(ok, con); opt.add(ok); con.anchor = GridBagConstraints.WEST; con.gridwidth = GridBagConstraints.REMAINDER; gbl.setConstraints(cancel, con); opt.add(cancel); getContentPane().add(main, BorderLayout.NORTH); getContentPane().add(settings, BorderLayout.CENTER); getContentPane().add(opt, BorderLayout.SOUTH); pack(); this.setLocationRelativeTo(parent); } public boolean okPressed() { return okPressed; } private boolean allFields() { return allFi.isSelected(); } public boolean selOnly() { return selOnly.isSelected(); } /** * Does the actual operation on a Bibtex entry based on the * settings specified in this same dialog. Returns the number of * occurences replaced. */ public int replace(BibEntry be, NamedCompound ce) { int counter = 0; if (allFields()) { for (String s : be.getFieldNames()) { if (!s.equals(BibEntry.KEY_FIELD)) { counter += replaceField(be, s, ce); } } } else { for (String fld : fieldStrings) { if (!fld.equals(BibEntry.KEY_FIELD)) { counter += replaceField(be, fld, ce); } } } return counter; } private int replaceField(BibEntry be, String fieldname, NamedCompound ce) { if (!be.hasField(fieldname)) { return 0; } String txt = be.getField(fieldname).get(); StringBuilder sb = new StringBuilder(); int ind; int piv = 0; int counter = 0; int len1 = fromString.length(); while ((ind = txt.indexOf(fromString, piv)) >= 0) { counter++; sb.append(txt.substring(piv, ind)); // Text leading up to s1 sb.append(toString); // Insert s2 piv = ind + len1; } sb.append(txt.substring(piv)); String newStr = sb.toString(); be.setField(fieldname, newStr); ce.addEdit(new UndoableFieldChange(be, fieldname, txt, newStr)); return counter; } }