package org.jabref.gui.mergeentries; import java.awt.event.ActionEvent; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JSeparator; import org.jabref.gui.BasePanel; import org.jabref.gui.JabRefDialog; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableChangeType; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.WindowLocation; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.InternalBibtexFields; import org.jabref.preferences.JabRefPreferences; import com.jgoodies.forms.builder.ButtonBarBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.ColumnSpec; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.RowSpec; /** * Dialog for merging Bibtex entry with fetched data */ public class MergeFetchedEntryDialog extends JabRefDialog { private static final String MARGIN = "5px"; private final BasePanel panel; private final CellConstraints cc = new CellConstraints(); private final BibEntry originalEntry; private final BibEntry fetchedEntry; private NamedCompound ce; private MergeEntries mergeEntries; private final String type; public MergeFetchedEntryDialog(BasePanel panel, BibEntry originalEntry, BibEntry fetchedEntry, String type) { super(panel.frame(), Localization.lang("Merge entry with %0 information", type), true, MergeFetchedEntryDialog.class); this.panel = panel; this.originalEntry = originalEntry; this.fetchedEntry = fetchedEntry; this.type = type; // Start setting up the dialog init(); } /** * Sets up the dialog */ private void init() { mergeEntries = new MergeEntries(this.originalEntry, this.fetchedEntry, Localization.lang("Original entry"), Localization.lang("Entry from %0", type), panel.getBibDatabaseContext().getMode()); // Create undo-compound ce = new NamedCompound(Localization.lang("Merge entry with %0 information", type)); FormLayout layout = new FormLayout("fill:700px:grow", "fill:400px:grow, 4px, p, 5px, p"); this.setLayout(layout); this.add(mergeEntries.getMergeEntryPanel(), cc.xy(1, 1)); this.add(new JSeparator(), cc.xy(1, 3)); // Create buttons ButtonBarBuilder bb = new ButtonBarBuilder(); bb.addGlue(); JButton cancel = new JButton(new CancelAction()); JButton replaceEntry = new JButton(new ReplaceAction()); bb.addButton(replaceEntry, cancel); this.add(bb.getPanel(), cc.xy(1, 5)); // Add some margin around the layout layout.appendRow(RowSpec.decode(MARGIN)); layout.appendColumn(ColumnSpec.decode(MARGIN)); layout.insertRow(1, RowSpec.decode(MARGIN)); layout.insertColumn(1, ColumnSpec.decode(MARGIN)); WindowLocation pw = new WindowLocation(this, JabRefPreferences.MERGEENTRIES_POS_X, JabRefPreferences.MERGEENTRIES_POS_Y, JabRefPreferences.MERGEENTRIES_SIZE_X, JabRefPreferences.MERGEENTRIES_SIZE_Y); pw.displayWindowAtStoredLocation(); } private class CancelAction extends AbstractAction { CancelAction() { putValue(Action.NAME, Localization.lang("Cancel")); } @Override public void actionPerformed(ActionEvent e) { panel.output(Localization.lang("Canceled merging entries")); dispose(); } } private class ReplaceAction extends AbstractAction { ReplaceAction() { putValue(Action.NAME, Localization.lang("Replace original entry")); } @Override public void actionPerformed(ActionEvent e) { BibEntry mergedEntry = mergeEntries.getMergeEntry(); // Updated the original entry with the new fields Set<String> jointFields = new TreeSet<>(mergedEntry.getFieldNames()); Set<String> originalFields = new TreeSet<>(originalEntry.getFieldNames()); boolean edited = false; // entry type String oldType = originalEntry.getType(); String newType = mergedEntry.getType(); if (!oldType.equalsIgnoreCase(newType)) { originalEntry.setType(newType); ce.addEdit(new UndoableChangeType(originalEntry, oldType, newType)); edited = true; } // fields for (String field : jointFields) { Optional<String> originalString = originalEntry.getField(field); Optional<String> mergedString = mergedEntry.getField(field); if (!originalString.isPresent() || !originalString.equals(mergedString)) { originalEntry.setField(field, mergedString.get()); // mergedString always present ce.addEdit(new UndoableFieldChange(originalEntry, field, originalString.orElse(null), mergedString.get())); edited = true; } } // Remove fields which are not in the merged entry, unless they are internal fields for (String field : originalFields) { if (!jointFields.contains(field) && !InternalBibtexFields.isInternalField(field)) { Optional<String> originalString = originalEntry.getField(field); originalEntry.clearField(field); ce.addEdit(new UndoableFieldChange(originalEntry, field, originalString.get(), null)); // originalString always present edited = true; } } if (edited) { ce.end(); panel.getUndoManager().addEdit(ce); panel.output(Localization.lang("Updated entry with info from %0", type)); panel.updateEntryEditorIfShowing(); panel.markBaseChanged(); } else { panel.output(Localization.lang("No information added")); } dispose(); } } }