Skip to content

Commit

Permalink
Convert merge entries dialog to JavaFX (#4410)
Browse files Browse the repository at this point in the history
* Convert to JavaFX

* Fix diff display

* Colorize diff

* Fix build and implement review feedback

* Move test file to tests

* Fix exception

* Maybe now...

* Fix NPE

* Remove obsolete language
  • Loading branch information
tobiasdiez authored Oct 30, 2018
1 parent 4cc775c commit 274fed4
Show file tree
Hide file tree
Showing 19 changed files with 668 additions and 776 deletions.
4 changes: 2 additions & 2 deletions src/main/java/org/jabref/gui/BasePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
import org.jabref.gui.journals.UnabbreviateAction;
import org.jabref.gui.maintable.MainTable;
import org.jabref.gui.maintable.MainTableDataModel;
import org.jabref.gui.mergeentries.MergeEntriesDialog;
import org.jabref.gui.mergeentries.MergeEntriesAction;
import org.jabref.gui.mergeentries.MergeWithFetchedEntryAction;
import org.jabref.gui.specialfields.SpecialFieldDatabaseChangeListener;
import org.jabref.gui.specialfields.SpecialFieldValueViewModel;
Expand Down Expand Up @@ -324,7 +324,7 @@ private void setupActions() {
// The action for cleaning up entry.
actions.put(Actions.CLEANUP, cleanUpAction);

actions.put(Actions.MERGE_ENTRIES, () -> new MergeEntriesDialog(BasePanel.this, dialogService));
actions.put(Actions.MERGE_ENTRIES, () -> new MergeEntriesAction(frame).execute());

// The action for copying the selected entry's key.
actions.put(Actions.COPY_KEY, this::copyKey);
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/jabref/gui/DuplicateResolverDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import javax.swing.JButton;
import javax.swing.JPanel;

import javafx.scene.Scene;

import org.jabref.gui.customjfx.CustomJFXPanel;
import org.jabref.gui.help.HelpAction;
import org.jabref.gui.importer.ImportInspectionDialog;
import org.jabref.gui.mergeentries.MergeEntries;
Expand Down Expand Up @@ -119,7 +122,7 @@ public void windowClosing(WindowEvent e) {
}
});

getContentPane().add(me.getMergeEntryPanel());
getContentPane().add(CustomJFXPanel.wrap(new Scene(me)));
getContentPane().add(options, BorderLayout.SOUTH);
pack();

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 @@ -69,7 +69,6 @@
import org.jabref.gui.actions.ManageJournalsAction;
import org.jabref.gui.actions.ManageKeywordsAction;
import org.jabref.gui.actions.ManageProtectedTermsAction;
import org.jabref.gui.actions.MergeEntriesAction;
import org.jabref.gui.actions.NewDatabaseAction;
import org.jabref.gui.actions.NewEntryAction;
import org.jabref.gui.actions.NewEntryFromPlainTextAction;
Expand Down Expand Up @@ -97,6 +96,7 @@
import org.jabref.gui.importer.actions.OpenDatabaseAction;
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.gui.menus.FileHistoryMenu;
import org.jabref.gui.mergeentries.MergeEntriesAction;
import org.jabref.gui.push.PushToApplicationButton;
import org.jabref.gui.push.PushToApplications;
import org.jabref.gui.search.GlobalSearchBar;
Expand Down
20 changes: 0 additions & 20 deletions src/main/java/org/jabref/gui/actions/MergeEntriesAction.java

This file was deleted.

108 changes: 108 additions & 0 deletions src/main/java/org/jabref/gui/mergeentries/DiffHighlighting.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.jabref.gui.mergeentries;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import javafx.scene.text.Text;

import difflib.Delta;
import difflib.DiffUtils;

