Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert DuplicateResolverDialog to javafx #4601

Merged
merged 5 commits into from
Jan 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 74 additions & 100 deletions src/main/java/org/jabref/gui/DuplicateResolverDialog.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
package org.jabref.gui;

import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.BorderPane;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JPanel;

import javafx.scene.Scene;

import org.jabref.gui.customjfx.CustomJFXPanel;
import org.jabref.gui.DuplicateResolverDialog.DuplicateResolverResult;
import org.jabref.gui.help.HelpAction;
import org.jabref.gui.importer.ImportInspectionDialog;
import org.jabref.gui.mergeentries.MergeEntries;
import org.jabref.gui.util.WindowLocation;
import org.jabref.gui.util.BaseDialog;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntry;
import org.jabref.preferences.JabRefPreferences;

public class DuplicateResolverDialog extends JabRefDialog {
public class DuplicateResolverDialog extends BaseDialog<DuplicateResolverResult> {

public enum DuplicateResolverType {
DUPLICATE_SEARCH,
Expand All @@ -30,7 +24,6 @@ public enum DuplicateResolverType {
}

public enum DuplicateResolverResult {
NOT_CHOSEN,
KEEP_BOTH,
KEEP_LEFT,
KEEP_RIGHT,
Expand All @@ -39,108 +32,89 @@ public enum DuplicateResolverResult {
BREAK
}

JButton helpButton = new HelpAction(Localization.lang("Help"), HelpFile.FIND_DUPLICATES).getHelpButton();
private final JButton cancel = new JButton(Localization.lang("Cancel"));
private final JButton merge = new JButton(Localization.lang("Keep merged entry only"));
private final JabRefFrame frame;
private final JPanel options = new JPanel();
private DuplicateResolverResult status = DuplicateResolverResult.NOT_CHOSEN;
private MergeEntries me;

public DuplicateResolverDialog(JabRefFrame frame, BibEntry one, BibEntry two, DuplicateResolverType type) {
super(Localization.lang("Possible duplicate entries"), true, DuplicateResolverDialog.class);
this.frame = frame;
init(one, two, type);
}

public DuplicateResolverDialog(ImportInspectionDialog dialog, BibEntry one, BibEntry two,
DuplicateResolverType type) {
super(dialog, Localization.lang("Possible duplicate entries"), true, DuplicateResolverDialog.class);
this.frame = dialog.getFrame();
this.setTitle(Localization.lang("Possible duplicate entries"));
init(one, two, type);
}

private void init(BibEntry one, BibEntry two, DuplicateResolverType type) {
JButton both;
JButton second;
JButton first;
JButton removeExact = null;
switch (type) {
case DUPLICATE_SEARCH:
first = new JButton(Localization.lang("Keep left"));
second = new JButton(Localization.lang("Keep right"));
both = new JButton(Localization.lang("Keep both"));
me = new MergeEntries(one, two, frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
case INSPECTION:
first = new JButton(Localization.lang("Remove old entry"));
second = new JButton(Localization.lang("Remove entry from import"));
both = new JButton(Localization.lang("Keep both"));
me = new MergeEntries(one, two, Localization.lang("Old entry"),
Localization.lang("From import"), frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
case DUPLICATE_SEARCH_WITH_EXACT:
first = new JButton(Localization.lang("Keep left"));
second = new JButton(Localization.lang("Keep right"));
both = new JButton(Localization.lang("Keep both"));
removeExact = new JButton(Localization.lang("Automatically remove exact duplicates"));
me = new MergeEntries(one, two, frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
default:
first = new JButton(Localization.lang("Import and remove old entry"));
second = new JButton(Localization.lang("Do not import entry"));
both = new JButton(Localization.lang("Import and keep old entry"));
me = new MergeEntries(one, two, Localization.lang("Old entry"),
Localization.lang("From import"), frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
}

if (removeExact != null) {
options.add(removeExact);
HelpAction helpCommand = new HelpAction(HelpFile.FIND_DUPLICATES);
ButtonType help = new ButtonType(Localization.lang("Help"), ButtonData.HELP);

ButtonType cancel = ButtonType.CANCEL;
ButtonType merge = new ButtonType(Localization.lang("Keep merged entry only"), ButtonData.APPLY);

ButtonBar options = new ButtonBar();
ButtonType both;
ButtonType second;
ButtonType first;
ButtonType removeExact = new ButtonType(Localization.lang("Automatically remove exact duplicates"), ButtonData.APPLY);
boolean removeExactVisible = false;

switch (type) {
case DUPLICATE_SEARCH:
first = new ButtonType(Localization.lang("Keep left"), ButtonData.APPLY);
second = new ButtonType(Localization.lang("Keep right"), ButtonData.APPLY);
both = new ButtonType(Localization.lang("Keep both"), ButtonData.APPLY);
me = new MergeEntries(one, two, frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
case INSPECTION:
first = new ButtonType(Localization.lang("Remove old entry"), ButtonData.APPLY);
second = new ButtonType(Localization.lang("Remove entry from import"), ButtonData.APPLY);
both = new ButtonType(Localization.lang("Keep both"), ButtonData.APPLY);
me = new MergeEntries(one, two, Localization.lang("Old entry"),
Localization.lang("From import"), frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
case DUPLICATE_SEARCH_WITH_EXACT:
first = new ButtonType(Localization.lang("Keep left"), ButtonData.APPLY);
second = new ButtonType(Localization.lang("Keep right"), ButtonData.APPLY);
both = new ButtonType(Localization.lang("Keep both"), ButtonData.APPLY);

removeExactVisible = true;

me = new MergeEntries(one, two, frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
default:
first = new ButtonType(Localization.lang("Import and remove old entry"), ButtonData.APPLY);
second = new ButtonType(Localization.lang("Do not import entry"), ButtonData.APPLY);
both = new ButtonType(Localization.lang("Import and keep old entry"), ButtonData.APPLY);
me = new MergeEntries(one, two, Localization.lang("Old entry"),
Localization.lang("From import"), frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
break;
}
options.add(first);
options.add(second);
options.add(both);
options.add(merge);
options.add(Box.createHorizontalStrut(5));
options.add(cancel);
options.add(helpButton);

first.addActionListener(e -> buttonPressed(DuplicateResolverResult.KEEP_LEFT));
second.addActionListener(e -> buttonPressed(DuplicateResolverResult.KEEP_RIGHT));
both.addActionListener(e -> buttonPressed(DuplicateResolverResult.KEEP_BOTH));
merge.addActionListener(e -> buttonPressed(DuplicateResolverResult.KEEP_MERGE));
if (removeExact != null) {
removeExact.addActionListener(e -> buttonPressed(DuplicateResolverResult.AUTOREMOVE_EXACT));
if (removeExactVisible) {
this.getDialogPane().getButtonTypes().add(removeExact);
}

cancel.addActionListener(e -> buttonPressed(DuplicateResolverResult.BREAK));
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
buttonPressed(DuplicateResolverResult.BREAK);
}
});
this.getDialogPane().getButtonTypes().addAll(first, second, both, merge, cancel, help);

getContentPane().add(CustomJFXPanel.wrap(new Scene(me)));
getContentPane().add(options, BorderLayout.SOUTH);
pack();
BorderPane borderPane = new BorderPane(me);
borderPane.setBottom(options);

WindowLocation pw = new WindowLocation(this, JabRefPreferences.DUPLICATES_POS_X,
JabRefPreferences.DUPLICATES_POS_Y, JabRefPreferences.DUPLICATES_SIZE_X,
JabRefPreferences.DUPLICATES_SIZE_Y);
pw.displayWindowAtStoredLocation();
this.setResultConverter(button -> {

both.requestFocus();
}

private void buttonPressed(DuplicateResolverResult result) {
status = result;
dispose();
}
if (button.equals(first)) {
return DuplicateResolverResult.KEEP_LEFT;
} else if (button.equals(second)) {
return DuplicateResolverResult.KEEP_RIGHT;
} else if (button.equals(both)) {
return DuplicateResolverResult.KEEP_BOTH;
} else if (button.equals(merge)) {
return DuplicateResolverResult.KEEP_MERGE;
} else if (button.equals(removeExact)) {
return DuplicateResolverResult.AUTOREMOVE_EXACT;
}
return null;
});

public DuplicateResolverResult getSelected() {
return status;
getDialogPane().setContent(borderPane);
Button helpButton = (Button) this.getDialogPane().lookupButton(help);
helpButton.setOnAction(evt -> helpCommand.getCommand().execute());
}

public BibEntry getMergedEntry() {
Expand Down
60 changes: 28 additions & 32 deletions src/main/java/org/jabref/gui/DuplicateSearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.SwingUtilities;

import org.jabref.Globals;
import org.jabref.JabRefExecutorService;
import org.jabref.gui.DuplicateResolverDialog.DuplicateResolverResult;
Expand All @@ -37,15 +35,17 @@ public class DuplicateSearch extends SimpleCommand {
private final AtomicBoolean libraryAnalyzed = new AtomicBoolean();
private final AtomicBoolean autoRemoveExactDuplicates = new AtomicBoolean();
private final AtomicInteger duplicateCount = new AtomicInteger();
private final DialogService dialogService;

public DuplicateSearch(JabRefFrame frame) {
public DuplicateSearch(JabRefFrame frame, DialogService dialogService) {
this.frame = frame;
this.dialogService = dialogService;
}

@Override
public void execute() {
BasePanel panel = frame.getCurrentBasePanel();
panel.output(Localization.lang("Searching for duplicates..."));
dialogService.notify(Localization.lang("Searching for duplicates..."));

List<BibEntry> entries = panel.getDatabase().getEntries();
duplicates.clear();
Expand All @@ -57,8 +57,7 @@ public void execute() {
return;
}

JabRefExecutorService.INSTANCE
.executeInterruptableTask(() -> searchPossibleDuplicates(entries, panel.getBibDatabaseContext().getMode()), "DuplicateSearcher");
JabRefExecutorService.INSTANCE.executeInterruptableTask(() -> searchPossibleDuplicates(entries, panel.getBibDatabaseContext().getMode()), "DuplicateSearcher");
BackgroundTask.wrap(this::verifyDuplicates)
.onSuccess(this::handleDuplicates)
.executeWith(Globals.TASK_EXECUTOR);
Expand Down Expand Up @@ -124,13 +123,11 @@ private DuplicateSearchResult verifyDuplicates() {

private void askResolveStrategy(DuplicateSearchResult result, BibEntry first, BibEntry second, DuplicateResolverType resolverType) {
DuplicateResolverDialog dialog = new DuplicateResolverDialog(frame, first, second, resolverType);
dialog.setVisible(true);
dialog.dispose();

DuplicateResolverResult resolverResult = dialog.getSelected();
DuplicateResolverResult resolverResult = dialog.showAndWait().orElse(DuplicateResolverResult.BREAK);

if ((resolverResult == DuplicateResolverResult.KEEP_LEFT)
|| (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT)) {
|| (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT)) {
result.remove(second);
if (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT) {
autoRemoveExactDuplicates.set(true); // Remember choice
Expand All @@ -150,31 +147,30 @@ private void handleDuplicates(DuplicateSearchResult result) {
return;
}

SwingUtilities.invokeLater(() -> {
BasePanel panel = frame.getCurrentBasePanel();
final NamedCompound compoundEdit = new NamedCompound(Localization.lang("duplicate removal"));
// Now, do the actual removal:
if (!result.getToRemove().isEmpty()) {
for (BibEntry entry : result.getToRemove()) {
panel.getDatabase().removeEntry(entry);
compoundEdit.addEdit(new UndoableRemoveEntry(panel.getDatabase(), entry, panel));
}
panel.markBaseChanged();
BasePanel panel = frame.getCurrentBasePanel();
final NamedCompound compoundEdit = new NamedCompound(Localization.lang("duplicate removal"));
// Now, do the actual removal:
if (!result.getToRemove().isEmpty()) {
for (BibEntry entry : result.getToRemove()) {
panel.getDatabase().removeEntry(entry);
compoundEdit.addEdit(new UndoableRemoveEntry(panel.getDatabase(), entry, panel));
}
// and adding merged entries:
if (!result.getToAdd().isEmpty()) {
for (BibEntry entry : result.getToAdd()) {
panel.getDatabase().insertEntry(entry);
compoundEdit.addEdit(new UndoableInsertEntry(panel.getDatabase(), entry));
}
panel.markBaseChanged();
panel.markBaseChanged();
}
// and adding merged entries:
if (!result.getToAdd().isEmpty()) {
for (BibEntry entry : result.getToAdd()) {
panel.getDatabase().insertEntry(entry);
compoundEdit.addEdit(new UndoableInsertEntry(panel.getDatabase(), entry));
}
panel.markBaseChanged();
}

dialogService.notify(Localization.lang("Duplicates found") + ": " + duplicateCount.get() + ' '
+ Localization.lang("pairs processed") + ": " + result.getDuplicateCount());
compoundEdit.end();
panel.getUndoManager().addEdit(compoundEdit);

panel.output(Localization.lang("Duplicates found") + ": " + duplicateCount.get() + ' '
+ Localization.lang("pairs processed") + ": " + result.getDuplicateCount());
compoundEdit.end();
panel.getUndoManager().addEdit(compoundEdit);
});
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ private MenuBar createMenu() {
}

quality.getItems().addAll(
factory.createMenuItem(StandardActions.FIND_DUPLICATES, new DuplicateSearch(this)),
factory.createMenuItem(StandardActions.FIND_DUPLICATES, new DuplicateSearch(this, dialogService)),
factory.createMenuItem(StandardActions.MERGE_ENTRIES, new MergeEntriesAction(this)),

new SeparatorMenuItem(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,11 @@ class ResolveDuplicateLabelDialog {
private boolean okPressed;
private boolean cancelPressed;


public ResolveDuplicateLabelDialog(BasePanel panel, String key, List<BibEntry> entries) {
diag = new JDialog((JFrame) null, Localization.lang("Duplicate BibTeX key"), true);

FormBuilder b = FormBuilder.create().layout(new FormLayout(
"left:pref, 4dlu, fill:pref", "p"));
"left:pref, 4dlu, fill:pref", "p"));
b.add(new JLabel(Localization.lang("Duplicate BibTeX key") + ": " + key)).xyw(1, 1, 3);
b.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

Expand All @@ -59,7 +58,7 @@ public ResolveDuplicateLabelDialog(BasePanel panel, String key, List<BibEntry> e
JCheckBox cb = new JCheckBox(Localization.lang("Generate BibTeX key"), !first);
b.appendRows("1dlu, p");
b.add(cb).xy(1, row);
PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService(), ExternalFileTypes.getInstance());
PreviewPanel previewPanel = new PreviewPanel(null, panel.getBibDatabaseContext(), Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService(), ExternalFileTypes.getInstance());
previewPanel.setEntry(entry);
JFXPanel container = CustomJFXPanel.wrap(new Scene(previewPanel));
container.setPreferredSize(new Dimension(800, 90));
Expand All @@ -86,8 +85,8 @@ public ResolveDuplicateLabelDialog(BasePanel panel, String key, List<BibEntry> e
diag.pack();

ok.addActionListener(e -> {
okPressed = true;
diag.dispose();
okPressed = true;
diag.dispose();
});

ignore.addActionListener(e -> diag.dispose());
Expand Down
Loading