public class DiffHighlighting {

private DiffHighlighting() {
}

public static List<Text> generateDiffHighlighting(String baseString, String modifiedString, String separator) {
List<String> stringList = Arrays.asList(baseString.split(separator));
List<Text> result = stringList.stream().map(DiffHighlighting::forUnchanged).collect(Collectors.toList());
List<Delta<String>> deltaList = DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas();
Collections.reverse(deltaList);
for (Delta<String> delta : deltaList) {
int startPos = delta.getOriginal().getPosition();
List<String> lines = delta.getOriginal().getLines();
int offset = 0;
switch (delta.getType()) {
case CHANGE:
for (String line : lines) {
result.set(startPos + offset, forRemoved(line + separator));
offset++;
}
result.set(startPos + offset - 1, forRemoved(stringList.get((startPos + offset) - 1) + separator));
result.add(startPos + offset, forAdded(String.join(separator, delta.getRevised().getLines())));
break;
case DELETE:
for (String line : lines) {
result.set(startPos + offset, forRemoved(line + separator));
offset++;
}
break;
case INSERT:
result.add(delta.getOriginal().getPosition(), forAdded(String.join(separator, delta.getRevised().getLines())));
break;
default:
break;
}
}
return result;
}

public static Text forChanged(String text) {
Text node = new Text(text);
node.getStyleClass().add("text-changed");
return node;
}

public static Text forUnchanged(String text) {
Text node = new Text(text);
node.getStyleClass().add("text-unchanged");
return node;
}

public static Text forAdded(String text) {
Text node = new Text(text);
node.getStyleClass().add("text-added");
return node;
}

public static Text forRemoved(String text) {
Text node = new Text(text);
node.getStyleClass().add("text-removed");
return node;
}

public static List<Text> generateSymmetricHighlighting(String baseString, String modifiedString, String separator) {
List<String> stringList = Arrays.asList(baseString.split(separator));
List<Text> result = stringList.stream().map(text -> DiffHighlighting.forUnchanged(text + separator)).collect(Collectors.toList());
List<Delta<String>> deltaList = DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas();
Collections.reverse(deltaList);
for (Delta<String> delta : deltaList) {
int startPos = delta.getOriginal().getPosition();
List<String> lines = delta.getOriginal().getLines();
int offset = 0;
switch (delta.getType()) {
case CHANGE:
for (String line : lines) {
result.set(startPos + offset, forChanged(line + separator));
offset++;
}
break;
case DELETE:
for (String line : lines) {
result.set(startPos + offset, forAdded(line + separator));
offset++;
}
break;
case INSERT:
break;
default:
break;
}
}

return result;
}

}
71 changes: 67 additions & 4 deletions src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;

import org.jabref.Globals;
import org.jabref.gui.BasePanel;
import org.jabref.gui.DialogService;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.gui.undo.UndoableChangeType;
import org.jabref.gui.undo.UndoableFieldChange;
import org.jabref.gui.util.BackgroundTask;
import org.jabref.gui.util.TaskExecutor;
import org.jabref.logic.importer.EntryBasedFetcher;
import org.jabref.logic.importer.IdBasedFetcher;
import org.jabref.logic.importer.WebFetcher;
import org.jabref.logic.importer.WebFetchers;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.FieldName;
import org.jabref.model.entry.InternalBibtexFields;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -56,8 +63,7 @@ public void fetchAndMerge(BibEntry entry, List<String> fields) {
.onSuccess(fetchedEntry -> {
String type = FieldName.getDisplayName(field);
if (fetchedEntry.isPresent()) {
MergeFetchedEntryDialog dialog = new MergeFetchedEntryDialog(panel, entry, fetchedEntry.get(), type);
dialog.setVisible(true);
showMergeDialog(entry, fetchedEntry.get(), fetcher.get());
} else {
panel.frame().setStatus(Localization.lang("Cannot get info based on given %0: %1", type, fieldContent.get()));
}
Expand All @@ -74,12 +80,69 @@ public void fetchAndMerge(BibEntry entry, List<String> fields) {
}
}

private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebFetcher fetcher) {
MergeEntriesDialog dialog = new MergeEntriesDialog(originalEntry, fetchedEntry, panel.getBibDatabaseContext().getMode());
dialog.setTitle(Localization.lang("Merge entry with %0 information", fetcher.getName()));
dialog.setLeftHeaderText(Localization.lang("Original entry"));
dialog.setRightHeaderText(Localization.lang("Entry from %0", fetcher.getName()));
Optional<BibEntry> mergedEntry = dialog.showAndWait();
if (mergedEntry.isPresent()) {
NamedCompound ce = new NamedCompound(Localization.lang("Merge entry with %0 information", fetcher.getName()));

// Updated the original entry with the new fields
Set<String> jointFields = new TreeSet<>(mergedEntry.get().getFieldNames());
Set<String> originalFields = new TreeSet<>(originalEntry.getFieldNames());
boolean edited = false;

// entry type
String oldType = originalEntry.getType();
String newType = mergedEntry.get().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.get().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);
dialogService.notify(Localization.lang("Updated entry with info from %0", fetcher.getName()));
} else {
dialogService.notify(Localization.lang("No information added"));
}
} else {
dialogService.notify(Localization.lang("Canceled merging entries"));
}
}

public void fetchAndMerge(BibEntry entry, EntryBasedFetcher fetcher) {
BackgroundTask.wrap(() -> fetcher.performSearch(entry).stream().findFirst())
.onSuccess(fetchedEntry -> {
if (fetchedEntry.isPresent()) {
MergeFetchedEntryDialog dialog = new MergeFetchedEntryDialog(panel, entry, fetchedEntry.get(), fetcher.getName());
dialog.setVisible(true);
showMergeDialog(entry, fetchedEntry.get(), fetcher);
} else {
dialogService.notify(Localization.lang("Could not find any bibliographic information."));
}
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/jabref/gui/mergeentries/MergeEntries.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.text-changed {
-fx-fill: darkgreen;
}

.text-unchanged {

}

.text-added {
-fx-fill: blue;
}

.text-removed {
-fx-fill: red;
}
Loading

0 comments on commit 274fed4

Please sign in to comment.