From 376760c24f7e7e46a189e557618321f5e05e8f4c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Thu, 24 Mar 2022 01:47:04 +0100 Subject: [PATCH 001/473] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f719dbf8742..a62785db499 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,6 @@ For IntelliJ IDEA, just import the project via a Gradle Import by pointing at th ## Sponsoring -JabRef development is powered by YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) +JabRef development is by YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) [JabRef]: https://www.jabref.org From 3c3fb02787dd450fd505aa65c80eaafccffd917a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 7 Jun 2022 13:49:26 +0100 Subject: [PATCH 002/473] Fix Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 677fcc7e75c..78a90d2785d 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,6 @@ For IntelliJ IDEA, just import the project via a Gradle Import by pointing at th ## Sponsoring -JabRef development is by YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) +JabRef development is by powered YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) [JabRef]: https://www.jabref.org From 1b12b75954895349917d8248e2df139465ad5011 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 01:58:15 +0100 Subject: [PATCH 003/473] Create grid cells for rendering field name and field value --- src/main/java/module-info.java | 1 + .../newmergedialog/ThreeWayMerge.java | 4 + .../newmergedialog/cell/AbstractCell.java | 69 +++++++++++ .../newmergedialog/cell/FieldNameCell.java | 7 ++ .../newmergedialog/cell/FieldValueCell.java | 108 ++++++++++++++++++ 5 files changed, 189 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 751863df3e1..68a5a571fbd 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -117,6 +117,7 @@ requires net.harawata.appdirs; requires org.eclipse.jgit; + requires wellbehavedfx; uses org.eclipse.jgit.transport.SshSessionFactory; uses org.eclipse.jgit.lib.GpgSigner; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java new file mode 100644 index 00000000000..bf2f9e651af --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java @@ -0,0 +1,4 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +public class ThreeWayMerge { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java new file mode 100644 index 00000000000..a1583987921 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java @@ -0,0 +1,69 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.geometry.Insets; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.HBox; +import javafx.scene.paint.Color; + +/** + * + */ +public abstract class AbstractCell extends HBox { + private final StringProperty text = new SimpleStringProperty(); + private final ObjectProperty backgroundTone = new SimpleObjectProperty<>(); + + public AbstractCell(String text, BackgroundTone backgroundTone) { + backgroundToneProperty().addListener(invalidated -> setBackground(Background.fill(getBackgroundTone().color()))); + setPadding(new Insets(8)); + + setText(text); + setBackgroundTone(backgroundTone); + } + + public AbstractCell(String text) { + this(text, BackgroundTone.DARK); + } + + public String getText() { + return textProperty().get(); + } + + public StringProperty textProperty() { + return text; + } + + public void setText(String text) { + textProperty().set(text); + } + + public void setBackgroundTone(BackgroundTone backgroundTone) { + backgroundToneProperty().set(backgroundTone); + } + + public BackgroundTone getBackgroundTone() { + return backgroundToneProperty().get(); + } + + public ObjectProperty backgroundToneProperty() { + return backgroundTone; + } + + public enum BackgroundTone { + LIGHT(Color.web("#F7F7F7")), DARK(Color.web("#FAFAFA")); + private final Color color; + + BackgroundTone(Color color) { + this.color = color; + } + + public Color color() { + return color; + } + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java new file mode 100644 index 00000000000..af73de11961 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -0,0 +1,7 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +/** + * A non-editable cell that contains the name of some field + */ +public class FieldNameCell { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java new file mode 100644 index 00000000000..7a91515987d --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -0,0 +1,108 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.event.Event; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.Toggle; +import javafx.scene.control.ToggleGroup; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Background; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.paint.Color; + +import org.fxmisc.flowless.VirtualizedScrollPane; +import org.fxmisc.richtext.StyleClassedTextArea; +import org.fxmisc.wellbehaved.event.InputMap; +import org.fxmisc.wellbehaved.event.Nodes; + +import static org.fxmisc.wellbehaved.event.EventPattern.anyOf; +import static org.fxmisc.wellbehaved.event.EventPattern.eventType; +import static org.fxmisc.wellbehaved.event.EventPattern.mousePressed; + +/** + * A non-editable and selectable field cell that contains the value of some field + */ +public class FieldValueCell extends AbstractCell implements Toggle { + private final ObjectProperty toggleGroup = new SimpleObjectProperty<>(); + private final BooleanProperty selected = new SimpleBooleanProperty(); + + private final StyleClassedTextArea label = new StyleClassedTextArea(); + + private final VirtualizedScrollPane scrollPane = new VirtualizedScrollPane<>(label); + + public FieldValueCell(String text, BackgroundTone backgroundTone) { + super(text, backgroundTone); + } + + public FieldValueCell(String text) { + super(text); + } + + private void initialize() { + initializeLabel(); + initializeSelectionBox(); + } + + private void initializeLabel() { + label.setEditable(false); + label.setBackground(Background.fill(Color.TRANSPARENT)); + label.appendText(textProperty().get()); + label.setAutoHeight(true); + label.setWrapText(true); + + preventTextSelectionViaMouseEvents(); + } + + private void initializeSelectionBox() { + } + + private void initializeScrollPane() { + HBox.setHgrow(scrollPane, Priority.ALWAYS); + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + } + + private void preventTextSelectionViaMouseEvents() { + InputMap preventSelection = InputMap.consume( + anyOf(eventType(MouseEvent.MOUSE_DRAGGED), + eventType(MouseEvent.DRAG_DETECTED), + eventType(MouseEvent.MOUSE_ENTERED), + mousePressed().unless(e -> e.getClickCount() == 1) + ) + ); + Nodes.addInputMap(label, preventSelection); + } + + @Override + public ToggleGroup getToggleGroup() { + return toggleGroupProperty().get(); + } + + @Override + public void setToggleGroup(ToggleGroup toggleGroup) { + toggleGroupProperty().set(toggleGroup); + } + + @Override + public ObjectProperty toggleGroupProperty() { + return toggleGroup; + } + + @Override + public boolean isSelected() { + return selectedProperty().get(); + } + + @Override + public void setSelected(boolean selected) { + selectedProperty().set(selected); + } + + @Override + public BooleanProperty selectedProperty() { + return selected; + } +} From 4c073d3b9a66ed3b8449677321ceb40758adfa3c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:02:59 +0100 Subject: [PATCH 004/473] Implement FieldNameCell and define style class --- .../newmergedialog/cell/FieldNameCell.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index af73de11961..ce3f33059ba 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -1,7 +1,29 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.scene.control.Label; + /** * A non-editable cell that contains the name of some field */ -public class FieldNameCell { +public class FieldNameCell extends AbstractCell { + public static final String DEFAULT_STYLE_CLASS = "field-name"; + private final Label label = new Label(); + + public FieldNameCell(String text, BackgroundTone backgroundTone) { + super(text, backgroundTone); + } + + public FieldNameCell(String text) { + super(text); + } + + private void initialize() { + getStyleClass().add(DEFAULT_STYLE_CLASS); + initializeLabel(); + getChildren().add(label); + } + + private void initializeLabel() { + label.textProperty().bind(textProperty()); + } } From 6359058217bb40c0f0a7075f04a6eef6a6cfff7b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:05:04 +0100 Subject: [PATCH 005/473] Make FieldValueCell selectable - Defined style class - Defined pseudo class for the selected state - Created the selection box UI --- .../newmergedialog/cell/FieldValueCell.java | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 7a91515987d..0188de09b13 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -1,50 +1,82 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; import javafx.beans.property.BooleanProperty; +import javafx.beans.property.BooleanPropertyBase; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.css.PseudoClass; import javafx.event.Event; +import javafx.geometry.Insets; +import javafx.geometry.Pos; import javafx.scene.control.ScrollPane; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import javafx.scene.input.MouseEvent; +import javafx.scene.input.ScrollEvent; import javafx.scene.layout.Background; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.StyleClassedTextArea; import org.fxmisc.wellbehaved.event.InputMap; import org.fxmisc.wellbehaved.event.Nodes; +import org.kordamp.ikonli.javafx.FontIcon; +import org.kordamp.ikonli.materialdesign2.MaterialDesignC; import static org.fxmisc.wellbehaved.event.EventPattern.anyOf; import static org.fxmisc.wellbehaved.event.EventPattern.eventType; import static org.fxmisc.wellbehaved.event.EventPattern.mousePressed; /** - * A non-editable and selectable field cell that contains the value of some field + * A readonly, selectable field cell that contains the value of some field */ public class FieldValueCell extends AbstractCell implements Toggle { + public static final String SELECTION_BOX_STYLE_CLASS = "selection-box"; + private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected"); private final ObjectProperty toggleGroup = new SimpleObjectProperty<>(); - private final BooleanProperty selected = new SimpleBooleanProperty(); - private final StyleClassedTextArea label = new StyleClassedTextArea(); private final VirtualizedScrollPane scrollPane = new VirtualizedScrollPane<>(label); + private final BooleanProperty selected = new BooleanPropertyBase() { + @Override + public Object getBean() { + return FieldValueCell.class; + } + + @Override + public String getName() { + return "selected"; + } + + @Override + protected void invalidated() { + pseudoClassStateChanged(SELECTED_PSEUDO_CLASS, get()); + } + }; + private final HBox selectionBox = new HBox(); + private final VBox checkmarkLayout = new VBox(); public FieldValueCell(String text, BackgroundTone backgroundTone) { super(text, backgroundTone); + initialize(); } public FieldValueCell(String text) { super(text); + initialize(); } private void initialize() { + initializeScrollPane(); initializeLabel(); initializeSelectionBox(); + textProperty().addListener(invalidated -> setUserData(getText())); + + selectionBox.getChildren().addAll(label, checkmarkLayout); + getChildren().setAll(selectionBox); } private void initializeLabel() { @@ -53,11 +85,25 @@ private void initializeLabel() { label.appendText(textProperty().get()); label.setAutoHeight(true); label.setWrapText(true); + // TODO: Set cursor to Cursor.HAND preventTextSelectionViaMouseEvents(); + + label.prefHeightProperty().bind(label.totalHeightEstimateProperty().orElseConst(-1d)); + + label.addEventFilter(ScrollEvent.SCROLL, e -> { + e.consume(); + FieldValueCell.this.fireEvent(e.copyFor(e.getSource(), FieldValueCell.this)); + }); } private void initializeSelectionBox() { + selectionBox.getStyleClass().add(SELECTION_BOX_STYLE_CLASS); + HBox.setHgrow(selectionBox, Priority.ALWAYS); + + checkmarkLayout.getChildren().setAll(new FontIcon(MaterialDesignC.CHECK)); + checkmarkLayout.setPadding(new Insets(1, 0, 0, 0)); + checkmarkLayout.setAlignment(Pos.TOP_RIGHT); } private void initializeScrollPane() { @@ -105,4 +151,14 @@ public void setSelected(boolean selected) { public BooleanProperty selectedProperty() { return selected; } + + @Override + public void setUserData(Object value) { + super.setText((String) value); + } + + @Override + public Object getUserData() { + return super.getText(); + } } From d45f4a13b98f74ebeff45228b53e9b4b45e54bc6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:06:12 +0100 Subject: [PATCH 006/473] Implement MergedFieldCell for rendering editable merged field value --- .../newmergedialog/cell/MergedFieldCell.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java new file mode 100644 index 00000000000..4bce784c13d --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java @@ -0,0 +1,51 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.input.ScrollEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; + +import org.fxmisc.richtext.StyleClassedTextArea; + +public class MergedFieldCell extends AbstractCell { + private static final String DEFAULT_STYLE_CLASS = "merged-field"; + + private final StyleClassedTextArea textArea = new StyleClassedTextArea(); + + public MergedFieldCell(String text, BackgroundTone backgroundTone) { + super(text, backgroundTone); + initialize(); + } + + public MergedFieldCell(String text) { + super(text); + initialize(); + } + + private void initialize() { + getStyleClass().add(DEFAULT_STYLE_CLASS); + initializeTextArea(); + getChildren().add(textArea); + } + + private void initializeTextArea() { + bindTextAreaValue(); + + setAlignment(Pos.CENTER); + textArea.setWrapText(true); + textArea.setAutoHeight(true); + textArea.setPadding(new Insets(8)); + HBox.setHgrow(textArea, Priority.ALWAYS); + + textArea.addEventFilter(ScrollEvent.SCROLL, e -> { + e.consume(); + MergedFieldCell.this.fireEvent(e.copyFor(e.getSource(), MergedFieldCell.this)); + }); + } + + private void bindTextAreaValue() { + textArea.replaceText(textProperty().get()); + textProperty().addListener(((observable, oldValue, newValue) -> textArea.replaceText(newValue))); + } +} From 7e226e2711d59f24b5e4e91d7699a5e68dfaed52 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:07:56 +0100 Subject: [PATCH 007/473] Change MergedFieldCell text based on the selected FieldValueCell --- .../newmergedialog/FieldRowController.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java new file mode 100644 index 00000000000..a25709c1e23 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -0,0 +1,40 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import javafx.beans.property.ReadOnlyStringProperty; +import javafx.scene.control.ToggleGroup; + +import org.jabref.gui.mergeentries.newmergedialog.cell.AbstractCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; +import org.jabref.model.strings.StringUtil; + +public class FieldRowController { + private final FieldNameCell fieldNameCell; + private final FieldValueCell leftValueCell; + private final FieldValueCell rightValueCell; + private final MergedFieldCell mergedValueCell; + + private final ToggleGroup toggleGroup = new ToggleGroup(); + + public FieldRowController(String fieldName, String leftValue, String rightValue, AbstractCell.BackgroundTone backgroundTone) { + fieldNameCell = new FieldNameCell(fieldName, backgroundTone); + leftValueCell = new FieldValueCell(leftValue, backgroundTone); + rightValueCell = new FieldValueCell(rightValue, backgroundTone); + mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, backgroundTone); + + toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); + toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); + toggleGroup.selectedToggleProperty().addListener(invalidated -> { + mergedValueCell.setText((String) toggleGroup.getSelectedToggle().getUserData()); + }); + } + + public String getMergedValue() { + return mergedValueProperty().getValue(); + } + + public ReadOnlyStringProperty mergedValueProperty() { + return mergedValueCell.textProperty(); + } +} From fb137cbcf0adfd8e4804532bede83db8bb6b3608 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:08:31 +0100 Subject: [PATCH 008/473] Style MergedFieldCell --- .../mergeentries/newmergedialog/cell/AbstractCell.java | 4 ++-- .../gui/mergeentries/newmergedialog/newmergedialog.css | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java index a1583987921..9cb60f44ba5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java @@ -6,8 +6,6 @@ import javafx.beans.property.StringProperty; import javafx.geometry.Insets; import javafx.scene.layout.Background; -import javafx.scene.layout.BackgroundFill; -import javafx.scene.layout.CornerRadii; import javafx.scene.layout.HBox; import javafx.scene.paint.Color; @@ -24,6 +22,8 @@ public AbstractCell(String text, BackgroundTone backgroundTone) { setText(text); setBackgroundTone(backgroundTone); + // TODO: Remove this when cells are added to the grid pane, and add the stylesheet to the root layout instead. + getStylesheets().add("../newmergedialog.css"); } public AbstractCell(String text) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css new file mode 100644 index 00000000000..e0f4741e73d --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css @@ -0,0 +1,10 @@ +.merged-field { + -fx-border-color: #dfdfdf; + -fx-border-width: 0 0 0 1.5; +} + +.merged-field .styled-text-area { + -fx-background-radius: 5; + -fx-border-radius: 5; + -fx-border-color: #dfdfdf +} From 8d76e405a1d39a1bad0daefdaa661a552e9808bb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:52:52 +0100 Subject: [PATCH 009/473] Rename ThreeWayMerge css stylesheet --- .../newmergedialog/ThreeWayMergeView.css | 62 +++++++++++++++++++ .../newmergedialog/cell/AbstractCell.java | 4 +- .../newmergedialog/newmergedialog.css | 10 --- 3 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css new file mode 100644 index 00000000000..c95470b32dc --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -0,0 +1,62 @@ +.merged-field { + -fx-border-color: #dfdfdf; + -fx-border-width: 0 0 0 1.5; +} + +.merged-field .styled-text-area { + -fx-background-radius: 5; + -fx-border-radius: 5; + -fx-border-color: #dfdfdf +} + +.field-value:selected .selection-box { + -fx-background-color: -jr-transparent-green; + -fx-border-color: -jr-green; +} + +.field-value .selection-box { + -fx-background-color: #0000; + -fx-padding: 8; + -fx-border-width: 1; + -fx-border-color: #219b3800; + -fx-border-style: SOLID; + -fx-border-radius: 8; + -fx-background-radius: 8; +} + +.field-value .label { + -fx-font-size: 13; +} + +.field-value .text-area { + -fx-font-size: 13; +} + +.field-value .checkmark { + -fx-icon-size: 13; + -fx-icon-color: #25b060; + -fx-opacity: 0%; +} + +.field-value:selected .checkmark { + -fx-icon-size: 14; + -fx-icon-color: -jr-green; + -fx-opacity: 100%; +} + +.unchanged { + +} + +.addition { + -rtfx-background-color: rgba(35, 225, 96, 0.26); +} + +.deletion { + -rtfx-background-color: rgba(248, 62, 68, 0.26); +} + + +* { + -jr-transparent-green: rgba(16, 172, 132, 0.15); +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java index 9cb60f44ba5..b57a14bce1f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java @@ -23,7 +23,7 @@ public AbstractCell(String text, BackgroundTone backgroundTone) { setText(text); setBackgroundTone(backgroundTone); // TODO: Remove this when cells are added to the grid pane, and add the stylesheet to the root layout instead. - getStylesheets().add("../newmergedialog.css"); + getStylesheets().add("../ThreeWayMergeView.css"); } public AbstractCell(String text) { @@ -55,7 +55,7 @@ public ObjectProperty backgroundToneProperty() { } public enum BackgroundTone { - LIGHT(Color.web("#F7F7F7")), DARK(Color.web("#FAFAFA")); + LIGHT(Color.web("#FEFEFE")), DARK(Color.web("#EFEFEF")); private final Color color; BackgroundTone(Color color) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css deleted file mode 100644 index e0f4741e73d..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/newmergedialog.css +++ /dev/null @@ -1,10 +0,0 @@ -.merged-field { - -fx-border-color: #dfdfdf; - -fx-border-width: 0 0 0 1.5; -} - -.merged-field .styled-text-area { - -fx-background-radius: 5; - -fx-border-radius: 5; - -fx-border-color: #dfdfdf -} From 98eea59084403d5308e5a20b255bf4d97d317824 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:54:00 +0100 Subject: [PATCH 010/473] Create HeadView for rendering left, right and merged entry headers --- .../gui/mergeentries/newmergedialog/HeaderView.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java new file mode 100644 index 00000000000..ea7049cd857 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java @@ -0,0 +1,10 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import javafx.scene.layout.HBox; + +public class HeaderView extends HBox { + public HeaderView() { + setPrefHeight(50d); + setStyle("-fx-background-color: #878787"); + } +} From 3187365bf701cc188dfb24dc7eefa495b7402ee3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 02:54:41 +0100 Subject: [PATCH 011/473] Fix typo --- .../gui/mergeentries/newmergedialog/cell/FieldNameCell.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index ce3f33059ba..7730b4d43ab 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -11,10 +11,12 @@ public class FieldNameCell extends AbstractCell { public FieldNameCell(String text, BackgroundTone backgroundTone) { super(text, backgroundTone); + initialize(); } public FieldNameCell(String text) { super(text); + initialize(); } private void initialize() { From d00bab32ad508dc45d3ff58d79b1d56e4a3d5959 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:00:17 +0100 Subject: [PATCH 012/473] Fix a bug that causes the selection of both left and right field cells simultaneously. - Added a style class for field value cell --- .../mergeentries/newmergedialog/cell/FieldValueCell.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 0188de09b13..a2d0b1c2118 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -34,7 +34,9 @@ * A readonly, selectable field cell that contains the value of some field */ public class FieldValueCell extends AbstractCell implements Toggle { + public static final String DEFAULT_STYLE_CLASS = "field-value"; public static final String SELECTION_BOX_STYLE_CLASS = "selection-box"; + private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected"); private final ObjectProperty toggleGroup = new SimpleObjectProperty<>(); private final StyleClassedTextArea label = new StyleClassedTextArea(); @@ -54,6 +56,9 @@ public String getName() { @Override protected void invalidated() { pseudoClassStateChanged(SELECTED_PSEUDO_CLASS, get()); + + ToggleGroup group = getToggleGroup(); + group.selectToggle(FieldValueCell.this); } }; private final HBox selectionBox = new HBox(); @@ -70,6 +75,7 @@ public FieldValueCell(String text) { } private void initialize() { + getStyleClass().add(DEFAULT_STYLE_CLASS); initializeScrollPane(); initializeLabel(); initializeSelectionBox(); From 02c040416da5ed56447bdbf2110b334073a4064f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:05:20 +0100 Subject: [PATCH 013/473] Prevent the selection of FieldValueCell when it's disabled - A cell is disabled when it's either empty or not visible e.g. when the left cell spans 2 columns, right cell is disabled because it's not visible - Added comments --- .../mergeentries/newmergedialog/cell/FieldValueCell.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index a2d0b1c2118..a8f4265e8be 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -80,6 +80,11 @@ private void initialize() { initializeLabel(); initializeSelectionBox(); textProperty().addListener(invalidated -> setUserData(getText())); + setOnMouseClicked(e -> { + if (!isDisabled()) { + setSelected(true); + } + }); selectionBox.getChildren().addAll(label, checkmarkLayout); getChildren().setAll(selectionBox); @@ -91,12 +96,13 @@ private void initializeLabel() { label.appendText(textProperty().get()); label.setAutoHeight(true); label.setWrapText(true); - // TODO: Set cursor to Cursor.HAND + // Workarounds preventTextSelectionViaMouseEvents(); label.prefHeightProperty().bind(label.totalHeightEstimateProperty().orElseConst(-1d)); + // Fix text area consuming scroll events before they rich the outer scrollable label.addEventFilter(ScrollEvent.SCROLL, e -> { e.consume(); FieldValueCell.this.fireEvent(e.copyFor(e.getSource(), FieldValueCell.this)); From 05527c6de821ba8a7ca8a195064a7873c259ee15 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:06:33 +0100 Subject: [PATCH 014/473] Display a copy icon inside FieldValueCell --- .../mergeentries/newmergedialog/cell/FieldValueCell.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index a8f4265e8be..33426a4e847 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -86,7 +86,7 @@ private void initialize() { } }); - selectionBox.getChildren().addAll(label, checkmarkLayout); + selectionBox.getChildren().addAll(scrollPane, checkmarkLayout); getChildren().setAll(selectionBox); } @@ -113,7 +113,9 @@ private void initializeSelectionBox() { selectionBox.getStyleClass().add(SELECTION_BOX_STYLE_CLASS); HBox.setHgrow(selectionBox, Priority.ALWAYS); - checkmarkLayout.getChildren().setAll(new FontIcon(MaterialDesignC.CHECK)); + FontIcon checkmarkCircleIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); + checkmarkCircleIcon.getStyleClass().add("checkmark-icon"); + checkmarkLayout.getChildren().setAll(checkmarkCircleIcon); checkmarkLayout.setPadding(new Insets(1, 0, 0, 0)); checkmarkLayout.setAlignment(Pos.TOP_RIGHT); } From b6db346f3a27f21971853e6565583b59ee40204b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:08:26 +0100 Subject: [PATCH 015/473] Disable left or right FieldValueCell when it's empty - Added getters for row cells --- .../newmergedialog/FieldRowController.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index a25709c1e23..117f1d83ce5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -28,6 +28,12 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, toggleGroup.selectedToggleProperty().addListener(invalidated -> { mergedValueCell.setText((String) toggleGroup.getSelectedToggle().getUserData()); }); + + if (StringUtil.isNullOrEmpty(leftValue)) { + leftValueCell.setDisable(true); + } else if (StringUtil.isNullOrEmpty(rightValue)) { + rightValueCell.setDisable(true); + } } public String getMergedValue() { @@ -37,4 +43,20 @@ public String getMergedValue() { public ReadOnlyStringProperty mergedValueProperty() { return mergedValueCell.textProperty(); } + + public FieldNameCell getFieldNameCell() { + return fieldNameCell; + } + + public FieldValueCell getLeftValueCell() { + return leftValueCell; + } + + public FieldValueCell getRightValueCell() { + return rightValueCell; + } + + public MergedFieldCell getMergedValueCell() { + return mergedValueCell; + } } From fa97b5949cf623bb432910076b1ebe938d161cf6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:09:33 +0100 Subject: [PATCH 016/473] Update Base CSS style --- src/main/java/org/jabref/gui/Base.css | 66 ++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 3a25f9afc25..6a49557ebbe 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -1,5 +1,68 @@ -.root { +.merged-field { + -fx-border-color: #dfdfdf; + -fx-border-width: 0 0 0 1.5; +} + +.merged-field .styled-text-area { + -fx-background-radius: 3; + -fx-border-radius: 3; + -fx-border-color: #dfdfdf; + -fx-background-color: white; +} + +.field-value:selected .selection-box { + -fx-background-color: derive(-jr-accent, 20%); + -fx-border-color: -jr-accent; +} + +.field-value .selection-box { + -fx-background-color: #0000; + -fx-padding: 8; + -fx-border-width: 1; + -fx-border-color: #0000; + -fx-border-radius: 8; + -fx-background-radius: 8; +} + +.field-value .label { + -fx-font-size: 13; +} + +.field-value .text-area { + -fx-font-size: 13; +} + +.field-value .checkmark-icon { + -fx-icon-size: 16; + -fx-icon-color: -jr-gray-2; + -fx-opacity: 100%; +} +.field-value:disabled .checkmark-icon { + -fx-opacity: 0%; +} + +.field-value:selected .checkmark-icon { + -fx-icon-size: 16; + -fx-icon-color: derive(-jr-accent, -30%);; + -fx-opacity: 100%; +} + +.unchanged { + +} + +.addition { + -rtfx-background-color: rgba(35, 225, 96, 0.26); +} + +.deletion { + -rtfx-background-color: rgba(248, 62, 68, 0.26); +} + + +.root { + -jr-transparent-green: rgba(16, 172, 132, 0.12); /* The theme color and some derived colors from it are used for icons, tab-headers, marking of selected inputs and hover colors for the main menu. It generally defines the look of JabRef. The highlighting colors below should @@ -9,6 +72,7 @@ /* This theme is the original JabRef dark blue color */ -jr-theme: #50618F; -jr-accent: #a3b7e6; + -jr-transparent-accent: rgba(163, 183, 230, 0.16); -jr-selected: -jr-accent; -jr-checked: -jr-theme; -jr-hover: #0002; From 52b56042a936f99018b277d03c07c0f5032299ff Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:11:02 +0100 Subject: [PATCH 017/473] Design and implement the merge toolbox - It will be added to the top of the merge dialog --- .../toolbox/ThreeWayMergeToolbox.fxml | 27 +++ .../toolbox/ThreeWayMergeToolbox.java | 179 ++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml new file mode 100644 index 00000000000..ccb22cb511e --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java new file mode 100644 index 00000000000..7f6b50beb88 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java @@ -0,0 +1,179 @@ +package org.jabref.gui.mergeentries.newmergedialog.toolbox; + +import java.util.Arrays; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import javafx.scene.control.RadioButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.AnchorPane; +import javafx.util.StringConverter; + +import com.airhacks.afterburner.views.ViewLoader; +import com.tobiasdiez.easybind.EasyBind; +import com.tobiasdiez.easybind.EasyBinding; + +public class ThreeWayMergeToolbox extends AnchorPane { + @FXML + private RadioButton compareCharactersRadioButtons; + + @FXML + private RadioButton compareWordsRadioButton; + + @FXML + private ToggleGroup diffCompareMethodToggleGroup; + + @FXML + private ComboBox diffViewComboBox; + + @FXML + private ComboBox plainTextOrDiffComboBox; + + private final ObjectProperty diffCompareMethod = new SimpleObjectProperty<>(); + private EasyBinding showDiff; + + public ThreeWayMergeToolbox() { + ViewLoader.view(this) + .root(this) + .load(); + } + + @FXML + public void initialize() { + showDiff = EasyBind.map(plainTextOrDiffComboBox.valueProperty(), plainTextOrDiff -> plainTextOrDiff == PlainTextOrDiff.Diff); + + plainTextOrDiffComboBox.getItems().addAll(PlainTextOrDiff.values()); + plainTextOrDiffComboBox.getSelectionModel().select(PlainTextOrDiff.PLAIN_TEXT); + plainTextOrDiffComboBox.setConverter(new StringConverter<>() { + @Override + public String toString(PlainTextOrDiff plainTextOrDiff) { + return plainTextOrDiff.getValue(); + } + + @Override + public PlainTextOrDiff fromString(String string) { + return PlainTextOrDiff.fromString(string); + } + }); + + diffViewComboBox.disableProperty().bind(notShowDiffProperty()); + diffViewComboBox.getItems().addAll(DiffView.values()); + diffViewComboBox.getSelectionModel().select(DiffView.UNIFIED); + diffViewComboBox.setConverter(new StringConverter<>() { + @Override + public String toString(DiffView diffView) { + return diffView.getValue(); + } + + @Override + public DiffView fromString(String string) { + return DiffView.fromString(string); + } + }); + + compareWordsRadioButton.disableProperty().bind(notShowDiffProperty()); + compareCharactersRadioButtons.disableProperty().bind(notShowDiffProperty()); + + diffCompareMethodToggleGroup.selectedToggleProperty().addListener((observable -> { + if (diffCompareMethodToggleGroup.getSelectedToggle().equals(compareCharactersRadioButtons)) { + diffCompareMethod.set(DiffCompareMethod.CHARS); + } else { + diffCompareMethod.set(DiffCompareMethod.WORDS); + } + })); + + diffCompareMethodToggleGroup.selectToggle(compareWordsRadioButton); + } + + private void initializeDiffViewComboBox() { + diffViewComboBox.getSelectionModel().select(DiffView.UNIFIED); + diffViewComboBox.setConverter(new StringConverter<>() { + @Override + public String toString(DiffView diffView) { + return diffView.getValue(); + } + + @Override + public DiffView fromString(String string) { + return DiffView.fromString(string); + } + }); + } + + public ReadOnlyObjectProperty diffViewProperty() { + return diffViewComboBox.valueProperty(); + } + + public DiffView getDiffView() { + return diffViewProperty().get(); + } + + public EasyBinding showDiffProperty() { + return showDiff; + } + + public EasyBinding notShowDiffProperty() { + return showDiffProperty().map(showDiff -> !showDiff); + } + + public Boolean isShowDiffEnabled() { + return showDiffProperty().get(); + } + + public ObjectProperty diffCompareMethodProperty() { + return diffCompareMethod; + } + + public DiffCompareMethod getDiffCompareMethod() { + return diffCompareMethodProperty().get(); + } + + public enum PlainTextOrDiff { + PLAIN_TEXT("Plain Text"), Diff("Show Diff"); + + private final String value; + + PlainTextOrDiff(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static PlainTextOrDiff fromString(String str) { + return Arrays.stream(values()) + .filter(plainTextOrDiff -> plainTextOrDiff.getValue().equals(str)) + .findAny() + .orElseThrow(IllegalArgumentException::new); + } + } + + public enum DiffView { + UNIFIED("Unified View"), + SPLIT("Split View"); + private final String value; + + DiffView(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static DiffView fromString(String str) { + return Arrays.stream(values()) + .filter(diffView -> diffView.getValue().equals(str)) + .findAny() + .orElseThrow(IllegalArgumentException::new); + } + } + + public enum DiffCompareMethod { + WORDS, CHARS + } +} From b2e5d38ed3ac2c99fc5454df990985e3a166b01a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:13:35 +0100 Subject: [PATCH 018/473] Implement the initial prototype of the new merge UI - Renamed ThreeWayMerge.java to ThreeWayMergeView --- .../newmergedialog/ThreeWayMerge.java | 4 - .../newmergedialog/ThreeWayMergeView.java | 78 +++++++++++++ .../ThreeWayMergeViewModel.java | 105 ++++++++++++++++++ 3 files changed, 183 insertions(+), 4 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java deleted file mode 100644 index bf2f9e651af..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMerge.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog; - -public class ThreeWayMerge { -} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java new file mode 100644 index 00000000000..c7b0cf5b64e --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -0,0 +1,78 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.stage.Screen; + +import org.jabref.gui.mergeentries.newmergedialog.toolbox.ThreeWayMergeToolbox; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; + +import static org.jabref.gui.mergeentries.newmergedialog.cell.AbstractCell.BackgroundTone; + +public class ThreeWayMergeView extends VBox { + public static final int GRID_COLUMN_MIN_WIDTH = 100; + public static final String LEFT_DEFAULT_HEADER = "Left Entry"; + public static final String RIGHT_DEFAULT_HEADER = "Right Entry"; + private ThreeWayMergeToolbox mergeToolbox; + private HeaderView headerView; + private final ScrollPane scrollPane; + private final GridPane mergeGridPane; + + private final ThreeWayMergeViewModel viewModel; + + public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { + // getStylesheets().add("newmergedialog.css"); + viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); + + mergeToolbox = new ThreeWayMergeToolbox(); + headerView = new HeaderView(); + scrollPane = new ScrollPane(); + scrollPane.setFitToWidth(true); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + mergeGridPane = new GridPane(); + initializeMergeGridPane(); + + scrollPane.setContent(mergeGridPane); + getChildren().addAll(mergeToolbox, headerView, scrollPane); + + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.78); + this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); + } + + public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry) { + this(leftEntry, rightEntry, LEFT_DEFAULT_HEADER, RIGHT_DEFAULT_HEADER); + } + + private void initializeMergeGridPane() { + ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); + fieldNameColumnConstraints.setHgrow(Priority.NEVER); + + ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + ColumnConstraints mergedEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + + leftEntryColumnConstraints.setHgrow(Priority.ALWAYS); + rightEntryColumnConstraints.setHgrow(Priority.ALWAYS); + mergedEntryColumnConstraints.setHgrow(Priority.ALWAYS); + + mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); + + for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { + addFieldRow(fieldIndex); + } + } + + private void addFieldRow(int index) { + Field field = viewModel.allFields().get(index); + String leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); + String rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); + BackgroundTone backgroundTone = index % 2 == 0 ? BackgroundTone.DARK : BackgroundTone.LIGHT; + + FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, backgroundTone); + mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java new file mode 100644 index 00000000000..47912bf9f5b --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java @@ -0,0 +1,105 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import org.jabref.gui.AbstractViewModel; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; + +class ThreeWayMergeViewModel extends AbstractViewModel { + + private final ObjectProperty leftEntry = new SimpleObjectProperty<>(); + private final ObjectProperty rightEntry = new SimpleObjectProperty<>(); + private final ObjectProperty mergedEntry = new SimpleObjectProperty<>(); + private final StringProperty leftHeader = new SimpleStringProperty(); + private final StringProperty rightHeader = new SimpleStringProperty(); + + private final ObservableList allFields = FXCollections.observableArrayList(); + + public ThreeWayMergeViewModel(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { + Objects.requireNonNull(leftEntry, "Left entry is required"); + Objects.requireNonNull(rightEntry, "Right entry is required"); + Objects.requireNonNull(leftHeader, "Left header entry is required"); + Objects.requireNonNull(rightHeader, "Right header is required"); + + setLeftEntry(leftEntry); + setRightEntry(rightEntry); + setLeftHeader(leftHeader); + setRightHeader(rightHeader); + + Set leftAndRightFieldsUnion = new HashSet<>(leftEntry.getFields()); + leftAndRightFieldsUnion.addAll(rightEntry.getFields()); + setAllFields(leftAndRightFieldsUnion); + } + + public StringProperty leftHeaderProperty() { + return leftHeader; + } + + public String getLeftHeader() { + return leftHeader.get(); + } + + public void setLeftHeader(String leftHeader) { + leftHeaderProperty().set(leftHeader); + } + + public StringProperty rightHeaderProperty() { + return rightHeader; + } + + public String getRightHeader() { + return rightHeaderProperty().get(); + } + + public void setRightHeader(String rightHeader) { + rightHeaderProperty().set(rightHeader); + } + + public BibEntry getLeftEntry() { + return leftEntry.get(); + } + + private void setLeftEntry(BibEntry bibEntry) { + leftEntry.set(bibEntry); + } + + public BibEntry getRightEntry() { + return rightEntry.get(); + } + + private void setRightEntry(BibEntry bibEntry) { + rightEntry.set(bibEntry); + } + + public BibEntry getMergedEntry() { + return mergedEntry.get(); + } + + public ObservableList allFields() { + return allFields; + } + + /** + * Convince method to determine the total number of fields in the union of the left and right fields. + */ + public int allFieldsSize() { + return allFields.size(); + } + + private void setAllFields(Set fields) { + allFields.clear(); + allFields.addAll(fields); + allFields.sort(Comparator.comparing(Field::getName)); + } +} From 51c6195b586ee385bd5d04e9db8bfd2d29a37a3e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:15:08 +0100 Subject: [PATCH 019/473] Use ThreeWayMergeView in MergeEntriesDialog - At this stage headers aren't updated and merged bib entry is not created --- .../org/jabref/gui/mergeentries/MergeEntriesDialog.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 65fb71648bd..c75f89023a4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -3,6 +3,7 @@ import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; +import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -10,9 +11,11 @@ public class MergeEntriesDialog extends BaseDialog { private final MergeEntries mergeEntries; + private final ThreeWayMergeView threeWayMergeView; public MergeEntriesDialog(BibEntry one, BibEntry two) { mergeEntries = new MergeEntries(one, two); + threeWayMergeView = new ThreeWayMergeView(one, two); init(); } @@ -21,14 +24,14 @@ public MergeEntriesDialog(BibEntry one, BibEntry two) { * Sets up the dialog */ private void init() { - this.getDialogPane().setContent(mergeEntries); + this.getDialogPane().setContent(threeWayMergeView); // Create buttons ButtonType replaceEntries = new ButtonType(Localization.lang("Merge entries"), ButtonBar.ButtonData.OK_DONE); this.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, replaceEntries); this.setResultConverter(buttonType -> { if (buttonType.equals(replaceEntries)) { - return mergeEntries.getMergedEntry(); + return null; } else { return null; } From e66ae3d33710005b8358384b407dcb285fbe1ad9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:18:58 +0100 Subject: [PATCH 020/473] Fix ThreeWayMergeView.css stylesheet not being imported --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index c7b0cf5b64e..fadc67c3f9d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -25,7 +25,7 @@ public class ThreeWayMergeView extends VBox { private final ThreeWayMergeViewModel viewModel; public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { - // getStylesheets().add("newmergedialog.css"); + getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); mergeToolbox = new ThreeWayMergeToolbox(); From d39171e97ce1db05c17a2c96c22d374dcb45f76d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:20:33 +0100 Subject: [PATCH 021/473] Span left field value to 2 columns when left and right field values are the same --- .../newmergedialog/FieldRowController.java | 10 ++++++++++ .../mergeentries/newmergedialog/ThreeWayMergeView.java | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 117f1d83ce5..6eebcaff257 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -59,4 +59,14 @@ public FieldValueCell getRightValueCell() { public MergedFieldCell getMergedValueCell() { return mergedValueCell; } + + public boolean hasEqualLeftAndRightValues() { + return !StringUtil.isNullOrEmpty(leftValueCell.getText()) && + !StringUtil.isNullOrEmpty(rightValueCell.getText()) && + leftValueCell.getText().equals(rightValueCell.getText()); + } + + public void deselectLeft() { + toggleGroup.getSelectedToggle().setSelected(false); + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index fadc67c3f9d..3d3d204ce2c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -73,6 +73,13 @@ private void addFieldRow(int index) { BackgroundTone backgroundTone = index % 2 == 0 ? BackgroundTone.DARK : BackgroundTone.LIGHT; FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, backgroundTone); - mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); + + if (fieldRow.hasEqualLeftAndRightValues()) { + mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index, 1, 1); + } else { + mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); + } } } From 6cdcec7f653ad9c1b3163cf83ad093e4b034ee21 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:23:16 +0100 Subject: [PATCH 022/473] Wrap the copy icon inside a button - Updated the selection box UI --- .../newmergedialog/cell/FieldValueCell.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 33426a4e847..69c42ab0229 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -42,6 +42,7 @@ public class FieldValueCell extends AbstractCell implements Toggle { private final StyleClassedTextArea label = new StyleClassedTextArea(); private final VirtualizedScrollPane scrollPane = new VirtualizedScrollPane<>(label); + HBox labelBox = new HBox(scrollPane); private final BooleanProperty selected = new BooleanPropertyBase() { @Override public Object getBean() { @@ -69,11 +70,6 @@ public FieldValueCell(String text, BackgroundTone backgroundTone) { initialize(); } - public FieldValueCell(String text) { - super(text); - initialize(); - } - private void initialize() { getStyleClass().add(DEFAULT_STYLE_CLASS); initializeScrollPane(); @@ -86,7 +82,7 @@ private void initialize() { } }); - selectionBox.getChildren().addAll(scrollPane, checkmarkLayout); + selectionBox.getChildren().addAll(labelBox, checkmarkLayout); getChildren().setAll(selectionBox); } @@ -113,11 +109,23 @@ private void initializeSelectionBox() { selectionBox.getStyleClass().add(SELECTION_BOX_STYLE_CLASS); HBox.setHgrow(selectionBox, Priority.ALWAYS); - FontIcon checkmarkCircleIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); - checkmarkCircleIcon.getStyleClass().add("checkmark-icon"); - checkmarkLayout.getChildren().setAll(checkmarkCircleIcon); - checkmarkLayout.setPadding(new Insets(1, 0, 0, 0)); - checkmarkLayout.setAlignment(Pos.TOP_RIGHT); + HBox.setHgrow(labelBox, Priority.ALWAYS); + labelBox.setPadding(new Insets(8)); + labelBox.setCursor(Cursor.HAND); + + FontIcon copyIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); + Button copyButton = new Button(); + copyButton.setGraphic(copyIcon); + copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + copyButton.setStyle("-fx-border-width: 0"); + + copyIcon.getStyleClass().add("checkmark-icon"); + checkmarkLayout.getChildren().setAll(copyButton); + checkmarkLayout.setAlignment(Pos.TOP_CENTER); + checkmarkLayout.setPrefWidth(28); + + copyButton.setMaxHeight(Double.MAX_VALUE); + VBox.setVgrow(copyButton, Priority.ALWAYS); } private void initializeScrollPane() { From c19d46ae9e27e651c8b29f3045d52e96c2ef0caf Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:24:07 +0100 Subject: [PATCH 023/473] Use HAND cursor when hover over FieldValueCell --- .../gui/mergeentries/newmergedialog/cell/FieldValueCell.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 69c42ab0229..473ae014e07 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -8,6 +8,9 @@ import javafx.event.Event; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.scene.Cursor; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; import javafx.scene.control.ScrollPane; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; @@ -92,6 +95,7 @@ private void initializeLabel() { label.appendText(textProperty().get()); label.setAutoHeight(true); label.setWrapText(true); + label.setStyle("-fx-cursor: hand"); // Workarounds preventTextSelectionViaMouseEvents(); From d1983ba5914127346561243072f532e82c0db68a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:25:03 +0100 Subject: [PATCH 024/473] Move field cells styles to ThreeWayMergeView.css --- src/main/java/org/jabref/gui/Base.css | 61 ------------------- .../newmergedialog/ThreeWayMergeView.css | 36 ++++++----- 2 files changed, 17 insertions(+), 80 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 6a49557ebbe..3ec5f717cf0 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -1,64 +1,3 @@ -.merged-field { - -fx-border-color: #dfdfdf; - -fx-border-width: 0 0 0 1.5; -} - -.merged-field .styled-text-area { - -fx-background-radius: 3; - -fx-border-radius: 3; - -fx-border-color: #dfdfdf; - -fx-background-color: white; -} - -.field-value:selected .selection-box { - -fx-background-color: derive(-jr-accent, 20%); - -fx-border-color: -jr-accent; -} - -.field-value .selection-box { - -fx-background-color: #0000; - -fx-padding: 8; - -fx-border-width: 1; - -fx-border-color: #0000; - -fx-border-radius: 8; - -fx-background-radius: 8; -} - -.field-value .label { - -fx-font-size: 13; -} - -.field-value .text-area { - -fx-font-size: 13; -} - - -.field-value .checkmark-icon { - -fx-icon-size: 16; - -fx-icon-color: -jr-gray-2; - -fx-opacity: 100%; -} -.field-value:disabled .checkmark-icon { - -fx-opacity: 0%; -} - -.field-value:selected .checkmark-icon { - -fx-icon-size: 16; - -fx-icon-color: derive(-jr-accent, -30%);; - -fx-opacity: 100%; -} - -.unchanged { - -} - -.addition { - -rtfx-background-color: rgba(35, 225, 96, 0.26); -} - -.deletion { - -rtfx-background-color: rgba(248, 62, 68, 0.26); -} .root { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index c95470b32dc..dbbe6a24b1c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -4,22 +4,21 @@ } .merged-field .styled-text-area { - -fx-background-radius: 5; - -fx-border-radius: 5; - -fx-border-color: #dfdfdf + -fx-background-radius: 3; + -fx-border-radius: 3; + -fx-border-color: #dfdfdf; + -fx-background-color: white; } .field-value:selected .selection-box { - -fx-background-color: -jr-transparent-green; - -fx-border-color: -jr-green; + -fx-background-color: derive(-jr-accent, 20%); + -fx-border-color: -jr-accent; } .field-value .selection-box { -fx-background-color: #0000; - -fx-padding: 8; -fx-border-width: 1; - -fx-border-color: #219b3800; - -fx-border-style: SOLID; + -fx-border-color: #0000; -fx-border-radius: 8; -fx-background-radius: 8; } @@ -32,15 +31,19 @@ -fx-font-size: 13; } -.field-value .checkmark { - -fx-icon-size: 13; - -fx-icon-color: #25b060; + +.field-value .checkmark-icon { + -fx-icon-size: 16; + -fx-icon-color: -jr-gray-2; + -fx-opacity: 100%; +} +.field-value:disabled .checkmark-icon { -fx-opacity: 0%; } -.field-value:selected .checkmark { - -fx-icon-size: 14; - -fx-icon-color: -jr-green; +.field-value:selected .checkmark-icon { + -fx-icon-size: 16; + -fx-icon-color: derive(-jr-accent, -30%);; -fx-opacity: 100%; } @@ -55,8 +58,3 @@ .deletion { -rtfx-background-color: rgba(248, 62, 68, 0.26); } - - -* { - -jr-transparent-green: rgba(16, 172, 132, 0.15); -} From 5d22e16ce9042ff7d77387fa6d8bdb04af6c12d2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:25:31 +0100 Subject: [PATCH 025/473] Update merge toolbox FXML UI --- .../newmergedialog/toolbox/ThreeWayMergeToolbox.fxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml index ccb22cb511e..8a729b85ecb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml @@ -10,7 +10,7 @@ - + From 23c6c9112a366ec668ceaae89dac374a001e9ac7 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:35:13 +0100 Subject: [PATCH 026/473] Implement and style HeaderCell --- .../newmergedialog/cell/HeaderCell.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java new file mode 100644 index 00000000000..d406a76cafe --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -0,0 +1,27 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import javafx.geometry.Insets; +import javafx.scene.control.Label; + +public class HeaderCell extends AbstractCell { + public static final String DEFAULT_STYLE_CLASS = "header-cell"; + private final Label label = new Label(); + + public HeaderCell(String text) { + super(text, 1); + initialize(); + } + + private void initialize() { + getStyleClass().add(DEFAULT_STYLE_CLASS); + initializeLabel(); + getChildren().add(label); + setStyle("-fx-border-width: 0 0 0.8 0; -fx-border-color: #424758"); + } + + private void initializeLabel() { + label.textProperty().bind(textProperty()); + label.setStyle("-fx-font-weight: bold; -fx-font-size: 13"); + label.setPadding(new Insets(1, 0, 1, 0)); + } +} From d2f8e2197f7c6bc705705b5a02743fa7de7aa3a1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:00:10 +0100 Subject: [PATCH 027/473] Take row index as an argument in AbstractCell - Created odd and even pseudo classes that will update the background color of the cell when state changes. - Created NO_ROW_INDEX to be used by HeaderCell, because HeaderCell doesn't base its background color on its row position which is 0. --- .../newmergedialog/cell/AbstractCell.java | 77 +++++++++++++------ 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java index b57a14bce1f..10b13bd5b71 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java @@ -1,11 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.BooleanPropertyBase; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import javafx.css.PseudoClass; import javafx.geometry.Insets; -import javafx.scene.layout.Background; import javafx.scene.layout.HBox; import javafx.scene.paint.Color; @@ -13,21 +13,60 @@ * */ public abstract class AbstractCell extends HBox { + public static final String ODD_PSEUDO_CLASS = "odd"; + public static final String EVEN_PSEUDO_CLASS = "even"; + public static final int NO_ROW_NUMBER = -1; + private static final String DEFAULT_STYLE_CLASS = "field-cell"; private final StringProperty text = new SimpleStringProperty(); - private final ObjectProperty backgroundTone = new SimpleObjectProperty<>(); + private final BooleanProperty odd = new BooleanPropertyBase() { + @Override + public Object getBean() { + return AbstractCell.this; + } + + @Override + public String getName() { + return "odd"; + } + + @Override + protected void invalidated() { + pseudoClassStateChanged(PseudoClass.getPseudoClass(ODD_PSEUDO_CLASS), get()); + pseudoClassStateChanged(PseudoClass.getPseudoClass(EVEN_PSEUDO_CLASS), !get()); + } + }; + + private final BooleanProperty even = new BooleanPropertyBase() { + @Override + public Object getBean() { + return AbstractCell.this; + } + + @Override + public String getName() { + return "even"; + } + + @Override + protected void invalidated() { + pseudoClassStateChanged(PseudoClass.getPseudoClass(EVEN_PSEUDO_CLASS), get()); + pseudoClassStateChanged(PseudoClass.getPseudoClass(ODD_PSEUDO_CLASS), !get()); + } + }; + + public AbstractCell(String text, int rowIndex) { + getStyleClass().add(DEFAULT_STYLE_CLASS); + if (rowIndex != NO_ROW_NUMBER) { + if (rowIndex % 2 == 1) { + odd.setValue(true); + } else { + even.setValue(true); + } + } - public AbstractCell(String text, BackgroundTone backgroundTone) { - backgroundToneProperty().addListener(invalidated -> setBackground(Background.fill(getBackgroundTone().color()))); setPadding(new Insets(8)); setText(text); - setBackgroundTone(backgroundTone); - // TODO: Remove this when cells are added to the grid pane, and add the stylesheet to the root layout instead. - getStylesheets().add("../ThreeWayMergeView.css"); - } - - public AbstractCell(String text) { - this(text, BackgroundTone.DARK); } public String getText() { @@ -42,18 +81,6 @@ public void setText(String text) { textProperty().set(text); } - public void setBackgroundTone(BackgroundTone backgroundTone) { - backgroundToneProperty().set(backgroundTone); - } - - public BackgroundTone getBackgroundTone() { - return backgroundToneProperty().get(); - } - - public ObjectProperty backgroundToneProperty() { - return backgroundTone; - } - public enum BackgroundTone { LIGHT(Color.web("#FEFEFE")), DARK(Color.web("#EFEFEF")); private final Color color; From 329e2f9ac038145d061a6ee149c199b27b42f974 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:37:33 +0100 Subject: [PATCH 028/473] Color cell background based on its row position (odd or even) --- .../newmergedialog/cell/FieldNameCell.java | 9 ++------- .../newmergedialog/cell/FieldValueCell.java | 8 ++++++-- .../newmergedialog/cell/MergedFieldCell.java | 11 ++++------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 7730b4d43ab..7ad435d59b1 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -9,13 +9,8 @@ public class FieldNameCell extends AbstractCell { public static final String DEFAULT_STYLE_CLASS = "field-name"; private final Label label = new Label(); - public FieldNameCell(String text, BackgroundTone backgroundTone) { - super(text, backgroundTone); - initialize(); - } - - public FieldNameCell(String text) { - super(text); + public FieldNameCell(String text, int rowIndex) { + super(text, rowIndex); initialize(); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 473ae014e07..9927276f621 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -22,6 +22,10 @@ import javafx.scene.layout.VBox; import javafx.scene.paint.Color; +import org.jabref.gui.Globals; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.logic.l10n.Localization; + import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.StyleClassedTextArea; import org.fxmisc.wellbehaved.event.InputMap; @@ -68,8 +72,8 @@ protected void invalidated() { private final HBox selectionBox = new HBox(); private final VBox checkmarkLayout = new VBox(); - public FieldValueCell(String text, BackgroundTone backgroundTone) { - super(text, backgroundTone); + public FieldValueCell(String text, int rowIndex) { + super(text, rowIndex); initialize(); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java index 4bce784c13d..7617cdd4f30 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java @@ -6,6 +6,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; +import org.jabref.gui.util.BindingsHelper; + import org.fxmisc.richtext.StyleClassedTextArea; public class MergedFieldCell extends AbstractCell { @@ -13,13 +15,8 @@ public class MergedFieldCell extends AbstractCell { private final StyleClassedTextArea textArea = new StyleClassedTextArea(); - public MergedFieldCell(String text, BackgroundTone backgroundTone) { - super(text, backgroundTone); - initialize(); - } - - public MergedFieldCell(String text) { - super(text); + public MergedFieldCell(String text, int rowIndex) { + super(text, rowIndex); initialize(); } From 3df63ae24660e79b825f1f19f32ed9cf454cdf40 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:38:53 +0100 Subject: [PATCH 029/473] Bind textArea.textProperty() and textProperty() using BindingsHelper --- .../newmergedialog/cell/MergedFieldCell.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java index 7617cdd4f30..77f170541d6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java @@ -27,7 +27,10 @@ private void initialize() { } private void initializeTextArea() { - bindTextAreaValue(); + BindingsHelper.bindBidirectional(textArea.textProperty(), + textProperty(), + textArea::replaceText, + textProperty()::setValue); setAlignment(Pos.CENTER); textArea.setWrapText(true); @@ -40,9 +43,4 @@ private void initializeTextArea() { MergedFieldCell.this.fireEvent(e.copyFor(e.getSource(), MergedFieldCell.this)); }); } - - private void bindTextAreaValue() { - textArea.replaceText(textProperty().get()); - textProperty().addListener(((observable, oldValue, newValue) -> textArea.replaceText(newValue))); - } } From dd28f10737dc3ec6051fe1c233070779996ca0e4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:40:57 +0100 Subject: [PATCH 030/473] Copy field value to Clipboard user clicks on the copy button - Renamed copy-icon style class - Used ActionFactory for creating the copy icon button --- .../cell/CopyFieldValueCommand.java | 23 +++++++++++++++++++ .../newmergedialog/cell/FieldValueCell.java | 10 ++++---- 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java new file mode 100644 index 00000000000..e18a831933b --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java @@ -0,0 +1,23 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import java.util.Objects; + +import org.jabref.gui.ClipBoardManager; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.preferences.PreferencesService; + +public class CopyFieldValueCommand extends SimpleCommand { + private final String fieldValue; + private final ClipBoardManager clipBoardManager; + + public CopyFieldValueCommand(PreferencesService preferencesService, final String fieldValue) { + Objects.requireNonNull(fieldValue, "Field value cannot be null"); + this.fieldValue = fieldValue; + this.clipBoardManager = new ClipBoardManager(preferencesService); + } + + @Override + public void execute() { + clipBoardManager.setContent(fieldValue); + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 9927276f621..8945cf688e5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -48,6 +48,8 @@ public class FieldValueCell extends AbstractCell implements Toggle { private final ObjectProperty toggleGroup = new SimpleObjectProperty<>(); private final StyleClassedTextArea label = new StyleClassedTextArea(); + private final ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + private final VirtualizedScrollPane scrollPane = new VirtualizedScrollPane<>(label); HBox labelBox = new HBox(scrollPane); private final BooleanProperty selected = new BooleanPropertyBase() { @@ -65,8 +67,7 @@ public String getName() { protected void invalidated() { pseudoClassStateChanged(SELECTED_PSEUDO_CLASS, get()); - ToggleGroup group = getToggleGroup(); - group.selectToggle(FieldValueCell.this); + getToggleGroup().selectToggle(FieldValueCell.this); } }; private final HBox selectionBox = new HBox(); @@ -122,12 +123,11 @@ private void initializeSelectionBox() { labelBox.setCursor(Cursor.HAND); FontIcon copyIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); - Button copyButton = new Button(); + Button copyButton = factory.createIconButton(() -> Localization.lang("Copy"), new CopyFieldValueCommand(Globals.prefs, getText())); copyButton.setGraphic(copyIcon); copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); - copyButton.setStyle("-fx-border-width: 0"); - copyIcon.getStyleClass().add("checkmark-icon"); + copyIcon.getStyleClass().add("copy-icon"); checkmarkLayout.getChildren().setAll(copyButton); checkmarkLayout.setAlignment(Pos.TOP_CENTER); checkmarkLayout.setPrefWidth(28); From 8231f75049a0c16b168da813db97859508f6adb6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:43:25 +0100 Subject: [PATCH 031/473] Implement a more complete HeaderView - Created ColumnConstraints that matches the field grid constraints, so when the window is resized grid and header resize equally --- .../newmergedialog/HeaderView.java | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java index ea7049cd857..359b11343c8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java @@ -1,10 +1,65 @@ package org.jabref.gui.mergeentries.newmergedialog; -import javafx.scene.layout.HBox; +import javafx.geometry.Insets; +import javafx.scene.control.Control; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.RowConstraints; -public class HeaderView extends HBox { - public HeaderView() { - setPrefHeight(50d); - setStyle("-fx-background-color: #878787"); +import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; + +/** + * I used a GridPane instead of a Hbox because Hbox allocates more space for cells + * with longer text, but I wanted all cells to have the same width + */ +public class HeaderView extends GridPane { + public static final int GRID_COLUMN_MIN_WIDTH = 250; + private final String leftHeader; + private final String rightHeader; + public HeaderView(String leftHeader, String rightHeader) { + this.leftHeader = leftHeader; + this.rightHeader = rightHeader; + setPrefHeight(Control.USE_COMPUTED_SIZE); + + setMaxHeight(Control.USE_PREF_SIZE); + setMinHeight(Control.USE_PREF_SIZE); + addRow( + 0, + new HeaderCell(""), + new HeaderCell(leftHeader), + new HeaderCell(rightHeader), + new HeaderCell("Merged Entry") + ); + + bindHeaderContainerWidthToFieldGridWidth(); + + ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); + fieldNameColumnConstraints.setHgrow(Priority.NEVER); + + ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + ColumnConstraints mergedEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + + leftEntryColumnConstraints.setHgrow(Priority.ALWAYS); + rightEntryColumnConstraints.setHgrow(Priority.ALWAYS); + mergedEntryColumnConstraints.setHgrow(Priority.ALWAYS); + + getColumnConstraints().setAll( + fieldNameColumnConstraints, + leftEntryColumnConstraints, + rightEntryColumnConstraints, + mergedEntryColumnConstraints + ); + } + + /** + * The fields grid pane is contained within a scroll pane, thus it doesn't allocate the full available width. In + * fact, it uses the available width minus the size of the scrollbar which is 8. This leads to header columns being + * always larger than fields columns. This hack should solve this problem. + */ + private void bindHeaderContainerWidthToFieldGridWidth() { + setPadding(new Insets(0, 8, 0, 0)); + setStyle("-fx-background-color: #EFEFEF"); } } From 3575569becf25de60b802d1c54579cbbfed8e232 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:45:34 +0100 Subject: [PATCH 032/473] Pass left and right headers to HeaderView --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 3d3d204ce2c..f3565505977 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -29,7 +29,7 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); mergeToolbox = new ThreeWayMergeToolbox(); - headerView = new HeaderView(); + headerView = new HeaderView(leftHeader, rightHeader); scrollPane = new ScrollPane(); scrollPane.setFitToWidth(true); scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); From 7aa387fc7ea696c15bbf50fdda3d261f7b48c366 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:49:28 +0100 Subject: [PATCH 033/473] Create merged entry --- .../gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java index 47912bf9f5b..3303b987501 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java @@ -37,6 +37,8 @@ public ThreeWayMergeViewModel(BibEntry leftEntry, BibEntry rightEntry, String le setLeftHeader(leftHeader); setRightHeader(rightHeader); + mergedEntry.set(new BibEntry()); + Set leftAndRightFieldsUnion = new HashSet<>(leftEntry.getFields()); leftAndRightFieldsUnion.addAll(rightEntry.getFields()); setAllFields(leftAndRightFieldsUnion); From 4a8f1e8e347cd59f24923c76e1bb351bf54714b4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:50:18 +0100 Subject: [PATCH 034/473] Add the entry type field at the top of the fields list - Sorted fields by name - Removed internal fields --- .../newmergedialog/ThreeWayMergeViewModel.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java index 3303b987501..5314a725875 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeViewModel.java @@ -15,6 +15,8 @@ import org.jabref.gui.AbstractViewModel; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldFactory; +import org.jabref.model.entry.field.InternalField; class ThreeWayMergeViewModel extends AbstractViewModel { @@ -102,6 +104,12 @@ public int allFieldsSize() { private void setAllFields(Set fields) { allFields.clear(); allFields.addAll(fields); + // Don't show internal fields. See org.jabref.model.entry.field.InternalField + allFields.removeIf(FieldFactory::isInternalField); + allFields.sort(Comparator.comparing(Field::getName)); + + // Add the entry type field as the first field to display + allFields.add(0, InternalField.TYPE_HEADER); } } From 70522eb1b62ea0e87603f6f83a41b261e27c40d3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:55:13 +0100 Subject: [PATCH 035/473] Display entry type and bind merged entry --- .../newmergedialog/FieldRowController.java | 36 +++++++++++++------ .../newmergedialog/ThreeWayMergeView.java | 35 ++++++++++++++---- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 6eebcaff257..9e9a077c3ea 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -3,7 +3,6 @@ import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; -import org.jabref.gui.mergeentries.newmergedialog.cell.AbstractCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; @@ -17,18 +16,37 @@ public class FieldRowController { private final ToggleGroup toggleGroup = new ToggleGroup(); - public FieldRowController(String fieldName, String leftValue, String rightValue, AbstractCell.BackgroundTone backgroundTone) { - fieldNameCell = new FieldNameCell(fieldName, backgroundTone); - leftValueCell = new FieldValueCell(leftValue, backgroundTone); - rightValueCell = new FieldValueCell(rightValue, backgroundTone); - mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, backgroundTone); + public FieldRowController(String fieldName, String leftValue, String rightValue, int rowIndex) { + fieldNameCell = new FieldNameCell(fieldName, rowIndex); + leftValueCell = new FieldValueCell(leftValue, rowIndex); + rightValueCell = new FieldValueCell(rightValue, rowIndex); + mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); toggleGroup.selectedToggleProperty().addListener(invalidated -> { - mergedValueCell.setText((String) toggleGroup.getSelectedToggle().getUserData()); + if (toggleGroup.getSelectedToggle() != null) { + mergedValueCell.setText((String) toggleGroup.getSelectedToggle().getUserData()); + } }); + mergedValueCell.textProperty().addListener((observable, old, mergedValue) -> { + if (!StringUtil.isNullOrEmpty(mergedValue)) { + if (mergedValue.equals(leftValue)) { + toggleGroup.selectToggle(leftValueCell); + } else if (mergedValue.equals(rightValue)) { + toggleGroup.selectToggle(rightValueCell); + } else { + // deselect all toggles because left and right values don't equal the merged value + toggleGroup.selectToggle(null); + } + } else { + // deselect all toggles because empty toggles cannot be selected + toggleGroup.selectToggle(null); + } + }); + + // empty toggles are disabled and cannot be selected if (StringUtil.isNullOrEmpty(leftValue)) { leftValueCell.setDisable(true); } else if (StringUtil.isNullOrEmpty(rightValue)) { @@ -65,8 +83,4 @@ public boolean hasEqualLeftAndRightValues() { !StringUtil.isNullOrEmpty(rightValueCell.getText()) && leftValueCell.getText().equals(rightValueCell.getText()); } - - public void deselectLeft() { - toggleGroup.getSelectedToggle().setSelected(false); - } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index f3565505977..268b98f3bd9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,8 +10,8 @@ import org.jabref.gui.mergeentries.newmergedialog.toolbox.ThreeWayMergeToolbox; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; - -import static org.jabref.gui.mergeentries.newmergedialog.cell.AbstractCell.BackgroundTone; +import org.jabref.model.entry.field.InternalField; +import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 100; @@ -68,11 +68,30 @@ private void initializeMergeGridPane() { private void addFieldRow(int index) { Field field = viewModel.allFields().get(index); - String leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); - String rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); - BackgroundTone backgroundTone = index % 2 == 0 ? BackgroundTone.DARK : BackgroundTone.LIGHT; - FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, backgroundTone); + String leftEntryValue; + String rightEntryValue; + if (field.equals(InternalField.TYPE_HEADER)) { + leftEntryValue = viewModel.getLeftEntry().getType().getDisplayName(); + rightEntryValue = viewModel.getRightEntry().getType().getDisplayName(); + } else { + leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); + rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); + } + + FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, index); + fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { + if (field.equals(InternalField.TYPE_HEADER)) { + getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); + } else { + getMergedEntry().setField(field, mergedValue); + } + }); + if (field.equals(InternalField.TYPE_HEADER)) { + getMergedEntry().setType(EntryTypeFactory.parse(fieldRow.getMergedValue())); + } else { + getMergedEntry().setField(field, fieldRow.getMergedValue()); + } if (fieldRow.hasEqualLeftAndRightValues()) { mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); @@ -82,4 +101,8 @@ private void addFieldRow(int index) { mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); } } + + public BibEntry getMergedEntry() { + return viewModel.getMergedEntry(); + } } From 9a052772e8869bf8cc749e4bb2ab16b3e7038780 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:55:29 +0100 Subject: [PATCH 036/473] Minor changes --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 268b98f3bd9..a6322b34d8e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -14,7 +14,7 @@ import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { - public static final int GRID_COLUMN_MIN_WIDTH = 100; + public static final int GRID_COLUMN_MIN_WIDTH = 250; public static final String LEFT_DEFAULT_HEADER = "Left Entry"; public static final String RIGHT_DEFAULT_HEADER = "Right Entry"; private ThreeWayMergeToolbox mergeToolbox; @@ -39,7 +39,7 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea scrollPane.setContent(mergeGridPane); getChildren().addAll(mergeToolbox, headerView, scrollPane); - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.78); + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); } From d578b7ed6168de3b913abaa235f558a5171d1e32 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:55:51 +0100 Subject: [PATCH 037/473] Style CSS --- src/main/java/org/jabref/gui/Base.css | 8 +++++ src/main/java/org/jabref/gui/Dark.css | 3 ++ .../newmergedialog/ThreeWayMergeView.css | 35 +++++++++++++------ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 3ec5f717cf0..4c93cc0defa 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -2,6 +2,14 @@ .root { -jr-transparent-green: rgba(16, 172, 132, 0.12); + -jr-row-odd-background: -fx-control-inner-background; + -jr-row-even-background: -fx-control-inner-background-alt; + /* + On light theme, the text is hard to see when it's on top of the accent color. This is an alternative lighter accent color + for better text visibility. + */ + -jr-accent-alt: derive(-jr-accent, 10%); + /* The theme color and some derived colors from it are used for icons, tab-headers, marking of selected inputs and hover colors for the main menu. It generally defines the look of JabRef. The highlighting colors below should diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index e1de8084646..1ccb79df1e3 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -4,6 +4,9 @@ -jr-selected: -jr-accent; -jr-hover: #fff1; + -jr-row-odd-background: #272b38; + -jr-row-even-background: #212330; + -jr-accent-alt: -jr-accent; -jr-red: #b71c1f; -jr-light-red: #db1d2b; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index dbbe6a24b1c..db916d9010a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -11,8 +11,8 @@ } .field-value:selected .selection-box { - -fx-background-color: derive(-jr-accent, 20%); - -fx-border-color: -jr-accent; + -fx-background-color: -jr-accent-alt; + -fx-border-color: -jr-accent-alt; } .field-value .selection-box { @@ -23,8 +23,8 @@ -fx-background-radius: 8; } -.field-value .label { - -fx-font-size: 13; +.field-value .styled-text-area .text{ + -fx-fill: -fx-text-background-color; } .field-value .text-area { @@ -32,21 +32,34 @@ } -.field-value .checkmark-icon { - -fx-icon-size: 16; - -fx-icon-color: -jr-gray-2; +.field-value .copy-icon { + -fx-icon-size: 15; + -fx-icon-color: -fx-text-background-color; -fx-opacity: 100%; } -.field-value:disabled .checkmark-icon { + +.field-value:disabled .copy-icon { -fx-opacity: 0%; } -.field-value:selected .checkmark-icon { - -fx-icon-size: 16; - -fx-icon-color: derive(-jr-accent, -30%);; +.field-value:selected .copy-icon { + -fx-icon-color: -fx-text-background-color; -fx-opacity: 100%; } +.field-cell:odd { + -fx-background-color: -jr-row-odd-background; +} + +.field-cell:even { + -fx-background-color: -jr-row-even-background; +} + +.merge-toolbox { + -fx-background-color: -jr-menu-background; +} + +/* Diff Highlighting */ .unchanged { } From 27dbcd160e7bfd8226030320b23f90c50f94ae63 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:56:08 +0100 Subject: [PATCH 038/473] Update ThreeWayMergeToolbox.fxml --- .../newmergedialog/toolbox/ThreeWayMergeToolbox.fxml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml index 8a729b85ecb..6829ee78b54 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml @@ -6,15 +6,16 @@ - + - + - - - + + + + From c9b87de680e33691f13d6288df602e58dc292b33 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 03:56:35 +0100 Subject: [PATCH 039/473] Remove MergeEntries from MergeEntriesDialog --- .../org/jabref/gui/mergeentries/MergeEntriesDialog.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index c75f89023a4..0a76be098a2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -9,12 +9,9 @@ import org.jabref.model.entry.BibEntry; public class MergeEntriesDialog extends BaseDialog { - - private final MergeEntries mergeEntries; private final ThreeWayMergeView threeWayMergeView; public MergeEntriesDialog(BibEntry one, BibEntry two) { - mergeEntries = new MergeEntries(one, two); threeWayMergeView = new ThreeWayMergeView(one, two); init(); @@ -31,7 +28,7 @@ private void init() { this.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, replaceEntries); this.setResultConverter(buttonType -> { if (buttonType.equals(replaceEntries)) { - return null; + return threeWayMergeView.getMergedEntry(); } else { return null; } @@ -39,10 +36,10 @@ private void init() { } public void setLeftHeaderText(String leftHeaderText) { - mergeEntries.setLeftHeaderText(leftHeaderText); + // mergeEntries.setLeftHeaderText(leftHeaderText); } public void setRightHeaderText(String rightHeaderText) { - mergeEntries.setRightHeaderText(rightHeaderText); + // mergeEntries.setRightHeaderText(rightHeaderText); } } From 5e306a410f73a73082cb9c6fb270b90a97083f94 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:01:52 +0100 Subject: [PATCH 040/473] Create EmptyCell for optimization - When cell is empty there is no point of creating a label object --- .../mergeentries/newmergedialog/cell/EmptyCell.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java new file mode 100644 index 00000000000..e52ada18b13 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java @@ -0,0 +1,13 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +public class EmptyCell extends AbstractCell { + public EmptyCell(String styleClass, int rowIndex) { + super("", rowIndex); + getStyleClass().add(styleClass); + setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + } + + public EmptyCell(String styleClass) { + this(styleClass, AbstractCell.NO_ROW_NUMBER); + } +} From 5c5c68a1bd504bb0885aaf8995d352c86c187b00 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:02:12 +0100 Subject: [PATCH 041/473] Update HeaderCell --- .../gui/mergeentries/newmergedialog/cell/HeaderCell.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index d406a76cafe..1bc003200ca 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -1,6 +1,5 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; -import javafx.geometry.Insets; import javafx.scene.control.Label; public class HeaderCell extends AbstractCell { @@ -8,7 +7,7 @@ public class HeaderCell extends AbstractCell { private final Label label = new Label(); public HeaderCell(String text) { - super(text, 1); + super(text, AbstractCell.NO_ROW_NUMBER); initialize(); } @@ -16,12 +15,9 @@ private void initialize() { getStyleClass().add(DEFAULT_STYLE_CLASS); initializeLabel(); getChildren().add(label); - setStyle("-fx-border-width: 0 0 0.8 0; -fx-border-color: #424758"); } private void initializeLabel() { label.textProperty().bind(textProperty()); - label.setStyle("-fx-font-weight: bold; -fx-font-size: 13"); - label.setPadding(new Insets(1, 0, 1, 0)); } } From d14cb0f00162ee4d81ab633d14315df886483996 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:02:50 +0100 Subject: [PATCH 042/473] Rename HeaderView to ThreeWayMergeHeaderView --- .../newmergedialog/HeaderView.java | 65 ------------------- .../ThreeWayMergeHeaderView.java | 58 +++++++++++++++++ 2 files changed, 58 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java deleted file mode 100644 index 359b11343c8..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/HeaderView.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog; - -import javafx.geometry.Insets; -import javafx.scene.control.Control; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Priority; -import javafx.scene.layout.RowConstraints; - -import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; - -/** - * I used a GridPane instead of a Hbox because Hbox allocates more space for cells - * with longer text, but I wanted all cells to have the same width - */ -public class HeaderView extends GridPane { - public static final int GRID_COLUMN_MIN_WIDTH = 250; - private final String leftHeader; - private final String rightHeader; - public HeaderView(String leftHeader, String rightHeader) { - this.leftHeader = leftHeader; - this.rightHeader = rightHeader; - setPrefHeight(Control.USE_COMPUTED_SIZE); - - setMaxHeight(Control.USE_PREF_SIZE); - setMinHeight(Control.USE_PREF_SIZE); - addRow( - 0, - new HeaderCell(""), - new HeaderCell(leftHeader), - new HeaderCell(rightHeader), - new HeaderCell("Merged Entry") - ); - - bindHeaderContainerWidthToFieldGridWidth(); - - ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); - fieldNameColumnConstraints.setHgrow(Priority.NEVER); - - ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); - ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); - ColumnConstraints mergedEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); - - leftEntryColumnConstraints.setHgrow(Priority.ALWAYS); - rightEntryColumnConstraints.setHgrow(Priority.ALWAYS); - mergedEntryColumnConstraints.setHgrow(Priority.ALWAYS); - - getColumnConstraints().setAll( - fieldNameColumnConstraints, - leftEntryColumnConstraints, - rightEntryColumnConstraints, - mergedEntryColumnConstraints - ); - } - - /** - * The fields grid pane is contained within a scroll pane, thus it doesn't allocate the full available width. In - * fact, it uses the available width minus the size of the scrollbar which is 8. This leads to header columns being - * always larger than fields columns. This hack should solve this problem. - */ - private void bindHeaderContainerWidthToFieldGridWidth() { - setPadding(new Insets(0, 8, 0, 0)); - setStyle("-fx-background-color: #EFEFEF"); - } -} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java new file mode 100644 index 00000000000..9299c5f2ef9 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -0,0 +1,58 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import javafx.geometry.Insets; +import javafx.scene.control.Control; +import javafx.scene.layout.GridPane; + +import org.jabref.gui.mergeentries.newmergedialog.cell.EmptyCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; + +/** + * I used a GridPane instead of a Hbox because Hbox allocates more space for cells + * with longer text, but I wanted all cells to have the same width + */ +public class ThreeWayMergeHeaderView extends GridPane { + public static final String DEFAULT_STYLE_CLASS = "merge-header"; + private final HeaderCell leftHeaderCell; + private final HeaderCell rightHeaderCell; + + private final HeaderCell mergedHeaderCell; + + public ThreeWayMergeHeaderView(String leftHeader, String rightHeader) { + getStyleClass().add(DEFAULT_STYLE_CLASS); + + this.leftHeaderCell = new HeaderCell(leftHeader); + this.rightHeaderCell = new HeaderCell(rightHeader); + this.mergedHeaderCell = new HeaderCell("Merged Entry"); + + addRow(0, + new EmptyCell(HeaderCell.DEFAULT_STYLE_CLASS), + leftHeaderCell, + rightHeaderCell, + mergedHeaderCell + ); + + setPrefHeight(Control.USE_COMPUTED_SIZE); + setMaxHeight(Control.USE_PREF_SIZE); + setMinHeight(Control.USE_PREF_SIZE); + + bindHeaderWidthToFieldGridWidth(); + } + + public void setLeftHeader(String leftHeader) { + leftHeaderCell.setText(leftHeader); + } + + public void setRightHeader(String rightHeader) { + rightHeaderCell.setText(rightHeader); + } + + /** + * The fields grid pane is contained within a scroll pane, thus it doesn't allocate the full available width. In + * fact, it uses the available width minus the size of the scrollbar which is 8. This leads to header columns being + * always larger than fields columns. This hack should fix it. + */ + private void bindHeaderWidthToFieldGridWidth() { + setPadding(new Insets(0, 8, 0, 0)); + } +} From 23be621d209662fed9c2e657fd1dc77dd7229366 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:04:13 +0100 Subject: [PATCH 043/473] Add buttons to accept all left or right entry changes to ThreeWayMergeToolbar --- .../java/org/jabref/gui/icon/IconTheme.java | 6 +- .../toolbar/ThreeWayMergeToolbar.fxml | 48 +++++++++++ .../ThreeWayMergeToolbar.java} | 79 +++++++++++-------- .../toolbox/ThreeWayMergeToolbox.fxml | 28 ------- 4 files changed, 98 insertions(+), 63 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{toolbox/ThreeWayMergeToolbox.java => toolbar/ThreeWayMergeToolbar.java} (65%) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml diff --git a/src/main/java/org/jabref/gui/icon/IconTheme.java b/src/main/java/org/jabref/gui/icon/IconTheme.java index cbaa6fac7d8..8ef3ed5d490 100644 --- a/src/main/java/org/jabref/gui/icon/IconTheme.java +++ b/src/main/java/org/jabref/gui/icon/IconTheme.java @@ -339,7 +339,11 @@ public enum JabRefIcons implements JabRefIcon { KEEP_SEARCH_STRING(MaterialDesignE.EARTH), KEEP_ON_TOP(MaterialDesignP.PIN), KEEP_ON_TOP_OFF(MaterialDesignP.PIN_OFF_OUTLINE), - OPEN_GLOBAL_SEARCH(MaterialDesignO.OPEN_IN_NEW); + OPEN_GLOBAL_SEARCH(MaterialDesignO.OPEN_IN_NEW), + + ACCEPT_LEFT(MaterialDesignS.SUBDIRECTORY_ARROW_LEFT), + + ACCEPT_RIGHT(MaterialDesignS.SUBDIRECTORY_ARROW_RIGHT); private final JabRefIcon icon; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml new file mode 100644 index 00000000000..39df997c47b --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java similarity index 65% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 7f6b50beb88..0703f49f7c2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -1,14 +1,18 @@ -package org.jabref.gui.mergeentries.newmergedialog.toolbox; +package org.jabref.gui.mergeentries.newmergedialog.toolbar; import java.util.Arrays; +import java.util.function.Consumer; +import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.fxml.FXML; +import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.RadioButton; import javafx.scene.control.ToggleGroup; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import javafx.util.StringConverter; @@ -16,15 +20,15 @@ import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; -public class ThreeWayMergeToolbox extends AnchorPane { +public class ThreeWayMergeToolbar extends AnchorPane { @FXML - private RadioButton compareCharactersRadioButtons; + private RadioButton highlightCharactersRadioButtons; @FXML - private RadioButton compareWordsRadioButton; + private RadioButton highlightWordsRadioButton; @FXML - private ToggleGroup diffCompareMethodToggleGroup; + private ToggleGroup diffHighlightModeToggleGroup; @FXML private ComboBox diffViewComboBox; @@ -32,10 +36,16 @@ public class ThreeWayMergeToolbox extends AnchorPane { @FXML private ComboBox plainTextOrDiffComboBox; - private final ObjectProperty diffCompareMethod = new SimpleObjectProperty<>(); + @FXML + private Button selectLeftEntryValuesButton; + + @FXML + private Button selectRightEntryValuesButton; + + private final ObjectProperty diffHighlightMode = new SimpleObjectProperty<>(); private EasyBinding showDiff; - public ThreeWayMergeToolbox() { + public ThreeWayMergeToolbar() { ViewLoader.view(this) .root(this) .load(); @@ -74,33 +84,18 @@ public DiffView fromString(String string) { } }); - compareWordsRadioButton.disableProperty().bind(notShowDiffProperty()); - compareCharactersRadioButtons.disableProperty().bind(notShowDiffProperty()); + highlightWordsRadioButton.disableProperty().bind(notShowDiffProperty()); + highlightCharactersRadioButtons.disableProperty().bind(notShowDiffProperty()); - diffCompareMethodToggleGroup.selectedToggleProperty().addListener((observable -> { - if (diffCompareMethodToggleGroup.getSelectedToggle().equals(compareCharactersRadioButtons)) { - diffCompareMethod.set(DiffCompareMethod.CHARS); + diffHighlightModeToggleGroup.selectedToggleProperty().addListener((observable -> { + if (diffHighlightModeToggleGroup.getSelectedToggle().equals(highlightCharactersRadioButtons)) { + diffHighlightMode.set(DiffHighlightMode.CHARS); } else { - diffCompareMethod.set(DiffCompareMethod.WORDS); + diffHighlightMode.set(DiffHighlightMode.WORDS); } })); - diffCompareMethodToggleGroup.selectToggle(compareWordsRadioButton); - } - - private void initializeDiffViewComboBox() { - diffViewComboBox.getSelectionModel().select(DiffView.UNIFIED); - diffViewComboBox.setConverter(new StringConverter<>() { - @Override - public String toString(DiffView diffView) { - return diffView.getValue(); - } - - @Override - public DiffView fromString(String string) { - return DiffView.fromString(string); - } - }); + diffHighlightModeToggleGroup.selectToggle(highlightWordsRadioButton); } public ReadOnlyObjectProperty diffViewProperty() { @@ -115,6 +110,14 @@ public EasyBinding showDiffProperty() { return showDiff; } + /** + * Convince method used to disable diff related views when diff is not selected. + * + *

+ * This method is required because {@link EasyBinding} class doesn't have a method to invert a boolean property, + * like {@link BooleanExpression#not()} + *

+ * */ public EasyBinding notShowDiffProperty() { return showDiffProperty().map(showDiff -> !showDiff); } @@ -123,12 +126,20 @@ public Boolean isShowDiffEnabled() { return showDiffProperty().get(); } - public ObjectProperty diffCompareMethodProperty() { - return diffCompareMethod; + public ObjectProperty diffHighlightModeProperty() { + return diffHighlightMode; + } + + public DiffHighlightMode getDiffHighlightMode() { + return diffHighlightModeProperty().get(); + } + + public void setOnSelectLeftEntryValuesButtonClicked(Consumer onClick) { + selectLeftEntryValuesButton.setOnMouseClicked(onClick::accept); } - public DiffCompareMethod getDiffCompareMethod() { - return diffCompareMethodProperty().get(); + public void setOnSelectRightEntryValuesButtonClicked(Consumer onClick) { + selectRightEntryValuesButton.setOnMouseClicked(onClick::accept); } public enum PlainTextOrDiff { @@ -173,7 +184,7 @@ public static DiffView fromString(String str) { } } - public enum DiffCompareMethod { + public enum DiffHighlightMode { WORDS, CHARS } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml deleted file mode 100644 index 6829ee78b54..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 0fe1f1ba107b5cb116485ba4a09f8546cf104098 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:05:07 +0100 Subject: [PATCH 044/473] Disable right field cell when it's not visible --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index a6322b34d8e..cee05b99050 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -97,6 +97,7 @@ private void addFieldRow(int index) { mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index, 1, 1); + fieldRow.getRightValueCell().setDisable(true); } else { mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); } From ae10410766eb90e89287b537e6fbf04b4f5a78b3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:06:15 +0100 Subject: [PATCH 045/473] Listen for select all left/right toolbar buttons --- .../newmergedialog/FieldRowController.java | 22 +++++++ .../newmergedialog/ThreeWayMergeView.java | 62 ++++++++++++++----- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 9e9a077c3ea..904ca57c390 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -54,6 +54,28 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } } + /** + * @return True if left value was selected, False otherwise + */ + public boolean selectLeftValue() { + if (!leftValueCell.isDisabled()) { + toggleGroup.selectToggle(leftValueCell); + return true; + } + return false; + } + + /** + * @return True if left value was selected, False otherwise + */ + public boolean selectRightValue() { + if (!rightValueCell.isDisabled()) { + toggleGroup.selectToggle(rightValueCell); + return true; + } + return false; + } + public String getMergedValue() { return mergedValueProperty().getValue(); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index cee05b99050..4ec81f6d6f2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -1,5 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog; +import java.util.ArrayList; +import java.util.List; + import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -7,58 +10,81 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.mergeentries.newmergedialog.toolbox.ThreeWayMergeToolbox; +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { + public static final int GRID_COLUMN_MIN_WIDTH = 250; public static final String LEFT_DEFAULT_HEADER = "Left Entry"; public static final String RIGHT_DEFAULT_HEADER = "Right Entry"; - private ThreeWayMergeToolbox mergeToolbox; - private HeaderView headerView; + + private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); + private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private final ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private final ColumnConstraints mergedEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private final ThreeWayMergeToolbar toolbar; + private final ThreeWayMergeHeaderView headerView; private final ScrollPane scrollPane; private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; + private final List fieldRowControllerList = new ArrayList<>(); public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); - mergeToolbox = new ThreeWayMergeToolbox(); - headerView = new HeaderView(leftHeader, rightHeader); - scrollPane = new ScrollPane(); - scrollPane.setFitToWidth(true); - scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); mergeGridPane = new GridPane(); - initializeMergeGridPane(); + scrollPane = new ScrollPane(); + headerView = new ThreeWayMergeHeaderView(leftHeader, rightHeader); + toolbar = new ThreeWayMergeToolbar(); - scrollPane.setContent(mergeGridPane); - getChildren().addAll(mergeToolbox, headerView, scrollPane); + initializeColumnConstraints(); + initializeMergeGridPane(); + initializeScrollPane(); + initializeHeaderView(); + initializeToolbar(); this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); + + getChildren().addAll(toolbar, headerView, scrollPane); } public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry) { this(leftEntry, rightEntry, LEFT_DEFAULT_HEADER, RIGHT_DEFAULT_HEADER); } - private void initializeMergeGridPane() { - ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); - fieldNameColumnConstraints.setHgrow(Priority.NEVER); + private void initializeToolbar() { + toolbar.setOnSelectLeftEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectLeftValue)); + toolbar.setOnSelectRightEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectRightValue)); + } + + private void initializeHeaderView() { + headerView.getColumnConstraints().addAll(fieldNameColumnConstraints, + leftEntryColumnConstraints, + rightEntryColumnConstraints, + mergedEntryColumnConstraints); + } - ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); - ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); - ColumnConstraints mergedEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private void initializeScrollPane() { + scrollPane.setFitToWidth(true); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setContent(mergeGridPane); + } + private void initializeColumnConstraints() { + fieldNameColumnConstraints.setHgrow(Priority.NEVER); leftEntryColumnConstraints.setHgrow(Priority.ALWAYS); rightEntryColumnConstraints.setHgrow(Priority.ALWAYS); mergedEntryColumnConstraints.setHgrow(Priority.ALWAYS); + } + private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { @@ -80,6 +106,8 @@ private void addFieldRow(int index) { } FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, index); + fieldRowControllerList.add(fieldRow); + fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); From d26a6bb7d06f91bcff8177b389ae16973d907127 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:07:45 +0100 Subject: [PATCH 046/473] Style stuff --- src/main/java/org/jabref/gui/Base.css | 31 +++++++++++-- src/main/java/org/jabref/gui/Dark.css | 25 +++++++++++ .../newmergedialog/ThreeWayMergeView.css | 44 +++++++------------ 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 4c93cc0defa..caf46e64a27 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -2,13 +2,13 @@ .root { -jr-transparent-green: rgba(16, 172, 132, 0.12); - -jr-row-odd-background: -fx-control-inner-background; - -jr-row-even-background: -fx-control-inner-background-alt; + -jr-row-odd-background: -fx-control-inner-background-alt; + -jr-row-even-background: -fx-control-inner-background; /* On light theme, the text is hard to see when it's on top of the accent color. This is an alternative lighter accent color for better text visibility. */ - -jr-accent-alt: derive(-jr-accent, 10%); + -jr-accent-alt: derive(-jr-accent, 15%); /* The theme color and some derived colors from it are used for icons, tab-headers, marking of selected inputs and @@ -615,6 +615,31 @@ TextFlow > .tooltip-text-monospaced { -fx-background-insets: 0; } +.field-value .copy-icon { + -fx-icon-size: 15; + -fx-icon-color: -fx-text-background-color; + -fx-blend-mode: multiply ; + -fx-opacity: 69%; +} + +.field-value:disabled .copy-icon { + -fx-opacity: 0%; +} + +.field-value:selected .copy-icon { + +} + +.header-cell { + -fx-border-width: 0 0 1 0; + -fx-border-color: -jr-gray-1; + -fx-background-color: -jr-row-even-background; +} + +.merge-header { + -fx-background-color: -jr-row-even-background; +} + .table-view .groupColumnBackground { -fx-stroke: -jr-gray-2; } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 1ccb79df1e3..08e7d34764c 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -81,6 +81,31 @@ .tree-table-row-cell:hover { -fx-background-color: -jr-hover; } +.field-value .copy-icon { + -fx-icon-size: 15; + -fx-icon-color: -fx-text-background-color; + -fx-blend-mode: inherit; + -fx-opacity: 100%; +} + +.field-value:disabled .copy-icon { + -fx-opacity: 0%; +} + +.field-value:selected .copy-icon { + -fx-icon-color: -fx-text-background-color; + -fx-opacity: 100%; +} + +.header-cell { + -fx-border-width: 0 0 1 0; + -fx-border-color: -fx-outer-border; + -fx-background-color: -jr-row-odd-background; +} + +.merge-header { + -fx-background-color: -jr-row-odd-background; +} .table-view .groupColumnBackground { -fx-stroke: -jr-gray-3; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index db916d9010a..815114bc7ae 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -1,13 +1,18 @@ .merged-field { - -fx-border-color: #dfdfdf; - -fx-border-width: 0 0 0 1.5; +/* -fx-border-color: #dfdfdf; + -fx-border-width: 0 0 0 1.5;*/ } .merged-field .styled-text-area { - -fx-background-radius: 3; - -fx-border-radius: 3; - -fx-border-color: #dfdfdf; - -fx-background-color: white; + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1; + -fx-prompt-text-fill: -fx-mid-text-color; +} +.merged-field .styled-text-area:focused { + -fx-highlight-fill: derive(-jr-accent, 20%); + -fx-background-color: -jr-accent, -fx-control-inner-background; + -fx-background-insets: 0, 2; + -fx-highlight-text-fill: -fx-text-inner-color; } .field-value:selected .selection-box { @@ -23,30 +28,10 @@ -fx-background-radius: 8; } -.field-value .styled-text-area .text{ +.styled-text-area .text{ -fx-fill: -fx-text-background-color; } -.field-value .text-area { - -fx-font-size: 13; -} - - -.field-value .copy-icon { - -fx-icon-size: 15; - -fx-icon-color: -fx-text-background-color; - -fx-opacity: 100%; -} - -.field-value:disabled .copy-icon { - -fx-opacity: 0%; -} - -.field-value:selected .copy-icon { - -fx-icon-color: -fx-text-background-color; - -fx-opacity: 100%; -} - .field-cell:odd { -fx-background-color: -jr-row-odd-background; } @@ -59,6 +44,11 @@ -fx-background-color: -jr-menu-background; } +.header-cell .label{ + -fx-font-weight: bold; + -fx-padding: 1, 0, 1, 0; +} + /* Diff Highlighting */ .unchanged { From d89d5587fef3a84c882462057bcd43ef5965e1fd Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:31:58 +0100 Subject: [PATCH 047/473] Add DiffHighlighter - Implemented UnifiedDiffHighlighter --- .../diffhighlighter/DiffHighlighter.java | 69 +++++++++++ .../diffhighlighter/SplitDiffHighlighter.java | 24 ++++ .../UnifiedDiffHighlighter.java | 117 ++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java new file mode 100644 index 00000000000..e92a85e0a96 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java @@ -0,0 +1,69 @@ +package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.fxmisc.richtext.StyleClassedTextArea; + +public abstract sealed class DiffHighlighter permits SplitDiffHighlighter, UnifiedDiffHighlighter { + protected final StyleClassedTextArea sourceTextview; + protected final StyleClassedTextArea targetTextview; + + protected DiffMethod diffMethod; + + public DiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview, DiffMethod diffMethod) { + Objects.requireNonNull(sourceTextview, "source text view MUST NOT be null."); + Objects.requireNonNull(targetTextview, "target text view MUST NOT be null."); + + this.sourceTextview = sourceTextview; + this.targetTextview = targetTextview; + this.diffMethod = diffMethod; + } + + abstract void highlight(); + + protected List splitString(String str) { + return Arrays.asList(str.split(diffMethod.separator())); + } + + private void setDiffMethod(DiffMethod diffMethod) { + this.diffMethod = diffMethod; + } + + public DiffMethod getDiffMethod() { + return diffMethod; + } + + public String getSeparator() { + return diffMethod.separator(); + } + + enum DiffMethod { + WORDS(" "), CHARS(""); + + private final String separator; + + DiffMethod(String separator) { + this.separator = separator; + } + + public String separator() { + return separator; + } + } + + protected String join(List stringList) { + return String.join(" ", stringList); + } + + enum ChangeType { + ADDITION, DELETION, CHANGE_DELETION + } + + record Change( + int position, + int spanSize, + ChangeType type) { + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java new file mode 100644 index 00000000000..c24868e9a37 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -0,0 +1,24 @@ +package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; + +import com.github.difflib.patch.DeltaType; +import org.fxmisc.richtext.StyleClassedTextArea; + +/** + * A diff highlighter in which changes of type {@link DeltaType#CHANGE} are split between source and target + * text view. They are represented by an addition in the target text view and deletion in the source text view. + * Normal addition and deletion are kept as they are. + */ +public final class SplitDiffHighlighter extends DiffHighlighter { + + public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview, DiffMethod diffMethod) { + super(sourceTextview, targetTextview, diffMethod); + } + + public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { + this(sourceTextview, targetTextview, DiffMethod.WORDS); + } + + @Override + public void highlight() { + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java new file mode 100644 index 00000000000..216ba52369f --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java @@ -0,0 +1,117 @@ +package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.github.difflib.DiffUtils; +import com.github.difflib.patch.AbstractDelta; +import com.github.difflib.patch.DeltaType; +import org.fxmisc.richtext.StyleClassedTextArea; + +/** + * A diff highlighter in which differences of type {@link DeltaType#CHANGE} are unified and represented by an insertion + * and deletion in the target text view. Normal addition and deletion are kept as they are. + */ +public final class UnifiedDiffHighlighter extends DiffHighlighter { + + public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview, DiffMethod diffMethod) { + super(sourceTextview, targetTextview, diffMethod); + } + + public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { + this(sourceTextview, targetTextview, DiffMethod.WORDS); + } + + @SuppressWarnings({"checkstyle:RegexpMultiline", "checkstyle:EmptyBlock"}) + @Override + public void highlight() { + String sourceContent = sourceTextview.getText(); + String targetContent = targetTextview.getText(); + if (sourceContent.equals(targetContent)) { + return; + } + + List sourceWords = splitString(sourceContent); + List targetWords = splitString(targetContent); + List unifiedWords = new ArrayList<>(targetWords); + + List> deltaList = DiffUtils.diff(sourceWords, targetWords).getDeltas(); + + List changeList = new ArrayList<>(); + + int deletionCount = 0; + for (AbstractDelta delta : deltaList) { + switch (delta.getType()) { + case CHANGE -> { + int changePosition = delta.getTarget().getPosition(); + int deletionPoint = changePosition + deletionCount; + int insertionPoint = deletionPoint + 1; + List deltaSourceWords = delta.getSource().getLines(); + List deltaTargetWords = delta.getTarget().getLines(); + + unifiedWords.add(deletionPoint, join(deltaSourceWords)); + + changeList.add(new Change(deletionPoint, 1, ChangeType.CHANGE_DELETION)); + changeList.add(new Change(insertionPoint, deltaTargetWords.size(), ChangeType.ADDITION)); + deletionCount++; + } + case DELETE -> { + int deletionPoint = delta.getTarget().getPosition() + deletionCount; + unifiedWords.add(deletionPoint, join(delta.getSource().getLines())); + + changeList.add(new Change(deletionPoint, 1, ChangeType.DELETION)); + deletionCount++; + } + case INSERT -> { + int insertionPoint = delta.getTarget().getPosition() + deletionCount; + changeList.add(new Change(insertionPoint, delta.getTarget().getLines().size(), ChangeType.ADDITION)); + } + } + } + targetTextview.clear(); + + boolean changeInProgress = false; + for (int position = 0; position < unifiedWords.size(); position++) { + String word = unifiedWords.get(position); + Optional changeAtPosition = findChange(position, changeList); + if (changeAtPosition.isEmpty()) { + appendToTextArea(targetTextview, getSeparator() + word, "unchanged"); + } else { + Change change = changeAtPosition.get(); + List changeWords = unifiedWords.subList(change.position(), change.position() + change.spanSize()); + + if (change.type() == ChangeType.DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + } else if (change.type() == ChangeType.ADDITION) { + if (changeInProgress) { + appendToTextArea(targetTextview, join(changeWords), "addition"); + changeInProgress = false; + } else { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "addition"); + } + } else if (change.type() == ChangeType.CHANGE_DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + changeInProgress = true; + } + position = position + changeWords.size() - 1; + } + } + } + + private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { + if (text.isEmpty()) { + return; + } + // Append separator without styling it + if (text.startsWith(getSeparator())) { + textArea.appendText(getSeparator()); + } + int separatorIndex = text.indexOf(getSeparator()); + textArea.append(text.substring(separatorIndex != -1 ? separatorIndex + 1 : 0), styleClass); + } + + private Optional findChange(int position, List changeList) { + return changeList.stream().filter(change -> change.position() == position).findAny(); + } +} From 9c5e623eb3467f7009fd08492a88ce56df401e69 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:32:28 +0100 Subject: [PATCH 048/473] Create DiffHighlighter.css --- .../newmergedialog/diffhighlighter/DiffHighlighter.css | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css new file mode 100644 index 00000000000..e69de29bb2d From 9e975985a9c3e8d7ee6fa9fcd14e4bc97994cdd2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:33:23 +0100 Subject: [PATCH 049/473] Add left padding to HeaderCell --- .../jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 1bc003200ca..5a7c6a9ff71 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -1,5 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.geometry.Insets; import javafx.scene.control.Label; public class HeaderCell extends AbstractCell { @@ -19,5 +20,6 @@ private void initialize() { private void initializeLabel() { label.textProperty().bind(textProperty()); + label.setPadding(new Insets(getPadding().getTop(), getPadding().getRight(), getPadding().getBottom(), 16)); } } From 6bad42874283ed8a4ccef075fb87764a880ead93 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:34:45 +0100 Subject: [PATCH 050/473] Move diff highlighting styles to Dark.css - Just for testing --- src/main/java/org/jabref/gui/Dark.css | 13 +++++++++++++ .../newmergedialog/ThreeWayMergeView.css | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 08e7d34764c..2a5141d545a 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -60,6 +60,19 @@ -jr-drag-target-hover: -jr-accent; } +.unchanged { + +} + +.addition { + -rtfx-background-color: #0B1935; +} + +.deletion { + -rtfx-background-color: #4E0A0D; + +} + #previewBody { background-color: #272b38; /* -fx-control-inner-background*/ color: #7d8591; /* -fx-mid-text-color*/ diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 815114bc7ae..5f4731c9f27 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -48,16 +48,3 @@ -fx-font-weight: bold; -fx-padding: 1, 0, 1, 0; } - -/* Diff Highlighting */ -.unchanged { - -} - -.addition { - -rtfx-background-color: rgba(35, 225, 96, 0.26); -} - -.deletion { - -rtfx-background-color: rgba(248, 62, 68, 0.26); -} From 9cc0d188c4882a1b24bd9713eba3751e77c1d962 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:35:53 +0100 Subject: [PATCH 051/473] Show differences between left and right values using a unified diff view - Just for testing --- .../gui/mergeentries/newmergedialog/FieldRowController.java | 6 ++++++ .../mergeentries/newmergedialog/cell/FieldValueCell.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 904ca57c390..f145ec1132d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -6,6 +6,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.model.strings.StringUtil; public class FieldRowController { @@ -52,6 +53,11 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } else if (StringUtil.isNullOrEmpty(rightValue)) { rightValueCell.setDisable(true); } + + // Debugging + if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel()).highlight(); + } } /** diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 8945cf688e5..440cf9e51a0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -191,4 +191,8 @@ public void setUserData(Object value) { public Object getUserData() { return super.getText(); } + + public StyleClassedTextArea getStyleClassedLabel() { + return label; + } } From c37c3c1a4ddab1834fd4a64b4f8f56d9867e2211 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:36:09 +0100 Subject: [PATCH 052/473] Change MergeEntriesDialog stage style --- .../java/org/jabref/gui/mergeentries/MergeEntriesDialog.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 0a76be098a2..b70a2dc915e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -2,6 +2,7 @@ import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; +import javafx.stage.StageStyle; import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; @@ -22,6 +23,7 @@ public MergeEntriesDialog(BibEntry one, BibEntry two) { */ private void init() { this.getDialogPane().setContent(threeWayMergeView); + this.initStyle(StageStyle.UTILITY); // Create buttons ButtonType replaceEntries = new ButtonType(Localization.lang("Merge entries"), ButtonBar.ButtonData.OK_DONE); From 39ee372dbd1e27ce2a2e17299d67b497c1f55d4e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:38:40 +0100 Subject: [PATCH 053/473] Remove BackgroundTone from AbstractCell --- .../newmergedialog/cell/AbstractCell.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java index 10b13bd5b71..ffb1f536986 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java @@ -7,7 +7,6 @@ import javafx.css.PseudoClass; import javafx.geometry.Insets; import javafx.scene.layout.HBox; -import javafx.scene.paint.Color; /** * @@ -80,17 +79,4 @@ public StringProperty textProperty() { public void setText(String text) { textProperty().set(text); } - - public enum BackgroundTone { - LIGHT(Color.web("#FEFEFE")), DARK(Color.web("#EFEFEF")); - private final Color color; - - BackgroundTone(Color color) { - this.color = color; - } - - public Color color() { - return color; - } - } } From 2ed006256d0d23fab497b8208cef970bad0aa701 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:39:09 +0100 Subject: [PATCH 054/473] Move CopyFieldValueCommand --- .../newmergedialog/{cell => }/CopyFieldValueCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{cell => }/CopyFieldValueCommand.java (92%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java similarity index 92% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java index e18a831933b..a3ef9024215 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java @@ -1,4 +1,4 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; +package org.jabref.gui.mergeentries.newmergedialog; import java.util.Objects; From 3ea5cd193e655d4f8e14e4ba3c09e083c44a1569 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:39:37 +0100 Subject: [PATCH 055/473] Make DiffMethod public --- .../newmergedialog/diffhighlighter/DiffHighlighter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java index e92a85e0a96..17149e368d6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java @@ -39,7 +39,7 @@ public String getSeparator() { return diffMethod.separator(); } - enum DiffMethod { + public enum DiffMethod { WORDS(" "), CHARS(""); private final String separator; @@ -54,7 +54,7 @@ public String separator() { } protected String join(List stringList) { - return String.join(" ", stringList); + return String.join(getSeparator(), stringList); } enum ChangeType { From 758c13dc5fab5eca2a325352415ff44c1b9bb984 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:40:54 +0100 Subject: [PATCH 056/473] Move CopyFieldValueCommand --- .../gui/mergeentries/newmergedialog/cell/FieldValueCell.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 440cf9e51a0..649d95e20d9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -24,6 +24,7 @@ import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.mergeentries.newmergedialog.CopyFieldValueCommand; import org.jabref.logic.l10n.Localization; import org.fxmisc.flowless.VirtualizedScrollPane; @@ -107,7 +108,7 @@ private void initializeLabel() { label.prefHeightProperty().bind(label.totalHeightEstimateProperty().orElseConst(-1d)); - // Fix text area consuming scroll events before they rich the outer scrollable + // Fix text area consuming scroll events before they reach the outer scrollable label.addEventFilter(ScrollEvent.SCROLL, e -> { e.consume(); FieldValueCell.this.fireEvent(e.copyFor(e.getSource(), FieldValueCell.this)); From d815bbe31e2968659c9ecfbf3f90d64a2b8210a1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:41:34 +0100 Subject: [PATCH 057/473] Implement SplitDiffHighlighter --- src/main/java/org/jabref/gui/Base.css | 13 +++ src/main/java/org/jabref/gui/Dark.css | 5 +- .../diffhighlighter/SplitDiffHighlighter.java | 99 +++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index caf46e64a27..bc2c914258e 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -253,6 +253,19 @@ -jr-header-height: 3em; } +.unchanged { + -rtfx-background-color:#0000; +} + +.addition { + -rtfx-background-color: rgba(29, 209, 161, 0.5); +} + +.deletion { + -rtfx-background-color: rgba(255, 107, 107, 0.55); +} + + #frame { -fx-background-color: -jr-background-alt; } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 2a5141d545a..63bd21c0a99 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -65,12 +65,11 @@ } .addition { - -rtfx-background-color: #0B1935; + -rtfx-background-color: -jr-green; } .deletion { - -rtfx-background-color: #4E0A0D; - + -rtfx-background-color: -jr-red; } #previewBody { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java index c24868e9a37..5e3ba6274c5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -1,5 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.github.difflib.DiffUtils; +import com.github.difflib.patch.AbstractDelta; import com.github.difflib.patch.DeltaType; import org.fxmisc.richtext.StyleClassedTextArea; @@ -20,5 +26,98 @@ public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTex @Override public void highlight() { + String sourceContent = sourceTextview.getText(); + String targetContent = targetTextview.getText(); + if (sourceContent.equals(targetContent)) { + return; + } + + List sourceWords = splitString(sourceContent); + List targetWords = splitString(targetContent); + List unifiedWords = new ArrayList<>(targetWords); + + List> deltaList = DiffUtils.diff(sourceWords, targetWords).getDeltas(); + + List changeList = new ArrayList<>(); + + int deletionCount = 0; + for (AbstractDelta delta : deltaList) { + switch (delta.getType()) { + case CHANGE -> { + int changePosition = delta.getTarget().getPosition(); + int deletionPoint = changePosition + deletionCount; + int insertionPoint = deletionPoint + 1; + List deltaSourceWords = delta.getSource().getLines(); + List deltaTargetWords = delta.getTarget().getLines(); + + unifiedWords.add(deletionPoint, join(deltaSourceWords)); + + changeList.add(new Change(deletionPoint, 1, ChangeType.CHANGE_DELETION)); + changeList.add(new Change(insertionPoint, deltaTargetWords.size(), ChangeType.ADDITION)); + deletionCount++; + } + case DELETE -> { + int deletionPoint = delta.getTarget().getPosition() + deletionCount; + unifiedWords.add(deletionPoint, join(delta.getSource().getLines())); + + changeList.add(new Change(deletionPoint, 1, ChangeType.DELETION)); + deletionCount++; + } + case INSERT -> { + int insertionPoint = delta.getTarget().getPosition() + deletionCount; + changeList.add(new Change(insertionPoint, delta.getTarget().getLines().size(), ChangeType.ADDITION)); + } + } + } + sourceTextview.clear(); + targetTextview.clear(); + + boolean changeInProgress = false; + for (int position = 0; position < unifiedWords.size(); position++) { + String word = unifiedWords.get(position); + Optional changeAtPosition = findChange(position, changeList); + if (changeAtPosition.isEmpty()) { + appendToTextArea(targetTextview, getSeparator() + word, "unchanged"); + } else { + Change change = changeAtPosition.get(); + List changeWords = unifiedWords.subList(change.position(), change.position() + change.spanSize()); + + if (change.type() == ChangeType.DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + } else if (change.type() == ChangeType.ADDITION) { + if (changeInProgress) { + appendToTextArea(targetTextview, join(changeWords), "addition"); + changeInProgress = false; + } else { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "addition"); + } + } else if (change.type() == ChangeType.CHANGE_DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + changeInProgress = true; + } + position = position + changeWords.size() - 1; + } + } + if (targetTextview.getLength() >= getSeparator().length()) { + // There always going to be an extra separator at the start + targetTextview.deleteText(0, getSeparator().length()); + } + } + + private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { + if (text.isEmpty()) { + return; + } + // Append separator without styling it + if (text.startsWith(getSeparator())) { + textArea.append(getSeparator(), "unchanged"); + textArea.append(text.substring(getSeparator().length()), styleClass); + } else { + textArea.append(text, styleClass); + } + } + + private Optional findChange(int position, List changeList) { + return changeList.stream().filter(change -> change.position() == position).findAny(); } } From d071fe41dbcc8276417b7fdf2585f5203dda6abf Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:44:12 +0100 Subject: [PATCH 058/473] Show diffs when user selects "Show Diff" in the toolbar UI - Only unified diff view will be shown for now --- .../newmergedialog/FieldRowController.java | 42 ++++++++++++++++--- .../newmergedialog/ShowDiffConfig.java | 6 +++ .../newmergedialog/ThreeWayMergeView.java | 14 +++++++ 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index f145ec1132d..64db8cf9fd0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -6,7 +6,9 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; public class FieldRowController { @@ -15,6 +17,10 @@ public class FieldRowController { private final FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; + private final String leftValue; + + private final String rightValue; + private final ToggleGroup toggleGroup = new ToggleGroup(); public FieldRowController(String fieldName, String leftValue, String rightValue, int rowIndex) { @@ -23,6 +29,9 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); + this.leftValue = leftValue; + this.rightValue = rightValue; + toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); toggleGroup.selectedToggleProperty().addListener(invalidated -> { @@ -53,11 +62,6 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } else if (StringUtil.isNullOrEmpty(rightValue)) { rightValueCell.setDisable(true); } - - // Debugging - if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel()).highlight(); - } } /** @@ -111,4 +115,32 @@ public boolean hasEqualLeftAndRightValues() { !StringUtil.isNullOrEmpty(rightValueCell.getText()) && leftValueCell.getText().equals(rightValueCell.getText()); } + + public void showDiffs(ShowDiffConfig diffConfig) { + // TODO: read this from diffConfig + if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { + if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { + hideDiffs(); + if (diffConfig.diffMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS) { + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.WORDS).highlight(); + } else { + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.CHARS).highlight(); + } + } + } + } + + public void hideDiffs() { + if (!StringUtil.isNullOrEmpty(leftValue)) { + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); + getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); + getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); + } + + if (!StringUtil.isNullOrEmpty(rightValue)) { + int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); + getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); + getRightValueCell().getStyleClassedLabel().replaceText(rightValue); + } + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java new file mode 100644 index 00000000000..e1de4e3fc9a --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java @@ -0,0 +1,6 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; + +public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, ThreeWayMergeToolbar.DiffHighlightMode diffMode) { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 4ec81f6d6f2..f741c1515ef 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -62,6 +62,20 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry) { private void initializeToolbar() { toolbar.setOnSelectLeftEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectLeftValue)); toolbar.setOnSelectRightEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectRightValue)); + + toolbar.showDiffProperty().addListener(e -> updateDiff()); + toolbar.diffViewProperty().addListener(e -> updateDiff()); + toolbar.diffHighlightModeProperty().addListener(e -> updateDiff()); + } + + private void updateDiff() { + if (toolbar.isShowDiffEnabled()) { + fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiffs( + new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightMode()) + )); + } else { + fieldRowControllerList.forEach(FieldRowController::hideDiffs); + } } private void initializeHeaderView() { From 735dc5a1b708716c197d132d2ad938131371eb1c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:44:37 +0100 Subject: [PATCH 059/473] Fix bugs in UnifiedDiffHighlighter --- .../diffhighlighter/UnifiedDiffHighlighter.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java index 216ba52369f..38d6a92c389 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java @@ -20,10 +20,9 @@ public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedT } public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { - this(sourceTextview, targetTextview, DiffMethod.WORDS); + this(sourceTextview, targetTextview, DiffMethod.CHARS); } - @SuppressWarnings({"checkstyle:RegexpMultiline", "checkstyle:EmptyBlock"}) @Override public void highlight() { String sourceContent = sourceTextview.getText(); @@ -97,6 +96,10 @@ public void highlight() { position = position + changeWords.size() - 1; } } + if (targetTextview.getLength() >= getSeparator().length()) { + // There always going to be an extra separator at the start + targetTextview.deleteText(0, getSeparator().length()); + } } private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { @@ -105,10 +108,11 @@ private void appendToTextArea(StyleClassedTextArea textArea, String text, String } // Append separator without styling it if (text.startsWith(getSeparator())) { - textArea.appendText(getSeparator()); + textArea.append(getSeparator(), "unchanged"); + textArea.append(text.substring(getSeparator().length()), styleClass); + } else { + textArea.append(text, styleClass); } - int separatorIndex = text.indexOf(getSeparator()); - textArea.append(text.substring(separatorIndex != -1 ? separatorIndex + 1 : 0), styleClass); } private Optional findChange(int position, List changeList) { From ff58de90937c0b6516123ad1ee96a6882473454a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:45:14 +0100 Subject: [PATCH 060/473] Style css stuff --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 5f4731c9f27..27dc070635a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -16,16 +16,18 @@ } .field-value:selected .selection-box { - -fx-background-color: -jr-accent-alt; - -fx-border-color: -jr-accent-alt; + /* -fx-background-color: -jr-accent-alt; + -fx-border-color: -jr-accent-alt;*/ + -fx-background-color: rgba(163, 183, 230, 0.7); + -fx-border-color: -jr-accent; } .field-value .selection-box { -fx-background-color: #0000; - -fx-border-width: 1; -fx-border-color: #0000; -fx-border-radius: 8; -fx-background-radius: 8; + -fx-border-width: 2.5; } .styled-text-area .text{ From 73454825e79aa1f4edec21ac4855cd72d6758cc2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:45:25 +0100 Subject: [PATCH 061/473] Fix typos --- .../mergeentries/newmergedialog/ThreeWayMergeHeaderView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index 9299c5f2ef9..4e9e15b3af5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -8,7 +8,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; /** - * I used a GridPane instead of a Hbox because Hbox allocates more space for cells + * GridPane was used instead of a Hbox because Hbox allocates more space for cells * with longer text, but I wanted all cells to have the same width */ public class ThreeWayMergeHeaderView extends GridPane { From d072bab3ee02a0e718c4e657f1839b8e5894e96b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:50:09 +0100 Subject: [PATCH 062/473] Refactor SplitDiffHighlighter and fix bugs - Added "updated" style class for styling CHANGE diffs --- src/main/java/org/jabref/gui/Base.css | 4 + .../diffhighlighter/SplitDiffHighlighter.java | 118 ++++++------------ 2 files changed, 40 insertions(+), 82 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index bc2c914258e..ccd0682d6c9 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -257,6 +257,10 @@ -rtfx-background-color:#0000; } +.updated { + -rtfx-background-color: rgba(41, 166, 236, 0.66); +} + .addition { -rtfx-background-color: rgba(29, 209, 161, 0.5); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java index 5e3ba6274c5..5b7275220eb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -10,9 +10,8 @@ import org.fxmisc.richtext.StyleClassedTextArea; /** - * A diff highlighter in which changes of type {@link DeltaType#CHANGE} are split between source and target - * text view. They are represented by an addition in the target text view and deletion in the source text view. - * Normal addition and deletion are kept as they are. + * A diff highlighter in which changes are split between source and target text view. + * They are represented by an addition in the target text view and deletion in the source text view. */ public final class SplitDiffHighlighter extends DiffHighlighter { @@ -20,10 +19,6 @@ public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTex super(sourceTextview, targetTextview, diffMethod); } - public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { - this(sourceTextview, targetTextview, DiffMethod.WORDS); - } - @Override public void highlight() { String sourceContent = sourceTextview.getText(); @@ -32,92 +27,51 @@ public void highlight() { return; } - List sourceWords = splitString(sourceContent); - List targetWords = splitString(targetContent); - List unifiedWords = new ArrayList<>(targetWords); - - List> deltaList = DiffUtils.diff(sourceWords, targetWords).getDeltas(); + List sourceTokens = splitString(sourceContent); + List targetTokens = splitString(targetContent); - List changeList = new ArrayList<>(); + List> deltaList = DiffUtils.diff(sourceTokens, targetTokens).getDeltas(); - int deletionCount = 0; for (AbstractDelta delta : deltaList) { + int affectedSourceTokensPosition = delta.getSource().getPosition(); + int affectedTargetTokensPosition = delta.getTarget().getPosition(); + + List affectedTokensInSource = delta.getSource().getLines(); + List affectedTokensInTarget = delta.getTarget().getLines(); + int joinedSourceTokensLength = affectedTokensInSource.stream() + .map(String::length) + .reduce(Integer::sum) + .map(value -> value + (getSeparator().length() * (affectedTokensInSource.size() - 1))) + .orElse(0); + + int joinedTargetTokensLength = affectedTokensInTarget.stream() + .map(String::length) + .reduce(Integer::sum) + .map(value -> value + (getSeparator().length() * (affectedTokensInTarget.size() - 1))) + .orElse(0); + int affectedSourceTokensPositionInText = getPositionInText(affectedSourceTokensPosition, sourceTokens); + int affectedTargetTokensPositionInText = getPositionInText(affectedTargetTokensPosition, targetTokens); switch (delta.getType()) { case CHANGE -> { - int changePosition = delta.getTarget().getPosition(); - int deletionPoint = changePosition + deletionCount; - int insertionPoint = deletionPoint + 1; - List deltaSourceWords = delta.getSource().getLines(); - List deltaTargetWords = delta.getTarget().getLines(); - - unifiedWords.add(deletionPoint, join(deltaSourceWords)); - - changeList.add(new Change(deletionPoint, 1, ChangeType.CHANGE_DELETION)); - changeList.add(new Change(insertionPoint, deltaTargetWords.size(), ChangeType.ADDITION)); - deletionCount++; - } - case DELETE -> { - int deletionPoint = delta.getTarget().getPosition() + deletionCount; - unifiedWords.add(deletionPoint, join(delta.getSource().getLines())); - - changeList.add(new Change(deletionPoint, 1, ChangeType.DELETION)); - deletionCount++; - } - case INSERT -> { - int insertionPoint = delta.getTarget().getPosition() + deletionCount; - changeList.add(new Change(insertionPoint, delta.getTarget().getLines().size(), ChangeType.ADDITION)); - } - } - } - sourceTextview.clear(); - targetTextview.clear(); - - boolean changeInProgress = false; - for (int position = 0; position < unifiedWords.size(); position++) { - String word = unifiedWords.get(position); - Optional changeAtPosition = findChange(position, changeList); - if (changeAtPosition.isEmpty()) { - appendToTextArea(targetTextview, getSeparator() + word, "unchanged"); - } else { - Change change = changeAtPosition.get(); - List changeWords = unifiedWords.subList(change.position(), change.position() + change.spanSize()); - - if (change.type() == ChangeType.DELETION) { - appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); - } else if (change.type() == ChangeType.ADDITION) { - if (changeInProgress) { - appendToTextArea(targetTextview, join(changeWords), "addition"); - changeInProgress = false; - } else { - appendToTextArea(targetTextview, getSeparator() + join(changeWords), "addition"); - } - } else if (change.type() == ChangeType.CHANGE_DELETION) { - appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); - changeInProgress = true; + sourceTextview.setStyleClass(affectedSourceTokensPositionInText, affectedSourceTokensPositionInText + joinedSourceTokensLength, "deletion"); + targetTextview.setStyleClass(affectedTargetTokensPositionInText, affectedTargetTokensPositionInText + joinedTargetTokensLength, "updated"); } - position = position + changeWords.size() - 1; + case DELETE -> + sourceTextview.setStyleClass(affectedSourceTokensPositionInText, affectedSourceTokensPositionInText + joinedSourceTokensLength, "deletion"); + case INSERT -> + targetTextview.setStyleClass(affectedTargetTokensPositionInText, affectedTargetTokensPositionInText + joinedTargetTokensLength, "addition"); } } - if (targetTextview.getLength() >= getSeparator().length()) { - // There always going to be an extra separator at the start - targetTextview.deleteText(0, getSeparator().length()); - } } - private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { - if (text.isEmpty()) { - return; - } - // Append separator without styling it - if (text.startsWith(getSeparator())) { - textArea.append(getSeparator(), "unchanged"); - textArea.append(text.substring(getSeparator().length()), styleClass); + public int getPositionInText(int positionInTokenList, List tokenList) { + if (positionInTokenList == 0) { + return 0; } else { - textArea.append(text, styleClass); + return tokenList.stream().limit(positionInTokenList).map(String::length) + .reduce(Integer::sum) + .map(value -> value + (getSeparator().length() * positionInTokenList)) + .orElse(0); } } - - private Optional findChange(int position, List changeList) { - return changeList.stream().filter(change -> change.position() == position).findAny(); - } } From 51879346765971c09ee79cf5f3dfca491c680767 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:51:21 +0100 Subject: [PATCH 063/473] Remove redundant constructor from UnifiedDiffHighlighter --- .../diffhighlighter/UnifiedDiffHighlighter.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java index 38d6a92c389..54824f06d61 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java @@ -19,10 +19,6 @@ public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedT super(sourceTextview, targetTextview, diffMethod); } - public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { - this(sourceTextview, targetTextview, DiffMethod.CHARS); - } - @Override public void highlight() { String sourceContent = sourceTextview.getText(); From cc3560fd1a5bafd5276c7a6fde9b3515686a9b55 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:53:14 +0100 Subject: [PATCH 064/473] Allow users to switch between split and unified diff view - Fixed some bugs --- .../newmergedialog/FieldRowController.java | 47 ++++++++++++------- .../newmergedialog/ShowDiffConfig.java | 3 +- .../newmergedialog/ThreeWayMergeView.java | 8 ++-- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 64db8cf9fd0..c599aebd81d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -6,7 +6,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; -import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; @@ -68,22 +68,32 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, * @return True if left value was selected, False otherwise */ public boolean selectLeftValue() { - if (!leftValueCell.isDisabled()) { + if (StringUtil.isNullOrEmpty(leftValue)) { + toggleGroup.selectToggle(null); + mergedValueCell.setText(""); + return false; + } else { toggleGroup.selectToggle(leftValueCell); return true; } - return false; } /** * @return True if left value was selected, False otherwise */ public boolean selectRightValue() { - if (!rightValueCell.isDisabled()) { - toggleGroup.selectToggle(rightValueCell); + if (StringUtil.isNullOrEmpty(rightValue)) { + toggleGroup.selectToggle(null); + mergedValueCell.setText(""); + return false; + } else { + if (hasEqualLeftAndRightValues()) { + toggleGroup.selectToggle(leftValueCell); + } else { + toggleGroup.selectToggle(rightValueCell); + } return true; } - return false; } public String getMergedValue() { @@ -116,21 +126,24 @@ public boolean hasEqualLeftAndRightValues() { leftValueCell.getText().equals(rightValueCell.getText()); } - public void showDiffs(ShowDiffConfig diffConfig) { - // TODO: read this from diffConfig + public void showDiff(ShowDiffConfig diffConfig) { + if (leftValueCell.isDisabled() || rightValueCell.isDisabled()) { + return; + } + // Clearing old diff styles + hideDiff(); if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { - if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { - hideDiffs(); - if (diffConfig.diffMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS) { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.WORDS).highlight(); - } else { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.CHARS).highlight(); - } - } + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), + rightValueCell.getStyleClassedLabel(), + diffConfig.diffMethod()).highlight(); + } else { + new SplitDiffHighlighter(leftValueCell.getStyleClassedLabel(), + rightValueCell.getStyleClassedLabel(), + diffConfig.diffMethod()).highlight(); } } - public void hideDiffs() { + public void hideDiff() { if (!StringUtil.isNullOrEmpty(leftValue)) { int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java index e1de4e3fc9a..05a4d0121a9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java @@ -1,6 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, ThreeWayMergeToolbar.DiffHighlightMode diffMode) { +public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, DiffHighlighter.DiffMethod diffMethod) { } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index f741c1515ef..efd7ea93316 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,6 +10,7 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -70,11 +71,10 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiffs( - new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightMode()) - )); + DiffHighlighter.DiffMethod diffMethod = toolbar.getDiffHighlightMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS ? DiffHighlighter.DiffMethod.WORDS : DiffHighlighter.DiffMethod.CHARS; + fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), diffMethod))); } else { - fieldRowControllerList.forEach(FieldRowController::hideDiffs); + fieldRowControllerList.forEach(FieldRowController::hideDiff); } } From b56e5d045b9c17df91f876f10e859024ba4361c1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:53:58 +0100 Subject: [PATCH 065/473] Set left and right headers in MergeEntriesDialog --- .../org/jabref/gui/mergeentries/MergeEntriesDialog.java | 7 ++++--- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index b70a2dc915e..34dcba8b6db 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,5 +1,6 @@ package org.jabref.gui.mergeentries; +import javafx.geometry.Insets; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; import javafx.stage.StageStyle; @@ -23,7 +24,7 @@ public MergeEntriesDialog(BibEntry one, BibEntry two) { */ private void init() { this.getDialogPane().setContent(threeWayMergeView); - this.initStyle(StageStyle.UTILITY); + this.getDialogPane().setPadding(new Insets(0)); // Create buttons ButtonType replaceEntries = new ButtonType(Localization.lang("Merge entries"), ButtonBar.ButtonData.OK_DONE); @@ -38,10 +39,10 @@ private void init() { } public void setLeftHeaderText(String leftHeaderText) { - // mergeEntries.setLeftHeaderText(leftHeaderText); + threeWayMergeView.setLeftHeader(leftHeaderText); } public void setRightHeaderText(String rightHeaderText) { - // mergeEntries.setRightHeaderText(rightHeaderText); + threeWayMergeView.setRightHeader(rightHeaderText); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index efd7ea93316..506bdffcb3f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -148,4 +148,12 @@ private void addFieldRow(int index) { public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } + + public void setLeftHeader(String leftHeader) { + headerView.setLeftHeader(leftHeader); + } + + public void setRightHeader(String rightHeader) { + headerView.setRightHeader(rightHeader); + } } From d09808b43e6c19c65980a6e7568d8176c8881251 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:54:14 +0100 Subject: [PATCH 066/473] Refactor ThreeWayMergeHeaderView --- .../newmergedialog/ThreeWayMergeHeaderView.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index 4e9e15b3af5..05acddd5017 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -36,7 +36,10 @@ public ThreeWayMergeHeaderView(String leftHeader, String rightHeader) { setMaxHeight(Control.USE_PREF_SIZE); setMinHeight(Control.USE_PREF_SIZE); - bindHeaderWidthToFieldGridWidth(); + // The fields grid pane is contained within a scroll pane, thus it doesn't allocate the full available width. In + // fact, it uses the available width minus the size of the scrollbar which is 8. This leads to header columns being + // always wider than fields columns. This hack should fix it. + setPadding(new Insets(0, 8, 0, 0)); } public void setLeftHeader(String leftHeader) { @@ -46,13 +49,4 @@ public void setLeftHeader(String leftHeader) { public void setRightHeader(String rightHeader) { rightHeaderCell.setText(rightHeader); } - - /** - * The fields grid pane is contained within a scroll pane, thus it doesn't allocate the full available width. In - * fact, it uses the available width minus the size of the scrollbar which is 8. This leads to header columns being - * always larger than fields columns. This hack should fix it. - */ - private void bindHeaderWidthToFieldGridWidth() { - setPadding(new Insets(0, 8, 0, 0)); - } } From 5c0b51fda256ffd0b9b009adb65625448dfd2f0f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 28 Jun 2022 22:02:34 +0100 Subject: [PATCH 067/473] Remove wellbehavedfx module dependency --- src/main/java/module-info.java | 1 - .../newmergedialog/cell/FieldValueCell.java | 26 ++++++++----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 68a5a571fbd..751863df3e1 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -117,7 +117,6 @@ requires net.harawata.appdirs; requires org.eclipse.jgit; - requires wellbehavedfx; uses org.eclipse.jgit.transport.SshSessionFactory; uses org.eclipse.jgit.lib.GpgSigner; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 649d95e20d9..e109c88caf2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -5,7 +5,6 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.PseudoClass; -import javafx.event.Event; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Cursor; @@ -29,15 +28,9 @@ import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.StyleClassedTextArea; -import org.fxmisc.wellbehaved.event.InputMap; -import org.fxmisc.wellbehaved.event.Nodes; import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.materialdesign2.MaterialDesignC; -import static org.fxmisc.wellbehaved.event.EventPattern.anyOf; -import static org.fxmisc.wellbehaved.event.EventPattern.eventType; -import static org.fxmisc.wellbehaved.event.EventPattern.mousePressed; - /** * A readonly, selectable field cell that contains the value of some field */ @@ -143,14 +136,17 @@ private void initializeScrollPane() { } private void preventTextSelectionViaMouseEvents() { - InputMap preventSelection = InputMap.consume( - anyOf(eventType(MouseEvent.MOUSE_DRAGGED), - eventType(MouseEvent.DRAG_DETECTED), - eventType(MouseEvent.MOUSE_ENTERED), - mousePressed().unless(e -> e.getClickCount() == 1) - ) - ); - Nodes.addInputMap(label, preventSelection); + label.addEventFilter(MouseEvent.ANY, e -> { + if (e.getEventType() == MouseEvent.MOUSE_DRAGGED || + e.getEventType() == MouseEvent.DRAG_DETECTED || + e.getEventType() == MouseEvent.MOUSE_ENTERED) { + e.consume(); + } else if (e.getEventType() == MouseEvent.MOUSE_PRESSED) { + if (e.getClickCount() > 1) { + e.consume(); + } + } + }); } @Override From 0c0db6a5ed9673500be7fd8b402cbf4ca78adcef Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:58:48 +0100 Subject: [PATCH 068/473] Delete EmptyCell.java - I might recreate it later, but for now, I'm choosing simplicity over performance --- .../newmergedialog/ThreeWayMergeHeaderView.java | 3 +-- .../mergeentries/newmergedialog/cell/EmptyCell.java | 13 ------------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index 05acddd5017..a3b33e99461 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -4,7 +4,6 @@ import javafx.scene.control.Control; import javafx.scene.layout.GridPane; -import org.jabref.gui.mergeentries.newmergedialog.cell.EmptyCell; import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; /** @@ -26,7 +25,7 @@ public ThreeWayMergeHeaderView(String leftHeader, String rightHeader) { this.mergedHeaderCell = new HeaderCell("Merged Entry"); addRow(0, - new EmptyCell(HeaderCell.DEFAULT_STYLE_CLASS), + new HeaderCell(""), leftHeaderCell, rightHeaderCell, mergedHeaderCell diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java deleted file mode 100644 index e52ada18b13..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; - -public class EmptyCell extends AbstractCell { - public EmptyCell(String styleClass, int rowIndex) { - super("", rowIndex); - getStyleClass().add(styleClass); - setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); - } - - public EmptyCell(String styleClass) { - this(styleClass, AbstractCell.NO_ROW_NUMBER); - } -} From d854958067a59fe2697378d0eb93dccd841a070e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:59:46 +0100 Subject: [PATCH 069/473] Refactor FieldValueCell --- .../newmergedialog/cell/FieldValueCell.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index e109c88caf2..cde5ae3ec9a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -116,18 +116,23 @@ private void initializeSelectionBox() { labelBox.setPadding(new Insets(8)); labelBox.setCursor(Cursor.HAND); + checkmarkLayout.getChildren().setAll(createCopyButton()); + checkmarkLayout.setAlignment(Pos.TOP_CENTER); + checkmarkLayout.setPrefWidth(28); + + } + + private Button createCopyButton() { FontIcon copyIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); + copyIcon.getStyleClass().add("copy-icon"); + Button copyButton = factory.createIconButton(() -> Localization.lang("Copy"), new CopyFieldValueCommand(Globals.prefs, getText())); copyButton.setGraphic(copyIcon); copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); - - copyIcon.getStyleClass().add("copy-icon"); - checkmarkLayout.getChildren().setAll(copyButton); - checkmarkLayout.setAlignment(Pos.TOP_CENTER); - checkmarkLayout.setPrefWidth(28); - copyButton.setMaxHeight(Double.MAX_VALUE); VBox.setVgrow(copyButton, Priority.ALWAYS); + + return copyButton; } private void initializeScrollPane() { From 1fe169738b4f87bd9650df46d303f5d921e6f873 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:00:34 +0100 Subject: [PATCH 070/473] Use the new merge UI in DuplicateResolverDialog --- .../DuplicateResolverDialog.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index 1dad9cae973..822c63bf77f 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -11,6 +11,7 @@ import org.jabref.gui.duplicationFinder.DuplicateResolverDialog.DuplicateResolverResult; import org.jabref.gui.help.HelpAction; import org.jabref.gui.mergeentries.MergeEntries; +import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.DialogWindowState; import org.jabref.logic.help.HelpFile; @@ -39,7 +40,7 @@ public enum DuplicateResolverResult { BREAK } - private MergeEntries mergeEntries; + private ThreeWayMergeView threeWayMerge; private final DialogService dialogService; public DuplicateResolverDialog(BibEntry one, BibEntry two, DuplicateResolverType type, BibDatabaseContext database, StateManager stateManager, DialogService dialogService) { @@ -69,14 +70,14 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { 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); - mergeEntries = new MergeEntries(one, two); + threeWayMerge = new ThreeWayMergeView(one, two); 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); - mergeEntries = new MergeEntries(one, two, Localization.lang("Old entry"), - Localization.lang("From import")); + threeWayMerge = new ThreeWayMergeView(one, two, Localization.lang("Old entry"), + Localization.lang("From import")); break; case DUPLICATE_SEARCH_WITH_EXACT: first = new ButtonType(Localization.lang("Keep left"), ButtonData.APPLY); @@ -85,14 +86,14 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { removeExactVisible = true; - mergeEntries = new MergeEntries(one, two); + threeWayMerge = new ThreeWayMergeView(one, two); 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); - mergeEntries = new MergeEntries(one, two, Localization.lang("Old entry"), - Localization.lang("From import")); + threeWayMerge = new ThreeWayMergeView(one, two, Localization.lang("Old entry"), + Localization.lang("From import")); break; } if (removeExactVisible) { @@ -109,7 +110,7 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { this.setY(state.getY()); } - BorderPane borderPane = new BorderPane(mergeEntries); + BorderPane borderPane = new BorderPane(threeWayMerge); borderPane.setBottom(options); this.setResultConverter(button -> { @@ -136,6 +137,6 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { } public BibEntry getMergedEntry() { - return mergeEntries.getMergedEntry(); + return threeWayMerge.getMergedEntry(); } } From b09933a0c4d41618ec1a97eaa19bca08db0f22f4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:04:43 +0100 Subject: [PATCH 071/473] Expose an API to change diff view and highlight method from outside the merge toolbar --- .../newmergedialog/cell/FieldValueCell.java | 1 - .../toolbar/ThreeWayMergeToolbar.java | 42 ++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index cde5ae3ec9a..d511d57d427 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -119,7 +119,6 @@ private void initializeSelectionBox() { checkmarkLayout.getChildren().setAll(createCopyButton()); checkmarkLayout.setAlignment(Pos.TOP_CENTER); checkmarkLayout.setPrefWidth(28); - } private Button createCopyButton() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 0703f49f7c2..d0f13f1d95f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -1,7 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog.toolbar; import java.util.Arrays; -import java.util.function.Consumer; +import java.util.Objects; import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; @@ -12,13 +12,17 @@ import javafx.scene.control.ComboBox; import javafx.scene.control.RadioButton; import javafx.scene.control.ToggleGroup; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import javafx.util.StringConverter; +import org.jabref.gui.mergeentries.DiffHighlighting; +import org.jabref.gui.mergeentries.DiffMode; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; + import com.airhacks.afterburner.views.ViewLoader; import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; +import org.apache.commons.lang3.builder.Diff; public class ThreeWayMergeToolbar extends AnchorPane { @FXML @@ -98,7 +102,7 @@ public DiffView fromString(String string) { diffHighlightModeToggleGroup.selectToggle(highlightWordsRadioButton); } - public ReadOnlyObjectProperty diffViewProperty() { + public ObjectProperty diffViewProperty() { return diffViewComboBox.valueProperty(); } @@ -106,18 +110,26 @@ public DiffView getDiffView() { return diffViewProperty().get(); } + public void setDiffView(DiffView diffView) { + diffViewProperty().set(diffView); + } + public EasyBinding showDiffProperty() { return showDiff; } + public void setShowDiff(boolean showDiff) { + plainTextOrDiffComboBox.valueProperty().set(showDiff ? PlainTextOrDiff.Diff : PlainTextOrDiff.PLAIN_TEXT); + } + /** - * Convince method used to disable diff related views when diff is not selected. + * Convenience method used to disable diff related views when diff is not selected. * *

* This method is required because {@link EasyBinding} class doesn't have a method to invert a boolean property, * like {@link BooleanExpression#not()} *

- * */ + */ public EasyBinding notShowDiffProperty() { return showDiffProperty().map(showDiff -> !showDiff); } @@ -134,12 +146,16 @@ public DiffHighlightMode getDiffHighlightMode() { return diffHighlightModeProperty().get(); } - public void setOnSelectLeftEntryValuesButtonClicked(Consumer onClick) { - selectLeftEntryValuesButton.setOnMouseClicked(onClick::accept); + public void setDiffHighlightMode(DiffHighlightMode diffHighlightMode) { + diffHighlightModeProperty().set(diffHighlightMode); } - public void setOnSelectRightEntryValuesButtonClicked(Consumer onClick) { - selectRightEntryValuesButton.setOnMouseClicked(onClick::accept); + public void setOnSelectLeftEntryValuesButtonClicked(Runnable onClick) { + selectLeftEntryValuesButton.setOnMouseClicked(e -> onClick.run()); + } + + public void setOnSelectRightEntryValuesButtonClicked(Runnable onClick) { + selectRightEntryValuesButton.setOnMouseClicked(e -> onClick.run()); } public enum PlainTextOrDiff { @@ -184,7 +200,13 @@ public static DiffView fromString(String str) { } } + // TODO: remove this and use DiffMethod public enum DiffHighlightMode { - WORDS, CHARS + WORDS, CHARS; + + public static DiffHighlightMode from(DiffHighlighter.DiffMethod diffMethod) { + Objects.requireNonNull(diffMethod, "Diff method is required"); + return diffMethod == DiffHighlighter.DiffMethod.WORDS ? WORDS : CHARS; + } } } From 2f39c4eb7ca14f75b27c26769030095204dfe21d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:05:27 +0100 Subject: [PATCH 072/473] Use the new merge UI when an entry is changed from external --- .../gui/collab/EntryChangeViewModel.java | 22 +++++++++++-------- .../newmergedialog/ThreeWayMergeView.java | 20 ++++++++++++++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java index 3ebed73f187..421e4c1fcd9 100644 --- a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java @@ -5,8 +5,10 @@ import javafx.scene.control.Label; import javafx.scene.layout.VBox; -import org.jabref.gui.mergeentries.MergeEntries; -import org.jabref.gui.mergeentries.MergeEntries.DefaultRadioButtonSelectionMode; +import org.jabref.gui.mergeentries.newmergedialog.ShowDiffConfig; +import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertEntries; import org.jabref.logic.l10n.Localization; @@ -17,7 +19,7 @@ class EntryChangeViewModel extends DatabaseChangeViewModel { private final BibEntry oldEntry; private final BibEntry newEntry; - private MergeEntries mergePanel; + private ThreeWayMergeView threeWayMergeView; public EntryChangeViewModel(BibEntry entry, BibEntry newEntry) { super(); @@ -37,9 +39,9 @@ public EntryChangeViewModel(BibEntry entry, BibEntry newEntry) { public void setAccepted(boolean accepted) { super.setAccepted(accepted); if (accepted) { - mergePanel.selectAllRightRadioButtons(); + threeWayMergeView.selectRightEntryValues(); } else { - mergePanel.selectAllLeftRadioButtons(); + threeWayMergeView.selectLeftEntryValues(); } } @@ -47,7 +49,7 @@ public void setAccepted(boolean accepted) { public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { this.description(); // Init dialog to prevent NPE database.getDatabase().removeEntry(oldEntry); - BibEntry mergedEntry = mergePanel.getMergedEntry(); + BibEntry mergedEntry = threeWayMergeView.getMergedEntry(); mergedEntry.setId(oldEntry.getId()); // Keep ID database.getDatabase().insertEntry(mergedEntry); undoEdit.addEdit(new UndoableInsertEntries(database.getDatabase(), oldEntry)); @@ -56,13 +58,15 @@ public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { @Override public Node description() { - mergePanel = new MergeEntries(oldEntry, newEntry, Localization.lang("In JabRef"), Localization.lang("On disk"), DefaultRadioButtonSelectionMode.LEFT); + threeWayMergeView = new ThreeWayMergeView(oldEntry, newEntry, Localization.lang("In JabRef"), Localization.lang("On disk")); + threeWayMergeView.selectLeftEntryValues(); + threeWayMergeView.showDiff(new ShowDiffConfig(ThreeWayMergeToolbar.DiffView.SPLIT, DiffHighlighter.DiffMethod.WORDS)); VBox container = new VBox(10); Label header = new Label(name); header.getStyleClass().add("sectionHeader"); container.getChildren().add(header); - container.getChildren().add(mergePanel); - VBox.setMargin(mergePanel, new Insets(5, 5, 5, 5)); + container.getChildren().add(threeWayMergeView); + VBox.setMargin(threeWayMergeView, new Insets(5, 5, 5, 5)); return container; } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 506bdffcb3f..ae7aa604904 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -50,7 +50,7 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea initializeHeaderView(); initializeToolbar(); - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.75); this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); getChildren().addAll(toolbar, headerView, scrollPane); @@ -61,8 +61,8 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry) { } private void initializeToolbar() { - toolbar.setOnSelectLeftEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectLeftValue)); - toolbar.setOnSelectRightEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectRightValue)); + toolbar.setOnSelectLeftEntryValuesButtonClicked(this::selectLeftEntryValues); + toolbar.setOnSelectRightEntryValuesButtonClicked(this::selectRightEntryValues); toolbar.showDiffProperty().addListener(e -> updateDiff()); toolbar.diffViewProperty().addListener(e -> updateDiff()); @@ -156,4 +156,18 @@ public void setLeftHeader(String leftHeader) { public void setRightHeader(String rightHeader) { headerView.setRightHeader(rightHeader); } + + public void selectLeftEntryValues() { + fieldRowControllerList.forEach(FieldRowController::selectLeftValue); + } + + public void selectRightEntryValues() { + fieldRowControllerList.forEach(FieldRowController::selectRightValue); + } + + public void showDiff(ShowDiffConfig diffConfig) { + toolbar.setDiffView(diffConfig.diffView()); + toolbar.setDiffHighlightMode(ThreeWayMergeToolbar.DiffHighlightMode.from(diffConfig.diffMethod())); + toolbar.setShowDiff(true); + } } From a8b2aed3c1231007b203ebd313cb5a8f6fcb4545 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 29 Jun 2022 17:51:51 +0100 Subject: [PATCH 073/473] Minor styling --- .../org/jabref/gui/mergeentries/MergeEntriesDialog.java | 6 +++--- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 2 +- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 34dcba8b6db..3486a9702d2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,9 +1,7 @@ package org.jabref.gui.mergeentries; -import javafx.geometry.Insets; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; -import javafx.stage.StageStyle; import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; @@ -23,8 +21,10 @@ public MergeEntriesDialog(BibEntry one, BibEntry two) { * Sets up the dialog */ private void init() { + this.setX(20); + this.setY(20); + this.getDialogPane().setContent(threeWayMergeView); - this.getDialogPane().setPadding(new Insets(0)); // Create buttons ButtonType replaceEntries = new ButtonType(Localization.lang("Merge entries"), ButtonBar.ButtonData.OK_DONE); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 27dc070635a..b776ff345c6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -18,7 +18,7 @@ .field-value:selected .selection-box { /* -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent-alt;*/ - -fx-background-color: rgba(163, 183, 230, 0.7); + -fx-background-color: rgba(163, 183, 230, 0.80); -fx-border-color: -jr-accent; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index ae7aa604904..1474fc249b6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -50,8 +50,8 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea initializeHeaderView(); initializeToolbar(); - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.75); - this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); + this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.97); getChildren().addAll(toolbar, headerView, scrollPane); } From aaf77addd27e5d0b654f0d62c07755cf6d13a487 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:06:43 +0100 Subject: [PATCH 074/473] Remove DiffHighlighter.css stylesheet - You can find diff styles in Base.css and Dark.css --- .../newmergedialog/diffhighlighter/DiffHighlighter.css | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css deleted file mode 100644 index e69de29bb2d..00000000000 From c96b122cfc26b8255107f88772f77d06b93cddf6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:08:14 +0100 Subject: [PATCH 075/473] Remove unused dependencies --- .../newmergedialog/toolbar/ThreeWayMergeToolbar.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index d0f13f1d95f..5c37e61a837 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -5,7 +5,6 @@ import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -15,14 +14,11 @@ import javafx.scene.layout.AnchorPane; import javafx.util.StringConverter; -import org.jabref.gui.mergeentries.DiffHighlighting; -import org.jabref.gui.mergeentries.DiffMode; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import com.airhacks.afterburner.views.ViewLoader; import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; -import org.apache.commons.lang3.builder.Diff; public class ThreeWayMergeToolbar extends AnchorPane { @FXML From f8abc0fa77074697b165c5bbbe02e8176d4dbd7c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:08:49 +0100 Subject: [PATCH 076/473] Allow selecting empty field values --- .../newmergedialog/FieldRowController.java | 84 ++++++------------- .../newmergedialog/ThreeWayMergeView.java | 3 +- 2 files changed, 28 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index c599aebd81d..24a949b230e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -11,6 +11,8 @@ import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; +import org.fxmisc.richtext.StyleClassedTextArea; + public class FieldRowController { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; @@ -41,58 +43,31 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, }); mergedValueCell.textProperty().addListener((observable, old, mergedValue) -> { - if (!StringUtil.isNullOrEmpty(mergedValue)) { - if (mergedValue.equals(leftValue)) { - toggleGroup.selectToggle(leftValueCell); - } else if (mergedValue.equals(rightValue)) { - toggleGroup.selectToggle(rightValueCell); - } else { - // deselect all toggles because left and right values don't equal the merged value - toggleGroup.selectToggle(null); - } + if (mergedValue.equals(leftValue)) { + toggleGroup.selectToggle(leftValueCell); + } else if (mergedValue.equals(rightValue)) { + toggleGroup.selectToggle(rightValueCell); } else { - // deselect all toggles because empty toggles cannot be selected + // deselect all toggles because left and right values don't equal the merged value toggleGroup.selectToggle(null); } }); - // empty toggles are disabled and cannot be selected - if (StringUtil.isNullOrEmpty(leftValue)) { - leftValueCell.setDisable(true); - } else if (StringUtil.isNullOrEmpty(rightValue)) { + // Because when both left and right have the same values, then only left value will be shown + if (hasEqualLeftAndRightValues()) { rightValueCell.setDisable(true); } } - /** - * @return True if left value was selected, False otherwise - */ - public boolean selectLeftValue() { - if (StringUtil.isNullOrEmpty(leftValue)) { - toggleGroup.selectToggle(null); - mergedValueCell.setText(""); - return false; - } else { - toggleGroup.selectToggle(leftValueCell); - return true; - } + public void selectLeftValue() { + toggleGroup.selectToggle(leftValueCell); } - /** - * @return True if left value was selected, False otherwise - */ - public boolean selectRightValue() { - if (StringUtil.isNullOrEmpty(rightValue)) { - toggleGroup.selectToggle(null); - mergedValueCell.setText(""); - return false; + public void selectRightValue() { + if (rightValueCell.isDisabled()) { + selectLeftValue(); } else { - if (hasEqualLeftAndRightValues()) { - toggleGroup.selectToggle(leftValueCell); - } else { - toggleGroup.selectToggle(rightValueCell); - } - return true; + toggleGroup.selectToggle(rightValueCell); } } @@ -130,30 +105,25 @@ public void showDiff(ShowDiffConfig diffConfig) { if (leftValueCell.isDisabled() || rightValueCell.isDisabled()) { return; } - // Clearing old diff styles + + StyleClassedTextArea leftLabel = leftValueCell.getStyleClassedLabel(); + StyleClassedTextArea rightLabel = rightValueCell.getStyleClassedLabel(); + // Clearing old diff styles based on previous diffConfig hideDiff(); if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), - rightValueCell.getStyleClassedLabel(), - diffConfig.diffMethod()).highlight(); + new UnifiedDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); } else { - new SplitDiffHighlighter(leftValueCell.getStyleClassedLabel(), - rightValueCell.getStyleClassedLabel(), - diffConfig.diffMethod()).highlight(); + new SplitDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); } } public void hideDiff() { - if (!StringUtil.isNullOrEmpty(leftValue)) { - int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); - getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); - getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); - } + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); + getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); + getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); - if (!StringUtil.isNullOrEmpty(rightValue)) { - int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); - getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); - getRightValueCell().getStyleClassedLabel().replaceText(rightValue); - } + int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); + getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); + getRightValueCell().getStyleClassedLabel().replaceText(rightValue); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 1474fc249b6..fe77ea972c5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -50,7 +50,7 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea initializeHeaderView(); initializeToolbar(); - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.76); this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.97); getChildren().addAll(toolbar, headerView, scrollPane); @@ -139,7 +139,6 @@ private void addFieldRow(int index) { mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index, 1, 1); - fieldRow.getRightValueCell().setDisable(true); } else { mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); } From 7af8944d14ae67f6d40f351a8c67a39de9bff463 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:15:37 +0100 Subject: [PATCH 077/473] Fix readme :( --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08b68588cfb..23cc6f637f6 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,6 @@ For IntelliJ IDEA, just import the project via a Gradle Import by pointing at th ## Sponsoring -JabRef development is by powered YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) +JabRef development is powered by YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) [JabRef]: https://www.jabref.org From 4e2e2d23bd4e82fb7044a7e18c4078b7c67991ad Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:31:03 +0100 Subject: [PATCH 078/473] Use a theme color for selection box background --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index b776ff345c6..59963812688 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -18,7 +18,7 @@ .field-value:selected .selection-box { /* -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent-alt;*/ - -fx-background-color: rgba(163, 183, 230, 0.80); + -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent; } From 30e817b770ed097bfc14a7c286bfcb94adf89c5e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 18:33:48 +0100 Subject: [PATCH 079/473] Refactor FieldValueCell --- .../newmergedialog/cell/FieldValueCell.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index d511d57d427..08ad2b33ff4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -65,7 +65,7 @@ protected void invalidated() { } }; private final HBox selectionBox = new HBox(); - private final VBox checkmarkLayout = new VBox(); + private final HBox actionsContainer = new HBox(); public FieldValueCell(String text, int rowIndex) { super(text, rowIndex); @@ -84,7 +84,7 @@ private void initialize() { } }); - selectionBox.getChildren().addAll(labelBox, checkmarkLayout); + selectionBox.getChildren().addAll(labelBox, actionsContainer); getChildren().setAll(selectionBox); } @@ -116,9 +116,9 @@ private void initializeSelectionBox() { labelBox.setPadding(new Insets(8)); labelBox.setCursor(Cursor.HAND); - checkmarkLayout.getChildren().setAll(createCopyButton()); - checkmarkLayout.setAlignment(Pos.TOP_CENTER); - checkmarkLayout.setPrefWidth(28); + actionsContainer.getChildren().setAll(createCopyButton()); + actionsContainer.setAlignment(Pos.TOP_CENTER); + actionsContainer.setPrefWidth(28); } private Button createCopyButton() { @@ -129,7 +129,6 @@ private Button createCopyButton() { copyButton.setGraphic(copyIcon); copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); copyButton.setMaxHeight(Double.MAX_VALUE); - VBox.setVgrow(copyButton, Priority.ALWAYS); return copyButton; } From c8a9e31b4e76bfbfdea905379e3a09ac2d2c2795 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 19:40:16 +0100 Subject: [PATCH 080/473] Add an action to FieldValueCell for opening Urls --- src/main/java/org/jabref/gui/Base.css | 8 ++-- src/main/java/org/jabref/gui/Dark.css | 8 ++-- .../{ => cell}/CopyFieldValueCommand.java | 2 +- .../newmergedialog/cell/FieldValueCell.java | 43 ++++++++++++++++--- .../cell/OpenExternalLinkAction.java | 32 ++++++++++++++ 5 files changed, 77 insertions(+), 16 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ => cell}/CopyFieldValueCommand.java (92%) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index ccd0682d6c9..98b8fc4df8e 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -632,18 +632,18 @@ TextFlow > .tooltip-text-monospaced { -fx-background-insets: 0; } -.field-value .copy-icon { - -fx-icon-size: 15; +.field-value .action-icon { + -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; -fx-blend-mode: multiply ; -fx-opacity: 69%; } -.field-value:disabled .copy-icon { +.field-value:disabled .action-icon { -fx-opacity: 0%; } -.field-value:selected .copy-icon { +.field-value:selected .action-icon { } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 63bd21c0a99..21ec0ac6b57 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -93,18 +93,18 @@ .tree-table-row-cell:hover { -fx-background-color: -jr-hover; } -.field-value .copy-icon { - -fx-icon-size: 15; +.field-value .action-icon { + -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; -fx-blend-mode: inherit; -fx-opacity: 100%; } -.field-value:disabled .copy-icon { +.field-value:disabled .action-icon { -fx-opacity: 0%; } -.field-value:selected .copy-icon { +.field-value:selected .action-icon { -fx-icon-color: -fx-text-background-color; -fx-opacity: 100%; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java similarity index 92% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java index a3ef9024215..e18a831933b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java @@ -1,4 +1,4 @@ -package org.jabref.gui.mergeentries.newmergedialog; +package org.jabref.gui.mergeentries.newmergedialog.cell; import java.util.Objects; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 08ad2b33ff4..acb1cb4d600 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -3,11 +3,13 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanPropertyBase; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.PseudoClass; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Cursor; +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ContentDisplay; import javafx.scene.control.ScrollPane; @@ -18,23 +20,29 @@ import javafx.scene.layout.Background; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; -import org.jabref.gui.mergeentries.newmergedialog.CopyFieldValueCommand; +import org.jabref.gui.fieldeditors.URLUtil; +import org.jabref.gui.icon.IconTheme; import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; +import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.StyleClassedTextArea; import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.materialdesign2.MaterialDesignC; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A readonly, selectable field cell that contains the value of some field */ public class FieldValueCell extends AbstractCell implements Toggle { + public static final Logger LOGGER = LoggerFactory.getLogger(FieldValueCell.class); + public static final String DEFAULT_STYLE_CLASS = "field-value"; public static final String SELECTION_BOX_STYLE_CLASS = "selection-box"; @@ -67,6 +75,8 @@ protected void invalidated() { private final HBox selectionBox = new HBox(); private final HBox actionsContainer = new HBox(); + private final BooleanProperty isUrl = new SimpleBooleanProperty(); + public FieldValueCell(String text, int rowIndex) { super(text, rowIndex); initialize(); @@ -77,6 +87,7 @@ private void initialize() { initializeScrollPane(); initializeLabel(); initializeSelectionBox(); + initializeActions(); textProperty().addListener(invalidated -> setUserData(getText())); setOnMouseClicked(e -> { if (!isDisabled()) { @@ -108,6 +119,12 @@ private void initializeLabel() { }); } + private void initializeActions() { + actionsContainer.getChildren().setAll(createOpenLinkButton(), createCopyButton()); + actionsContainer.setAlignment(Pos.TOP_CENTER); + actionsContainer.setPrefWidth(28); + } + private void initializeSelectionBox() { selectionBox.getStyleClass().add(SELECTION_BOX_STYLE_CLASS); HBox.setHgrow(selectionBox, Priority.ALWAYS); @@ -115,24 +132,36 @@ private void initializeSelectionBox() { HBox.setHgrow(labelBox, Priority.ALWAYS); labelBox.setPadding(new Insets(8)); labelBox.setCursor(Cursor.HAND); - - actionsContainer.getChildren().setAll(createCopyButton()); - actionsContainer.setAlignment(Pos.TOP_CENTER); - actionsContainer.setPrefWidth(28); } private Button createCopyButton() { FontIcon copyIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); - copyIcon.getStyleClass().add("copy-icon"); + copyIcon.getStyleClass().add("action-icon"); Button copyButton = factory.createIconButton(() -> Localization.lang("Copy"), new CopyFieldValueCommand(Globals.prefs, getText())); copyButton.setGraphic(copyIcon); copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); copyButton.setMaxHeight(Double.MAX_VALUE); + copyButton.visibleProperty().bind(textProperty().isEmpty().not()); return copyButton; } + public Button createOpenLinkButton() { + Node openLinkIcon = IconTheme.JabRefIcons.OPEN_LINK.getGraphicNode(); + openLinkIcon.getStyleClass().add("action-icon"); + + Button openLinkButton = factory.createIconButton(() -> Localization.lang("Open Link"), new OpenExternalLinkAction(getText())); + openLinkButton.setGraphic(openLinkIcon); + openLinkButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + openLinkButton.setMaxHeight(Double.MAX_VALUE); + + isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && URLUtil.isURL(input))); + openLinkButton.visibleProperty().bind(isUrl); + + return openLinkButton; + } + private void initializeScrollPane() { HBox.setHgrow(scrollPane, Priority.ALWAYS); scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java new file mode 100644 index 00000000000..6651be0d530 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java @@ -0,0 +1,32 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import java.io.IOException; + +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.model.strings.StringUtil; + +/** + * This action can open an Url and DOI + * */ +public class OpenExternalLinkAction extends SimpleCommand { + private final String urlOrDoi; + + public OpenExternalLinkAction(String urlOrDoi) { + this.urlOrDoi = urlOrDoi; + } + + @Override + public void execute() { + if (StringUtil.isBlank(urlOrDoi)) { + return; + } + + try { + JabRefDesktop.openBrowser(urlOrDoi); + } catch ( + IOException ex) { + // TODO: Do something + } + } +} From 815d415c0f2f7dfc95b0b10cd18ac7cfe50818b8 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 19:55:19 +0100 Subject: [PATCH 081/473] Add the ability to open DOI identifier --- .../newmergedialog/cell/FieldValueCell.java | 3 ++- .../newmergedialog/cell/OpenExternalLinkAction.java | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index acb1cb4d600..9e86ab58e15 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -27,6 +27,7 @@ import org.jabref.gui.fieldeditors.URLUtil; import org.jabref.gui.icon.IconTheme; import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.identifier.DOI; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -156,7 +157,7 @@ public Button createOpenLinkButton() { openLinkButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); openLinkButton.setMaxHeight(Double.MAX_VALUE); - isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && URLUtil.isURL(input))); + isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && (URLUtil.isURL(input) || DOI.isValid(input)))); openLinkButton.visibleProperty().bind(isUrl); return openLinkButton; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java index 6651be0d530..102b192458a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java @@ -1,9 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; import java.io.IOException; +import java.net.URI; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.model.entry.identifier.DOI; import org.jabref.model.strings.StringUtil; /** @@ -23,7 +25,14 @@ public void execute() { } try { - JabRefDesktop.openBrowser(urlOrDoi); + String url; + if (DOI.isValid(urlOrDoi)) { + url = DOI.parse(urlOrDoi).flatMap(DOI::getExternalURI).map(URI::toString).orElse(""); + } else { + url = urlOrDoi; + } + + JabRefDesktop.openBrowser(url); } catch ( IOException ex) { // TODO: Do something From 89357c6ed4a6307d91dfc70b0eeae88d014244d4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 20:07:02 +0100 Subject: [PATCH 082/473] Cleanup --- .../mergeentries/newmergedialog/cell/FieldValueCell.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 9e86ab58e15..82ca6b0c235 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -3,7 +3,6 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanPropertyBase; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.PseudoClass; import javafx.geometry.Insets; @@ -76,8 +75,6 @@ protected void invalidated() { private final HBox selectionBox = new HBox(); private final HBox actionsContainer = new HBox(); - private final BooleanProperty isUrl = new SimpleBooleanProperty(); - public FieldValueCell(String text, int rowIndex) { super(text, rowIndex); initialize(); @@ -157,8 +154,7 @@ public Button createOpenLinkButton() { openLinkButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); openLinkButton.setMaxHeight(Double.MAX_VALUE); - isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && (URLUtil.isURL(input) || DOI.isValid(input)))); - openLinkButton.visibleProperty().bind(isUrl); + openLinkButton.visibleProperty().bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && (URLUtil.isURL(input) || DOI.isValid(input)))); return openLinkButton; } From 9973e03d11959f73cd0912ec4fc5f717dd2a60df Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 20:12:01 +0100 Subject: [PATCH 083/473] Checkstyle --- .../jabref/gui/duplicationFinder/DuplicateResolverDialog.java | 1 - .../newmergedialog/diffhighlighter/SplitDiffHighlighter.java | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index 822c63bf77f..cec54b0d192 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -10,7 +10,6 @@ import org.jabref.gui.StateManager; import org.jabref.gui.duplicationFinder.DuplicateResolverDialog.DuplicateResolverResult; import org.jabref.gui.help.HelpAction; -import org.jabref.gui.mergeentries.MergeEntries; import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.DialogWindowState; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java index 5b7275220eb..14570f6b2a8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -1,12 +1,9 @@ package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; -import java.util.ArrayList; import java.util.List; -import java.util.Optional; import com.github.difflib.DiffUtils; import com.github.difflib.patch.AbstractDelta; -import com.github.difflib.patch.DeltaType; import org.fxmisc.richtext.StyleClassedTextArea; /** From ee64212d5bcece7c20a873d0996296cd9b8d59a2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 4 Jul 2022 21:29:07 +0100 Subject: [PATCH 084/473] Improve URL validation logic --- src/main/java/org/jabref/gui/fieldeditors/URLUtil.java | 7 ++++++- src/test/java/org/jabref/logic/net/URLUtilTest.java | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java b/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java index bb73b95a6d9..1ee8e8b2652 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java +++ b/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java @@ -74,7 +74,12 @@ public static String cleanGoogleSearchURL(String url) { * @return true if url contains a valid URL */ public static boolean isURL(String url) { - return url.contains("://"); + try { + new URL(url); + return true; + } catch (MalformedURLException e) { + return false; + } } /** diff --git a/src/test/java/org/jabref/logic/net/URLUtilTest.java b/src/test/java/org/jabref/logic/net/URLUtilTest.java index 04ed0e99a94..d69d7a1df7e 100644 --- a/src/test/java/org/jabref/logic/net/URLUtilTest.java +++ b/src/test/java/org/jabref/logic/net/URLUtilTest.java @@ -73,4 +73,9 @@ void isURLshouldRejectInvalidURL() { assertFalse(URLUtil.isURL("www.google.com")); assertFalse(URLUtil.isURL("google.com")); } + + @Test + void isURLshouldRejectEmbeddedURL() { + assertFalse(URLUtil.isURL("dblp computer science bibliography, http://dblp.org")); + } } From 5af4864faf3f42316395acf4007f9df581ca80d6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 4 Jul 2022 21:42:18 +0100 Subject: [PATCH 085/473] Use DiffMethod in merge toolbar for consistency --- .../newmergedialog/FieldRowController.java | 6 +-- .../newmergedialog/ShowDiffConfig.java | 8 ++-- .../newmergedialog/ThreeWayMergeView.java | 8 ++-- .../toolbar/ThreeWayMergeToolbar.fxml | 4 +- .../toolbar/ThreeWayMergeToolbar.java | 39 +++++++------------ 5 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 24a949b230e..d1fb3b248a9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -53,7 +53,7 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } }); - // Because when both left and right have the same values, then only left value will be shown + // When left and right have the same value, only the left value will be shown if (hasEqualLeftAndRightValues()) { rightValueCell.setDisable(true); } @@ -111,9 +111,9 @@ public void showDiff(ShowDiffConfig diffConfig) { // Clearing old diff styles based on previous diffConfig hideDiff(); if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { - new UnifiedDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); + new UnifiedDiffHighlighter(leftLabel, rightLabel, diffConfig.diffHighlightingMethod()).highlight(); } else { - new SplitDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); + new SplitDiffHighlighter(leftLabel, rightLabel, diffConfig.diffHighlightingMethod()).highlight(); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java index 05a4d0121a9..62697e3119b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java @@ -1,7 +1,9 @@ package org.jabref.gui.mergeentries.newmergedialog; -import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; -import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import static org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter.DiffMethod; +import static org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar.DiffView; -public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, DiffHighlighter.DiffMethod diffMethod) { +public record ShowDiffConfig( + DiffView diffView, + DiffMethod diffHighlightingMethod) { } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index fe77ea972c5..0c6221450f4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,7 +10,6 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -66,13 +65,12 @@ private void initializeToolbar() { toolbar.showDiffProperty().addListener(e -> updateDiff()); toolbar.diffViewProperty().addListener(e -> updateDiff()); - toolbar.diffHighlightModeProperty().addListener(e -> updateDiff()); + toolbar.diffHighlightingMethodProperty().addListener(e -> updateDiff()); } private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - DiffHighlighter.DiffMethod diffMethod = toolbar.getDiffHighlightMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS ? DiffHighlighter.DiffMethod.WORDS : DiffHighlighter.DiffMethod.CHARS; - fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), diffMethod))); + fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { fieldRowControllerList.forEach(FieldRowController::hideDiff); } @@ -166,7 +164,7 @@ public void selectRightEntryValues() { public void showDiff(ShowDiffConfig diffConfig) { toolbar.setDiffView(diffConfig.diffView()); - toolbar.setDiffHighlightMode(ThreeWayMergeToolbar.DiffHighlightMode.from(diffConfig.diffMethod())); + toolbar.setDiffHighlightingMethod(diffConfig.diffHighlightingMethod()); toolbar.setShowDiff(true); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml index 39df997c47b..2361c686981 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml @@ -38,10 +38,10 @@
- + - +
diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 5c37e61a837..6efadffa2bf 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -1,7 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog.toolbar; import java.util.Arrays; -import java.util.Objects; import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; @@ -20,6 +19,8 @@ import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; +import static org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter.DiffMethod; + public class ThreeWayMergeToolbar extends AnchorPane { @FXML private RadioButton highlightCharactersRadioButtons; @@ -28,7 +29,7 @@ public class ThreeWayMergeToolbar extends AnchorPane { private RadioButton highlightWordsRadioButton; @FXML - private ToggleGroup diffHighlightModeToggleGroup; + private ToggleGroup diffHighlightingMethodToggleGroup; @FXML private ComboBox diffViewComboBox; @@ -42,7 +43,7 @@ public class ThreeWayMergeToolbar extends AnchorPane { @FXML private Button selectRightEntryValuesButton; - private final ObjectProperty diffHighlightMode = new SimpleObjectProperty<>(); + private final ObjectProperty diffHighlightingMethod = new SimpleObjectProperty<>(); private EasyBinding showDiff; public ThreeWayMergeToolbar() { @@ -87,15 +88,15 @@ public DiffView fromString(String string) { highlightWordsRadioButton.disableProperty().bind(notShowDiffProperty()); highlightCharactersRadioButtons.disableProperty().bind(notShowDiffProperty()); - diffHighlightModeToggleGroup.selectedToggleProperty().addListener((observable -> { - if (diffHighlightModeToggleGroup.getSelectedToggle().equals(highlightCharactersRadioButtons)) { - diffHighlightMode.set(DiffHighlightMode.CHARS); + diffHighlightingMethodToggleGroup.selectedToggleProperty().addListener((observable -> { + if (diffHighlightingMethodToggleGroup.getSelectedToggle().equals(highlightCharactersRadioButtons)) { + diffHighlightingMethod.set(DiffMethod.CHARS); } else { - diffHighlightMode.set(DiffHighlightMode.WORDS); + diffHighlightingMethod.set(DiffMethod.WORDS); } })); - diffHighlightModeToggleGroup.selectToggle(highlightWordsRadioButton); + diffHighlightingMethodToggleGroup.selectToggle(highlightWordsRadioButton); } public ObjectProperty diffViewProperty() { @@ -134,16 +135,16 @@ public Boolean isShowDiffEnabled() { return showDiffProperty().get(); } - public ObjectProperty diffHighlightModeProperty() { - return diffHighlightMode; + public ObjectProperty diffHighlightingMethodProperty() { + return diffHighlightingMethod; } - public DiffHighlightMode getDiffHighlightMode() { - return diffHighlightModeProperty().get(); + public DiffMethod getDiffHighlightingMethod() { + return diffHighlightingMethodProperty().get(); } - public void setDiffHighlightMode(DiffHighlightMode diffHighlightMode) { - diffHighlightModeProperty().set(diffHighlightMode); + public void setDiffHighlightingMethod(DiffMethod diffHighlightingMethod) { + diffHighlightingMethodProperty().set(diffHighlightingMethod); } public void setOnSelectLeftEntryValuesButtonClicked(Runnable onClick) { @@ -195,14 +196,4 @@ public static DiffView fromString(String str) { .orElseThrow(IllegalArgumentException::new); } } - - // TODO: remove this and use DiffMethod - public enum DiffHighlightMode { - WORDS, CHARS; - - public static DiffHighlightMode from(DiffHighlighter.DiffMethod diffMethod) { - Objects.requireNonNull(diffMethod, "Diff method is required"); - return diffMethod == DiffHighlighter.DiffMethod.WORDS ? WORDS : CHARS; - } - } } From ed2a0acb84a0c55482cef472c71d64149c7e16ec Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:15:11 +0100 Subject: [PATCH 086/473] i18n --- src/main/resources/l10n/JabRef_en.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index e66b587e6a1..9f1625d21a6 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2506,3 +2506,5 @@ Move\ value=Move value Swap\ values=Swap values Copy\ or\ move\ the\ value\ of\ one\ field\ to\ another=Copy or move the value of one field to another Automatic\ field\ editor=Automatic field editor + +Open\ Link=Open Link From bcec6a85484bc59cda2bc5a0c8dfdd2a0eca77e5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:19:42 +0100 Subject: [PATCH 087/473] Cleanup css --- src/main/java/org/jabref/gui/Base.css | 3 +-- src/main/java/org/jabref/gui/Dark.css | 2 +- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 7 ------- .../gui/mergeentries/newmergedialog/cell/HeaderCell.java | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 98b8fc4df8e..550796b5ac8 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -1,7 +1,6 @@ .root { - -jr-transparent-green: rgba(16, 172, 132, 0.12); -jr-row-odd-background: -fx-control-inner-background-alt; -jr-row-even-background: -fx-control-inner-background; /* @@ -647,7 +646,7 @@ TextFlow > .tooltip-text-monospaced { } -.header-cell { +.merge-header-cell { -fx-border-width: 0 0 1 0; -fx-border-color: -jr-gray-1; -fx-background-color: -jr-row-even-background; diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 21ec0ac6b57..55405297abd 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -109,7 +109,7 @@ -fx-opacity: 100%; } -.header-cell { +.merge-header-cell { -fx-border-width: 0 0 1 0; -fx-border-color: -fx-outer-border; -fx-background-color: -jr-row-odd-background; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 59963812688..5686b37d855 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -1,8 +1,3 @@ -.merged-field { -/* -fx-border-color: #dfdfdf; - -fx-border-width: 0 0 0 1.5;*/ -} - .merged-field .styled-text-area { -fx-background-color: -fx-outer-border, -fx-control-inner-background; -fx-background-insets: 0, 1; @@ -16,8 +11,6 @@ } .field-value:selected .selection-box { - /* -fx-background-color: -jr-accent-alt; - -fx-border-color: -jr-accent-alt;*/ -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 5a7c6a9ff71..2fd82afd38b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -4,7 +4,7 @@ import javafx.scene.control.Label; public class HeaderCell extends AbstractCell { - public static final String DEFAULT_STYLE_CLASS = "header-cell"; + public static final String DEFAULT_STYLE_CLASS = "merge-header-cell"; private final Label label = new Label(); public HeaderCell(String text) { From be0a7fbf620bebd7754e722b4237e9a96b2aee35 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:35:00 +0100 Subject: [PATCH 088/473] Remove redundant icon style --- src/main/java/org/jabref/gui/Base.css | 8 ++------ src/main/java/org/jabref/gui/Dark.css | 16 +++------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 550796b5ac8..09262fc587e 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -632,20 +632,16 @@ TextFlow > .tooltip-text-monospaced { } .field-value .action-icon { + -fx-blend-mode: multiply; + -fx-opacity: 69%; -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; - -fx-blend-mode: multiply ; - -fx-opacity: 69%; } .field-value:disabled .action-icon { -fx-opacity: 0%; } -.field-value:selected .action-icon { - -} - .merge-header-cell { -fx-border-width: 0 0 1 0; -fx-border-color: -jr-gray-1; diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 55405297abd..4dd3e5eb65f 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -93,20 +93,10 @@ .tree-table-row-cell:hover { -fx-background-color: -jr-hover; } -.field-value .action-icon { - -fx-icon-size: 14; - -fx-icon-color: -fx-text-background-color; - -fx-blend-mode: inherit; - -fx-opacity: 100%; -} -.field-value:disabled .action-icon { - -fx-opacity: 0%; -} - -.field-value:selected .action-icon { - -fx-icon-color: -fx-text-background-color; - -fx-opacity: 100%; +.field-value .action-icon { + -fx-blend-mode: none; + -fx-opacity: 90%; } .merge-header-cell { From 0602237e442127bd684e06da94556d71d53bf80f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:38:22 +0100 Subject: [PATCH 089/473] Rename style class field-value to merge-field-value - Since it is used in Base.css and Dark.css, it is critical to distinguish the field cell used is related to the merge UI. --- src/main/java/org/jabref/gui/Base.css | 4 ++-- src/main/java/org/jabref/gui/Dark.css | 2 +- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 4 ++-- .../gui/mergeentries/newmergedialog/cell/FieldValueCell.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 09262fc587e..aad81750edd 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -631,14 +631,14 @@ TextFlow > .tooltip-text-monospaced { -fx-background-insets: 0; } -.field-value .action-icon { +.merge-field-value .action-icon { -fx-blend-mode: multiply; -fx-opacity: 69%; -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; } -.field-value:disabled .action-icon { +.merge-field-value:disabled .action-icon { -fx-opacity: 0%; } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 4dd3e5eb65f..3271900cf05 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -94,7 +94,7 @@ -fx-background-color: -jr-hover; } -.field-value .action-icon { +.merge-field-value .action-icon { -fx-blend-mode: none; -fx-opacity: 90%; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 5686b37d855..fbfdf859411 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -10,12 +10,12 @@ -fx-highlight-text-fill: -fx-text-inner-color; } -.field-value:selected .selection-box { +.merge-field-value:selected .selection-box { -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent; } -.field-value .selection-box { +.merge-field-value .selection-box { -fx-background-color: #0000; -fx-border-color: #0000; -fx-border-radius: 8; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 82ca6b0c235..f31639ccc25 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -43,7 +43,7 @@ public class FieldValueCell extends AbstractCell implements Toggle { public static final Logger LOGGER = LoggerFactory.getLogger(FieldValueCell.class); - public static final String DEFAULT_STYLE_CLASS = "field-value"; + public static final String DEFAULT_STYLE_CLASS = "merge-field-value"; public static final String SELECTION_BOX_STYLE_CLASS = "selection-box"; private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected"); From 41cae265bb8f70241d1c9c9298ac750987b1b5c3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:43:17 +0100 Subject: [PATCH 090/473] Remove old Merge entries UI --- .../jabref/gui/mergeentries/MergeEntries.css | 12 - .../jabref/gui/mergeentries/MergeEntries.java | 417 ------------------ 2 files changed, 429 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeEntries.css delete mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeEntries.java diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.css b/src/main/java/org/jabref/gui/mergeentries/MergeEntries.css deleted file mode 100644 index 82f5ca6d3ee..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.css +++ /dev/null @@ -1,12 +0,0 @@ -.text-changed { - -fx-fill: darkgreen; -} - -.text-added { - -fx-fill: #54A3F2; -} - -.text-removed { - -fx-fill: #FA5B68; -} - diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java deleted file mode 100644 index 99472efdd89..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java +++ /dev/null @@ -1,417 +0,0 @@ -package org.jabref.gui.mergeentries; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; - -import javafx.collections.FXCollections; -import javafx.geometry.HPos; -import javafx.geometry.Insets; -import javafx.scene.control.Button; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.ToggleGroup; -import javafx.scene.control.Tooltip; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.text.Text; -import javafx.scene.text.TextFlow; -import javafx.stage.Screen; - -import org.jabref.gui.Globals; -import org.jabref.gui.icon.IconTheme.JabRefIcons; -import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.gui.util.component.DiffHighlightingTextPane; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.FieldFactory; - -import com.tobiasdiez.easybind.EasyBind; - -public class MergeEntries extends BorderPane { - - private static final int NUMBER_OF_COLUMNS = 6; - private static final int LEFT_RADIOBUTTON_INDEX = 0; - private static final int RIGHT_RADIOBUTTON_INDEX = 2; - private final ComboBox diffMode = new ComboBox<>(); - - // Headings - private final List columnHeadings = Arrays.asList( - Localization.lang("Field"), - Localization.lang("Left entry"), - "left icon", - Localization.lang("None"), - "right icon", - Localization.lang("Right entry")); - private final Set identicalFields = new HashSet<>(); - private final Set differentFields = new HashSet<>(); - private final BibEntry mergedEntry = new BibEntry(); - private final BibEntry leftEntry; - private final BibEntry rightEntry; - private final Map leftTextPanes = new HashMap<>(); - private final Set allFields = new TreeSet<>(Comparator.comparing(Field::getName)); - private final Map rightTextPanes = new HashMap<>(); - private final Map> radioButtons = new HashMap<>(); - private Boolean identicalTypes; - private List typeRadioButtons; - private final DefaultRadioButtonSelectionMode defaultRadioButtonSelectionMode; - private final List leftRadioButtons = new ArrayList<>(); - private final List rightRadioButtons = new ArrayList<>(); - - /** - * Constructor with optional column captions for the two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - * @param headingLeft Heading for left entry - * @param headingRight Heading for right entry - * @param defaultRadioButtonSelectionMode If the left or the right side of the radio button should be preselected - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight, String headingLeft, String headingRight, DefaultRadioButtonSelectionMode defaultRadioButtonSelectionMode) { - this.leftEntry = entryLeft; - this.rightEntry = entryRight; - this.defaultRadioButtonSelectionMode = defaultRadioButtonSelectionMode; - - initialize(); - setLeftHeaderText(headingLeft); - setRightHeaderText(headingRight); - } - - /** - * Constructor with optional column captions for the two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - * @param headingLeft Heading for left entry - * @param headingRight Heading for right entry - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight, String headingLeft, String headingRight) { - this(entryLeft, entryRight, headingLeft, headingRight, DefaultRadioButtonSelectionMode.LEFT); - } - - /** - * Constructor taking two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - * @param defaultRadioButtonSelectionMode If the left or the right side of the radio button should be preselected - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight, DefaultRadioButtonSelectionMode defaultRadioButtonSelectionMode) { - leftEntry = entryLeft; - rightEntry = entryRight; - this.defaultRadioButtonSelectionMode = defaultRadioButtonSelectionMode; - initialize(); - } - - /** - * Constructor taking two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight) { - this(entryLeft, entryRight, DefaultRadioButtonSelectionMode.LEFT); - } - - private static String getDisplayText(DiffMode mode) { - return switch (mode) { - case PLAIN -> Localization.lang("Plain text"); - case WORD -> Localization.lang("Show diff") + " - " + Localization.lang("word"); - case CHARACTER -> Localization.lang("Show diff") + " - " + Localization.lang("character"); - case WORD_SYMMETRIC -> Localization.lang("Show symmetric diff") + " - " + Localization.lang("word"); - case CHARACTER_SYMMETRIC -> Localization.lang("Show symmetric diff") + " - " + Localization.lang("character"); - }; - } - - /** - * Main function for building the merge entry JPanel - */ - private void initialize() { - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.75); - this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.75); - - setupFields(); - - fillDiffModes(); - - GridPane mergePanel = new GridPane(); - mergePanel.setVgap(10); - mergePanel.setHgap(15); - ColumnConstraints columnLabel = new ColumnConstraints(); - columnLabel.setHgrow(Priority.ALWAYS); - ColumnConstraints columnValues = new ColumnConstraints(); - columnValues.setHgrow(Priority.NEVER); - columnValues.setPercentWidth(40); - ColumnConstraints columnSelect = new ColumnConstraints(); - columnSelect.setHgrow(Priority.NEVER); - columnSelect.setHalignment(HPos.CENTER); - // See columnHeadings variable for the headings: 1) field, 2) left content, 3) left arrow, 4) "none", 5) right arrow, 6) right content - mergePanel.getColumnConstraints().setAll(columnLabel, columnValues, columnSelect, columnSelect, columnSelect, columnValues); - - setupHeadingRows(mergePanel); - setupEntryTypeRow(mergePanel); - setupFieldRows(mergePanel); - - ScrollPane scrollPane = new ScrollPane(mergePanel); - scrollPane.setFitToWidth(true); - setCenter(scrollPane); - - updateFieldValues(allFields); - - updateMergedEntry(); - - getStylesheets().add(0, MergeEntries.class.getResource("MergeEntries.css").toExternalForm()); - } - - private void setupFieldRows(GridPane mergePanel) { - // For all fields in joint add a row and possibly radio buttons - int row = 2; - for (Field field : allFields) { - Label label = new Label(field.getDisplayName()); - label.setMinWidth(USE_PREF_SIZE); - mergePanel.add(label, 0, row); - Optional leftString = leftEntry.getField(field); - Optional rightString = rightEntry.getField(field); - if (leftString.equals(rightString)) { - identicalFields.add(field); - } else { - differentFields.add(field); - } - - // Left text pane - if (leftString.isPresent()) { - TextFlow tf = new DiffHighlightingTextPane(); - mergePanel.add(tf, 1, row); - leftTextPanes.put(field, tf); - } - - // Add radio buttons if the two entries do not have identical fields - if (identicalFields.contains(field)) { - mergedEntry.setField(field, leftString.get()); // Will only happen if both entries have the field and the content is identical - } else { - ToggleGroup group = new ToggleGroup(); - List list = new ArrayList<>(3); - for (int k = 0; k < 3; k++) { - RadioButton button = new RadioButton(); - EasyBind.subscribe(button.selectedProperty(), selected -> updateMergedEntry()); - group.getToggles().add(button); - mergePanel.add(button, 2 + k, row); - list.add(button); - } - radioButtons.put(field, list); - if (leftString.isPresent()) { - leftRadioButtons.add(list.get(LEFT_RADIOBUTTON_INDEX)); - list.get(LEFT_RADIOBUTTON_INDEX).setSelected(true); - if (rightString.isEmpty()) { - list.get(RIGHT_RADIOBUTTON_INDEX).setDisable(true); - } else if (this.defaultRadioButtonSelectionMode == DefaultRadioButtonSelectionMode.RIGHT) { - list.get(RIGHT_RADIOBUTTON_INDEX).setSelected(true); - rightRadioButtons.add(list.get(RIGHT_RADIOBUTTON_INDEX)); - } else { - rightRadioButtons.add(list.get(RIGHT_RADIOBUTTON_INDEX)); - } - } else { - list.get(LEFT_RADIOBUTTON_INDEX).setDisable(true); - list.get(RIGHT_RADIOBUTTON_INDEX).setSelected(true); - rightRadioButtons.add(list.get(RIGHT_RADIOBUTTON_INDEX)); - } - } - - // Right text pane - if (rightString.isPresent()) { - TextFlow tf = new DiffHighlightingTextPane(); - mergePanel.add(tf, 5, row); - rightTextPanes.put(field, tf); - } - row++; - } - } - - private void setupEntryTypeRow(GridPane mergePanel) { - // Start with entry type - int rowIndex = 1; - mergePanel.add(new Label(Localization.lang("Entry type")), 0, rowIndex); - if (leftEntry.getType().equals(rightEntry.getType())) { - mergePanel.add(DiffHighlighting.forUnchanged(leftEntry.getType().getDisplayName()), 1, rowIndex); - mergePanel.add(DiffHighlighting.forUnchanged(rightEntry.getType().getDisplayName()), 5, rowIndex); - identicalTypes = true; - } else { - mergePanel.add(DiffHighlighting.forChanged(leftEntry.getType().getDisplayName()), 1, rowIndex); - mergePanel.add(DiffHighlighting.forChanged(rightEntry.getType().getDisplayName()), 5, rowIndex); - identicalTypes = false; - ToggleGroup group = new ToggleGroup(); - typeRadioButtons = new ArrayList<>(2); - - for (int k = 0; k < 3; k += 2) { - RadioButton button = new RadioButton(); - EasyBind.subscribe(button.selectedProperty(), selected -> updateMergedEntry()); - typeRadioButtons.add(button); - group.getToggles().add(button); - mergePanel.add(button, 2 + k, rowIndex); - } - if (defaultRadioButtonSelectionMode == DefaultRadioButtonSelectionMode.RIGHT) { - typeRadioButtons.get(1).setSelected(true); // This Radio Button list does not have a third option as compared to the fields, so do not use the constants here - rightRadioButtons.add(typeRadioButtons.get(1)); - } else { - typeRadioButtons.get(0).setSelected(true); - leftRadioButtons.add(typeRadioButtons.get(0)); - } - } - } - - private void setupHeadingRows(GridPane mergePanel) { - // Set headings - for (int i = 0; i < NUMBER_OF_COLUMNS; i++) { - if (i == 2) { - Button selectAllLeft = new Button(); - selectAllLeft.setGraphic(JabRefIcons.LEFT.getGraphicNode()); - selectAllLeft.setOnAction(evt -> this.selectAllLeftRadioButtons()); - selectAllLeft.setTooltip(new Tooltip(Localization.lang("Select all changes on the left"))); - mergePanel.add(selectAllLeft, i, 0); - } else if (i == 4) { - Button selectAllRight = new Button(); - selectAllRight.setOnAction(evt -> this.selectAllRightRadioButtons()); - selectAllRight.setGraphic(JabRefIcons.RIGHT.getGraphicNode()); - selectAllRight.setTooltip(new Tooltip(Localization.lang("Select all changes on the right"))); - mergePanel.add(selectAllRight, i, 0); - } else { - Label colHeading = new Label(columnHeadings.get(i)); - colHeading.setMinWidth(USE_PREF_SIZE); - mergePanel.add(colHeading, i, 0); - } - } - } - - private void fillDiffModes() { - diffMode.setItems(FXCollections.observableList(Arrays.asList(DiffMode.values()))); - new ViewModelListCellFactory() - .withText(MergeEntries::getDisplayText) - .install(diffMode); - DiffMode diffModePref = Globals.prefs.getGuiPreferences().getMergeDiffMode(); - diffMode.setValue(diffModePref); - EasyBind.subscribe(this.diffMode.valueProperty(), mode -> { - updateFieldValues(differentFields); - Globals.prefs.getGuiPreferences().setMergeDiffMode(mode); - }); - - HBox heading = new HBox(10); - heading.getChildren().setAll(this.diffMode); - setTop(heading); - BorderPane.setMargin(heading, new Insets(0, 0, 10, 0)); - } - - private void setupFields() { - allFields.addAll(leftEntry.getFields()); - allFields.addAll(rightEntry.getFields()); - - // Do not show internal fields - Set internalFields = allFields.stream().filter(FieldFactory::isInternalField).collect(Collectors.toSet()); - allFields.removeAll(internalFields); - } - - private void updateFieldValues(Collection fields) { - for (Field field : fields) { - String leftString = leftEntry.getField(field).orElse(""); - String rightString = rightEntry.getField(field).orElse(""); - List leftText = leftString.isEmpty() ? Collections.emptyList() : Collections.singletonList(DiffHighlighting.forUnchanged(leftString)); - List rightText = rightString.isEmpty() ? Collections.emptyList() : Collections.singletonList(DiffHighlighting.forUnchanged(rightString)); - switch (diffMode.getValue()) { - case PLAIN: - break; - case WORD: - rightText = DiffHighlighting.generateDiffHighlighting(leftString, rightString, " "); - break; - case CHARACTER: - rightText = DiffHighlighting.generateDiffHighlighting(leftString, rightString, ""); - break; - case WORD_SYMMETRIC: - leftText = DiffHighlighting.generateSymmetricHighlighting(leftString, rightString, " "); - rightText = DiffHighlighting.generateSymmetricHighlighting(rightString, leftString, " "); - break; - case CHARACTER_SYMMETRIC: - leftText = DiffHighlighting.generateSymmetricHighlighting(leftString, rightString, ""); - rightText = DiffHighlighting.generateSymmetricHighlighting(rightString, leftString, ""); - break; - default: - throw new UnsupportedOperationException("Not implemented " + diffMode.getValue()); - } - if (!leftText.isEmpty() && leftTextPanes.containsKey(field)) { - leftTextPanes.get(field).getChildren().setAll(leftText); - } - if (!rightText.isEmpty() && rightTextPanes.containsKey(field)) { - rightTextPanes.get(field).getChildren().setAll(rightText); - } - } - } - - public void selectAllRightRadioButtons() { - for (RadioButton radioButton : rightRadioButtons) { - radioButton.setSelected(true); - } - } - - public void selectAllLeftRadioButtons() { - for (RadioButton radioButton : leftRadioButtons) { - radioButton.setSelected(true); - } - } - - public BibEntry getMergedEntry() { - return mergedEntry; - } - - private void updateMergedEntry() { - // Check if the type has changed - if (!identicalTypes && !typeRadioButtons.isEmpty() && typeRadioButtons.get(0).isSelected()) { - mergedEntry.setType(leftEntry.getType()); - } else { - mergedEntry.setType(rightEntry.getType()); - } - - // Check the potentially different fields - for (Field field : differentFields) { - if (!radioButtons.containsKey(field)) { - // May happen during initialization -> just ignore - continue; - } - if (radioButtons.get(field).get(LEFT_RADIOBUTTON_INDEX).isSelected()) { - mergedEntry.setField(field, leftEntry.getField(field).get()); // Will only happen if field exists - } else if (radioButtons.get(field).get(RIGHT_RADIOBUTTON_INDEX).isSelected()) { - mergedEntry.setField(field, rightEntry.getField(field).get()); // Will only happen if field exists - } else { - mergedEntry.clearField(field); - } - } - } - - public void setLeftHeaderText(String leftHeaderText) { - columnHeadings.set(1, leftHeaderText); - initialize(); - } - - public void setRightHeaderText(String rightHeaderText) { - columnHeadings.set(5, rightHeaderText); - initialize(); - } - - public enum DefaultRadioButtonSelectionMode { - LEFT, - RIGHT - } -} From 6859ca4bc33ed002335a49579e0976cabaf07a04 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:56:28 +0100 Subject: [PATCH 091/473] Fix missing header styles --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index fbfdf859411..416b55b308a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -39,7 +39,7 @@ -fx-background-color: -jr-menu-background; } -.header-cell .label{ +.merge-header-cell .label{ -fx-font-weight: bold; -fx-padding: 1, 0, 1, 0; } From 5df2d50e4131041cdae82a9cd47b12edbc949917 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 02:39:00 +0100 Subject: [PATCH 092/473] i18n --- .../ThreeWayMergeHeaderView.java | 3 ++- .../newmergedialog/ThreeWayMergeView.java | 5 +++-- .../toolbar/ThreeWayMergeToolbar.fxml | 6 +++--- .../toolbar/ThreeWayMergeToolbar.java | 7 ++++--- src/main/resources/l10n/JabRef_en.properties | 18 +++++++++--------- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index a3b33e99461..bf896f4b8a5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -5,6 +5,7 @@ import javafx.scene.layout.GridPane; import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; +import org.jabref.logic.l10n.Localization; /** * GridPane was used instead of a Hbox because Hbox allocates more space for cells @@ -22,7 +23,7 @@ public ThreeWayMergeHeaderView(String leftHeader, String rightHeader) { this.leftHeaderCell = new HeaderCell(leftHeader); this.rightHeaderCell = new HeaderCell(rightHeader); - this.mergedHeaderCell = new HeaderCell("Merged Entry"); + this.mergedHeaderCell = new HeaderCell(Localization.lang("Merged Entry")); addRow(0, new HeaderCell(""), diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 0c6221450f4..7ab42c83d2f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -11,6 +11,7 @@ import javafx.stage.Screen; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; @@ -19,8 +20,8 @@ public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; - public static final String LEFT_DEFAULT_HEADER = "Left Entry"; - public static final String RIGHT_DEFAULT_HEADER = "Right Entry"; + public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); + public static final String RIGHT_DEFAULT_HEADER = Localization.lang("Right Entry"); private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml index 2361c686981..59fde5d824b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml @@ -30,18 +30,18 @@
- + - + - + diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 6efadffa2bf..08189a7647b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -14,6 +14,7 @@ import javafx.util.StringConverter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; +import org.jabref.logic.l10n.Localization; import com.airhacks.afterburner.views.ViewLoader; import com.tobiasdiez.easybind.EasyBind; @@ -156,7 +157,7 @@ public void setOnSelectRightEntryValuesButtonClicked(Runnable onClick) { } public enum PlainTextOrDiff { - PLAIN_TEXT("Plain Text"), Diff("Show Diff"); + PLAIN_TEXT(Localization.lang("Plain Text")), Diff(Localization.lang("Show Diff")); private final String value; @@ -177,8 +178,8 @@ public static PlainTextOrDiff fromString(String str) { } public enum DiffView { - UNIFIED("Unified View"), - SPLIT("Split View"); + UNIFIED(Localization.lang("Unified View")), + SPLIT(Localization.lang("Split View")); private final String value; DiffView(String value) { diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0e7b47e2982..d29620e12c4 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -323,7 +323,6 @@ Entry\ preview=Entry preview Entry\ table=Entry table Entry\ table\ columns=Entry table columns Entry\ Title\ (Required\ to\ deliver\ recommendations.)=Entry Title (Required to deliver recommendations.) -Entry\ type=Entry type Error=Error Error\ occurred\ when\ parsing\ entry=Error occurred when parsing entry Error\ opening\ file=Error opening file @@ -1306,8 +1305,8 @@ Help\ on\ Name\ Formatting=Help on Name Formatting Add\ new\ file\ type=Add new file type -Left\ entry=Left entry -Right\ entry=Right entry +Left\ Entry=Left Entry +Right\ Entry=Right Entry Original\ entry=Original entry No\ information\ added=No information added Select\ at\ least\ one\ entry\ to\ manage\ keywords.=Select at least one entry to manage keywords. @@ -1552,11 +1551,7 @@ Verse=Verse change\ entries\ of\ group=change entries of group odd\ number\ of\ unescaped\ '\#'=odd number of unescaped '#' -Plain\ text=Plain text Show\ diff=Show diff -character=character -word=word -Show\ symmetric\ diff=Show symmetric diff Copy\ Version=Copy Version Maintainers=Maintainers Contributors=Contributors @@ -2081,8 +2076,6 @@ Linked\ identifiers=Linked identifiers insert\ entries=insert entries In\ JabRef=In JabRef On\ disk=On disk -Select\ all\ changes\ on\ the\ left=Select all changes on the left -Select\ all\ changes\ on\ the\ right=Select all changes on the right Dismiss=Dismiss Mark\ all\ changes\ as\ accepted=Mark all changes as accepted Unmark\ all\ changes=Unmark all changes @@ -2508,6 +2501,13 @@ Copy\ or\ move\ the\ value\ of\ one\ field\ to\ another=Copy or move the value o Automatic\ field\ editor=Automatic field editor Open\ Link=Open Link +Highlight\ words=Highlight words +Highlight\ characters=Highlight characters +Unified\ View=Unified View +Split\ View=Split View +Plain\ Text=Plain Text +Show\ Diff=Show Diff +Merged\ Entry=Merged Entry (Note\:\ If\ original\ entries\ lack\ keywords\ to\ qualify\ for\ the\ new\ group\ configuration,\ confirming\ here\ will\ add\ them)=(Note: If original entries lack keywords to qualify for the new group configuration, confirming here will add them) Assign=Assign From db706a81e48ac86a695163f8e01094f0ad2baa11 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 6 Jul 2022 02:08:39 +0100 Subject: [PATCH 093/473] Garbage collect right cell when it's invisible - When both the left and right cells have the same value, only the left value is displayed, making it unnecessary to keep allocating memory for the right cell. --- .../newmergedialog/FieldRowController.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index d1fb3b248a9..38d02467e13 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -16,7 +16,7 @@ public class FieldRowController { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; - private final FieldValueCell rightValueCell; + private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; private final String leftValue; @@ -53,9 +53,11 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } }); - // When left and right have the same value, only the left value will be shown + // When both the left and right cells have the same value, only the left value is displayed, + // making it unnecessary to keep allocating memory for the right cell. if (hasEqualLeftAndRightValues()) { - rightValueCell.setDisable(true); + // Setting this to null so the GC release the memory allocated to the right cell. + this.rightValueCell = null; } } @@ -64,7 +66,7 @@ public void selectLeftValue() { } public void selectRightValue() { - if (rightValueCell.isDisabled()) { + if (rightValueCell == null) { selectLeftValue(); } else { toggleGroup.selectToggle(rightValueCell); @@ -96,13 +98,13 @@ public MergedFieldCell getMergedValueCell() { } public boolean hasEqualLeftAndRightValues() { - return !StringUtil.isNullOrEmpty(leftValueCell.getText()) && + return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && !StringUtil.isNullOrEmpty(rightValueCell.getText()) && - leftValueCell.getText().equals(rightValueCell.getText()); + leftValueCell.getText().equals(rightValueCell.getText())); } public void showDiff(ShowDiffConfig diffConfig) { - if (leftValueCell.isDisabled() || rightValueCell.isDisabled()) { + if (isRightValueCellHidden()) { return; } @@ -118,6 +120,10 @@ public void showDiff(ShowDiffConfig diffConfig) { } public void hideDiff() { + if (isRightValueCellHidden()) { + return; + } + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); @@ -126,4 +132,8 @@ public void hideDiff() { getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); getRightValueCell().getStyleClassedLabel().replaceText(rightValue); } + + private boolean isRightValueCellHidden() { + return rightValueCell == null; + } } From fffc5d1ad2ceac2ab7dd579cdb1ffd9892f6a96d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 6 Jul 2022 02:12:15 +0100 Subject: [PATCH 094/473] Fix typo --- .../gui/mergeentries/newmergedialog/FieldRowController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 38d02467e13..8f2411d89cf 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -66,7 +66,7 @@ public void selectLeftValue() { } public void selectRightValue() { - if (rightValueCell == null) { + if (isRightValueCellHidden()) { selectLeftValue(); } else { toggleGroup.selectToggle(rightValueCell); From b4827ecf294c51b26309e3f86e6fd909f7198381 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:55:26 +0100 Subject: [PATCH 095/473] Create GroupsFieldNameCell --- .../newmergedialog/cell/FieldNameCell.java | 2 ++ .../cell/GroupsFieldNameCell.java | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 7ad435d59b1..93b0b20d84e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -2,6 +2,8 @@ import javafx.scene.control.Label; +import org.jabref.gui.actions.Action; + /** * A non-editable cell that contains the name of some field */ diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java new file mode 100644 index 00000000000..b20c1ffcb11 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java @@ -0,0 +1,33 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +public class GroupsFieldNameCell extends FieldNameCell { + private Runnable onMergeGroups; + private Runnable onUnmergeGroups; + private boolean isMerged = false; + + public GroupsFieldNameCell(String text, int rowIndex, boolean groupsMerged) { + super(text, rowIndex); + isMerged = groupsMerged; + setOnMouseClicked(e -> { + if (isMerged) { + if (onUnmergeGroups != null) { + onUnmergeGroups.run(); + isMerged = false; + } + } else { + if (onMergeGroups != null) { + onMergeGroups.run(); + isMerged = true; + } + } + }); + } + + public void setOnMergeGroups(Runnable mergeGroups) { + this.onMergeGroups = mergeGroups; + } + + public void setOnUnmergeGroups(Runnable unmergeGroups) { + this.onUnmergeGroups = unmergeGroups; + } +} From a94acd4c597c3318bdbf525daecb6652c27e1a89 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:56:21 +0100 Subject: [PATCH 096/473] Create MergedGroups to record the state of the groups before and after the merge --- .../gui/mergeentries/newmergedialog/MergedGroups.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java new file mode 100644 index 00000000000..f2b1e03da70 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java @@ -0,0 +1,6 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +public record MergedGroups( + String leftEntryGroups, String rightEntryGroups, String mergedGroups +) { +} From 484a3685d975d2d54c350922f7bf7a6bb1bf2a1e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:57:26 +0100 Subject: [PATCH 097/473] Create a factory class for creating field name cells --- ...ldRowController.java => ThreeFieldValues.java} | 11 ++++++++--- .../newmergedialog/cell/FieldNameCellFactory.java | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{FieldRowController.java => ThreeFieldValues.java} (92%) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java similarity index 92% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 8f2411d89cf..45f34afe920 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -4,16 +4,18 @@ import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; import org.fxmisc.richtext.StyleClassedTextArea; -public class FieldRowController { +public class ThreeFieldValues { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; @@ -23,16 +25,19 @@ public class FieldRowController { private final String rightValue; + private final String fieldName; + private final ToggleGroup toggleGroup = new ToggleGroup(); - public FieldRowController(String fieldName, String leftValue, String rightValue, int rowIndex) { - fieldNameCell = new FieldNameCell(fieldName, rowIndex); + public ThreeFieldValues(Field field, String leftValue, String rightValue, int rowIndex, boolean groupsMerged) { + fieldNameCell = FieldNameCellFactory.create(field, rowIndex, groupsMerged); leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); this.leftValue = leftValue; this.rightValue = rightValue; + this.fieldName = field.getDisplayName(); toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java new file mode 100644 index 00000000000..4a87c2645cf --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -0,0 +1,15 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.StandardField; + +public class FieldNameCellFactory { + + public static FieldNameCell create(Field field, int rowIndex, boolean groupsMerged) { + if (field.equals(StandardField.GROUPS)) { + return new GroupsFieldNameCell("Groups", rowIndex, groupsMerged); + } else { + return new FieldNameCell(field.getDisplayName(), rowIndex); + } + } +} From dc02f37ad67a4101a0081fa5d2697e626342773e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:59:25 +0100 Subject: [PATCH 098/473] Perform experiments for implementing groups merging --- .../newmergedialog/ThreeWayMergeView.java | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 7ab42c83d2f..8aa1b9dc5ce 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,11 +10,13 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { @@ -33,7 +35,9 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List fieldRowControllerList = new ArrayList<>(); + private final List threeFieldValuesList = new ArrayList<>(); + + private MergedGroups mergedGroupsRecord; public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); @@ -71,9 +75,9 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); + threeFieldValuesList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - fieldRowControllerList.forEach(FieldRowController::hideDiff); + threeFieldValuesList.forEach(ThreeFieldValues::hideDiff); } } @@ -101,13 +105,19 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - addFieldRow(fieldIndex); + addFieldValues(viewModel.allFields().get(fieldIndex), fieldIndex); } } - private void addFieldRow(int index) { - Field field = viewModel.allFields().get(index); + private void addFieldName(Field field, int rowIndex) { + + } + + private Field getFieldAtIndex(int index) { + return viewModel.allFields().get(index); + } + private void addFieldValues(Field field, int index) { String leftEntryValue; String rightEntryValue; if (field.equals(InternalField.TYPE_HEADER)) { @@ -118,8 +128,38 @@ private void addFieldRow(int index) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, index); - fieldRowControllerList.add(fieldRow); + ThreeFieldValues fieldRow = new ThreeFieldValues(field, leftEntryValue, rightEntryValue, index, mergedGroupsRecord != null); + threeFieldValuesList.add(fieldRow); + + if (field.equals(StandardField.GROUPS)) { + // attach listener + GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldRow.getFieldNameCell(); + groupsField.setOnMergeGroups(() -> { + if (!fieldRow.hasEqualLeftAndRightValues()) { + removeRow(index); + String mergedGroups = mergeEntryGroups(); + viewModel.getLeftEntry().setField(field, mergedGroups); + viewModel.getRightEntry().setField(field, mergedGroups); + addFieldValues(field, index); + System.out.println("Groups merged: " + mergedGroups); + mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); + } else { + System.out.println("Groups already have the same value"); + } + }); + + groupsField.setOnUnmergeGroups(() -> { + if (fieldRow.hasEqualLeftAndRightValues()) { + if (mergedGroupsRecord != null) { + viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); + removeRow(index); + addFieldValues(field, index); + mergedGroupsRecord = null; + } + } + }); + } fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { @@ -143,6 +183,17 @@ private void addFieldRow(int index) { } } + public void removeRow(int index) { + threeFieldValuesList.remove(index); + mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index); + } + + private String mergeEntryGroups() { + // TODO: Update the merging logic + return viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("") + + viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + } + public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } @@ -156,11 +207,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - fieldRowControllerList.forEach(FieldRowController::selectLeftValue); + threeFieldValuesList.forEach(ThreeFieldValues::selectLeftValue); } public void selectRightEntryValues() { - fieldRowControllerList.forEach(FieldRowController::selectRightValue); + threeFieldValuesList.forEach(ThreeFieldValues::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 6aac5fdd2fad6de0b806d11f17d4dcd15c8c5ae0 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:08:01 +0100 Subject: [PATCH 099/473] Delegate field name cells creation to ThreeWayMergeView - Seperated field values and field name cells because now it's easier to update field values cells without touching the field name cell --- .../newmergedialog/ThreeFieldValues.java | 13 +---------- .../newmergedialog/ThreeWayMergeView.java | 22 +++++++++++-------- .../cell/FieldNameCellFactory.java | 4 ++-- .../cell/GroupsFieldNameCell.java | 3 +-- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 45f34afe920..57e2a21f4a7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -4,19 +4,16 @@ import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; import org.fxmisc.richtext.StyleClassedTextArea; public class ThreeFieldValues { - private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; @@ -25,19 +22,15 @@ public class ThreeFieldValues { private final String rightValue; - private final String fieldName; - private final ToggleGroup toggleGroup = new ToggleGroup(); - public ThreeFieldValues(Field field, String leftValue, String rightValue, int rowIndex, boolean groupsMerged) { - fieldNameCell = FieldNameCellFactory.create(field, rowIndex, groupsMerged); + public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); this.leftValue = leftValue; this.rightValue = rightValue; - this.fieldName = field.getDisplayName(); toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); @@ -86,10 +79,6 @@ public ReadOnlyStringProperty mergedValueProperty() { return mergedValueCell.textProperty(); } - public FieldNameCell getFieldNameCell() { - return fieldNameCell; - } - public FieldValueCell getLeftValueCell() { return leftValueCell; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 8aa1b9dc5ce..647221b71b7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,7 +10,8 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -105,12 +106,14 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - addFieldValues(viewModel.allFields().get(fieldIndex), fieldIndex); + addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); + addFieldValues(getFieldAtIndex(fieldIndex), fieldIndex); } } private void addFieldName(Field field, int rowIndex) { - + FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, rowIndex); + mergeGridPane.add(fieldNameCell, 0, rowIndex); } private Field getFieldAtIndex(int index) { @@ -128,10 +131,10 @@ private void addFieldValues(Field field, int index) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldRow = new ThreeFieldValues(field, leftEntryValue, rightEntryValue, index, mergedGroupsRecord != null); + ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, index); threeFieldValuesList.add(fieldRow); - if (field.equals(StandardField.GROUPS)) { +/* if (field.equals(StandardField.GROUPS)) { // attach listener GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldRow.getFieldNameCell(); groupsField.setOnMergeGroups(() -> { @@ -159,7 +162,7 @@ private void addFieldValues(Field field, int index) { } } }); - } + }*/ fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { @@ -175,11 +178,12 @@ private void addFieldValues(Field field, int index) { } if (fieldRow.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index, 1, 1); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); } else { - mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index); + mergeGridPane.add(fieldRow.getRightValueCell(), 1, index); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index 4a87c2645cf..ecc352af4c0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -5,9 +5,9 @@ public class FieldNameCellFactory { - public static FieldNameCell create(Field field, int rowIndex, boolean groupsMerged) { + public static FieldNameCell create(Field field, int rowIndex) { if (field.equals(StandardField.GROUPS)) { - return new GroupsFieldNameCell("Groups", rowIndex, groupsMerged); + return new GroupsFieldNameCell("Groups", rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java index b20c1ffcb11..f70a7e79b1a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java @@ -5,9 +5,8 @@ public class GroupsFieldNameCell extends FieldNameCell { private Runnable onUnmergeGroups; private boolean isMerged = false; - public GroupsFieldNameCell(String text, int rowIndex, boolean groupsMerged) { + public GroupsFieldNameCell(String text, int rowIndex) { super(text, rowIndex); - isMerged = groupsMerged; setOnMouseClicked(e -> { if (isMerged) { if (onUnmergeGroups != null) { From ce9735deded0698060190d06028ee52b320b4080 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:09:56 +0100 Subject: [PATCH 100/473] Improve groups merging function --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 647221b71b7..999fc29a982 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -198,6 +198,14 @@ private String mergeEntryGroups() { viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); } + private String mergeLeftAndRightEntryGroups() { + List leftGroups = new ArrayList<>(Arrays.stream(viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList()); + List rightGroups = Arrays.stream(viewModel.getRightEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList(); + leftGroups.addAll(rightGroups); + + return String.join(", ", leftGroups); + } + public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } From 6e8e08f838643e59eb6877f391c5c3eb6ccc3bb5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:12:08 +0100 Subject: [PATCH 101/473] Implement updateFieldValues to redraw the field row when left or right entry changes --- .../newmergedialog/ThreeWayMergeView.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 999fc29a982..8ed0268df2b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -1,6 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javafx.scene.control.ScrollPane; @@ -12,6 +13,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; +import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -23,9 +25,11 @@ public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; + public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); public static final String RIGHT_DEFAULT_HEADER = Localization.lang("Right Entry"); + private static final int FIELD_NAME_COLUMN = 0; private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); private final ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); @@ -120,7 +124,8 @@ private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } - private void addFieldValues(Field field, int index) { + private void addFieldValues(int fieldIndex) { + Field field = getFieldAtIndex(fieldIndex); String leftEntryValue; String rightEntryValue; if (field.equals(InternalField.TYPE_HEADER)) { @@ -178,24 +183,23 @@ private void addFieldValues(Field field, int index) { } if (fieldRow.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex, 2, 1); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); } else { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index); - mergeGridPane.add(fieldRow.getRightValueCell(), 1, index); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldRow.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); } } - public void removeRow(int index) { - threeFieldValuesList.remove(index); - mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index); + public void updateFieldValues(int fieldIndex) { + removeFieldValues(fieldIndex); + addFieldValues(fieldIndex); } - private String mergeEntryGroups() { - // TODO: Update the merging logic - return viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("") + - viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + public void removeFieldValues(int index) { + threeFieldValuesList.remove(index); + mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } private String mergeLeftAndRightEntryGroups() { From d3aacaee309c928377a35a655983c8fd0dc8ca68 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:14:07 +0100 Subject: [PATCH 102/473] Write a draft version of the logic to merge groups --- .../newmergedialog/ThreeWayMergeView.java | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 8ed0268df2b..3096ddaef9c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -111,13 +111,39 @@ private void initializeMergeGridPane() { for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); - addFieldValues(getFieldAtIndex(fieldIndex), fieldIndex); + addFieldValues(fieldIndex); } } - private void addFieldName(Field field, int rowIndex) { - FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, rowIndex); - mergeGridPane.add(fieldNameCell, 0, rowIndex); + private void addFieldName(Field field, int fieldIndex) { + FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, fieldIndex); + mergeGridPane.add(fieldNameCell, FIELD_NAME_COLUMN, fieldIndex); + + if (field.equals(StandardField.GROUPS)) { + GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; + groupsField.setOnMergeGroups(() -> { + if (mergedGroupsRecord == null) { + String leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); + String rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); + + String mergedGroups = mergeLeftAndRightEntryGroups(); + viewModel.getLeftEntry().setField(field, mergedGroups); + viewModel.getRightEntry().setField(field, mergedGroups); + System.out.println("Groups merged: " + mergedGroups); + mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); + updateFieldValues(fieldIndex); + } + }); + + groupsField.setOnUnmergeGroups(() -> { + if (mergedGroupsRecord != null) { + viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); + updateFieldValues(fieldIndex); + mergedGroupsRecord = null; + } + }); + } } private Field getFieldAtIndex(int index) { @@ -136,39 +162,9 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, index); + ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); threeFieldValuesList.add(fieldRow); -/* if (field.equals(StandardField.GROUPS)) { - // attach listener - GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldRow.getFieldNameCell(); - groupsField.setOnMergeGroups(() -> { - if (!fieldRow.hasEqualLeftAndRightValues()) { - removeRow(index); - String mergedGroups = mergeEntryGroups(); - viewModel.getLeftEntry().setField(field, mergedGroups); - viewModel.getRightEntry().setField(field, mergedGroups); - addFieldValues(field, index); - System.out.println("Groups merged: " + mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); - } else { - System.out.println("Groups already have the same value"); - } - }); - - groupsField.setOnUnmergeGroups(() -> { - if (fieldRow.hasEqualLeftAndRightValues()) { - if (mergedGroupsRecord != null) { - viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); - removeRow(index); - addFieldValues(field, index); - mergedGroupsRecord = null; - } - } - }); - }*/ - fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); From 194be4d0b036014d9ef452a6a6965b9b7b419f6e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:15:25 +0100 Subject: [PATCH 103/473] Refactoring --- .../newmergedialog/ThreeFieldValues.java | 4 +- .../newmergedialog/ThreeWayMergeView.java | 48 +++++++++++-------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 57e2a21f4a7..74bf76fe8b2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -3,7 +3,6 @@ import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; @@ -13,6 +12,9 @@ import org.fxmisc.richtext.StyleClassedTextArea; +/** + * A controller class to control left, right and merged field values + */ public class ThreeFieldValues { private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 3096ddaef9c..5a3f3b16ae7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -121,31 +121,39 @@ private void addFieldName(Field field, int fieldIndex) { if (field.equals(StandardField.GROUPS)) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setOnMergeGroups(() -> { - if (mergedGroupsRecord == null) { - String leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); - String rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); - - String mergedGroups = mergeLeftAndRightEntryGroups(); - viewModel.getLeftEntry().setField(field, mergedGroups); - viewModel.getRightEntry().setField(field, mergedGroups); - System.out.println("Groups merged: " + mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); - updateFieldValues(fieldIndex); - } - }); - - groupsField.setOnUnmergeGroups(() -> { - if (mergedGroupsRecord != null) { - viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); - updateFieldValues(fieldIndex); - mergedGroupsRecord = null; + groupsField.setOnAction(() -> { + if (areGroupsMerged()) { + unmergeGroups(); + } else { + mergeGroups(); } }); } } + public void mergeGroups() { + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + + String mergedGroups = mergeLeftAndRightEntryGroups(); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + } + + public void unmergeGroups() { + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + mergedGroupsRecord = null; + } + + private boolean areGroupsMerged() { + return mergedGroupsRecord != null; + } + private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } From 031e6f052cff4ff477aa9677de3592f3946f37f9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:19:11 +0100 Subject: [PATCH 104/473] More Refactoring --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 5a3f3b16ae7..efe45679d0b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -135,7 +135,7 @@ public void mergeGroups() { String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - String mergedGroups = mergeLeftAndRightEntryGroups(); + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); @@ -206,9 +206,9 @@ public void removeFieldValues(int index) { mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } - private String mergeLeftAndRightEntryGroups() { - List leftGroups = new ArrayList<>(Arrays.stream(viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList()); - List rightGroups = Arrays.stream(viewModel.getRightEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList(); + private String mergeLeftAndRightEntryGroups(String left, String right) { + List leftGroups = new ArrayList<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); leftGroups.addAll(rightGroups); return String.join(", ", leftGroups); From 54f2ab3f6b298f9392d14d5e448425315fc0c43f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:51:57 +0100 Subject: [PATCH 105/473] Merge groups only when left and right entries have different groups --- .../newmergedialog/ThreeWayMergeView.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index efe45679d0b..a6f93197779 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -135,12 +135,14 @@ public void mergeGroups() { String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + if (!leftEntryGroups.equals(rightEntryGroups)) { + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + } } public void unmergeGroups() { From d1a3ed9e981b615db4686e671233ef1d7063e5d2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:53:44 +0100 Subject: [PATCH 106/473] Add row constraints to fix UI lagging when updating field values --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index a6f93197779..77d78663be6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -8,6 +8,7 @@ import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.Priority; +import javafx.scene.layout.RowConstraints; import javafx.scene.layout.VBox; import javafx.stage.Screen; @@ -112,6 +113,12 @@ private void initializeMergeGridPane() { for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); + + if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { + mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); + } else { + mergeGridPane.getRowConstraints().add(new RowConstraints()); + } } } From c217cf82d1313fbd46e70c27ad7b1822760ade63 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 11:01:07 +0100 Subject: [PATCH 107/473] Minor refactoring --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 77d78663be6..c7604ecca2c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -114,6 +114,7 @@ private void initializeMergeGridPane() { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); + // Removing this will cause a UI lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); } else { @@ -205,12 +206,12 @@ private void addFieldValues(int fieldIndex) { } } - public void updateFieldValues(int fieldIndex) { + private void updateFieldValues(int fieldIndex) { removeFieldValues(fieldIndex); addFieldValues(fieldIndex); } - public void removeFieldValues(int index) { + private void removeFieldValues(int index) { threeFieldValuesList.remove(index); mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } From 0ea0da19ab354c8bab34c5746eb505cadfef2183 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 11:06:55 +0100 Subject: [PATCH 108/473] Don't merge common groups between left and right entries --- .../newmergedialog/ThreeWayMergeView.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index c7604ecca2c..684a09dcad4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -2,7 +2,9 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; @@ -41,7 +43,7 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List threeFieldValuesList = new ArrayList<>(); + private final List fieldValuesList = new ArrayList<>(); private MergedGroups mergedGroupsRecord; @@ -81,9 +83,9 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - threeFieldValuesList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); + fieldValuesList.forEach(fieldValues -> fieldValues.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - threeFieldValuesList.forEach(ThreeFieldValues::hideDiff); + fieldValuesList.forEach(ThreeFieldValues::hideDiff); } } @@ -114,7 +116,7 @@ private void initializeMergeGridPane() { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); - // Removing this will cause a UI lag when updating field values + // Removing this will cause UI to lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); } else { @@ -181,7 +183,7 @@ private void addFieldValues(int fieldIndex) { } ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); - threeFieldValuesList.add(fieldRow); + fieldValuesList.add(fieldRow); fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { @@ -212,12 +214,12 @@ private void updateFieldValues(int fieldIndex) { } private void removeFieldValues(int index) { - threeFieldValuesList.remove(index); + fieldValuesList.remove(index); mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } private String mergeLeftAndRightEntryGroups(String left, String right) { - List leftGroups = new ArrayList<>(Arrays.stream(left.split(", ")).toList()); + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); List rightGroups = Arrays.stream(right.split(", ")).toList(); leftGroups.addAll(rightGroups); @@ -237,11 +239,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - threeFieldValuesList.forEach(ThreeFieldValues::selectLeftValue); + fieldValuesList.forEach(ThreeFieldValues::selectLeftValue); } public void selectRightEntryValues() { - threeFieldValuesList.forEach(ThreeFieldValues::selectRightValue); + fieldValuesList.forEach(ThreeFieldValues::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 675669fcdb956652ac600c6d91d55e9f666a34ea Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:17:35 +0100 Subject: [PATCH 109/473] Refactor GroupsFieldNameCell constructor --- .../mergeentries/newmergedialog/cell/FieldNameCellFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index ecc352af4c0..01a2fa90aff 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -7,7 +7,7 @@ public class FieldNameCellFactory { public static FieldNameCell create(Field field, int rowIndex) { if (field.equals(StandardField.GROUPS)) { - return new GroupsFieldNameCell("Groups", rowIndex); + return new GroupsFieldNameCell(rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); } From e9ab51df2c3e756e96a09acdec7c4c1438bc445a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:20:05 +0100 Subject: [PATCH 110/473] Allow groups field row to grow in height --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 684a09dcad4..37ba0212e69 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -118,7 +118,7 @@ private void initializeMergeGridPane() { // Removing this will cause UI to lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { - mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); + mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, Double.MAX_VALUE)); } else { mergeGridPane.getRowConstraints().add(new RowConstraints()); } From d166273ea3519f36e3feddc5635608d6f57440ac Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:25:09 +0100 Subject: [PATCH 111/473] Fix select all left/right not working properly --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 37ba0212e69..61401763dcd 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -183,7 +183,7 @@ private void addFieldValues(int fieldIndex) { } ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); - fieldValuesList.add(fieldRow); + fieldValuesList.add(fieldIndex, fieldRow); fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { From 2f4d6d3837fa6bca92000e7258c3471df750c2e6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:29:39 +0100 Subject: [PATCH 112/473] Update diff when a field value changes --- .../newmergedialog/ThreeWayMergeView.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 61401763dcd..331a2a4e970 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -182,10 +182,10 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); - fieldValuesList.add(fieldIndex, fieldRow); + ThreeFieldValues fieldValues = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); + fieldValuesList.add(fieldIndex, fieldValues); - fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { + fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); } else { @@ -193,24 +193,25 @@ private void addFieldValues(int fieldIndex) { } }); if (field.equals(InternalField.TYPE_HEADER)) { - getMergedEntry().setType(EntryTypeFactory.parse(fieldRow.getMergedValue())); + getMergedEntry().setType(EntryTypeFactory.parse(fieldValues.getMergedValue())); } else { - getMergedEntry().setField(field, fieldRow.getMergedValue()); + getMergedEntry().setField(field, fieldValues.getMergedValue()); } - if (fieldRow.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex, 2, 1); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); + if (fieldValues.hasEqualLeftAndRightValues()) { + mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex, 2, 1); + mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } else { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex); - mergeGridPane.add(fieldRow.getRightValueCell(), 2, fieldIndex); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); + mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } } private void updateFieldValues(int fieldIndex) { removeFieldValues(fieldIndex); addFieldValues(fieldIndex); + updateDiff(); } private void removeFieldValues(int index) { From 9463db7bad2c838e7b09c586e34969e60456a0b3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 23:16:18 +0100 Subject: [PATCH 113/473] Add the merge icon and style css --- .../java/org/jabref/gui/icon/IconTheme.java | 4 ++- .../newmergedialog/ThreeWayMergeView.css | 6 ++++ .../newmergedialog/cell/FieldNameCell.java | 29 +++++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/icon/IconTheme.java b/src/main/java/org/jabref/gui/icon/IconTheme.java index 8ef3ed5d490..80eb1824a9b 100644 --- a/src/main/java/org/jabref/gui/icon/IconTheme.java +++ b/src/main/java/org/jabref/gui/icon/IconTheme.java @@ -343,7 +343,9 @@ public enum JabRefIcons implements JabRefIcon { ACCEPT_LEFT(MaterialDesignS.SUBDIRECTORY_ARROW_LEFT), - ACCEPT_RIGHT(MaterialDesignS.SUBDIRECTORY_ARROW_RIGHT); + ACCEPT_RIGHT(MaterialDesignS.SUBDIRECTORY_ARROW_RIGHT), + + MERGE_GROUPS(MaterialDesignS.SOURCE_MERGE); private final JabRefIcon icon; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 416b55b308a..ac73d7593f0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -43,3 +43,9 @@ -fx-font-weight: bold; -fx-padding: 1, 0, 1, 0; } + +.field-name .glyph-icon, +.field-name .ikonli-font-icon { + -fx-icon-size: 17; + -fx-icon-color: -jr-theme-text; +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 93b0b20d84e..95664eb7566 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -1,16 +1,30 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; -import org.jabref.gui.actions.Action; +import org.jabref.gui.Globals; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.icon.IconTheme; +import org.jabref.logic.l10n.Localization; + +import de.saxsys.mvvmfx.utils.commands.Command; /** * A non-editable cell that contains the name of some field */ public class FieldNameCell extends AbstractCell { public static final String DEFAULT_STYLE_CLASS = "field-name"; + protected final HBox actionLayout = new HBox(); private final Label label = new Label(); + private final HBox labelBox = new HBox(label); + private final ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + public FieldNameCell(String text, int rowIndex) { super(text, rowIndex); initialize(); @@ -19,10 +33,21 @@ public FieldNameCell(String text, int rowIndex) { private void initialize() { getStyleClass().add(DEFAULT_STYLE_CLASS); initializeLabel(); - getChildren().add(label); + getChildren().addAll(labelBox, actionLayout); } private void initializeLabel() { label.textProperty().bind(textProperty()); + HBox.setHgrow(labelBox, Priority.ALWAYS); + } + + protected void addAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + Node iconNode = icon.getGraphicNode(); + Button actionButton = factory.createIconButton(() -> Localization.lang(actionName), command); + actionButton.setGraphic(iconNode); + actionButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + actionButton.setMaxHeight(Double.MAX_VALUE); + + actionLayout.getChildren().add(actionButton); } } From 0992b22caa1c9e961b18eb96919c88050a9b33ac Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 23:31:31 +0100 Subject: [PATCH 114/473] Extract merge and unmerge commands into their own classes --- .../newmergedialog/ThreeWayMergeView.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 331a2a4e970..ab1cd97b6d1 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -14,6 +14,7 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; @@ -131,37 +132,11 @@ private void addFieldName(Field field, int fieldIndex) { if (field.equals(StandardField.GROUPS)) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setOnAction(() -> { - if (areGroupsMerged()) { - unmergeGroups(); - } else { - mergeGroups(); - } - }); - } - } - - public void mergeGroups() { - String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - - if (!leftEntryGroups.equals(rightEntryGroups)) { - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + groupsField.setMergeGroupsCommand(new MergeGroupsCommand()); + groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand()); } } - public void unmergeGroups() { - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - mergedGroupsRecord = null; - } - private boolean areGroupsMerged() { return mergedGroupsRecord != null; } @@ -252,4 +227,36 @@ public void showDiff(ShowDiffConfig diffConfig) { toolbar.setDiffHighlightingMethod(diffConfig.diffHighlightingMethod()); toolbar.setShowDiff(true); } + + public class MergeGroupsCommand extends SimpleCommand { + @Override + public void execute() { + if (!areGroupsMerged()) { + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + + if (!leftEntryGroups.equals(rightEntryGroups)) { + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + } + } + } + } + + public class UnmergeGroupsCommand extends SimpleCommand { + + @Override + public void execute() { + if (areGroupsMerged()) { + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + mergedGroupsRecord = null; + } + } + } } From 05518ea32f77073c107e7460d16ba19020f39973 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 02:36:10 +0100 Subject: [PATCH 115/473] Refactoring --- .../newmergedialog/ThreeWayMergeView.java | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index ab1cd97b6d1..c69695f36fa 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -6,6 +6,9 @@ import java.util.List; import java.util.Set; +import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -48,6 +51,9 @@ public class ThreeWayMergeView extends VBox { private MergedGroups mergedGroupsRecord; + private final BooleanProperty areGroupsMerged = new SimpleBooleanProperty(); + + public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); @@ -132,8 +138,8 @@ private void addFieldName(Field field, int fieldIndex) { if (field.equals(StandardField.GROUPS)) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setMergeGroupsCommand(new MergeGroupsCommand()); - groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand()); + groupsField.setMergeGroupsCommand(new MergeGroupsCommand(groupsField)); + groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand(groupsField)); } } @@ -229,34 +235,61 @@ public void showDiff(ShowDiffConfig diffConfig) { } public class MergeGroupsCommand extends SimpleCommand { + private final GroupsFieldNameCell groupsFieldNameCell; + + public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + this.groupsFieldNameCell = groupsFieldCell; + + this.executable.bind(Bindings.and(areGroupsMerged.not(), Bindings.createBooleanBinding(() -> { + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + + return !leftEntryGroups.equals(rightEntryGroups); + }))); + } + @Override public void execute() { - if (!areGroupsMerged()) { + assert !areGroupsMerged(); + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - if (!leftEntryGroups.equals(rightEntryGroups)) { - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + assert !leftEntryGroups.equals(rightEntryGroups); - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - } - } + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + groupsFieldNameCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.UNMERGE); } } public class UnmergeGroupsCommand extends SimpleCommand { + private final GroupsFieldNameCell groupsFieldCell; + + public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + this.groupsFieldCell = groupsFieldCell; + } @Override public void execute() { - if (areGroupsMerged()) { + assert areGroupsMerged(); viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); mergedGroupsRecord = null; - } + groupsFieldCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.MERGE); } } + + /* + * Notes + * 1. Left and Right could have the same value + * + * Merge Button Clicked: + * 1. + * */ } From b38eeec7f85ec07b3a25a616cf33031b1d5c942d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 02:59:39 +0100 Subject: [PATCH 116/473] Record groups merging operation using CompoundEdit - Exposed a public API to be able to cancel groups merge --- .../newmergedialog/ThreeWayMergeView.java | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index c69695f36fa..5d29549d8ef 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -6,6 +6,8 @@ import java.util.List; import java.util.Set; +import javax.swing.undo.CompoundEdit; + import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -22,6 +24,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -49,10 +52,9 @@ public class ThreeWayMergeView extends VBox { private final ThreeWayMergeViewModel viewModel; private final List fieldValuesList = new ArrayList<>(); - private MergedGroups mergedGroupsRecord; - private final BooleanProperty areGroupsMerged = new SimpleBooleanProperty(); + private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); @@ -143,10 +145,6 @@ private void addFieldName(Field field, int fieldIndex) { } } - private boolean areGroupsMerged() { - return mergedGroupsRecord != null; - } - private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } @@ -234,6 +232,12 @@ public void showDiff(ShowDiffConfig diffConfig) { toolbar.setShowDiff(true); } + public void cancelGroupsMerge() { + if (mergeGroupsEdit.canUndo()) { + mergeGroupsEdit.undo(); + } + } + public class MergeGroupsCommand extends SimpleCommand { private final GroupsFieldNameCell groupsFieldNameCell; @@ -250,20 +254,28 @@ public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { @Override public void execute() { - assert !areGroupsMerged(); + BibEntry leftEntry = viewModel.getLeftEntry(); + BibEntry rightEntry = viewModel.getRightEntry(); - String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + String leftEntryGroups = leftEntry.getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = rightEntry.getField(StandardField.GROUPS).orElse(""); - assert !leftEntryGroups.equals(rightEntryGroups); + assert !leftEntryGroups.equals(rightEntryGroups); - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.UNMERGE); + if (mergeGroupsEdit.canRedo()) { + mergeGroupsEdit.redo(); + } else { + mergeGroupsEdit.addEdit(new UndoableFieldChange(leftEntry, StandardField.GROUPS, leftEntryGroups, mergedGroups)); + mergeGroupsEdit.addEdit(new UndoableFieldChange(rightEntry, StandardField.GROUPS, rightEntryGroups, mergedGroups)); + mergeGroupsEdit.end(); + } + + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + groupsFieldNameCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.UNMERGE); } } @@ -272,24 +284,16 @@ public class UnmergeGroupsCommand extends SimpleCommand { public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { this.groupsFieldCell = groupsFieldCell; + this.executable.bind(Bindings.createBooleanBinding(mergeGroupsEdit::canUndo)); } @Override public void execute() { - assert areGroupsMerged(); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); + if (mergeGroupsEdit.canUndo()) { + mergeGroupsEdit.undo(); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - mergedGroupsRecord = null; - groupsFieldCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.MERGE); + groupsFieldCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.MERGE); + } } } - - /* - * Notes - * 1. Left and Right could have the same value - * - * Merge Button Clicked: - * 1. - * */ } From 0d4a8c2f0b46d00a4966d7ce7f9d9e497830fd15 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:25:57 +0100 Subject: [PATCH 117/473] Cancel groups merge when user choose 'Cancel' in the merge entries dialog --- .../java/org/jabref/gui/mergeentries/MergeEntriesDialog.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 3486a9702d2..4c2f5ace0ec 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -33,6 +33,7 @@ private void init() { if (buttonType.equals(replaceEntries)) { return threeWayMergeView.getMergedEntry(); } else { + threeWayMergeView.cancelGroupsMerge(); return null; } }); From 3469ffc4dfff7832b1930e92b70715e7d5ddd098 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:28:38 +0100 Subject: [PATCH 118/473] Make FieldNameCell take only one action --- .../gui/mergeentries/newmergedialog/cell/FieldNameCell.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 95664eb7566..5391b0f0b4c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -41,7 +41,8 @@ private void initializeLabel() { HBox.setHgrow(labelBox, Priority.ALWAYS); } - protected void addAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + protected void setAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + actionLayout.getChildren().clear(); Node iconNode = icon.getGraphicNode(); Button actionButton = factory.createIconButton(() -> Localization.lang(actionName), command); actionButton.setGraphic(iconNode); From 22eea6418da6a558cc11b9f723c810bfe26a1784 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:46:43 +0100 Subject: [PATCH 119/473] Set groups merge action to MERGE by default --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 5d29549d8ef..eba9651eba7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -142,6 +142,7 @@ private void addFieldName(Field field, int fieldIndex) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; groupsField.setMergeGroupsCommand(new MergeGroupsCommand(groupsField)); groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand(groupsField)); + groupsField.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); } } From 8809bea96f92e3fd8287fa9ec1fa84a534c0fc42 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:50:08 +0100 Subject: [PATCH 120/473] Fix Unmerge button always disabled --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index eba9651eba7..7e94f06bd4e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -285,7 +285,6 @@ public class UnmergeGroupsCommand extends SimpleCommand { public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { this.groupsFieldCell = groupsFieldCell; - this.executable.bind(Bindings.createBooleanBinding(mergeGroupsEdit::canUndo)); } @Override From 30b90bd78195d60d88f93cf4c353216ddd329d5a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:52:35 +0100 Subject: [PATCH 121/473] Cleanup --- .../newmergedialog/ThreeWayMergeView.java | 20 +++++++++---------- .../newmergedialog/cell/FieldNameCell.java | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 7e94f06bd4e..2194dd19c08 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -199,14 +199,6 @@ private void removeFieldValues(int index) { mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } - private String mergeLeftAndRightEntryGroups(String left, String right) { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); - - return String.join(", ", leftGroups); - } - public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } @@ -276,7 +268,15 @@ public void execute() { } updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.UNMERGE); + groupsFieldNameCell.setMergeAction(GroupsFieldNameCell.MergeAction.UNMERGE); + } + + private String mergeLeftAndRightEntryGroups(String left, String right) { + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); + leftGroups.addAll(rightGroups); + + return String.join(", ", leftGroups); } } @@ -292,7 +292,7 @@ public void execute() { if (mergeGroupsEdit.canUndo()) { mergeGroupsEdit.undo(); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.MERGE); + groupsFieldCell.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 5391b0f0b4c..c00d55ba4aa 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -44,7 +44,7 @@ private void initializeLabel() { protected void setAction(String actionName, IconTheme.JabRefIcons icon, Command command) { actionLayout.getChildren().clear(); Node iconNode = icon.getGraphicNode(); - Button actionButton = factory.createIconButton(() -> Localization.lang(actionName), command); + Button actionButton = factory.createIconButton(() -> actionName, command); actionButton.setGraphic(iconNode); actionButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); actionButton.setMaxHeight(Double.MAX_VALUE); From 421705779179ff546a09067a2f8de6743ea54fb5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:31:28 +0100 Subject: [PATCH 122/473] Almost f**** everything up. I deleted GroupsFieldNameCell content by mistake, it's all ok now - I did a rebase and then when resolving conflicts, I chose "Accept Theirs" all the way but that didn't go well, now I have no history of GroupsFieldNameCell --- .../cell/GroupsFieldNameCell.java | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java index f70a7e79b1a..94a232cf3d2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java @@ -1,32 +1,48 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import org.jabref.gui.icon.IconTheme; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.field.StandardField; + +import de.saxsys.mvvmfx.utils.commands.Command; + public class GroupsFieldNameCell extends FieldNameCell { - private Runnable onMergeGroups; - private Runnable onUnmergeGroups; - private boolean isMerged = false; - - public GroupsFieldNameCell(String text, int rowIndex) { - super(text, rowIndex); - setOnMouseClicked(e -> { - if (isMerged) { - if (onUnmergeGroups != null) { - onUnmergeGroups.run(); - isMerged = false; - } + private Command mergeGroupsCommand; + private Command unmergeGroupsCommand; + + private final ObjectProperty mergeAction = new SimpleObjectProperty<>(); + + public GroupsFieldNameCell(int rowIndex) { + super(StandardField.GROUPS.getDisplayName(), rowIndex); + mergeActionProperty().addListener((obs, old, newValue) -> { + if (newValue == MergeAction.MERGE) { + setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeGroupsCommand); } else { - if (onMergeGroups != null) { - onMergeGroups.run(); - isMerged = true; - } + setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeGroupsCommand); } }); } - public void setOnMergeGroups(Runnable mergeGroups) { - this.onMergeGroups = mergeGroups; + public void setMergeGroupsCommand(Command mergeGroupsCommand) { + this.mergeGroupsCommand = mergeGroupsCommand; + } + + public void setUnmergeGroupsCommand(Command unmergeGroupsCommand) { + this.unmergeGroupsCommand = unmergeGroupsCommand; + } + + public ObjectProperty mergeActionProperty() { + return mergeAction; + } + + public void setMergeAction(MergeAction mergeAction) { + mergeActionProperty().set(mergeAction); } - public void setOnUnmergeGroups(Runnable unmergeGroups) { - this.onUnmergeGroups = unmergeGroups; + public enum MergeAction { + MERGE, UNMERGE } } From 3fde84c1b888451934ffdbe9edf1c2797d6877a0 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:59:32 +0100 Subject: [PATCH 123/473] Checkstyle --- .../gui/mergeentries/newmergedialog/cell/FieldNameCell.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index c00d55ba4aa..0f82beac6c6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -10,7 +10,6 @@ import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.icon.IconTheme; -import org.jabref.logic.l10n.Localization; import de.saxsys.mvvmfx.utils.commands.Command; From fcb2bd70e01760d6177b39cf9be9b07fbf44b784 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 10 Jul 2022 08:02:10 +0100 Subject: [PATCH 124/473] Remove unused MergedGroups class - Because now groups merge history is kept in a compound Edit --- .../gui/mergeentries/newmergedialog/MergedGroups.java | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java deleted file mode 100644 index f2b1e03da70..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog; - -public record MergedGroups( - String leftEntryGroups, String rightEntryGroups, String mergedGroups -) { -} From 7f25240a4125b5a7266666152491640e13a2a7da Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 10 Jul 2022 23:42:15 +0100 Subject: [PATCH 125/473] Register groups merge edit into UndoManager --- .../DuplicateResolverDialog.java | 6 ++++++ .../gui/duplicationFinder/DuplicateSearch.java | 18 ++++++++++++++++++ .../gui/mergeentries/FetchAndMergeEntry.java | 4 ++++ .../gui/mergeentries/MergeEntriesAction.java | 1 + .../gui/mergeentries/MergeEntriesDialog.java | 6 ++++++ .../newmergedialog/ThreeWayMergeView.java | 4 ++++ 6 files changed, 39 insertions(+) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index cec54b0d192..f25b680b936 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -1,5 +1,7 @@ package org.jabref.gui.duplicationFinder; +import javax.swing.undo.CompoundEdit; + import javafx.scene.control.Button; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar.ButtonData; @@ -138,4 +140,8 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { public BibEntry getMergedEntry() { return threeWayMerge.getMergedEntry(); } + + public CompoundEdit getMergeGroupsEdit() { + return threeWayMerge.getMergeGroupsEdit(); + } } diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java index 7ccc1b19402..50bce360ff9 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java @@ -5,12 +5,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import javax.swing.undo.CompoundEdit; + import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; @@ -163,6 +166,10 @@ private void askResolveStrategy(DuplicateSearchResult result, BibEntry first, Bi } else if (resolverResult == DuplicateResolverResult.KEEP_MERGE) { result.replace(first, second, dialog.getMergedEntry()); } + + if (dialog.getMergeGroupsEdit().canUndo()) { + result.setMergeGroupsEdit(dialog.getMergeGroupsEdit()); + } } private void handleDuplicates(DuplicateSearchResult result) { @@ -184,6 +191,7 @@ private void handleDuplicates(DuplicateSearchResult result) { libraryTab.getDatabase().insertEntries(result.getToAdd()); libraryTab.markBaseChanged(); } + result.getMergedGroupsEdit().ifPresent(compoundEdit::addEdit); duplicateProgress.set(0); @@ -203,6 +211,8 @@ static class DuplicateSearchResult { private final Map toRemove = new HashMap<>(); private final List toAdd = new ArrayList<>(); + private CompoundEdit mergeGroupsEdit; + private int duplicates = 0; public synchronized List getToRemove() { @@ -232,5 +242,13 @@ public synchronized boolean isToRemove(BibEntry entry) { public synchronized int getDuplicateCount() { return duplicates; } + + public synchronized void setMergeGroupsEdit(CompoundEdit mergeGroupsEdit) { + this.mergeGroupsEdit = mergeGroupsEdit; + } + + public Optional getMergedGroupsEdit() { + return Optional.ofNullable(mergeGroupsEdit); + } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index 7c1a9e127ba..fe6ffd80283 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -133,6 +133,10 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF edited = true; } } + if (dialog.getMergeGroupsEdit().canUndo()) { + ce.addEdit(dialog.getMergeGroupsEdit()); + edited = true; + } if (edited) { ce.end(); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index 3a24e84246b..ca0feb50de4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -81,6 +81,7 @@ public void execute() { ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergedEntry.get())); List entriesToRemove = Arrays.asList(one, two); ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); + ce.addEdit(dlg.getMergeGroupsEdit()); databaseContext.getDatabase().removeEntries(entriesToRemove); ce.end(); Globals.undoManager.addEdit(ce); // ToDo: Rework UndoManager and extract Globals diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 4c2f5ace0ec..30255f6c7eb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,5 +1,7 @@ package org.jabref.gui.mergeentries; +import javax.swing.undo.CompoundEdit; + import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; @@ -46,4 +48,8 @@ public void setLeftHeaderText(String leftHeaderText) { public void setRightHeaderText(String rightHeaderText) { threeWayMergeView.setRightHeader(rightHeaderText); } + + public CompoundEdit getMergeGroupsEdit() { + return threeWayMergeView.getMergeGroupsEdit(); + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 2194dd19c08..3262797f2d7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -231,6 +231,10 @@ public void cancelGroupsMerge() { } } + public CompoundEdit getMergeGroupsEdit() { + return mergeGroupsEdit; + } + public class MergeGroupsCommand extends SimpleCommand { private final GroupsFieldNameCell groupsFieldNameCell; From 6785fbcff6d16e0d7a27401f7ef256142686f62d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 10 Jul 2022 09:00:42 +0100 Subject: [PATCH 126/473] Cancel merge groups edit in the DuplicateResolverDialog when user choose 'Cancel' button --- .../jabref/gui/duplicationFinder/DuplicateResolverDialog.java | 1 + .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index f25b680b936..0bfd6cf4ed3 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -129,6 +129,7 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { } else if (button.equals(removeExact)) { return DuplicateResolverResult.AUTOREMOVE_EXACT; } + threeWayMerge.cancelGroupsMerge(); return null; }); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 3262797f2d7..1104d47ac73 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -33,7 +33,7 @@ import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { - + public static final String GROUPS_SEPARATOR = ", "; public static final int GRID_COLUMN_MIN_WIDTH = 250; public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); @@ -280,7 +280,7 @@ private String mergeLeftAndRightEntryGroups(String left, String right) { List rightGroups = Arrays.stream(right.split(", ")).toList(); leftGroups.addAll(rightGroups); - return String.join(", ", leftGroups); + return String.join(GROUPS_SEPARATOR, leftGroups); } } From b7fc3d87536a4064c0e4ee5de44eab34e1abb4d8 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 10 Jul 2022 22:50:02 +0100 Subject: [PATCH 127/473] i18n --- src/main/resources/l10n/JabRef_en.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index d29620e12c4..141f369f35d 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2512,3 +2512,6 @@ Merged\ Entry=Merged Entry (Note\:\ If\ original\ entries\ lack\ keywords\ to\ qualify\ for\ the\ new\ group\ configuration,\ confirming\ here\ will\ add\ them)=(Note: If original entries lack keywords to qualify for the new group configuration, confirming here will add them) Assign=Assign Do\ not\ assign=Do not assign + +Merge\ Groups=Merge Groups +Unmerge\ Groups=Unmerge Groups From 79d5f8428416198802753b8124ae83c289217994 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 13:18:53 +0100 Subject: [PATCH 128/473] Introduce ThreeFieldValuesViewModel --- .../newmergedialog/ThreeFieldValues.java | 6 +++ .../ThreeFieldValuesViewModel.java | 47 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 74bf76fe8b2..98f97bde8fe 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -1,6 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog; +import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; @@ -26,11 +28,15 @@ public class ThreeFieldValues { private final ToggleGroup toggleGroup = new ToggleGroup(); + private final ThreeFieldValuesViewModel viewModel; + public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); + viewModel = new ThreeFieldValuesViewModel(); + this.leftValue = leftValue; this.rightValue = rightValue; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java new file mode 100644 index 00000000000..e965ab8e729 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -0,0 +1,47 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import org.jabref.model.strings.StringUtil; + +public class ThreeFieldValuesViewModel { + public enum Selection { + LEFT, RIGHT, MERGED + } + + private final ObjectProperty selectedCell = new SimpleObjectProperty<>(); + + private final StringProperty leftFieldValue = new SimpleStringProperty(); + private final StringProperty rightFieldValue = new SimpleStringProperty(); + private final StringProperty mergedFieldValue = new SimpleStringProperty(); + + private final BooleanBinding hasEqualLeftAndRight; + + public ThreeFieldValuesViewModel() { + hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + } + + public boolean hasEqualLeftAndRightValues() { + return (!StringUtil.isNullOrEmpty(leftFieldValue.get()) && + !StringUtil.isNullOrEmpty(rightFieldValue.get()) && + leftFieldValue.get().equals(rightFieldValue.get())); + } + + public void selectLeftValue() { + selectedCell.set(Selection.LEFT); + mergedFieldValue.set(leftFieldValue.getValue()); + } + + public void merge() { + selectedCell.set(Selection.MERGED); + } + + public BooleanBinding hasEqualLeftAndRightBinding() { + return hasEqualLeftAndRight; + } +} From c5f185f8be805281c26990265afc1e828a28a097 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 12:52:21 +0100 Subject: [PATCH 129/473] Merge clones of left & right entry rather than the original ones --- .../gui/mergeentries/FetchAndMergeEntry.java | 6 +---- .../gui/mergeentries/MergeEntriesAction.java | 23 ++++++++----------- .../gui/mergeentries/MergeEntriesDialog.java | 10 ++------ .../jabref/gui/mergeentries/MergeResult.java | 8 +++++++ .../newmergedialog/ThreeWayMergeView.java | 10 +++++++- .../gui/shared/SharedDatabaseUIManager.java | 3 ++- 6 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeResult.java diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index fe6ffd80283..542788431cc 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -91,7 +91,7 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF 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 mergedEntry = dialogService.showCustomDialogAndWait(dialog); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); if (mergedEntry.isPresent()) { NamedCompound ce = new NamedCompound(Localization.lang("Merge entry with %0 information", fetcher.getName())); @@ -133,10 +133,6 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF edited = true; } } - if (dialog.getMergeGroupsEdit().canUndo()) { - ce.addEdit(dialog.getMergeGroupsEdit()); - edited = true; - } if (edited) { ce.end(); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index ca0feb50de4..7820cd95c92 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -66,29 +66,24 @@ public void execute() { second = one; } - MergeEntriesDialog dlg = new MergeEntriesDialog(first, second); - dlg.setTitle(Localization.lang("Merge entries")); - Optional mergedEntry = dialogService.showCustomDialogAndWait(dlg); - if (mergedEntry.isPresent()) { - // ToDo: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark + MergeEntriesDialog dialog = new MergeEntriesDialog(first, second); + dialog.setTitle(Localization.lang("Merge entries")); + Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); + mergeResultOpt.ifPresentOrElse(mergeResult -> { + // TODO: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark // entries with a timestamp, only BasePanel::insertEntry does. Workaround for the moment is to get the // BasePanel from the constructor injected JabRefFrame. Should be refactored and extracted! - frame.getCurrentLibraryTab().insertEntry(mergedEntry.get()); + frame.getCurrentLibraryTab().insertEntry(mergeResult.mergedEntry()); - // Create a new entry and add it to the undo stack - // Remove the other two entries and add them to the undo stack (which is not working...) NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); - ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergedEntry.get())); + ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergeResult.mergedEntry())); List entriesToRemove = Arrays.asList(one, two); ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); - ce.addEdit(dlg.getMergeGroupsEdit()); databaseContext.getDatabase().removeEntries(entriesToRemove); ce.end(); - Globals.undoManager.addEdit(ce); // ToDo: Rework UndoManager and extract Globals + Globals.undoManager.addEdit(ce); dialogService.notify(Localization.lang("Merged entries")); - } else { - dialogService.notify(Localization.lang("Canceled merging entries")); - } + }, () -> dialogService.notify(Localization.lang("Canceled merging entries"))); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 30255f6c7eb..adaea1a0c46 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,7 +1,5 @@ package org.jabref.gui.mergeentries; -import javax.swing.undo.CompoundEdit; - import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; @@ -10,7 +8,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; -public class MergeEntriesDialog extends BaseDialog { +public class MergeEntriesDialog extends BaseDialog { private final ThreeWayMergeView threeWayMergeView; public MergeEntriesDialog(BibEntry one, BibEntry two) { @@ -33,7 +31,7 @@ private void init() { this.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, replaceEntries); this.setResultConverter(buttonType -> { if (buttonType.equals(replaceEntries)) { - return threeWayMergeView.getMergedEntry(); + return new MergeResult(threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); } else { threeWayMergeView.cancelGroupsMerge(); return null; @@ -48,8 +46,4 @@ public void setLeftHeaderText(String leftHeaderText) { public void setRightHeaderText(String rightHeaderText) { threeWayMergeView.setRightHeader(rightHeaderText); } - - public CompoundEdit getMergeGroupsEdit() { - return threeWayMergeView.getMergeGroupsEdit(); - } } diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeResult.java b/src/main/java/org/jabref/gui/mergeentries/MergeResult.java new file mode 100644 index 00000000000..6db5a7a60e5 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/MergeResult.java @@ -0,0 +1,8 @@ +package org.jabref.gui.mergeentries; + +import org.jabref.model.entry.BibEntry; + +public record MergeResult( + BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry +) { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 1104d47ac73..4552c654db5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -58,7 +58,7 @@ public class ThreeWayMergeView extends VBox { public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); - viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); + viewModel = new ThreeWayMergeViewModel((BibEntry) leftEntry.clone(), (BibEntry) rightEntry.clone(), leftHeader, rightHeader); mergeGridPane = new GridPane(); scrollPane = new ScrollPane(); @@ -235,6 +235,14 @@ public CompoundEdit getMergeGroupsEdit() { return mergeGroupsEdit; } + public BibEntry getLeftEntry() { + return viewModel.getLeftEntry(); + } + + public BibEntry getRightEntry() { + return viewModel.getRightEntry(); + } + public class MergeGroupsCommand extends SimpleCommand { private final GroupsFieldNameCell groupsFieldNameCell; diff --git a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java index 055ea30a983..e5c2a0e9732 100644 --- a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java +++ b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java @@ -16,6 +16,7 @@ import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.gui.mergeentries.MergeEntriesDialog; +import org.jabref.gui.mergeentries.MergeResult; import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; @@ -99,7 +100,7 @@ public void listen(UpdateRefusedEvent updateRefusedEvent) { if (response.isPresent() && response.get().equals(merge)) { MergeEntriesDialog dialog = new MergeEntriesDialog(localBibEntry, sharedBibEntry); - Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); mergedEntry.ifPresent(mergedBibEntry -> { mergedBibEntry.getSharedBibEntryData().setSharedID(sharedBibEntry.getSharedBibEntryData().getSharedID()); From 439bf058134d2cd419322153a871589880b19c1e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 12:52:40 +0100 Subject: [PATCH 130/473] Optimize imports --- .../gui/mergeentries/newmergedialog/ThreeFieldValues.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 98f97bde8fe..369c8e4de41 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -1,8 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog; -import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; From f429860d269b9f805270dfe98e4dac20c48085a5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 13:16:37 +0100 Subject: [PATCH 131/473] Refactor DuplicateResolverDialog to merge clones of left and right entry --- .../DuplicateResolverDialog.java | 10 ++++--- .../duplicationFinder/DuplicateSearch.java | 28 +++++++------------ .../newmergedialog/ThreeWayMergeView.java | 4 --- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index 0bfd6cf4ed3..d3c70e06bfe 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -1,7 +1,5 @@ package org.jabref.gui.duplicationFinder; -import javax.swing.undo.CompoundEdit; - import javafx.scene.control.Button; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar.ButtonData; @@ -142,7 +140,11 @@ public BibEntry getMergedEntry() { return threeWayMerge.getMergedEntry(); } - public CompoundEdit getMergeGroupsEdit() { - return threeWayMerge.getMergeGroupsEdit(); + public BibEntry getNewLeftEntry() { + return threeWayMerge.getLeftEntry(); + } + + public BibEntry getNewRightEntry() { + return threeWayMerge.getRightEntry(); } } diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java index 50bce360ff9..46ddfaf6f3b 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java @@ -5,15 +5,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import javax.swing.undo.CompoundEdit; - import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; @@ -155,20 +152,21 @@ private void askResolveStrategy(DuplicateSearchResult result, BibEntry first, Bi if ((resolverResult == DuplicateResolverResult.KEEP_LEFT) || (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT)) { result.remove(second); + result.replace(first, dialog.getNewLeftEntry()); if (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT) { autoRemoveExactDuplicates.set(true); // Remember choice } } else if (resolverResult == DuplicateResolverResult.KEEP_RIGHT) { result.remove(first); + result.replace(second, dialog.getNewRightEntry()); } else if (resolverResult == DuplicateResolverResult.BREAK) { libraryAnalyzed.set(true); duplicates.clear(); } else if (resolverResult == DuplicateResolverResult.KEEP_MERGE) { result.replace(first, second, dialog.getMergedEntry()); - } - - if (dialog.getMergeGroupsEdit().canUndo()) { - result.setMergeGroupsEdit(dialog.getMergeGroupsEdit()); + } else if (resolverResult == DuplicateResolverResult.KEEP_BOTH) { + result.replace(first, dialog.getNewLeftEntry()); + result.replace(second, dialog.getNewRightEntry()); } } @@ -191,7 +189,6 @@ private void handleDuplicates(DuplicateSearchResult result) { libraryTab.getDatabase().insertEntries(result.getToAdd()); libraryTab.markBaseChanged(); } - result.getMergedGroupsEdit().ifPresent(compoundEdit::addEdit); duplicateProgress.set(0); @@ -211,8 +208,6 @@ static class DuplicateSearchResult { private final Map toRemove = new HashMap<>(); private final List toAdd = new ArrayList<>(); - private CompoundEdit mergeGroupsEdit; - private int duplicates = 0; public synchronized List getToRemove() { @@ -235,6 +230,11 @@ public synchronized void replace(BibEntry first, BibEntry second, BibEntry repla duplicates++; } + public synchronized void replace(BibEntry entry, BibEntry replacement) { + remove(entry); + getToAdd().add(replacement); + } + public synchronized boolean isToRemove(BibEntry entry) { return toRemove.containsKey(System.identityHashCode(entry)); } @@ -242,13 +242,5 @@ public synchronized boolean isToRemove(BibEntry entry) { public synchronized int getDuplicateCount() { return duplicates; } - - public synchronized void setMergeGroupsEdit(CompoundEdit mergeGroupsEdit) { - this.mergeGroupsEdit = mergeGroupsEdit; - } - - public Optional getMergedGroupsEdit() { - return Optional.ofNullable(mergeGroupsEdit); - } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 4552c654db5..eb90ba14fbb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -231,10 +231,6 @@ public void cancelGroupsMerge() { } } - public CompoundEdit getMergeGroupsEdit() { - return mergeGroupsEdit; - } - public BibEntry getLeftEntry() { return viewModel.getLeftEntry(); } From 01001289d2a0c2ff3e149dbb0b13191bb19ee7e2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 13:37:15 +0100 Subject: [PATCH 132/473] Select the other entry groups when one entry has no group --- .../newmergedialog/ThreeWayMergeView.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index eb90ba14fbb..90c8616e3cf 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -31,6 +31,7 @@ import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.EntryTypeFactory; +import org.jabref.model.strings.StringUtil; public class ThreeWayMergeView extends VBox { public static final String GROUPS_SEPARATOR = ", "; @@ -280,11 +281,17 @@ public void execute() { } private String mergeLeftAndRightEntryGroups(String left, String right) { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); + if (StringUtil.isBlank(left)) { + return right; + } else if (StringUtil.isBlank(right)) { + return left; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); + leftGroups.addAll(rightGroups); - return String.join(GROUPS_SEPARATOR, leftGroups); + return String.join(GROUPS_SEPARATOR, leftGroups); + } } } From 0ad83ba2b3a3174a1bc8190d6b036a8e538cf7ef Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 17 Jul 2022 18:42:37 +0100 Subject: [PATCH 133/473] Remove unused property --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 90c8616e3cf..515a45d7648 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -9,8 +9,6 @@ import javax.swing.undo.CompoundEdit; import javafx.beans.binding.Bindings; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -53,8 +51,6 @@ public class ThreeWayMergeView extends VBox { private final ThreeWayMergeViewModel viewModel; private final List fieldValuesList = new ArrayList<>(); - private final BooleanProperty areGroupsMerged = new SimpleBooleanProperty(); - private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { @@ -246,12 +242,12 @@ public class MergeGroupsCommand extends SimpleCommand { public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { this.groupsFieldNameCell = groupsFieldCell; - this.executable.bind(Bindings.and(areGroupsMerged.not(), Bindings.createBooleanBinding(() -> { + this.executable.bind(Bindings.createBooleanBinding(() -> { String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); return !leftEntryGroups.equals(rightEntryGroups); - }))); + })); } @Override From 145a7c72a064d2bc0f0cac89327f29ce71c7a739 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 17 Jul 2022 19:47:49 +0100 Subject: [PATCH 134/473] [WIP] Convert ThreeFieldValues to MVVM - Together with my mentors, we decided to convert ThreeFieldValues to MVVM in order to maintain the codebase consistency and facilitate testing. The view is ThreeFieldValues, and it has a view model. --- .../newmergedialog/ThreeFieldValues.java | 28 ++++-- .../ThreeFieldValuesViewModel.java | 86 +++++++++++++++++-- 2 files changed, 103 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 369c8e4de41..836027073d7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -1,5 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog; +import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; @@ -12,6 +13,8 @@ import org.fxmisc.richtext.StyleClassedTextArea; +import static org.jabref.gui.mergeentries.newmergedialog.ThreeFieldValuesViewModel.Selection; + /** * A controller class to control left, right and merged field values */ @@ -57,6 +60,19 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); + mergedValueCell.textProperty().bindBidirectional(viewModel.mergedFieldValueProperty()); + + viewModel.selectionProperty().addListener(obs -> { + Selection selection = viewModel.getSelection(); + if (selection == Selection.LEFT) { + toggleGroup.selectToggle(leftValueCell); + } else if (selection == Selection.RIGHT) { + toggleGroup.selectToggle(rightValueCell); + } else if (selection == Selection.NONE) { + toggleGroup.selectToggle(null); + } + }); + // When both the left and right cells have the same value, only the left value is displayed, // making it unnecessary to keep allocating memory for the right cell. if (hasEqualLeftAndRightValues()) { @@ -66,15 +82,11 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } public void selectLeftValue() { - toggleGroup.selectToggle(leftValueCell); + viewModel.selectLeftValue(); } public void selectRightValue() { - if (isRightValueCellHidden()) { - selectLeftValue(); - } else { - toggleGroup.selectToggle(rightValueCell); - } + viewModel.selectRightValue(); } public String getMergedValue() { @@ -136,4 +148,8 @@ public void hideDiff() { private boolean isRightValueCellHidden() { return rightValueCell == null; } + + private ObjectProperty selectionProperty() { + return viewModel.selectionProperty(); + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index e965ab8e729..2ae5f7129a6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -2,7 +2,9 @@ import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -11,10 +13,19 @@ public class ThreeFieldValuesViewModel { public enum Selection { - LEFT, RIGHT, MERGED + LEFT, + RIGHT, + /** + * When the user types something into the merged field value and neither the left nor + * right values match it, NONE is selected + * */ + NONE } - private final ObjectProperty selectedCell = new SimpleObjectProperty<>(); + + private final BooleanProperty isFieldsMerged = new SimpleBooleanProperty(Boolean.FALSE); + + private final ObjectProperty selection = new SimpleObjectProperty<>(); private final StringProperty leftFieldValue = new SimpleStringProperty(); private final StringProperty rightFieldValue = new SimpleStringProperty(); @@ -33,15 +44,80 @@ public boolean hasEqualLeftAndRightValues() { } public void selectLeftValue() { - selectedCell.set(Selection.LEFT); - mergedFieldValue.set(leftFieldValue.getValue()); + setSelection(Selection.LEFT); + setMergedFieldValue(getLeftFieldValue()); + } + + public void selectRightValue() { + if (isIsFieldsMerged()) { + selectLeftValue(); + } else { + setSelection(Selection.RIGHT); + setMergedFieldValue(getRightFieldValue()); + } + } + + public void setMergedFieldValue(String mergedFieldValue) { + mergedFieldValueProperty().set(mergedFieldValue); + } + + public StringProperty mergedFieldValueProperty() { + return mergedFieldValue; } public void merge() { - selectedCell.set(Selection.MERGED); + setIsFieldsMerged(true); } public BooleanBinding hasEqualLeftAndRightBinding() { return hasEqualLeftAndRight; } + + public ObjectProperty selectionProperty() { + return selection; + } + + public void setSelection(Selection select) { + selectionProperty().set(select); + } + + public Selection getSelection() { + return selectionProperty().get(); + } + + public boolean isIsFieldsMerged() { + return isFieldsMerged.get(); + } + + public BooleanProperty isFieldsMergedProperty() { + return isFieldsMerged; + } + + public void setIsFieldsMerged(boolean isFieldsMerged) { + this.isFieldsMerged.set(isFieldsMerged); + } + + public String getLeftFieldValue() { + return leftFieldValue.get(); + } + + public StringProperty leftFieldValueProperty() { + return leftFieldValue; + } + + public void setLeftFieldValue(String leftFieldValue) { + this.leftFieldValue.set(leftFieldValue); + } + + public String getRightFieldValue() { + return rightFieldValue.get(); + } + + public StringProperty rightFieldValueProperty() { + return rightFieldValue; + } + + public void setRightFieldValue(String rightFieldValue) { + this.rightFieldValue.set(rightFieldValue); + } } From c3044d12691535af636a9410bfbc9563cc402a2d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 13:38:24 +0100 Subject: [PATCH 135/473] Move business logic to the view-model and update UI via binding --- .../newmergedialog/ThreeFieldValues.java | 49 ++++++++++--------- .../ThreeFieldValuesViewModel.java | 47 +++++++++++++++--- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 836027073d7..739d2842089 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -2,6 +2,7 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; +import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; @@ -36,31 +37,16 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); - viewModel = new ThreeFieldValuesViewModel(); + viewModel = new ThreeFieldValuesViewModel(leftValue, rightValue); this.leftValue = leftValue; this.rightValue = rightValue; toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); - toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); - toggleGroup.selectedToggleProperty().addListener(invalidated -> { - if (toggleGroup.getSelectedToggle() != null) { - mergedValueCell.setText((String) toggleGroup.getSelectedToggle().getUserData()); - } - }); - - mergedValueCell.textProperty().addListener((observable, old, mergedValue) -> { - if (mergedValue.equals(leftValue)) { - toggleGroup.selectToggle(leftValueCell); - } else if (mergedValue.equals(rightValue)) { - toggleGroup.selectToggle(rightValueCell); - } else { - // deselect all toggles because left and right values don't equal the merged value - toggleGroup.selectToggle(null); - } - }); mergedValueCell.textProperty().bindBidirectional(viewModel.mergedFieldValueProperty()); + leftValueCell.textProperty().bindBidirectional(viewModel.leftFieldValueProperty()); + rightValueCell.textProperty().bindBidirectional(viewModel.rightFieldValueProperty()); viewModel.selectionProperty().addListener(obs -> { Selection selection = viewModel.getSelection(); @@ -73,6 +59,23 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); + toggleGroup.selectedToggleProperty().addListener(obs -> { + Toggle selectedToggle = toggleGroup.getSelectedToggle(); + if (selectedToggle == leftValueCell) { + selectLeftValue(); + } else if (selectedToggle == rightValueCell) { + selectRightValue(); + } else { + selectNone(); + } + }); + + if (StringUtil.isNullOrEmpty(leftValue)) { + selectRightValue(); + } else { + selectLeftValue(); + } + // When both the left and right cells have the same value, only the left value is displayed, // making it unnecessary to keep allocating memory for the right cell. if (hasEqualLeftAndRightValues()) { @@ -89,12 +92,16 @@ public void selectRightValue() { viewModel.selectRightValue(); } + public void selectNone() { + viewModel.selectNone(); + } + public String getMergedValue() { return mergedValueProperty().getValue(); } public ReadOnlyStringProperty mergedValueProperty() { - return mergedValueCell.textProperty(); + return viewModel.mergedFieldValueProperty(); } public FieldValueCell getLeftValueCell() { @@ -110,9 +117,7 @@ public MergedFieldCell getMergedValueCell() { } public boolean hasEqualLeftAndRightValues() { - return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && - !StringUtil.isNullOrEmpty(rightValueCell.getText()) && - leftValueCell.getText().equals(rightValueCell.getText())); + return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && !StringUtil.isNullOrEmpty(rightValueCell.getText()) && leftValueCell.getText().equals(rightValueCell.getText())); } public void showDiff(ShowDiffConfig diffConfig) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 2ae5f7129a6..5a501f7d618 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -27,14 +27,31 @@ public enum Selection { private final ObjectProperty selection = new SimpleObjectProperty<>(); - private final StringProperty leftFieldValue = new SimpleStringProperty(); - private final StringProperty rightFieldValue = new SimpleStringProperty(); - private final StringProperty mergedFieldValue = new SimpleStringProperty(); + private final StringProperty leftFieldValue = new SimpleStringProperty(""); + private final StringProperty rightFieldValue = new SimpleStringProperty(""); + private final StringProperty mergedFieldValue = new SimpleStringProperty(""); private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel() { + public ThreeFieldValuesViewModel(String leftValue, String rightValue) { + leftFieldValueProperty().set(leftValue); + rightFieldValueProperty().set(rightValue); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + selectionProperty().addListener((obs, old, newVal) -> { + switch (newVal) { + case LEFT -> onLeftSelected(); + case RIGHT -> onRightSelected(); + } + }); + mergedFieldValueProperty().addListener(obs -> { + if (getMergedFieldValue().equals(getLeftFieldValue())) { + selectLeftValue(); + } else if (getMergedFieldValue().equals(getRightFieldValue())) { + selectRightValue(); + } else { + selectNone(); + } + }); } public boolean hasEqualLeftAndRightValues() { @@ -43,9 +60,20 @@ public boolean hasEqualLeftAndRightValues() { leftFieldValue.get().equals(rightFieldValue.get())); } + private void onLeftSelected() { + setMergedFieldValue(getLeftFieldValue()); + } + + private void onRightSelected() { + if (isIsFieldsMerged()) { + onLeftSelected(); + } else { + setMergedFieldValue(getRightFieldValue()); + } + } + public void selectLeftValue() { setSelection(Selection.LEFT); - setMergedFieldValue(getLeftFieldValue()); } public void selectRightValue() { @@ -53,10 +81,13 @@ public void selectRightValue() { selectLeftValue(); } else { setSelection(Selection.RIGHT); - setMergedFieldValue(getRightFieldValue()); } } + public void selectNone() { + setSelection(Selection.NONE); + } + public void setMergedFieldValue(String mergedFieldValue) { mergedFieldValueProperty().set(mergedFieldValue); } @@ -65,6 +96,10 @@ public StringProperty mergedFieldValueProperty() { return mergedFieldValue; } + public String getMergedFieldValue() { + return mergedFieldValue.get(); + } + public void merge() { setIsFieldsMerged(true); } From 8a0437a96633281e7fc31d13b79e39364808cebb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 13:55:57 +0100 Subject: [PATCH 136/473] Consider equal left and right fields as merged --- .../ThreeFieldValuesViewModel.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 5a501f7d618..27b2ed57ebc 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -37,12 +37,14 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { leftFieldValueProperty().set(leftValue); rightFieldValueProperty().set(rightValue); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + selectionProperty().addListener((obs, old, newVal) -> { switch (newVal) { - case LEFT -> onLeftSelected(); - case RIGHT -> onRightSelected(); + case LEFT -> setMergedFieldValue(getLeftFieldValue()); + case RIGHT -> setMergedFieldValue(getRightFieldValue()); } }); + mergedFieldValueProperty().addListener(obs -> { if (getMergedFieldValue().equals(getLeftFieldValue())) { selectLeftValue(); @@ -52,6 +54,20 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { selectNone(); } }); + + if (StringUtil.isNullOrEmpty(leftValue)) { + selectRightValue(); + } else { + selectLeftValue(); + } + + if (hasEqualLeftAndRight.get()) { + setIsFieldsMerged(true); + } + + hasEqualLeftAndRight.addListener(obs -> { + setIsFieldsMerged(true); + }); } public boolean hasEqualLeftAndRightValues() { @@ -60,18 +76,6 @@ public boolean hasEqualLeftAndRightValues() { leftFieldValue.get().equals(rightFieldValue.get())); } - private void onLeftSelected() { - setMergedFieldValue(getLeftFieldValue()); - } - - private void onRightSelected() { - if (isIsFieldsMerged()) { - onLeftSelected(); - } else { - setMergedFieldValue(getRightFieldValue()); - } - } - public void selectLeftValue() { setSelection(Selection.LEFT); } From 1cda0d7ecb1a8805304d915082852a665a6f673a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:18:52 +0100 Subject: [PATCH 137/473] Move initial selection code to the view model - Replaced addListener() with EasyBind#subscribe --- .../newmergedialog/ThreeFieldValues.java | 24 ++++----------- .../ThreeFieldValuesViewModel.java | 30 ++++++++----------- 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 739d2842089..1ebbd84de74 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -12,6 +12,7 @@ import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; +import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; import static org.jabref.gui.mergeentries.newmergedialog.ThreeFieldValuesViewModel.Selection; @@ -48,8 +49,7 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { leftValueCell.textProperty().bindBidirectional(viewModel.leftFieldValueProperty()); rightValueCell.textProperty().bindBidirectional(viewModel.rightFieldValueProperty()); - viewModel.selectionProperty().addListener(obs -> { - Selection selection = viewModel.getSelection(); + EasyBind.subscribe(viewModel.selectionProperty(), selection -> { if (selection == Selection.LEFT) { toggleGroup.selectToggle(leftValueCell); } else if (selection == Selection.RIGHT) { @@ -59,29 +59,15 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); - toggleGroup.selectedToggleProperty().addListener(obs -> { - Toggle selectedToggle = toggleGroup.getSelectedToggle(); - if (selectedToggle == leftValueCell) { + EasyBind.subscribe(toggleGroup.selectedToggleProperty(), val -> { + if (val == leftValueCell) { selectLeftValue(); - } else if (selectedToggle == rightValueCell) { + } else if (val == rightValueCell) { selectRightValue(); } else { selectNone(); } }); - - if (StringUtil.isNullOrEmpty(leftValue)) { - selectRightValue(); - } else { - selectLeftValue(); - } - - // When both the left and right cells have the same value, only the left value is displayed, - // making it unnecessary to keep allocating memory for the right cell. - if (hasEqualLeftAndRightValues()) { - // Setting this to null so the GC release the memory allocated to the right cell. - this.rightValueCell = null; - } } public void selectLeftValue() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 27b2ed57ebc..acd2bc94c57 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -11,6 +11,8 @@ import org.jabref.model.strings.StringUtil; +import com.tobiasdiez.easybind.EasyBind; + public class ThreeFieldValuesViewModel { public enum Selection { LEFT, @@ -38,15 +40,21 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { rightFieldValueProperty().set(rightValue); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); - selectionProperty().addListener((obs, old, newVal) -> { - switch (newVal) { + if (StringUtil.isNullOrEmpty(leftValue)) { + selectRightValue(); + } else { + selectLeftValue(); + } + + EasyBind.subscribe(selectionProperty(), selection -> { + switch (selection) { case LEFT -> setMergedFieldValue(getLeftFieldValue()); case RIGHT -> setMergedFieldValue(getRightFieldValue()); } }); - mergedFieldValueProperty().addListener(obs -> { - if (getMergedFieldValue().equals(getLeftFieldValue())) { + EasyBind.subscribe(mergedFieldValueProperty(), mergedValue -> { + if (mergedValue.equals(getLeftFieldValue())) { selectLeftValue(); } else if (getMergedFieldValue().equals(getRightFieldValue())) { selectRightValue(); @@ -55,19 +63,7 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { } }); - if (StringUtil.isNullOrEmpty(leftValue)) { - selectRightValue(); - } else { - selectLeftValue(); - } - - if (hasEqualLeftAndRight.get()) { - setIsFieldsMerged(true); - } - - hasEqualLeftAndRight.addListener(obs -> { - setIsFieldsMerged(true); - }); + EasyBind.subscribe(hasEqualLeftAndRightBinding(), this::setIsFieldsMerged); } public boolean hasEqualLeftAndRightValues() { From 0873e6e08385f8b6aeed45ab43b9c7792e415ec9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:20:22 +0100 Subject: [PATCH 138/473] Refactor --- .../mergeentries/newmergedialog/ThreeFieldValues.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 1ebbd84de74..ffa294f3c4c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -2,7 +2,6 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; -import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; @@ -59,10 +58,10 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); - EasyBind.subscribe(toggleGroup.selectedToggleProperty(), val -> { - if (val == leftValueCell) { + EasyBind.subscribe(toggleGroup.selectedToggleProperty(), selectedToggle -> { + if (selectedToggle == leftValueCell) { selectLeftValue(); - } else if (val == rightValueCell) { + } else if (selectedToggle == rightValueCell) { selectRightValue(); } else { selectNone(); @@ -103,7 +102,7 @@ public MergedFieldCell getMergedValueCell() { } public boolean hasEqualLeftAndRightValues() { - return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && !StringUtil.isNullOrEmpty(rightValueCell.getText()) && leftValueCell.getText().equals(rightValueCell.getText())); + return viewModel.hasEqualLeftAndRightValues(); } public void showDiff(ShowDiffConfig diffConfig) { From fb711574c0e57965d06b08f0653ab05177f6aca7 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:31:20 +0100 Subject: [PATCH 139/473] Hide rightValueCell and extend leftValueCell to 2 columns when fields are merged --- .../newmergedialog/ThreeFieldValues.java | 12 ++++++++++++ .../newmergedialog/ThreeWayMergeView.java | 11 +++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index ffa294f3c4c..561b6c03608 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -3,6 +3,7 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.GridPane; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; @@ -67,6 +68,17 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { selectNone(); } }); + + // Hide rightValueCell and extend leftValueCell to 2 columns when fields are merged + EasyBind.subscribe(viewModel.isFieldsMergedProperty(), isFieldsMerged -> { + if (isFieldsMerged) { + rightValueCell.setVisible(false); + GridPane.setColumnSpan(leftValueCell, 2); + } else { + rightValueCell.setVisible(true); + GridPane.setColumnSpan(leftValueCell, 1); + } + }); } public void selectLeftValue() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 515a45d7648..4c359a36970 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -175,14 +175,9 @@ private void addFieldValues(int fieldIndex) { getMergedEntry().setField(field, fieldValues.getMergedValue()); } - if (fieldValues.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex, 2, 1); - mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); - } else { - mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); - mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); - mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); - } + mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } private void updateFieldValues(int fieldIndex) { From 2a4a9a5cbae5ffb9a8aa2bcf956fe6aa2519c629 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:41:23 +0100 Subject: [PATCH 140/473] Prepare for adding the ability to merge fields other than groups --- .../newmergedialog/ThreeWayMergeView.java | 24 +++++++++---------- .../cell/FieldNameCellFactory.java | 8 +++++-- ...dNameCell.java => MergeableFieldCell.java} | 24 +++++++++---------- 3 files changed, 30 insertions(+), 26 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/{GroupsFieldNameCell.java => MergeableFieldCell.java} (59%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 4c359a36970..b64dae403a9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -20,7 +20,7 @@ import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; -import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; @@ -135,11 +135,11 @@ private void addFieldName(Field field, int fieldIndex) { FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, fieldIndex); mergeGridPane.add(fieldNameCell, FIELD_NAME_COLUMN, fieldIndex); - if (field.equals(StandardField.GROUPS)) { - GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setMergeGroupsCommand(new MergeGroupsCommand(groupsField)); - groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand(groupsField)); - groupsField.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); + if (FieldNameCellFactory.isMergeableField(field)) { + MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; + mergeableFieldCell.setMergeCommand(new MergeGroupsCommand(mergeableFieldCell)); + mergeableFieldCell.setUnmergeCommand(new UnmergeGroupsCommand(mergeableFieldCell)); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } @@ -232,9 +232,9 @@ public BibEntry getRightEntry() { } public class MergeGroupsCommand extends SimpleCommand { - private final GroupsFieldNameCell groupsFieldNameCell; + private final MergeableFieldCell groupsFieldNameCell; - public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + public MergeGroupsCommand(MergeableFieldCell groupsFieldCell) { this.groupsFieldNameCell = groupsFieldCell; this.executable.bind(Bindings.createBooleanBinding(() -> { @@ -268,7 +268,7 @@ public void execute() { } updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.setMergeAction(GroupsFieldNameCell.MergeAction.UNMERGE); + groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } private String mergeLeftAndRightEntryGroups(String left, String right) { @@ -287,9 +287,9 @@ private String mergeLeftAndRightEntryGroups(String left, String right) { } public class UnmergeGroupsCommand extends SimpleCommand { - private final GroupsFieldNameCell groupsFieldCell; + private final MergeableFieldCell groupsFieldCell; - public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + public UnmergeGroupsCommand(MergeableFieldCell groupsFieldCell) { this.groupsFieldCell = groupsFieldCell; } @@ -298,7 +298,7 @@ public void execute() { if (mergeGroupsEdit.canUndo()) { mergeGroupsEdit.undo(); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldCell.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); + groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index 01a2fa90aff..b30245014f4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -5,9 +5,13 @@ public class FieldNameCellFactory { + public static boolean isMergeableField(Field field) { + return field == StandardField.GROUPS; + } + public static FieldNameCell create(Field field, int rowIndex) { - if (field.equals(StandardField.GROUPS)) { - return new GroupsFieldNameCell(rowIndex); + if (isMergeableField(field)) { + return new MergeableFieldCell(field, rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java similarity index 59% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 94a232cf3d2..519c65d50ad 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -5,33 +5,33 @@ import org.jabref.gui.icon.IconTheme; import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.field.Field; import de.saxsys.mvvmfx.utils.commands.Command; -public class GroupsFieldNameCell extends FieldNameCell { - private Command mergeGroupsCommand; - private Command unmergeGroupsCommand; +public class MergeableFieldCell extends FieldNameCell { + private Command mergeCommand; + private Command unmergeCommand; private final ObjectProperty mergeAction = new SimpleObjectProperty<>(); - public GroupsFieldNameCell(int rowIndex) { - super(StandardField.GROUPS.getDisplayName(), rowIndex); + public MergeableFieldCell(Field field, int rowIndex) { + super(field.getDisplayName(), rowIndex); mergeActionProperty().addListener((obs, old, newValue) -> { if (newValue == MergeAction.MERGE) { - setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeGroupsCommand); + setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); } else { - setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeGroupsCommand); + setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeCommand); } }); } - public void setMergeGroupsCommand(Command mergeGroupsCommand) { - this.mergeGroupsCommand = mergeGroupsCommand; + public void setMergeCommand(Command mergeCommand) { + this.mergeCommand = mergeCommand; } - public void setUnmergeGroupsCommand(Command unmergeGroupsCommand) { - this.unmergeGroupsCommand = unmergeGroupsCommand; + public void setUnmergeCommand(Command unmergeCommand) { + this.unmergeCommand = unmergeCommand; } public ObjectProperty mergeActionProperty() { From 31aed868aef11f5afa3e1c14acd20a00dc3ae742 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:44:28 +0100 Subject: [PATCH 141/473] Rename ThreeFieldValues to ThreeFieldValuesView --- ...ThreeFieldValues.java => ThreeFieldValuesView.java} | 4 ++-- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ThreeFieldValues.java => ThreeFieldValuesView.java} (97%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java similarity index 97% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 561b6c03608..3f27db4b092 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -20,7 +20,7 @@ /** * A controller class to control left, right and merged field values */ -public class ThreeFieldValues { +public class ThreeFieldValuesView { private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; @@ -33,7 +33,7 @@ public class ThreeFieldValues { private final ThreeFieldValuesViewModel viewModel; - public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { + public ThreeFieldValuesView(String leftValue, String rightValue, int rowIndex) { leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index b64dae403a9..3b8bcd05b32 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -49,7 +49,7 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List fieldValuesList = new ArrayList<>(); + private final List fieldValuesList = new ArrayList<>(); private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); @@ -91,7 +91,7 @@ private void updateDiff() { if (toolbar.isShowDiffEnabled()) { fieldValuesList.forEach(fieldValues -> fieldValues.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - fieldValuesList.forEach(ThreeFieldValues::hideDiff); + fieldValuesList.forEach(ThreeFieldValuesView::hideDiff); } } @@ -159,7 +159,7 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldValues = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(leftEntryValue, rightEntryValue, fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { @@ -204,11 +204,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - fieldValuesList.forEach(ThreeFieldValues::selectLeftValue); + fieldValuesList.forEach(ThreeFieldValuesView::selectLeftValue); } public void selectRightEntryValues() { - fieldValuesList.forEach(ThreeFieldValues::selectRightValue); + fieldValuesList.forEach(ThreeFieldValuesView::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 5be501a0e7e7839d3d732857f78750bff57c7ba0 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:56:03 +0100 Subject: [PATCH 142/473] Delegate FieldNameCell creation to ThreeFieldValuesView --- .../newmergedialog/ThreeFieldValuesView.java | 11 ++++++++++- .../newmergedialog/ThreeWayMergeView.java | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 3f27db4b092..075fe81a45f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -5,11 +5,14 @@ import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -21,6 +24,7 @@ * A controller class to control left, right and merged field values */ public class ThreeFieldValuesView { + private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; @@ -33,7 +37,8 @@ public class ThreeFieldValuesView { private final ThreeFieldValuesViewModel viewModel; - public ThreeFieldValuesView(String leftValue, String rightValue, int rowIndex) { + public ThreeFieldValuesView(Field field, String leftValue, String rightValue, int rowIndex) { + fieldNameCell = FieldNameCellFactory.create(field, rowIndex); leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); @@ -101,6 +106,10 @@ public ReadOnlyStringProperty mergedValueProperty() { return viewModel.mergedFieldValueProperty(); } + public FieldNameCell getFieldNameCell() { + return fieldNameCell; + } + public FieldValueCell getLeftValueCell() { return leftValueCell; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 3b8bcd05b32..93721d19745 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -119,7 +119,7 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); + // addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); // Removing this will cause UI to lag when updating field values @@ -159,7 +159,7 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(leftEntryValue, rightEntryValue, fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, leftEntryValue, rightEntryValue, fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { @@ -175,6 +175,7 @@ private void addFieldValues(int fieldIndex) { getMergedEntry().setField(field, fieldValues.getMergedValue()); } + mergeGridPane.add(fieldValues.getFieldNameCell(), 0, fieldIndex); mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); From 7c4684f99a276c63b3e7cf1a2b9452a7321b10c1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 19:01:10 +0100 Subject: [PATCH 143/473] Pass Bib entries to ThreeFieldValuesView rather than raw string - Because I want to add the merge/unmerge commands to ThreeFieldValuesView and I need to have a reference to left and right bib entries --- .../newmergedialog/ThreeFieldValuesView.java | 25 ++++------- .../ThreeFieldValuesViewModel.java | 41 +++++++++++++++---- .../newmergedialog/ThreeWayMergeView.java | 11 +---- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 075fe81a45f..3717a4068e8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -12,8 +12,8 @@ import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; @@ -29,24 +29,17 @@ public class ThreeFieldValuesView { private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; - private final String leftValue; - - private final String rightValue; - private final ToggleGroup toggleGroup = new ToggleGroup(); private final ThreeFieldValuesViewModel viewModel; - public ThreeFieldValuesView(Field field, String leftValue, String rightValue, int rowIndex) { - fieldNameCell = FieldNameCellFactory.create(field, rowIndex); - leftValueCell = new FieldValueCell(leftValue, rowIndex); - rightValueCell = new FieldValueCell(rightValue, rowIndex); - mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, int rowIndex) { + viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry); - viewModel = new ThreeFieldValuesViewModel(leftValue, rightValue); - - this.leftValue = leftValue; - this.rightValue = rightValue; + fieldNameCell = FieldNameCellFactory.create(field, rowIndex); + leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); + rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); + mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); @@ -149,11 +142,11 @@ public void hideDiff() { int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); - getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); + getLeftValueCell().getStyleClassedLabel().replaceText(viewModel.getLeftFieldValue()); int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); - getRightValueCell().getStyleClassedLabel().replaceText(rightValue); + getRightValueCell().getStyleClassedLabel().replaceText(viewModel.getRightFieldValue()); } private boolean isRightValueCellHidden() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index acd2bc94c57..b8fe4bef004 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -9,6 +9,9 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.InternalField; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -33,14 +36,30 @@ public enum Selection { private final StringProperty rightFieldValue = new SimpleStringProperty(""); private final StringProperty mergedFieldValue = new SimpleStringProperty(""); + private final Field field; + + private final BibEntry leftEntry; + + private final BibEntry rightEntry; + private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel(String leftValue, String rightValue) { - leftFieldValueProperty().set(leftValue); - rightFieldValueProperty().set(rightValue); - hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry) { + this.field = field; + this.leftEntry = leftEntry; + this.rightEntry = rightEntry; + + if (field.equals(InternalField.TYPE_HEADER)) { + setLeftFieldValue(leftEntry.getType().getDisplayName()); + setRightFieldValue(rightEntry.getType().getDisplayName()); + } else { + setLeftFieldValue(leftEntry.getField(field).orElse("")); + setRightFieldValue(rightEntry.getField(field).orElse("")); + } - if (StringUtil.isNullOrEmpty(leftValue)) { + hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); + + if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { selectRightValue(); } else { selectLeftValue(); @@ -140,7 +159,7 @@ public StringProperty leftFieldValueProperty() { return leftFieldValue; } - public void setLeftFieldValue(String leftFieldValue) { + private void setLeftFieldValue(String leftFieldValue) { this.leftFieldValue.set(leftFieldValue); } @@ -152,7 +171,15 @@ public StringProperty rightFieldValueProperty() { return rightFieldValue; } - public void setRightFieldValue(String rightFieldValue) { + private void setRightFieldValue(String rightFieldValue) { this.rightFieldValue.set(rightFieldValue); } + + public BibEntry getLeftEntry() { + return leftEntry; + } + + public BibEntry getRightEntry() { + return rightEntry; + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 93721d19745..a56098f7e30 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -149,17 +149,8 @@ private Field getFieldAtIndex(int index) { private void addFieldValues(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - String leftEntryValue; - String rightEntryValue; - if (field.equals(InternalField.TYPE_HEADER)) { - leftEntryValue = viewModel.getLeftEntry().getType().getDisplayName(); - rightEntryValue = viewModel.getRightEntry().getType().getDisplayName(); - } else { - leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); - rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); - } - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, leftEntryValue, rightEntryValue, fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { From 0b03f4652f35f34d122c26ce9064ac479c847993 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 19:31:07 +0100 Subject: [PATCH 144/473] Move merge/unmerge commands to ThreeFieldValuesView --- .../newmergedialog/ThreeFieldValuesView.java | 93 +++++++++++++++ .../ThreeFieldValuesViewModel.java | 4 + .../newmergedialog/ThreeWayMergeView.java | 107 ------------------ 3 files changed, 97 insertions(+), 107 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 3717a4068e8..45e432528b0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -1,19 +1,31 @@ package org.jabref.gui.mergeentries.newmergedialog; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.undo.CompoundEdit; + +import javafx.beans.binding.Bindings; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; +import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; @@ -33,6 +45,8 @@ public class ThreeFieldValuesView { private final ThreeFieldValuesViewModel viewModel; + private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, int rowIndex) { viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry); @@ -41,6 +55,13 @@ public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); + if (FieldNameCellFactory.isMergeableField(field)) { + MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; + mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell)); + mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + } + toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); mergedValueCell.textProperty().bindBidirectional(viewModel.mergedFieldValueProperty()); @@ -156,4 +177,76 @@ private boolean isRightValueCellHidden() { private ObjectProperty selectionProperty() { return viewModel.selectionProperty(); } + + public class MergeCommand extends SimpleCommand { + private final MergeableFieldCell groupsFieldNameCell; + + public MergeCommand(MergeableFieldCell groupsFieldCell) { + this.groupsFieldNameCell = groupsFieldCell; + + this.executable.bind(Bindings.createBooleanBinding(() -> { + String leftEntryGroups = viewModel.getLeftEntry().getField(viewModel.getField()).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(viewModel.getField()).orElse(""); + + return !leftEntryGroups.equals(rightEntryGroups); + })); + } + + @Override + public void execute() { + BibEntry leftEntry = viewModel.getLeftEntry(); + BibEntry rightEntry = viewModel.getRightEntry(); + + String leftEntryGroups = leftEntry.getField(viewModel.getField()).orElse(""); + String rightEntryGroups = rightEntry.getField(viewModel.getField()).orElse(""); + + assert !leftEntryGroups.equals(rightEntryGroups); + + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(viewModel.getField(), mergedGroups); + viewModel.getRightEntry().setField(viewModel.getField(), mergedGroups); + + if (fieldsMergedEdit.canRedo()) { + fieldsMergedEdit.redo(); + } else { + fieldsMergedEdit.addEdit(new UndoableFieldChange(leftEntry, viewModel.getField(), leftEntryGroups, mergedGroups)); + fieldsMergedEdit.addEdit(new UndoableFieldChange(rightEntry, viewModel.getField(), rightEntryGroups, mergedGroups)); + fieldsMergedEdit.end(); + } + + groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); + viewModel.setIsFieldsMerged(true); + } + + private String mergeLeftAndRightEntryGroups(String left, String right) { + if (StringUtil.isBlank(left)) { + return right; + } else if (StringUtil.isBlank(right)) { + return left; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); + leftGroups.addAll(rightGroups); + + return String.join(", ", leftGroups); + } + } + } + + public class UnmergeCommand extends SimpleCommand { + private final MergeableFieldCell groupsFieldCell; + + public UnmergeCommand(MergeableFieldCell groupsFieldCell) { + this.groupsFieldCell = groupsFieldCell; + } + + @Override + public void execute() { + if (fieldsMergedEdit.canUndo()) { + fieldsMergedEdit.undo(); + groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + viewModel.setIsFieldsMerged(false); + } + } + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index b8fe4bef004..6bb1f195e34 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -175,6 +175,10 @@ private void setRightFieldValue(String rightFieldValue) { this.rightFieldValue.set(rightFieldValue); } + public Field getField() { + return field; + } + public BibEntry getLeftEntry() { return leftEntry; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index a56098f7e30..5b6695bce0e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -1,14 +1,10 @@ package org.jabref.gui.mergeentries.newmergedialog; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; import javax.swing.undo.CompoundEdit; -import javafx.beans.binding.Bindings; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -17,28 +13,20 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.actions.SimpleCommand; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; -import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.EntryTypeFactory; -import org.jabref.model.strings.StringUtil; public class ThreeWayMergeView extends VBox { - public static final String GROUPS_SEPARATOR = ", "; public static final int GRID_COLUMN_MIN_WIDTH = 250; public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); public static final String RIGHT_DEFAULT_HEADER = Localization.lang("Right Entry"); - private static final int FIELD_NAME_COLUMN = 0; private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); private final ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); @@ -131,18 +119,6 @@ private void initializeMergeGridPane() { } } - private void addFieldName(Field field, int fieldIndex) { - FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, fieldIndex); - mergeGridPane.add(fieldNameCell, FIELD_NAME_COLUMN, fieldIndex); - - if (FieldNameCellFactory.isMergeableField(field)) { - MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setMergeCommand(new MergeGroupsCommand(mergeableFieldCell)); - mergeableFieldCell.setUnmergeCommand(new UnmergeGroupsCommand(mergeableFieldCell)); - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); - } - } - private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } @@ -172,17 +148,6 @@ private void addFieldValues(int fieldIndex) { mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } - private void updateFieldValues(int fieldIndex) { - removeFieldValues(fieldIndex); - addFieldValues(fieldIndex); - updateDiff(); - } - - private void removeFieldValues(int index) { - fieldValuesList.remove(index); - mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); - } - public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } @@ -222,76 +187,4 @@ public BibEntry getLeftEntry() { public BibEntry getRightEntry() { return viewModel.getRightEntry(); } - - public class MergeGroupsCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldNameCell; - - public MergeGroupsCommand(MergeableFieldCell groupsFieldCell) { - this.groupsFieldNameCell = groupsFieldCell; - - this.executable.bind(Bindings.createBooleanBinding(() -> { - String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - - return !leftEntryGroups.equals(rightEntryGroups); - })); - } - - @Override - public void execute() { - BibEntry leftEntry = viewModel.getLeftEntry(); - BibEntry rightEntry = viewModel.getRightEntry(); - - String leftEntryGroups = leftEntry.getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = rightEntry.getField(StandardField.GROUPS).orElse(""); - - assert !leftEntryGroups.equals(rightEntryGroups); - - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - - if (mergeGroupsEdit.canRedo()) { - mergeGroupsEdit.redo(); - } else { - mergeGroupsEdit.addEdit(new UndoableFieldChange(leftEntry, StandardField.GROUPS, leftEntryGroups, mergedGroups)); - mergeGroupsEdit.addEdit(new UndoableFieldChange(rightEntry, StandardField.GROUPS, rightEntryGroups, mergedGroups)); - mergeGroupsEdit.end(); - } - - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); - } - - private String mergeLeftAndRightEntryGroups(String left, String right) { - if (StringUtil.isBlank(left)) { - return right; - } else if (StringUtil.isBlank(right)) { - return left; - } else { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); - - return String.join(GROUPS_SEPARATOR, leftGroups); - } - } - } - - public class UnmergeGroupsCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldCell; - - public UnmergeGroupsCommand(MergeableFieldCell groupsFieldCell) { - this.groupsFieldCell = groupsFieldCell; - } - - @Override - public void execute() { - if (mergeGroupsEdit.canUndo()) { - mergeGroupsEdit.undo(); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); - } - } - } } From c297a48a7c4135abc709fd61c9676ae36b99ee5a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:38:49 +0100 Subject: [PATCH 145/473] Bind field value cell text property --- .../gui/mergeentries/newmergedialog/cell/FieldValueCell.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index f31639ccc25..4019c8f9a21 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -100,7 +100,7 @@ private void initialize() { private void initializeLabel() { label.setEditable(false); label.setBackground(Background.fill(Color.TRANSPARENT)); - label.appendText(textProperty().get()); + EasyBind.subscribe(textProperty(), label::replaceText); label.setAutoHeight(true); label.setWrapText(true); label.setStyle("-fx-cursor: hand"); From d2782224b38541fa7c648d16e6c120d4c2c4785d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:45:05 +0100 Subject: [PATCH 146/473] Create an undoable edit for undoing fields merging --- .../newmergedialog/ThreeFieldValuesView.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 45e432528b0..654c17e64b8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -5,6 +5,9 @@ import java.util.List; import java.util.Set; +import javax.swing.undo.AbstractUndoableEdit; +import javax.swing.undo.CannotRedoException; +import javax.swing.undo.CannotUndoException; import javax.swing.undo.CompoundEdit; import javafx.beans.binding.Bindings; @@ -249,4 +252,30 @@ public void execute() { } } } + + class MergeFieldsUndo extends AbstractUndoableEdit { + private final String oldLeft; + private final String oldRight; + private final String mergedFields; + + MergeFieldsUndo(String oldLeft, String oldRight, String mergedFields) { + this.oldLeft = oldLeft; + this.oldRight = oldRight; + this.mergedFields = mergedFields; + } + + @Override + public void undo() throws CannotUndoException { + super.undo(); + viewModel.setLeftFieldValue(oldLeft); + viewModel.setRightFieldValue(oldRight); + } + + @Override + public void redo() throws CannotRedoException { + super.redo(); + viewModel.setLeftFieldValue(mergedFields); + viewModel.setRightFieldValue(mergedFields); + } + } } From 1cadb8d135bb7bb6c8e7c0c7bed3864340f10f63 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:48:36 +0100 Subject: [PATCH 147/473] Update bib entries when left and right field value properties change --- .../newmergedialog/ThreeFieldValuesViewModel.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 6bb1f195e34..28fbe18d062 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -57,6 +57,9 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right setRightFieldValue(rightEntry.getField(field).orElse("")); } + EasyBind.listen(leftFieldValueProperty(), (obs, old, leftValue) -> leftEntry.setField(field, leftValue)); + EasyBind.listen(rightFieldValueProperty(), (obs, old, rightValue) -> rightEntry.setField(field, rightValue)); + hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { @@ -67,8 +70,8 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right EasyBind.subscribe(selectionProperty(), selection -> { switch (selection) { - case LEFT -> setMergedFieldValue(getLeftFieldValue()); - case RIGHT -> setMergedFieldValue(getRightFieldValue()); + case LEFT -> mergedFieldValueProperty().bind(leftFieldValueProperty()); + case RIGHT -> mergedFieldValueProperty().bind(rightFieldValueProperty()); } }); @@ -159,7 +162,7 @@ public StringProperty leftFieldValueProperty() { return leftFieldValue; } - private void setLeftFieldValue(String leftFieldValue) { + public void setLeftFieldValue(String leftFieldValue) { this.leftFieldValue.set(leftFieldValue); } @@ -171,7 +174,7 @@ public StringProperty rightFieldValueProperty() { return rightFieldValue; } - private void setRightFieldValue(String rightFieldValue) { + public void setRightFieldValue(String rightFieldValue) { this.rightFieldValue.set(rightFieldValue); } From 6258b6ded16a00bac4eb02f9e8b748dbcc04edb3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:49:16 +0100 Subject: [PATCH 148/473] Update left and right field value properties when merging fields rather than the bib entries --- .../newmergedialog/ThreeFieldValuesView.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 654c17e64b8..00967908671 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -25,7 +25,6 @@ import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; @@ -197,23 +196,19 @@ public MergeCommand(MergeableFieldCell groupsFieldCell) { @Override public void execute() { - BibEntry leftEntry = viewModel.getLeftEntry(); - BibEntry rightEntry = viewModel.getRightEntry(); + assert !viewModel.getLeftFieldValue().equals(viewModel.getRightFieldValue()); - String leftEntryGroups = leftEntry.getField(viewModel.getField()).orElse(""); - String rightEntryGroups = rightEntry.getField(viewModel.getField()).orElse(""); + String oldLeftFieldValue = viewModel.getLeftFieldValue(); + String oldRightFieldValue = viewModel.getRightFieldValue(); - assert !leftEntryGroups.equals(rightEntryGroups); - - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(viewModel.getField(), mergedGroups); - viewModel.getRightEntry().setField(viewModel.getField(), mergedGroups); + String mergedGroups = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); + viewModel.setLeftFieldValue(mergedGroups); + viewModel.setRightFieldValue(mergedGroups); if (fieldsMergedEdit.canRedo()) { fieldsMergedEdit.redo(); } else { - fieldsMergedEdit.addEdit(new UndoableFieldChange(leftEntry, viewModel.getField(), leftEntryGroups, mergedGroups)); - fieldsMergedEdit.addEdit(new UndoableFieldChange(rightEntry, viewModel.getField(), rightEntryGroups, mergedGroups)); + fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedGroups)); fieldsMergedEdit.end(); } From aabf394ea04867629ef2e058c97a513bb889b802 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:58:35 +0100 Subject: [PATCH 149/473] Unbind MergedFieldValue property because it can't be edited when bound --- .../newmergedialog/ThreeFieldValuesViewModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 28fbe18d062..15bb5981b82 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -70,8 +70,8 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right EasyBind.subscribe(selectionProperty(), selection -> { switch (selection) { - case LEFT -> mergedFieldValueProperty().bind(leftFieldValueProperty()); - case RIGHT -> mergedFieldValueProperty().bind(rightFieldValueProperty()); + case LEFT -> EasyBind.subscribe(leftFieldValueProperty(), this::setMergedFieldValue); + case RIGHT -> EasyBind.subscribe(rightFieldValueProperty(), this::setMergedFieldValue); } }); From 0b1977a3f0d9e46be0cc0fe0feb2ab808213be7f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 23:01:18 +0100 Subject: [PATCH 150/473] Cleanup --- .../newmergedialog/ThreeFieldValuesView.java | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 00967908671..12898acf3af 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -11,7 +11,6 @@ import javax.swing.undo.CompoundEdit; import javafx.beans.binding.Bindings; -import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; @@ -40,7 +39,7 @@ public class ThreeFieldValuesView { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; - private FieldValueCell rightValueCell; + private final FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; private final ToggleGroup toggleGroup = new ToggleGroup(); @@ -138,12 +137,8 @@ public MergedFieldCell getMergedValueCell() { return mergedValueCell; } - public boolean hasEqualLeftAndRightValues() { - return viewModel.hasEqualLeftAndRightValues(); - } - public void showDiff(ShowDiffConfig diffConfig) { - if (isRightValueCellHidden()) { + if (!rightValueCell.isVisible()) { return; } @@ -159,7 +154,7 @@ public void showDiff(ShowDiffConfig diffConfig) { } public void hideDiff() { - if (isRightValueCellHidden()) { + if (!rightValueCell.isVisible()) { return; } @@ -172,14 +167,6 @@ public void hideDiff() { getRightValueCell().getStyleClassedLabel().replaceText(viewModel.getRightFieldValue()); } - private boolean isRightValueCellHidden() { - return rightValueCell == null; - } - - private ObjectProperty selectionProperty() { - return viewModel.selectionProperty(); - } - public class MergeCommand extends SimpleCommand { private final MergeableFieldCell groupsFieldNameCell; @@ -201,19 +188,18 @@ public void execute() { String oldLeftFieldValue = viewModel.getLeftFieldValue(); String oldRightFieldValue = viewModel.getRightFieldValue(); - String mergedGroups = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); - viewModel.setLeftFieldValue(mergedGroups); - viewModel.setRightFieldValue(mergedGroups); + String mergedFields = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); + viewModel.setLeftFieldValue(mergedFields); + viewModel.setRightFieldValue(mergedFields); if (fieldsMergedEdit.canRedo()) { fieldsMergedEdit.redo(); } else { - fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedGroups)); + fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedFields)); fieldsMergedEdit.end(); } groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); - viewModel.setIsFieldsMerged(true); } private String mergeLeftAndRightEntryGroups(String left, String right) { @@ -243,7 +229,6 @@ public void execute() { if (fieldsMergedEdit.canUndo()) { fieldsMergedEdit.undo(); groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); - viewModel.setIsFieldsMerged(false); } } } From 21fbde28d998f13f5d03558dfa829b0da1693462 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 23:09:29 +0100 Subject: [PATCH 151/473] Move merged entry update logic to ThreeFieldValuesViewModel --- .../newmergedialog/ThreeFieldValuesView.java | 4 ++-- .../ThreeFieldValuesViewModel.java | 17 ++++++++++++++++- .../newmergedialog/ThreeWayMergeView.java | 18 ++---------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 12898acf3af..54f264cfd7d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -48,8 +48,8 @@ public class ThreeFieldValuesView { private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); - public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, int rowIndex) { - viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry); + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, int rowIndex) { + viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry, mergedEntry); fieldNameCell = FieldNameCellFactory.create(field, rowIndex); leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 15bb5981b82..5a88a9ec447 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -12,6 +12,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; +import org.jabref.model.entry.types.EntryTypeFactory; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -42,12 +43,15 @@ public enum Selection { private final BibEntry rightEntry; + private final BibEntry mergedEntry; + private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry) { + public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry) { this.field = field; this.leftEntry = leftEntry; this.rightEntry = rightEntry; + this.mergedEntry = mergedEntry; if (field.equals(InternalField.TYPE_HEADER)) { setLeftFieldValue(leftEntry.getType().getDisplayName()); @@ -59,6 +63,13 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right EasyBind.listen(leftFieldValueProperty(), (obs, old, leftValue) -> leftEntry.setField(field, leftValue)); EasyBind.listen(rightFieldValueProperty(), (obs, old, rightValue) -> rightEntry.setField(field, rightValue)); + EasyBind.listen(mergedFieldValueProperty(), (obs, old, mergedFieldValue) -> { + if (field.equals(InternalField.TYPE_HEADER)) { + getMergedEntry().setType(EntryTypeFactory.parse(mergedFieldValue)); + } else { + getMergedEntry().setField(field, mergedFieldValue); + } + }); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); @@ -189,4 +200,8 @@ public BibEntry getLeftEntry() { public BibEntry getRightEntry() { return rightEntry; } + + public BibEntry getMergedEntry() { + return mergedEntry; + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 5b6695bce0e..85475213092 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -17,9 +17,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.field.StandardField; -import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; @@ -126,21 +124,9 @@ private Field getFieldAtIndex(int index) { private void addFieldValues(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), fieldIndex); - fieldValuesList.add(fieldIndex, fieldValues); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldIndex); - fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { - if (field.equals(InternalField.TYPE_HEADER)) { - getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); - } else { - getMergedEntry().setField(field, mergedValue); - } - }); - if (field.equals(InternalField.TYPE_HEADER)) { - getMergedEntry().setType(EntryTypeFactory.parse(fieldValues.getMergedValue())); - } else { - getMergedEntry().setField(field, fieldValues.getMergedValue()); - } + fieldValuesList.add(fieldIndex, fieldValues); mergeGridPane.add(fieldValues.getFieldNameCell(), 0, fieldIndex); mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); From 027c684eee8a863d04847aac4cca9f51e5f7de7c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:21:56 +0100 Subject: [PATCH 152/473] Implement algorithms for merging groups and keywords --- .../fieldsmerger/FieldMerger.java | 9 +++++ .../fieldsmerger/FieldMergerFactory.java | 23 +++++++++++ .../fieldsmerger/GroupMerger.java | 29 ++++++++++++++ .../fieldsmerger/KeywordMerger.java | 38 +++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java new file mode 100644 index 00000000000..8119a892abb --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java @@ -0,0 +1,9 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +/** + * This class is responsible for taking two values for some field and merging them to into one value + * */ +@FunctionalInterface +public interface FieldMerger { + String merge(String fieldValueA, String fieldValueB); +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java new file mode 100644 index 00000000000..d5da07e06e7 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -0,0 +1,23 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.StandardField; +import org.jabref.preferences.PreferencesService; + +public class FieldMergerFactory { + private final PreferencesService preferencesService; + + public FieldMergerFactory(PreferencesService preferencesService) { + this.preferencesService = preferencesService; + } + + public FieldMerger create(Field field) { + if (field.equals(StandardField.GROUPS)) { + return new GroupMerger(); + } else if (field.equals(StandardField.KEYWORDS)) { + return new KeywordMerger(preferencesService); + } else { + throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); + } + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java new file mode 100644 index 00000000000..e6580b948d0 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java @@ -0,0 +1,29 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jabref.model.strings.StringUtil; + +public class GroupMerger implements FieldMerger { + public static final String GROUPS_SEPARATOR = ", "; + + @Override + public String merge(String groupsA, String groupsB) { + if (StringUtil.isBlank(groupsA) && StringUtil.isBlank(groupsB)) { + return ""; + } else if (StringUtil.isBlank(groupsA)) { + return groupsB; + } else if (StringUtil.isBlank(groupsB)) { + return groupsA; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(groupsA.split(GROUPS_SEPARATOR)).toList()); + List rightGroups = Arrays.stream(groupsB.split(GROUPS_SEPARATOR)).toList(); + leftGroups.addAll(rightGroups); + + return String.join(GROUPS_SEPARATOR, leftGroups); + } + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java new file mode 100644 index 00000000000..6535a2774f9 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -0,0 +1,38 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.jabref.model.strings.StringUtil; +import org.jabref.preferences.PreferencesService; + +public class KeywordMerger implements FieldMerger { + private final PreferencesService preferencesService; + + public KeywordMerger(PreferencesService preferencesService) { + Objects.requireNonNull(preferencesService); + this.preferencesService = preferencesService; + } + + @Override + public String merge(String keywordsA, String keywordsB) { + String keywordSeparator = " " + preferencesService.getGroupsPreferences().getKeywordSeparator(); + + if (StringUtil.isBlank(keywordsA) && StringUtil.isBlank(keywordsB)) { + return ""; + } else if (StringUtil.isBlank(keywordsA)) { + return keywordsB; + } else if (StringUtil.isBlank(keywordsB)) { + return keywordsA; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); + List rightGroups = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); + leftGroups.addAll(rightGroups); + + return String.join(keywordSeparator, leftGroups); + } + } +} From ca158e708c28ef9f92fac5d356f2c95bcd196c99 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:30:18 +0100 Subject: [PATCH 153/473] Pass FieldMergerFactory to ThreeFieldValuesView --- .../newmergedialog/ThreeFieldValuesView.java | 32 +++++-------------- .../newmergedialog/ThreeWayMergeView.java | 8 ++++- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 54f264cfd7d..a7fb369a0b6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -1,10 +1,5 @@ package org.jabref.gui.mergeentries.newmergedialog; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; @@ -23,10 +18,11 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMerger; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; @@ -48,7 +44,7 @@ public class ThreeFieldValuesView { private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); - public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, int rowIndex) { + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry, mergedEntry); fieldNameCell = FieldNameCellFactory.create(field, rowIndex); @@ -58,7 +54,7 @@ public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry if (FieldNameCellFactory.isMergeableField(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell)); + mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field))); mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } @@ -169,9 +165,11 @@ public void hideDiff() { public class MergeCommand extends SimpleCommand { private final MergeableFieldCell groupsFieldNameCell; + private final FieldMerger fieldMerger; - public MergeCommand(MergeableFieldCell groupsFieldCell) { + public MergeCommand(MergeableFieldCell groupsFieldCell, FieldMerger fieldMerger) { this.groupsFieldNameCell = groupsFieldCell; + this.fieldMerger = fieldMerger; this.executable.bind(Bindings.createBooleanBinding(() -> { String leftEntryGroups = viewModel.getLeftEntry().getField(viewModel.getField()).orElse(""); @@ -188,7 +186,7 @@ public void execute() { String oldLeftFieldValue = viewModel.getLeftFieldValue(); String oldRightFieldValue = viewModel.getRightFieldValue(); - String mergedFields = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); + String mergedFields = fieldMerger.merge(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); viewModel.setLeftFieldValue(mergedFields); viewModel.setRightFieldValue(mergedFields); @@ -201,20 +199,6 @@ public void execute() { groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } - - private String mergeLeftAndRightEntryGroups(String left, String right) { - if (StringUtil.isBlank(left)) { - return right; - } else if (StringUtil.isBlank(right)) { - return left; - } else { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); - - return String.join(", ", leftGroups); - } - } } public class UnmergeCommand extends SimpleCommand { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 85475213092..26f2068824b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -13,6 +13,8 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.Globals; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -39,9 +41,13 @@ public class ThreeWayMergeView extends VBox { private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); + private final FieldMergerFactory fieldMergerFactory; + public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); viewModel = new ThreeWayMergeViewModel((BibEntry) leftEntry.clone(), (BibEntry) rightEntry.clone(), leftHeader, rightHeader); + // TODO: Inject 'preferenceService' into the constructor + this.fieldMergerFactory = new FieldMergerFactory(Globals.prefs); mergeGridPane = new GridPane(); scrollPane = new ScrollPane(); @@ -124,7 +130,7 @@ private Field getFieldAtIndex(int index) { private void addFieldValues(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldMergerFactory, fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); From fd1f229a4e20219574d1046fe57fc41ce852fb07 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:34:08 +0100 Subject: [PATCH 154/473] Move isMergeableField method to FieldMergerFactory --- .../newmergedialog/ThreeFieldValuesView.java | 2 +- .../newmergedialog/cell/FieldNameCellFactory.java | 9 ++------- .../newmergedialog/fieldsmerger/FieldMergerFactory.java | 4 ++++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index a7fb369a0b6..fa9a31183ad 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -52,7 +52,7 @@ public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); - if (FieldNameCellFactory.isMergeableField(field)) { + if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field))); mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index b30245014f4..ee038e53eca 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -1,16 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.StandardField; public class FieldNameCellFactory { - - public static boolean isMergeableField(Field field) { - return field == StandardField.GROUPS; - } - public static FieldNameCell create(Field field, int rowIndex) { - if (isMergeableField(field)) { + if (FieldMergerFactory.canMerge(field)) { return new MergeableFieldCell(field, rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java index d5da07e06e7..63777a514fb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -20,4 +20,8 @@ public FieldMerger create(Field field) { throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); } } + + public static boolean canMerge(Field field) { + return field == StandardField.GROUPS || field == StandardField.KEYWORDS; + } } From 2dcc8993656596dc18051b2945c9abedc5d6b426 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:35:31 +0100 Subject: [PATCH 155/473] Delete cancelGroupsEdit() --- .../gui/duplicationFinder/DuplicateResolverDialog.java | 1 - .../jabref/gui/mergeentries/MergeEntriesDialog.java | 1 - .../mergeentries/newmergedialog/ThreeWayMergeView.java | 10 ---------- 3 files changed, 12 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index d3c70e06bfe..6a89a239500 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -127,7 +127,6 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { } else if (button.equals(removeExact)) { return DuplicateResolverResult.AUTOREMOVE_EXACT; } - threeWayMerge.cancelGroupsMerge(); return null; }); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index adaea1a0c46..a93598494b0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -33,7 +33,6 @@ private void init() { if (buttonType.equals(replaceEntries)) { return new MergeResult(threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); } else { - threeWayMergeView.cancelGroupsMerge(); return null; } }); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 26f2068824b..0b1f01a6803 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.List; -import javax.swing.undo.CompoundEdit; - import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -39,8 +37,6 @@ public class ThreeWayMergeView extends VBox { private final ThreeWayMergeViewModel viewModel; private final List fieldValuesList = new ArrayList<>(); - private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); - private final FieldMergerFactory fieldMergerFactory; public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { @@ -166,12 +162,6 @@ public void showDiff(ShowDiffConfig diffConfig) { toolbar.setShowDiff(true); } - public void cancelGroupsMerge() { - if (mergeGroupsEdit.canUndo()) { - mergeGroupsEdit.undo(); - } - } - public BibEntry getLeftEntry() { return viewModel.getLeftEntry(); } From ef072f75d45c72c7e96d2a18e5a08d530dbe1e59 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:47:55 +0100 Subject: [PATCH 156/473] Fix KeywordMerger implementation --- .../newmergedialog/fieldsmerger/KeywordMerger.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java index 6535a2774f9..af73dab692a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -19,7 +19,7 @@ public KeywordMerger(PreferencesService preferencesService) { @Override public String merge(String keywordsA, String keywordsB) { - String keywordSeparator = " " + preferencesService.getGroupsPreferences().getKeywordSeparator(); + String keywordSeparator = preferencesService.getGroupsPreferences().getKeywordSeparator() + " "; if (StringUtil.isBlank(keywordsA) && StringUtil.isBlank(keywordsB)) { return ""; @@ -28,11 +28,11 @@ public String merge(String keywordsA, String keywordsB) { } else if (StringUtil.isBlank(keywordsB)) { return keywordsA; } else { - Set leftGroups = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); - List rightGroups = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); - leftGroups.addAll(rightGroups); + Set keywordsASet = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); + List keywordsBList = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); + keywordsASet.addAll(keywordsBList); - return String.join(keywordSeparator, leftGroups); + return String.join(keywordSeparator, keywordsASet); } } } From 63650792977eb8e1f9ef757686c7f89a798ac9d1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:04:51 +0100 Subject: [PATCH 157/473] Fix a bug that deselects both fields after they are unmerged --- .../newmergedialog/ThreeFieldValuesViewModel.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 5a88a9ec447..17ae31b0eee 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -100,9 +100,7 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right } public boolean hasEqualLeftAndRightValues() { - return (!StringUtil.isNullOrEmpty(leftFieldValue.get()) && - !StringUtil.isNullOrEmpty(rightFieldValue.get()) && - leftFieldValue.get().equals(rightFieldValue.get())); + return leftFieldValue.get().equals(rightFieldValue.get()); } public void selectLeftValue() { From d276e4bd970e5c78d32ff7942de99ae04a898f44 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:16:22 +0100 Subject: [PATCH 158/473] Rename 'ThreeFieldValues' to 'FieldRow' --- ...FieldValuesView.java => FieldRowView.java} | 10 +++---- ...sViewModel.java => FieldRowViewModel.java} | 4 +-- .../newmergedialog/ThreeWayMergeView.java | 26 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ThreeFieldValuesView.java => FieldRowView.java} (95%) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ThreeFieldValuesViewModel.java => FieldRowViewModel.java} (97%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java similarity index 95% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index fa9a31183ad..75fda80810c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -27,12 +27,12 @@ import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; -import static org.jabref.gui.mergeentries.newmergedialog.ThreeFieldValuesViewModel.Selection; +import static org.jabref.gui.mergeentries.newmergedialog.FieldRowViewModel.Selection; /** * A controller class to control left, right and merged field values */ -public class ThreeFieldValuesView { +public class FieldRowView { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private final FieldValueCell rightValueCell; @@ -40,12 +40,12 @@ public class ThreeFieldValuesView { private final ToggleGroup toggleGroup = new ToggleGroup(); - private final ThreeFieldValuesViewModel viewModel; + private final FieldRowViewModel viewModel; private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); - public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { - viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry, mergedEntry); + public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { + viewModel = new FieldRowViewModel(field, leftEntry, rightEntry, mergedEntry); fieldNameCell = FieldNameCellFactory.create(field, rowIndex); leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java similarity index 97% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java index 17ae31b0eee..94959d8a1fb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java @@ -17,7 +17,7 @@ import com.tobiasdiez.easybind.EasyBind; -public class ThreeFieldValuesViewModel { +public class FieldRowViewModel { public enum Selection { LEFT, RIGHT, @@ -47,7 +47,7 @@ public enum Selection { private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry) { + public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry) { this.field = field; this.leftEntry = leftEntry; this.rightEntry = rightEntry; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 0b1f01a6803..b417bf2ca0a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -35,7 +35,7 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List fieldValuesList = new ArrayList<>(); + private final List fieldRows = new ArrayList<>(); private final FieldMergerFactory fieldMergerFactory; @@ -77,9 +77,9 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - fieldValuesList.forEach(fieldValues -> fieldValues.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); + fieldRows.forEach(row -> row.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - fieldValuesList.forEach(ThreeFieldValuesView::hideDiff); + fieldRows.forEach(FieldRowView::hideDiff); } } @@ -108,7 +108,7 @@ private void initializeMergeGridPane() { for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { // addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); - addFieldValues(fieldIndex); + addRow(fieldIndex); // Removing this will cause UI to lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { @@ -123,17 +123,17 @@ private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } - private void addFieldValues(int fieldIndex) { + private void addRow(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldMergerFactory, fieldIndex); + FieldRowView fieldRow = new FieldRowView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldMergerFactory, fieldIndex); - fieldValuesList.add(fieldIndex, fieldValues); + fieldRows.add(fieldIndex, fieldRow); - mergeGridPane.add(fieldValues.getFieldNameCell(), 0, fieldIndex); - mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); - mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); - mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); + mergeGridPane.add(fieldRow.getFieldNameCell(), 0, fieldIndex); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldRow.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); } public BibEntry getMergedEntry() { @@ -149,11 +149,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - fieldValuesList.forEach(ThreeFieldValuesView::selectLeftValue); + fieldRows.forEach(FieldRowView::selectLeftValue); } public void selectRightEntryValues() { - fieldValuesList.forEach(ThreeFieldValuesView::selectRightValue); + fieldRows.forEach(FieldRowView::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 25389662bab494d87785d56b5c772cc65763524e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:17:49 +0100 Subject: [PATCH 159/473] Cleanup --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index b417bf2ca0a..a61833456f8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -17,7 +17,6 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.StandardField; public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; @@ -107,15 +106,9 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - // addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addRow(fieldIndex); - // Removing this will cause UI to lag when updating field values - if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { - mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, Double.MAX_VALUE)); - } else { - mergeGridPane.getRowConstraints().add(new RowConstraints()); - } + mergeGridPane.getRowConstraints().add(new RowConstraints()); } } From 6386e9f66d1fddc465679a0957646779a5445640 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:21:05 +0100 Subject: [PATCH 160/473] Hide diffs when both values are equal --- .../gui/mergeentries/newmergedialog/FieldRowView.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 75fda80810c..a7a09631e90 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -95,6 +95,12 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt GridPane.setColumnSpan(leftValueCell, 1); } }); + + EasyBind.listen(viewModel.hasEqualLeftAndRightBinding(), (obs, old, isEqual) -> { + if (isEqual) { + hideDiff(); + } + }); } public void selectLeftValue() { From 0cff22feb3c55928a4c97efa8c7a3cb4e77a401c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 15:54:27 +0100 Subject: [PATCH 161/473] Fix typos --- .../newmergedialog/FieldRowView.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index a7a09631e90..0e1b62b91a4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -5,7 +5,6 @@ import javax.swing.undo.CannotUndoException; import javax.swing.undo.CompoundEdit; -import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; @@ -170,19 +169,14 @@ public void hideDiff() { } public class MergeCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldNameCell; + private final MergeableFieldCell mergeableFieldCell; private final FieldMerger fieldMerger; - public MergeCommand(MergeableFieldCell groupsFieldCell, FieldMerger fieldMerger) { - this.groupsFieldNameCell = groupsFieldCell; + public MergeCommand(MergeableFieldCell mergeableFieldCell, FieldMerger fieldMerger) { + this.mergeableFieldCell = mergeableFieldCell; this.fieldMerger = fieldMerger; - this.executable.bind(Bindings.createBooleanBinding(() -> { - String leftEntryGroups = viewModel.getLeftEntry().getField(viewModel.getField()).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(viewModel.getField()).orElse(""); - - return !leftEntryGroups.equals(rightEntryGroups); - })); + this.executable.bind(viewModel.hasEqualLeftAndRightBinding().not()); } @Override @@ -203,22 +197,22 @@ public void execute() { fieldsMergedEdit.end(); } - groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } } public class UnmergeCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldCell; + private final MergeableFieldCell mergeableFieldCell; - public UnmergeCommand(MergeableFieldCell groupsFieldCell) { - this.groupsFieldCell = groupsFieldCell; + public UnmergeCommand(MergeableFieldCell mergeableFieldCell) { + this.mergeableFieldCell = mergeableFieldCell; } @Override public void execute() { if (fieldsMergedEdit.canUndo()) { fieldsMergedEdit.undo(); - groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } } From 586d979fc06aeadce7a17404dee50087dadf1916 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 16:01:48 +0100 Subject: [PATCH 162/473] Select LEFT value after merging fields --- .../newmergedialog/FieldRowViewModel.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java index 94959d8a1fb..2fc07acd282 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java @@ -73,11 +73,15 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); - if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { - selectRightValue(); - } else { - selectLeftValue(); - } + selectNonEmptyValue(); + + EasyBind.listen(isFieldsMergedProperty(), (obs, old, areFieldsMerged) -> { + if (areFieldsMerged) { + selectLeftValue(); + } else { + selectNonEmptyValue(); + } + }); EasyBind.subscribe(selectionProperty(), selection -> { switch (selection) { @@ -99,6 +103,14 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B EasyBind.subscribe(hasEqualLeftAndRightBinding(), this::setIsFieldsMerged); } + public void selectNonEmptyValue() { + if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { + selectRightValue(); + } else { + selectLeftValue(); + } + } + public boolean hasEqualLeftAndRightValues() { return leftFieldValue.get().equals(rightFieldValue.get()); } From 47555ad0ee4241ac4565de2ce3f30a2eb7e70065 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 17:12:01 +0100 Subject: [PATCH 163/473] Logging --- .../gui/mergeentries/newmergedialog/FieldRowViewModel.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java index 2fc07acd282..06356de4177 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java @@ -16,6 +16,8 @@ import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FieldRowViewModel { public enum Selection { @@ -28,7 +30,7 @@ public enum Selection { NONE } - + private final Logger LOGGER = LoggerFactory.getLogger(FieldRowViewModel.class); private final BooleanProperty isFieldsMerged = new SimpleBooleanProperty(Boolean.FALSE); private final ObjectProperty selection = new SimpleObjectProperty<>(); @@ -76,6 +78,7 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B selectNonEmptyValue(); EasyBind.listen(isFieldsMergedProperty(), (obs, old, areFieldsMerged) -> { + LOGGER.debug("Field are merged: {}", areFieldsMerged); if (areFieldsMerged) { selectLeftValue(); } else { @@ -84,6 +87,7 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B }); EasyBind.subscribe(selectionProperty(), selection -> { + LOGGER.debug("Selecting {}' value for field {}", selection, field.getDisplayName()); switch (selection) { case LEFT -> EasyBind.subscribe(leftFieldValueProperty(), this::setMergedFieldValue); case RIGHT -> EasyBind.subscribe(rightFieldValueProperty(), this::setMergedFieldValue); @@ -91,6 +95,7 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B }); EasyBind.subscribe(mergedFieldValueProperty(), mergedValue -> { + LOGGER.debug("Merged value is {} for field {}", mergedValue, field.getDisplayName()); if (mergedValue.equals(getLeftFieldValue())) { selectLeftValue(); } else if (getMergedFieldValue().equals(getRightFieldValue())) { From ee75326a74cd94e6b7d5c14596e7538c408b023f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 19:56:57 +0100 Subject: [PATCH 164/473] Implement merging comments --- .../newmergedialog/fieldsmerger/CommentMerger.java | 10 ++++++++++ .../fieldsmerger/FieldMergerFactory.java | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java new file mode 100644 index 00000000000..5599bfb2470 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java @@ -0,0 +1,10 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import org.jabref.logic.util.OS; + +public class CommentMerger implements FieldMerger { + @Override + public String merge(String fieldValueA, String fieldValueB) { + return fieldValueA + OS.NEWLINE + fieldValueB; + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java index 63777a514fb..e794830ba26 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -16,12 +16,14 @@ public FieldMerger create(Field field) { return new GroupMerger(); } else if (field.equals(StandardField.KEYWORDS)) { return new KeywordMerger(preferencesService); + } else if (field == StandardField.COMMENT) { + return new CommentMerger(); } else { throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); } } public static boolean canMerge(Field field) { - return field == StandardField.GROUPS || field == StandardField.KEYWORDS; + return field == StandardField.GROUPS || field == StandardField.KEYWORDS || field == StandardField.COMMENT; } } From a05cc7f54a65d353b1c31df1f9616a0533b1152a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 19:57:28 +0100 Subject: [PATCH 165/473] Improve groups and keywords merger implementation --- .../newmergedialog/fieldsmerger/GroupMerger.java | 12 ++++-------- .../newmergedialog/fieldsmerger/KeywordMerger.java | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java index e6580b948d0..8af126aac61 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java @@ -1,9 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.stream.Collectors; import org.jabref.model.strings.StringUtil; @@ -19,11 +17,9 @@ public String merge(String groupsA, String groupsB) { } else if (StringUtil.isBlank(groupsB)) { return groupsA; } else { - Set leftGroups = new HashSet<>(Arrays.stream(groupsA.split(GROUPS_SEPARATOR)).toList()); - List rightGroups = Arrays.stream(groupsB.split(GROUPS_SEPARATOR)).toList(); - leftGroups.addAll(rightGroups); - - return String.join(GROUPS_SEPARATOR, leftGroups); + return Arrays.stream((groupsA + GROUPS_SEPARATOR + groupsB).split(GROUPS_SEPARATOR)) + .distinct() + .collect(Collectors.joining(GROUPS_SEPARATOR)); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java index af73dab692a..62b5ca2bb11 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -1,10 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; import java.util.Objects; -import java.util.Set; +import java.util.stream.Collectors; import org.jabref.model.strings.StringUtil; import org.jabref.preferences.PreferencesService; @@ -28,11 +26,9 @@ public String merge(String keywordsA, String keywordsB) { } else if (StringUtil.isBlank(keywordsB)) { return keywordsA; } else { - Set keywordsASet = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); - List keywordsBList = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); - keywordsASet.addAll(keywordsBList); - - return String.join(keywordSeparator, keywordsASet); + return Arrays.stream((keywordsA + keywordSeparator + keywordsB).split(keywordSeparator)) + .distinct() + .collect(Collectors.joining(keywordSeparator)); } } } From 5844d5d9e9d3b5ca4be4d46cec8dcbcfb18e5dc4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 22 Jul 2022 16:03:29 +0100 Subject: [PATCH 166/473] Change merge/unmerge buttons tooltip text based on the field to merge --- .../mergeentries/newmergedialog/cell/MergeableFieldCell.java | 4 ++-- src/main/resources/l10n/JabRef_en.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 519c65d50ad..d9cab3a38ed 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -19,9 +19,9 @@ public MergeableFieldCell(Field field, int rowIndex) { super(field.getDisplayName(), rowIndex); mergeActionProperty().addListener((obs, old, newValue) -> { if (newValue == MergeAction.MERGE) { - setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); + setAction(Localization.lang("Merge %0", field.getDisplayName()), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); } else { - setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeCommand); + setAction(Localization.lang("Unmerge %0", field.getDisplayName()), IconTheme.JabRefIcons.UNDO, unmergeCommand); } }); } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 141f369f35d..5ae7dae2bab 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2513,5 +2513,5 @@ Merged\ Entry=Merged Entry Assign=Assign Do\ not\ assign=Do not assign -Merge\ Groups=Merge Groups -Unmerge\ Groups=Unmerge Groups +Merge\ %0=Merge %0 +Unmerge\ %0=Unmerge %0 From ea55d424df44e95be29badafa1f0376d3baf5084 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 12:13:44 +0100 Subject: [PATCH 167/473] Implement file merging --- .../fieldsmerger/FieldMergerFactory.java | 4 ++- .../fieldsmerger/FileMerger.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java index e794830ba26..3c275dfcb7d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -18,12 +18,14 @@ public FieldMerger create(Field field) { return new KeywordMerger(preferencesService); } else if (field == StandardField.COMMENT) { return new CommentMerger(); + } else if (field == StandardField.FILE) { + return new FileMerger(); } else { throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); } } public static boolean canMerge(Field field) { - return field == StandardField.GROUPS || field == StandardField.KEYWORDS || field == StandardField.COMMENT; + return field == StandardField.GROUPS || field == StandardField.KEYWORDS || field == StandardField.COMMENT || field == StandardField.FILE; } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java new file mode 100644 index 00000000000..c8fb940870b --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java @@ -0,0 +1,29 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.jabref.logic.importer.util.FileFieldParser; +import org.jabref.model.entry.LinkedFile; +import org.jabref.model.strings.StringUtil; + +public class FileMerger implements FieldMerger { + @Override + public String merge(String filesA, String filesB) { + if (StringUtil.isBlank(filesA + filesB)) { + return ""; + } else if (StringUtil.isBlank(filesA)) { + return filesB; + } else if (StringUtil.isBlank(filesB)) { + return filesA; + } else { + List linkedFilesA = FileFieldParser.parse(filesA); + List linkedFilesB = FileFieldParser.parse(filesB); + // TODO: If one of the linked files list is empty then the its string value is malformed. + return Stream.concat(linkedFilesA.stream(), linkedFilesB.stream()) + .map(LinkedFile::getLink) + .collect(Collectors.joining(";")); + } + } +} From f6a281aebbac8408c7db7290b327b94f52f2ab29 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 12:37:34 +0100 Subject: [PATCH 168/473] Encode the resulting string from merging files --- .../mergeentries/newmergedialog/fieldsmerger/FileMerger.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java index c8fb940870b..3033fe32dfd 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java @@ -4,6 +4,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jabref.logic.bibtex.FileFieldWriter; import org.jabref.logic.importer.util.FileFieldParser; import org.jabref.model.entry.LinkedFile; import org.jabref.model.strings.StringUtil; @@ -22,8 +23,8 @@ public String merge(String filesA, String filesB) { List linkedFilesB = FileFieldParser.parse(filesB); // TODO: If one of the linked files list is empty then the its string value is malformed. return Stream.concat(linkedFilesA.stream(), linkedFilesB.stream()) - .map(LinkedFile::getLink) - .collect(Collectors.joining(";")); + .map(FileFieldWriter::getStringRepresentation) + .collect(Collectors.joining()); } } } From 470bc8b5b982bd8b826f247e77649c3189a762a9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 15:48:03 +0100 Subject: [PATCH 169/473] Refactor merge/unmerge fields command handling --- .../newmergedialog/FieldRowView.java | 13 +-- .../newmergedialog/cell/FieldNameCell.java | 16 +--- .../cell/MergeableFieldCell.java | 94 ++++++++++++++----- 3 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 0e1b62b91a4..233c34ba9fb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -53,9 +53,13 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field))); - mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { + if (fieldState == MergeableFieldCell.FieldState.MERGED) { + new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field)).execute(); + } else { + new UnmergeCommand(mergeableFieldCell).execute(); + } + })); } toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); @@ -196,8 +200,6 @@ public void execute() { fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedFields)); fieldsMergedEdit.end(); } - - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } } @@ -212,7 +214,6 @@ public UnmergeCommand(MergeableFieldCell mergeableFieldCell) { public void execute() { if (fieldsMergedEdit.canUndo()) { fieldsMergedEdit.undo(); - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 0f82beac6c6..9eb133c267b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -1,17 +1,12 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; -import javafx.scene.Node; import javafx.scene.control.Button; -import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; -import org.jabref.gui.icon.IconTheme; - -import de.saxsys.mvvmfx.utils.commands.Command; /** * A non-editable cell that contains the name of some field @@ -40,14 +35,9 @@ private void initializeLabel() { HBox.setHgrow(labelBox, Priority.ALWAYS); } - protected void setAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + protected void addSideButton(Button sideButton) { + // TODO: Allow adding more than one side button actionLayout.getChildren().clear(); - Node iconNode = icon.getGraphicNode(); - Button actionButton = factory.createIconButton(() -> actionName, command); - actionButton.setGraphic(iconNode); - actionButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); - actionButton.setMaxHeight(Double.MAX_VALUE); - - actionLayout.getChildren().add(actionButton); + actionLayout.getChildren().setAll(sideButton); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index d9cab3a38ed..3c367b30917 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -1,48 +1,100 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import java.util.Optional; + import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.control.Button; +import org.jabref.gui.Globals; +import org.jabref.gui.actions.Action; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.icon.JabRefIcon; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; -import de.saxsys.mvvmfx.utils.commands.Command; - public class MergeableFieldCell extends FieldNameCell { - private Command mergeCommand; - private Command unmergeCommand; + private final ObjectProperty fieldState = new SimpleObjectProperty<>(FieldState.UNMERGED); + + private Button toggleMergeUnmergeButton; - private final ObjectProperty mergeAction = new SimpleObjectProperty<>(); + private final ActionFactory actionFactory = new ActionFactory(Globals.getKeyPrefs()); + + private final Field field; public MergeableFieldCell(Field field, int rowIndex) { super(field.getDisplayName(), rowIndex); - mergeActionProperty().addListener((obs, old, newValue) -> { - if (newValue == MergeAction.MERGE) { - setAction(Localization.lang("Merge %0", field.getDisplayName()), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); - } else { - setAction(Localization.lang("Unmerge %0", field.getDisplayName()), IconTheme.JabRefIcons.UNDO, unmergeCommand); + this.field = field; + + configureMergeButton(); + addSideButton(toggleMergeUnmergeButton); + } + + private void configureMergeButton() { + Action mergeAction = new Action() { + @Override + public String getText() { + return Localization.lang("Merge %", field.getDisplayName()); + } + + @Override + public Optional getIcon() { + return Optional.of(IconTheme.JabRefIcons.MERGE_GROUPS); } - }); + }; + + if (toggleMergeUnmergeButton == null) { + toggleMergeUnmergeButton = actionFactory.createIconButton(mergeAction, new ToggleMergeUnmergeAction()); + toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); + } + actionFactory.configureIconButton(mergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); } - public void setMergeCommand(Command mergeCommand) { - this.mergeCommand = mergeCommand; + private void configureUnmergeButton() { + Action unmergeAction = new Action() { + @Override + public String getText() { + return Localization.lang("Unmerge %", field.getDisplayName()); + } + + @Override + public Optional getIcon() { + return Optional.of(IconTheme.JabRefIcons.UNDO); + } + }; + + if (toggleMergeUnmergeButton == null) { + toggleMergeUnmergeButton = actionFactory.createIconButton(unmergeAction, new ToggleMergeUnmergeAction()); + toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); + } + actionFactory.configureIconButton(unmergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); } - public void setUnmergeCommand(Command unmergeCommand) { - this.unmergeCommand = unmergeCommand; + public ObjectProperty fieldStateProperty() { + return fieldState; } - public ObjectProperty mergeActionProperty() { - return mergeAction; + private void setFieldState(FieldState fieldState) { + fieldStateProperty().set(fieldState); } - public void setMergeAction(MergeAction mergeAction) { - mergeActionProperty().set(mergeAction); + private class ToggleMergeUnmergeAction extends SimpleCommand { + + @Override + public void execute() { + if (fieldStateProperty().get() == FieldState.MERGED) { + setFieldState(FieldState.UNMERGED); + configureMergeButton(); + } else { + setFieldState(FieldState.MERGED); + configureUnmergeButton(); + } + } } - public enum MergeAction { - MERGE, UNMERGE + public enum FieldState { + MERGED, UNMERGED } } From 73542645aed2f5c8ea6e2305697bdf9554109d31 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 15:57:34 +0100 Subject: [PATCH 170/473] Declare Actions with the builder design pattern --- .../java/org/jabref/gui/actions/Action.java | 68 +++++++++++++++++++ .../cell/MergeableFieldCell.java | 29 ++------ 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/actions/Action.java b/src/main/java/org/jabref/gui/actions/Action.java index e6ccfe487b2..28859e00225 100644 --- a/src/main/java/org/jabref/gui/actions/Action.java +++ b/src/main/java/org/jabref/gui/actions/Action.java @@ -1,5 +1,6 @@ package org.jabref.gui.actions; +import java.util.Objects; import java.util.Optional; import org.jabref.gui.icon.JabRefIcon; @@ -19,4 +20,71 @@ default Optional getKeyBinding() { default String getDescription() { return ""; } + + class Builder { + private final ActionImpl actionImpl; + + public Builder(String text) { + this.actionImpl = new ActionImpl(); + setText(text); + } + + public Builder() { + this(""); + } + + public Action setIcon(JabRefIcon icon) { + Objects.requireNonNull(icon); + actionImpl.icon = icon; + return actionImpl; + } + + public Action setText(String text) { + Objects.requireNonNull(text); + actionImpl.text = text; + return actionImpl; + } + + public Action setKeyBinding(KeyBinding keyBinding) { + Objects.requireNonNull(keyBinding); + actionImpl.keyBinding = keyBinding; + return actionImpl; + } + + public Action setDescription(String description) { + Objects.requireNonNull(description); + actionImpl.description = description; + return actionImpl; + } + } + + class ActionImpl implements Action { + private JabRefIcon icon; + private KeyBinding keyBinding; + private String text; + private String description; + + private ActionImpl() { + } + + @Override + public Optional getIcon() { + return Optional.ofNullable(icon); + } + + @Override + public Optional getKeyBinding() { + return Optional.ofNullable(keyBinding); + } + + @Override + public String getText() { + return text != null ? text : ""; + } + + @Override + public String getDescription() { + return description != null ? description : ""; + } + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 3c367b30917..2556de991c0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -1,7 +1,5 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; -import java.util.Optional; - import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.Button; @@ -11,7 +9,6 @@ import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.icon.IconTheme; -import org.jabref.gui.icon.JabRefIcon; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; @@ -33,17 +30,8 @@ public MergeableFieldCell(Field field, int rowIndex) { } private void configureMergeButton() { - Action mergeAction = new Action() { - @Override - public String getText() { - return Localization.lang("Merge %", field.getDisplayName()); - } - - @Override - public Optional getIcon() { - return Optional.of(IconTheme.JabRefIcons.MERGE_GROUPS); - } - }; + Action mergeAction = new Action.Builder(Localization.lang("Merge %", field.getDisplayName())) + .setIcon(IconTheme.JabRefIcons.MERGE_GROUPS); if (toggleMergeUnmergeButton == null) { toggleMergeUnmergeButton = actionFactory.createIconButton(mergeAction, new ToggleMergeUnmergeAction()); @@ -53,17 +41,8 @@ public Optional getIcon() { } private void configureUnmergeButton() { - Action unmergeAction = new Action() { - @Override - public String getText() { - return Localization.lang("Unmerge %", field.getDisplayName()); - } - - @Override - public Optional getIcon() { - return Optional.of(IconTheme.JabRefIcons.UNDO); - } - }; + Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %", field.getDisplayName())) + .setIcon(IconTheme.JabRefIcons.UNDO); if (toggleMergeUnmergeButton == null) { toggleMergeUnmergeButton = actionFactory.createIconButton(unmergeAction, new ToggleMergeUnmergeAction()); From c9b6db70fd679a882512281cd59c9554dc07c395 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:01:08 +0100 Subject: [PATCH 171/473] Remove MergeableFieldCell dependency from the merge/unmerge commands - Thus commands can be moved to the view model --- .../mergeentries/newmergedialog/FieldRowView.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 233c34ba9fb..b41f4dfc98e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -55,9 +55,9 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { if (fieldState == MergeableFieldCell.FieldState.MERGED) { - new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field)).execute(); + new MergeCommand(fieldMergerFactory.create(field)).execute(); } else { - new UnmergeCommand(mergeableFieldCell).execute(); + new UnmergeCommand().execute(); } })); } @@ -173,11 +173,9 @@ public void hideDiff() { } public class MergeCommand extends SimpleCommand { - private final MergeableFieldCell mergeableFieldCell; private final FieldMerger fieldMerger; - public MergeCommand(MergeableFieldCell mergeableFieldCell, FieldMerger fieldMerger) { - this.mergeableFieldCell = mergeableFieldCell; + public MergeCommand(FieldMerger fieldMerger) { this.fieldMerger = fieldMerger; this.executable.bind(viewModel.hasEqualLeftAndRightBinding().not()); @@ -204,10 +202,8 @@ public void execute() { } public class UnmergeCommand extends SimpleCommand { - private final MergeableFieldCell mergeableFieldCell; - public UnmergeCommand(MergeableFieldCell mergeableFieldCell) { - this.mergeableFieldCell = mergeableFieldCell; + public UnmergeCommand() { } @Override From dab2813f95647767b1ef0f39aa07715b2aae2da4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:09:12 +0100 Subject: [PATCH 172/473] Add logs --- .../gui/mergeentries/newmergedialog/FieldRowView.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index b41f4dfc98e..783fdcb89c1 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -25,6 +25,8 @@ import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.jabref.gui.mergeentries.newmergedialog.FieldRowViewModel.Selection; @@ -32,6 +34,7 @@ * A controller class to control left, right and merged field values */ public class FieldRowView { + private static final Logger LOGGER = LoggerFactory.getLogger(FieldRowView.class); private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private final FieldValueCell rightValueCell; @@ -54,6 +57,7 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { + LOGGER.debug("Field merge state is {} for field {}", fieldState, field); if (fieldState == MergeableFieldCell.FieldState.MERGED) { new MergeCommand(fieldMergerFactory.create(field)).execute(); } else { @@ -100,7 +104,9 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt }); EasyBind.listen(viewModel.hasEqualLeftAndRightBinding(), (obs, old, isEqual) -> { + if (isEqual) { + LOGGER.debug("Left and right values are equal, LEFT==RIGHT=={}", viewModel.getLeftFieldValue()); hideDiff(); } }); @@ -146,6 +152,7 @@ public void showDiff(ShowDiffConfig diffConfig) { if (!rightValueCell.isVisible()) { return; } + LOGGER.debug("Showing diffs..."); StyleClassedTextArea leftLabel = leftValueCell.getStyleClassedLabel(); StyleClassedTextArea rightLabel = rightValueCell.getStyleClassedLabel(); @@ -163,6 +170,8 @@ public void hideDiff() { return; } + LOGGER.debug("Hiding diffs..."); + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); getLeftValueCell().getStyleClassedLabel().replaceText(viewModel.getLeftFieldValue()); From 705e8ccf09cd3bd6989cbfa3225fd6b37102e972 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:25:27 +0100 Subject: [PATCH 173/473] Disable field's merge button when field values are equal --- .../newmergedialog/FieldRowView.java | 3 ++- .../cell/MergeableFieldCell.java | 25 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 783fdcb89c1..dc1add53c31 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -56,6 +56,8 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; + mergeableFieldCell.setCanMerge(!viewModel.hasEqualLeftAndRightValues()); + EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { LOGGER.debug("Field merge state is {} for field {}", fieldState, field); if (fieldState == MergeableFieldCell.FieldState.MERGED) { @@ -104,7 +106,6 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt }); EasyBind.listen(viewModel.hasEqualLeftAndRightBinding(), (obs, old, isEqual) -> { - if (isEqual) { LOGGER.debug("Left and right values are equal, LEFT==RIGHT=={}", viewModel.getLeftFieldValue()); hideDiff(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 2556de991c0..097ccd15569 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -1,6 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.Button; @@ -14,6 +16,7 @@ public class MergeableFieldCell extends FieldNameCell { private final ObjectProperty fieldState = new SimpleObjectProperty<>(FieldState.UNMERGED); + private final BooleanProperty canMerge = new SimpleBooleanProperty(Boolean.TRUE); private Button toggleMergeUnmergeButton; @@ -26,7 +29,8 @@ public MergeableFieldCell(Field field, int rowIndex) { this.field = field; configureMergeButton(); - addSideButton(toggleMergeUnmergeButton); + super.addSideButton(toggleMergeUnmergeButton); + toggleMergeUnmergeButton.disableProperty().bind(canMergeProperty().not()); } private void configureMergeButton() { @@ -59,6 +63,25 @@ private void setFieldState(FieldState fieldState) { fieldStateProperty().set(fieldState); } + public FieldState getFieldState() { + return fieldState.get(); + } + + public BooleanProperty canMergeProperty() { + return canMerge; + } + + public boolean canMerge() { + return canMerge.get(); + } + + /** + * Setting {@code canMerge} to {@code false} will disable the merge/unmerge button + * */ + public void setCanMerge(boolean value) { + canMergeProperty().set(value); + } + private class ToggleMergeUnmergeAction extends SimpleCommand { @Override From 0e9a7842d4bcd34458705cc3c3d3bccd3f4b4313 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:51:18 +0100 Subject: [PATCH 174/473] Update code documentation --- .../gui/mergeentries/newmergedialog/cell/FieldNameCell.java | 6 +----- .../gui/mergeentries/newmergedialog/cell/HeaderCell.java | 3 +++ .../newmergedialog/cell/OpenExternalLinkAction.java | 2 +- .../newmergedialog/fieldsmerger/CommentMerger.java | 4 ++++ .../newmergedialog/fieldsmerger/FileMerger.java | 4 ++++ .../newmergedialog/fieldsmerger/GroupMerger.java | 4 ++++ .../newmergedialog/fieldsmerger/KeywordMerger.java | 4 ++++ 7 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 9eb133c267b..43e0a19f053 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -5,11 +5,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import org.jabref.gui.Globals; -import org.jabref.gui.actions.ActionFactory; - /** - * A non-editable cell that contains the name of some field + * A readonly cell used to display the name of some field. */ public class FieldNameCell extends AbstractCell { public static final String DEFAULT_STYLE_CLASS = "field-name"; @@ -17,7 +14,6 @@ public class FieldNameCell extends AbstractCell { private final Label label = new Label(); private final HBox labelBox = new HBox(label); - private final ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); public FieldNameCell(String text, int rowIndex) { super(text, rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 2fd82afd38b..65f89f13713 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -3,6 +3,9 @@ import javafx.geometry.Insets; import javafx.scene.control.Label; +/** + * A readonly cell used to display the header of the ThreeWayMerge UI at the top of the layout. + * */ public class HeaderCell extends AbstractCell { public static final String DEFAULT_STYLE_CLASS = "merge-header-cell"; private final Label label = new Label(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java index 102b192458a..1b5087b413a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java @@ -9,7 +9,7 @@ import org.jabref.model.strings.StringUtil; /** - * This action can open an Url and DOI + * A command for opening DOIs and URLs. This was created primarily for simplifying {@link FieldValueCell}. * */ public class OpenExternalLinkAction extends SimpleCommand { private final String urlOrDoi; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java index 5599bfb2470..9beb1819423 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java @@ -1,7 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; import org.jabref.logic.util.OS; +import org.jabref.model.entry.field.StandardField; +/** + * A merger for the {@link StandardField#COMMENT} field + * */ public class CommentMerger implements FieldMerger { @Override public String merge(String fieldValueA, String fieldValueB) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java index 3033fe32dfd..4b4e2034226 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java @@ -7,8 +7,12 @@ import org.jabref.logic.bibtex.FileFieldWriter; import org.jabref.logic.importer.util.FileFieldParser; import org.jabref.model.entry.LinkedFile; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.strings.StringUtil; +/** + * A merger for the {@link StandardField#FILE} field + * */ public class FileMerger implements FieldMerger { @Override public String merge(String filesA, String filesB) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java index 8af126aac61..fdbbddbb268 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java @@ -3,8 +3,12 @@ import java.util.Arrays; import java.util.stream.Collectors; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.strings.StringUtil; +/** + * A merger for the {@link StandardField#GROUPS} field + * */ public class GroupMerger implements FieldMerger { public static final String GROUPS_SEPARATOR = ", "; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java index 62b5ca2bb11..22d1479e3d4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -4,9 +4,13 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.strings.StringUtil; import org.jabref.preferences.PreferencesService; +/** + * A merger for the {@link StandardField#KEYWORDS} field + * */ public class KeywordMerger implements FieldMerger { private final PreferencesService preferencesService; From 2a512c54c41f753aef07219142db8bf5fabcecb0 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:52:07 +0100 Subject: [PATCH 175/473] Rename 'AbstractCell' to 'ThreeWayMergeCell' --- .../mergeentries/newmergedialog/cell/FieldNameCell.java | 2 +- .../mergeentries/newmergedialog/cell/FieldValueCell.java | 2 +- .../gui/mergeentries/newmergedialog/cell/HeaderCell.java | 4 ++-- .../mergeentries/newmergedialog/cell/MergedFieldCell.java | 2 +- .../cell/{AbstractCell.java => ThreeWayMergeCell.java} | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/{AbstractCell.java => ThreeWayMergeCell.java} (91%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 43e0a19f053..a93e6b23308 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -8,7 +8,7 @@ /** * A readonly cell used to display the name of some field. */ -public class FieldNameCell extends AbstractCell { +public class FieldNameCell extends ThreeWayMergeCell { public static final String DEFAULT_STYLE_CLASS = "field-name"; protected final HBox actionLayout = new HBox(); private final Label label = new Label(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 4019c8f9a21..04fda36975d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -40,7 +40,7 @@ /** * A readonly, selectable field cell that contains the value of some field */ -public class FieldValueCell extends AbstractCell implements Toggle { +public class FieldValueCell extends ThreeWayMergeCell implements Toggle { public static final Logger LOGGER = LoggerFactory.getLogger(FieldValueCell.class); public static final String DEFAULT_STYLE_CLASS = "merge-field-value"; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 65f89f13713..76d3fceff0a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -6,12 +6,12 @@ /** * A readonly cell used to display the header of the ThreeWayMerge UI at the top of the layout. * */ -public class HeaderCell extends AbstractCell { +public class HeaderCell extends ThreeWayMergeCell { public static final String DEFAULT_STYLE_CLASS = "merge-header-cell"; private final Label label = new Label(); public HeaderCell(String text) { - super(text, AbstractCell.NO_ROW_NUMBER); + super(text, ThreeWayMergeCell.NO_ROW_NUMBER); initialize(); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java index 77f170541d6..89c591ee0ac 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java @@ -10,7 +10,7 @@ import org.fxmisc.richtext.StyleClassedTextArea; -public class MergedFieldCell extends AbstractCell { +public class MergedFieldCell extends ThreeWayMergeCell { private static final String DEFAULT_STYLE_CLASS = "merged-field"; private final StyleClassedTextArea textArea = new StyleClassedTextArea(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/ThreeWayMergeCell.java similarity index 91% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/ThreeWayMergeCell.java index ffb1f536986..c3496fcecb6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/ThreeWayMergeCell.java @@ -11,7 +11,7 @@ /** * */ -public abstract class AbstractCell extends HBox { +public abstract class ThreeWayMergeCell extends HBox { public static final String ODD_PSEUDO_CLASS = "odd"; public static final String EVEN_PSEUDO_CLASS = "even"; public static final int NO_ROW_NUMBER = -1; @@ -20,7 +20,7 @@ public abstract class AbstractCell extends HBox { private final BooleanProperty odd = new BooleanPropertyBase() { @Override public Object getBean() { - return AbstractCell.this; + return ThreeWayMergeCell.this; } @Override @@ -38,7 +38,7 @@ protected void invalidated() { private final BooleanProperty even = new BooleanPropertyBase() { @Override public Object getBean() { - return AbstractCell.this; + return ThreeWayMergeCell.this; } @Override @@ -53,7 +53,7 @@ protected void invalidated() { } }; - public AbstractCell(String text, int rowIndex) { + public ThreeWayMergeCell(String text, int rowIndex) { getStyleClass().add(DEFAULT_STYLE_CLASS); if (rowIndex != NO_ROW_NUMBER) { if (rowIndex % 2 == 1) { From 8081bc5cee6a4cab1c6e1fa01e7da87ead466d7e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 27 Jul 2022 14:58:49 +0100 Subject: [PATCH 176/473] Pass arguments to Localization.lang using '%0' not '%' --- .../mergeentries/newmergedialog/cell/MergeableFieldCell.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 097ccd15569..61afc11cd91 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -34,7 +34,7 @@ public MergeableFieldCell(Field field, int rowIndex) { } private void configureMergeButton() { - Action mergeAction = new Action.Builder(Localization.lang("Merge %", field.getDisplayName())) + Action mergeAction = new Action.Builder(Localization.lang("Merge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.MERGE_GROUPS); if (toggleMergeUnmergeButton == null) { @@ -45,7 +45,7 @@ private void configureMergeButton() { } private void configureUnmergeButton() { - Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %", field.getDisplayName())) + Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.UNDO); if (toggleMergeUnmergeButton == null) { From 235a243ce85ea42819952659a93a399e46e9b743 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 27 Jul 2022 15:14:55 +0100 Subject: [PATCH 177/473] Decompose the ToggleMergeUnmergeButton into its own class (or component) - Removed FieldNameCellFactory.java and MergeableFieldCell.java - Made it easier to add more side buttons in the future --- .../newmergedialog/FieldRowView.java | 14 +++++----- .../newmergedialog/cell/FieldNameCell.java | 2 +- .../cell/FieldNameCellFactory.java | 14 ---------- .../ToggleMergeUnmergeButton.java} | 27 ++++++------------- 4 files changed, 16 insertions(+), 41 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/{MergeableFieldCell.java => sidebuttons/ToggleMergeUnmergeButton.java} (72%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index dc1add53c31..51ced825162 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -11,10 +11,9 @@ import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.sidebuttons.ToggleMergeUnmergeButton; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMerger; @@ -49,18 +48,19 @@ public class FieldRowView { public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { viewModel = new FieldRowViewModel(field, leftEntry, rightEntry, mergedEntry); - fieldNameCell = FieldNameCellFactory.create(field, rowIndex); + fieldNameCell = new FieldNameCell(field.getDisplayName(), rowIndex); leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); if (FieldMergerFactory.canMerge(field)) { - MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setCanMerge(!viewModel.hasEqualLeftAndRightValues()); + ToggleMergeUnmergeButton toggleMergeUnmergeButton = new ToggleMergeUnmergeButton(field); + toggleMergeUnmergeButton.setCanMerge(!viewModel.hasEqualLeftAndRightValues()); + fieldNameCell.addSideButton(toggleMergeUnmergeButton); - EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { + EasyBind.listen(toggleMergeUnmergeButton.fieldStateProperty(), ((observableValue, old, fieldState) -> { LOGGER.debug("Field merge state is {} for field {}", fieldState, field); - if (fieldState == MergeableFieldCell.FieldState.MERGED) { + if (fieldState == ToggleMergeUnmergeButton.FieldState.MERGED) { new MergeCommand(fieldMergerFactory.create(field)).execute(); } else { new UnmergeCommand().execute(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index a93e6b23308..a435f623187 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -31,7 +31,7 @@ private void initializeLabel() { HBox.setHgrow(labelBox, Priority.ALWAYS); } - protected void addSideButton(Button sideButton) { + public void addSideButton(Button sideButton) { // TODO: Allow adding more than one side button actionLayout.getChildren().clear(); actionLayout.getChildren().setAll(sideButton); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java deleted file mode 100644 index ee038e53eca..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; - -import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; -import org.jabref.model.entry.field.Field; - -public class FieldNameCellFactory { - public static FieldNameCell create(Field field, int rowIndex) { - if (FieldMergerFactory.canMerge(field)) { - return new MergeableFieldCell(field, rowIndex); - } else { - return new FieldNameCell(field.getDisplayName(), rowIndex); - } - } -} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/sidebuttons/ToggleMergeUnmergeButton.java similarity index 72% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/sidebuttons/ToggleMergeUnmergeButton.java index 61afc11cd91..de958837778 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/sidebuttons/ToggleMergeUnmergeButton.java @@ -1,4 +1,4 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; +package org.jabref.gui.mergeentries.newmergedialog.cell.sidebuttons; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; @@ -14,45 +14,34 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; -public class MergeableFieldCell extends FieldNameCell { +public class ToggleMergeUnmergeButton extends Button { private final ObjectProperty fieldState = new SimpleObjectProperty<>(FieldState.UNMERGED); private final BooleanProperty canMerge = new SimpleBooleanProperty(Boolean.TRUE); - private Button toggleMergeUnmergeButton; - private final ActionFactory actionFactory = new ActionFactory(Globals.getKeyPrefs()); private final Field field; - public MergeableFieldCell(Field field, int rowIndex) { - super(field.getDisplayName(), rowIndex); + public ToggleMergeUnmergeButton(Field field) { this.field = field; + setMaxHeight(Double.MAX_VALUE); + setFocusTraversable(false); configureMergeButton(); - super.addSideButton(toggleMergeUnmergeButton); - toggleMergeUnmergeButton.disableProperty().bind(canMergeProperty().not()); + this.disableProperty().bind(canMergeProperty().not()); } private void configureMergeButton() { Action mergeAction = new Action.Builder(Localization.lang("Merge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.MERGE_GROUPS); - if (toggleMergeUnmergeButton == null) { - toggleMergeUnmergeButton = actionFactory.createIconButton(mergeAction, new ToggleMergeUnmergeAction()); - toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); - } - actionFactory.configureIconButton(mergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); + actionFactory.configureIconButton(mergeAction, new ToggleMergeUnmergeAction(), this); } private void configureUnmergeButton() { Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.UNDO); - - if (toggleMergeUnmergeButton == null) { - toggleMergeUnmergeButton = actionFactory.createIconButton(unmergeAction, new ToggleMergeUnmergeAction()); - toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); - } - actionFactory.configureIconButton(unmergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); + actionFactory.configureIconButton(unmergeAction, new ToggleMergeUnmergeAction(), this); } public ObjectProperty fieldStateProperty() { From 891feb6ae26d11666ab5805a31fd3efeeb72c233 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 16:31:44 +0100 Subject: [PATCH 178/473] Include original left and right entries in EntriesMergeResult --- .../jabref/gui/mergeentries/EntriesMergeResult.java | 8 ++++++++ .../jabref/gui/mergeentries/FetchAndMergeEntry.java | 2 +- .../jabref/gui/mergeentries/MergeEntriesAction.java | 10 +++++----- .../jabref/gui/mergeentries/MergeEntriesDialog.java | 8 ++++++-- .../java/org/jabref/gui/mergeentries/MergeResult.java | 8 -------- .../org/jabref/gui/shared/SharedDatabaseUIManager.java | 4 ++-- 6 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java delete mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeResult.java diff --git a/src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java b/src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java new file mode 100644 index 00000000000..b134b11688a --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java @@ -0,0 +1,8 @@ +package org.jabref.gui.mergeentries; + +import org.jabref.model.entry.BibEntry; + +public record EntriesMergeResult( + BibEntry originalLeftEntry, BibEntry originalRightEntry, BibEntry newLeftEntry, BibEntry newRightEntry, BibEntry mergedEntry +) { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index 542788431cc..04eda76e077 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -91,7 +91,7 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF 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 mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(EntriesMergeResult::mergedEntry); if (mergedEntry.isPresent()) { NamedCompound ce = new NamedCompound(Localization.lang("Merge entry with %0 information", fetcher.getName())); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index 7820cd95c92..0bf58e4f65c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -68,16 +68,16 @@ public void execute() { MergeEntriesDialog dialog = new MergeEntriesDialog(first, second); dialog.setTitle(Localization.lang("Merge entries")); - Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); - mergeResultOpt.ifPresentOrElse(mergeResult -> { + Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); + mergeResultOpt.ifPresentOrElse(entriesMergeResult -> { // TODO: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark // entries with a timestamp, only BasePanel::insertEntry does. Workaround for the moment is to get the // BasePanel from the constructor injected JabRefFrame. Should be refactored and extracted! - frame.getCurrentLibraryTab().insertEntry(mergeResult.mergedEntry()); + frame.getCurrentLibraryTab().insertEntry(entriesMergeResult.mergedEntry()); NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); - ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergeResult.mergedEntry())); - List entriesToRemove = Arrays.asList(one, two); + ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), entriesMergeResult.mergedEntry())); + List entriesToRemove = Arrays.asList(entriesMergeResult.originalLeftEntry(), entriesMergeResult.originalRightEntry()); ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); databaseContext.getDatabase().removeEntries(entriesToRemove); ce.end(); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index a93598494b0..4d9c06c4ef9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -8,11 +8,15 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; -public class MergeEntriesDialog extends BaseDialog { +public class MergeEntriesDialog extends BaseDialog { private final ThreeWayMergeView threeWayMergeView; + private final BibEntry one; + private final BibEntry two; public MergeEntriesDialog(BibEntry one, BibEntry two) { threeWayMergeView = new ThreeWayMergeView(one, two); + this.one = one; + this.two = two; init(); } @@ -31,7 +35,7 @@ private void init() { this.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, replaceEntries); this.setResultConverter(buttonType -> { if (buttonType.equals(replaceEntries)) { - return new MergeResult(threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); + return new EntriesMergeResult(one, two, threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); } else { return null; } diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeResult.java b/src/main/java/org/jabref/gui/mergeentries/MergeResult.java deleted file mode 100644 index 6db5a7a60e5..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/MergeResult.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.jabref.gui.mergeentries; - -import org.jabref.model.entry.BibEntry; - -public record MergeResult( - BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry -) { -} diff --git a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java index e5c2a0e9732..6b87d7c620a 100644 --- a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java +++ b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java @@ -15,8 +15,8 @@ import org.jabref.gui.LibraryTab; import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.exporter.SaveDatabaseAction; +import org.jabref.gui.mergeentries.EntriesMergeResult; import org.jabref.gui.mergeentries.MergeEntriesDialog; -import org.jabref.gui.mergeentries.MergeResult; import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; @@ -100,7 +100,7 @@ public void listen(UpdateRefusedEvent updateRefusedEvent) { if (response.isPresent() && response.get().equals(merge)) { MergeEntriesDialog dialog = new MergeEntriesDialog(localBibEntry, sharedBibEntry); - Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(EntriesMergeResult::mergedEntry); mergedEntry.ifPresent(mergedBibEntry -> { mergedBibEntry.getSharedBibEntryData().setSharedID(sharedBibEntry.getSharedBibEntryData().getSharedID()); From feb062837815b00b12c707de81c754446175e465 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 16:52:21 +0100 Subject: [PATCH 179/473] Make entries merging logic reusable --- .../gui/mergeentries/MergeEntriesAction.java | 20 +------- .../mergeentries/MergeTwoEntriesAction.java | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index 0bf58e4f65c..82652a75fb4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -1,21 +1,15 @@ package org.jabref.gui.mergeentries; -import java.util.Arrays; import java.util.List; import java.util.Optional; import org.jabref.gui.DialogService; -import org.jabref.gui.Globals; import org.jabref.gui.JabRefFrame; import org.jabref.gui.StateManager; import org.jabref.gui.actions.ActionHelper; import org.jabref.gui.actions.SimpleCommand; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableInsertEntries; -import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.logic.bibtex.comparator.EntryComparator; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.InternalField; @@ -38,7 +32,6 @@ public void execute() { if (stateManager.getActiveDatabase().isEmpty()) { return; } - BibDatabaseContext databaseContext = stateManager.getActiveDatabase().get(); // Check if there are two entries selected List selectedEntries = stateManager.getSelectedEntries(); @@ -70,18 +63,7 @@ public void execute() { dialog.setTitle(Localization.lang("Merge entries")); Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); mergeResultOpt.ifPresentOrElse(entriesMergeResult -> { - // TODO: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark - // entries with a timestamp, only BasePanel::insertEntry does. Workaround for the moment is to get the - // BasePanel from the constructor injected JabRefFrame. Should be refactored and extracted! - frame.getCurrentLibraryTab().insertEntry(entriesMergeResult.mergedEntry()); - - NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); - ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), entriesMergeResult.mergedEntry())); - List entriesToRemove = Arrays.asList(entriesMergeResult.originalLeftEntry(), entriesMergeResult.originalRightEntry()); - ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); - databaseContext.getDatabase().removeEntries(entriesToRemove); - ce.end(); - Globals.undoManager.addEdit(ce); + new MergeTwoEntriesAction(entriesMergeResult, frame, stateManager).execute(); dialogService.notify(Localization.lang("Merged entries")); }, () -> dialogService.notify(Localization.lang("Canceled merging entries"))); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java new file mode 100644 index 00000000000..e494e1966b5 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java @@ -0,0 +1,46 @@ +package org.jabref.gui.mergeentries; + +import java.util.Arrays; +import java.util.List; + +import org.jabref.gui.Globals; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.undo.NamedCompound; +import org.jabref.gui.undo.UndoableInsertEntries; +import org.jabref.gui.undo.UndoableRemoveEntries; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; + +public class MergeTwoEntriesAction extends SimpleCommand { + private final EntriesMergeResult entriesMergeResult; + private final JabRefFrame frame; + private final StateManager stateManager; + + public MergeTwoEntriesAction(EntriesMergeResult entriesMergeResult, JabRefFrame frame, StateManager stateManager) { + this.entriesMergeResult = entriesMergeResult; + this.frame = frame; + this.stateManager = stateManager; + } + + @Override + public void execute() { + if (stateManager.getActiveDatabase().isEmpty()) { + return; + } + + BibDatabase database = stateManager.getActiveDatabase().get().getDatabase(); + + frame.getCurrentLibraryTab().insertEntry(entriesMergeResult.mergedEntry()); + + NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); + ce.addEdit(new UndoableInsertEntries(stateManager.getActiveDatabase().get().getDatabase(), entriesMergeResult.mergedEntry())); + List entriesToRemove = Arrays.asList(entriesMergeResult.originalLeftEntry(), entriesMergeResult.originalRightEntry()); + ce.addEdit(new UndoableRemoveEntries(database, entriesToRemove)); + database.removeEntries(entriesToRemove); + ce.end(); + Globals.undoManager.addEdit(ce); + } +} From 328ce9773146f230ea50d3efd50ba3a58de8b706 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 18:20:16 +0100 Subject: [PATCH 180/473] Rename ChangeDisplayDialog.java to ExternalChangesResolverDialog.java --- .../java/org/jabref/gui/collab/DatabaseChangeMonitor.java | 2 +- ...eDisplayDialog.java => ExternalChangesResolverDialog.java} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/org/jabref/gui/collab/{ChangeDisplayDialog.java => ExternalChangesResolverDialog.java} (96%) diff --git a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java index 575307bcda8..20263b36ab6 100644 --- a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java +++ b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java @@ -67,7 +67,7 @@ public DatabaseChangeMonitor(BibDatabaseContext database, Localization.lang("The library has been modified by another program."), List.of(new Action(Localization.lang("Dismiss changes"), event -> notificationPane.hide()), new Action(Localization.lang("Review changes"), event -> { - dialogService.showCustomDialogAndWait(new ChangeDisplayDialog(database, changes)); + dialogService.showCustomDialogAndWait(new ExternalChangesResolverDialog(database, changes)); notificationPane.hide(); })), Duration.ZERO)); diff --git a/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.java similarity index 96% rename from src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java rename to src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.java index e9f0751cc07..aa9b802da73 100644 --- a/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java +++ b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.java @@ -23,13 +23,13 @@ import com.tobiasdiez.easybind.EasyBind; -class ChangeDisplayDialog extends BaseDialog { +class ExternalChangesResolverDialog extends BaseDialog { private final ListView changesList; private final BorderPane infoPanel = new BorderPane(); private final CheckBox cb = new CheckBox(Localization.lang("Accept change")); - public ChangeDisplayDialog(BibDatabaseContext database, List changes) { + public ExternalChangesResolverDialog(BibDatabaseContext database, List changes) { this.setTitle(Localization.lang("External changes")); this.getDialogPane().setPrefSize(800, 600); From b8ce5492373579b617dc2480cbd3a1f761a7ae02 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 18:21:21 +0100 Subject: [PATCH 181/473] Create ExternalChangesResolverViewModel --- .../jabref/gui/collab/ExternalChangesResolverViewModel.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java diff --git a/src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java new file mode 100644 index 00000000000..1453a9cf033 --- /dev/null +++ b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java @@ -0,0 +1,6 @@ +package org.jabref.gui.collab; + +import org.jabref.gui.AbstractViewModel; + +public class ExternalChangesResolverViewModel extends AbstractViewModel { +} From 588db575ee2fd21fc37963f8193972597548f897 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 19:18:47 +0100 Subject: [PATCH 182/473] Design the ExternalChangesResolverDialog --- .../collab/ExternalChangesResolverDialog.fxml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml diff --git a/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml new file mode 100644 index 00000000000..e532d7a055c --- /dev/null +++ b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java similarity index 65% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 7f6b50beb88..0703f49f7c2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -1,14 +1,18 @@ -package org.jabref.gui.mergeentries.newmergedialog.toolbox; +package org.jabref.gui.mergeentries.newmergedialog.toolbar; import java.util.Arrays; +import java.util.function.Consumer; +import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.fxml.FXML; +import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.RadioButton; import javafx.scene.control.ToggleGroup; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import javafx.util.StringConverter; @@ -16,15 +20,15 @@ import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; -public class ThreeWayMergeToolbox extends AnchorPane { +public class ThreeWayMergeToolbar extends AnchorPane { @FXML - private RadioButton compareCharactersRadioButtons; + private RadioButton highlightCharactersRadioButtons; @FXML - private RadioButton compareWordsRadioButton; + private RadioButton highlightWordsRadioButton; @FXML - private ToggleGroup diffCompareMethodToggleGroup; + private ToggleGroup diffHighlightModeToggleGroup; @FXML private ComboBox diffViewComboBox; @@ -32,10 +36,16 @@ public class ThreeWayMergeToolbox extends AnchorPane { @FXML private ComboBox plainTextOrDiffComboBox; - private final ObjectProperty diffCompareMethod = new SimpleObjectProperty<>(); + @FXML + private Button selectLeftEntryValuesButton; + + @FXML + private Button selectRightEntryValuesButton; + + private final ObjectProperty diffHighlightMode = new SimpleObjectProperty<>(); private EasyBinding showDiff; - public ThreeWayMergeToolbox() { + public ThreeWayMergeToolbar() { ViewLoader.view(this) .root(this) .load(); @@ -74,33 +84,18 @@ public DiffView fromString(String string) { } }); - compareWordsRadioButton.disableProperty().bind(notShowDiffProperty()); - compareCharactersRadioButtons.disableProperty().bind(notShowDiffProperty()); + highlightWordsRadioButton.disableProperty().bind(notShowDiffProperty()); + highlightCharactersRadioButtons.disableProperty().bind(notShowDiffProperty()); - diffCompareMethodToggleGroup.selectedToggleProperty().addListener((observable -> { - if (diffCompareMethodToggleGroup.getSelectedToggle().equals(compareCharactersRadioButtons)) { - diffCompareMethod.set(DiffCompareMethod.CHARS); + diffHighlightModeToggleGroup.selectedToggleProperty().addListener((observable -> { + if (diffHighlightModeToggleGroup.getSelectedToggle().equals(highlightCharactersRadioButtons)) { + diffHighlightMode.set(DiffHighlightMode.CHARS); } else { - diffCompareMethod.set(DiffCompareMethod.WORDS); + diffHighlightMode.set(DiffHighlightMode.WORDS); } })); - diffCompareMethodToggleGroup.selectToggle(compareWordsRadioButton); - } - - private void initializeDiffViewComboBox() { - diffViewComboBox.getSelectionModel().select(DiffView.UNIFIED); - diffViewComboBox.setConverter(new StringConverter<>() { - @Override - public String toString(DiffView diffView) { - return diffView.getValue(); - } - - @Override - public DiffView fromString(String string) { - return DiffView.fromString(string); - } - }); + diffHighlightModeToggleGroup.selectToggle(highlightWordsRadioButton); } public ReadOnlyObjectProperty diffViewProperty() { @@ -115,6 +110,14 @@ public EasyBinding showDiffProperty() { return showDiff; } + /** + * Convince method used to disable diff related views when diff is not selected. + * + *

+ * This method is required because {@link EasyBinding} class doesn't have a method to invert a boolean property, + * like {@link BooleanExpression#not()} + *

+ * */ public EasyBinding notShowDiffProperty() { return showDiffProperty().map(showDiff -> !showDiff); } @@ -123,12 +126,20 @@ public Boolean isShowDiffEnabled() { return showDiffProperty().get(); } - public ObjectProperty diffCompareMethodProperty() { - return diffCompareMethod; + public ObjectProperty diffHighlightModeProperty() { + return diffHighlightMode; + } + + public DiffHighlightMode getDiffHighlightMode() { + return diffHighlightModeProperty().get(); + } + + public void setOnSelectLeftEntryValuesButtonClicked(Consumer onClick) { + selectLeftEntryValuesButton.setOnMouseClicked(onClick::accept); } - public DiffCompareMethod getDiffCompareMethod() { - return diffCompareMethodProperty().get(); + public void setOnSelectRightEntryValuesButtonClicked(Consumer onClick) { + selectRightEntryValuesButton.setOnMouseClicked(onClick::accept); } public enum PlainTextOrDiff { @@ -173,7 +184,7 @@ public static DiffView fromString(String str) { } } - public enum DiffCompareMethod { + public enum DiffHighlightMode { WORDS, CHARS } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml deleted file mode 100644 index 6829ee78b54..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbox/ThreeWayMergeToolbox.fxml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 91b9cd94fe52133d3ad2ffc129fb692f1f9c4953 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:05:07 +0100 Subject: [PATCH 243/473] Disable right field cell when it's not visible --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index a6322b34d8e..cee05b99050 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -97,6 +97,7 @@ private void addFieldRow(int index) { mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index, 1, 1); + fieldRow.getRightValueCell().setDisable(true); } else { mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); } From d6a7a825913307aa483a6931dd875792f4fd1008 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:06:15 +0100 Subject: [PATCH 244/473] Listen for select all left/right toolbar buttons --- .../newmergedialog/FieldRowController.java | 22 +++++++ .../newmergedialog/ThreeWayMergeView.java | 62 ++++++++++++++----- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 9e9a077c3ea..904ca57c390 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -54,6 +54,28 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } } + /** + * @return True if left value was selected, False otherwise + */ + public boolean selectLeftValue() { + if (!leftValueCell.isDisabled()) { + toggleGroup.selectToggle(leftValueCell); + return true; + } + return false; + } + + /** + * @return True if left value was selected, False otherwise + */ + public boolean selectRightValue() { + if (!rightValueCell.isDisabled()) { + toggleGroup.selectToggle(rightValueCell); + return true; + } + return false; + } + public String getMergedValue() { return mergedValueProperty().getValue(); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index cee05b99050..4ec81f6d6f2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -1,5 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog; +import java.util.ArrayList; +import java.util.List; + import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -7,58 +10,81 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.mergeentries.newmergedialog.toolbox.ThreeWayMergeToolbox; +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { + public static final int GRID_COLUMN_MIN_WIDTH = 250; public static final String LEFT_DEFAULT_HEADER = "Left Entry"; public static final String RIGHT_DEFAULT_HEADER = "Right Entry"; - private ThreeWayMergeToolbox mergeToolbox; - private HeaderView headerView; + + private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); + private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private final ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private final ColumnConstraints mergedEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private final ThreeWayMergeToolbar toolbar; + private final ThreeWayMergeHeaderView headerView; private final ScrollPane scrollPane; private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; + private final List fieldRowControllerList = new ArrayList<>(); public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); - mergeToolbox = new ThreeWayMergeToolbox(); - headerView = new HeaderView(leftHeader, rightHeader); - scrollPane = new ScrollPane(); - scrollPane.setFitToWidth(true); - scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); mergeGridPane = new GridPane(); - initializeMergeGridPane(); + scrollPane = new ScrollPane(); + headerView = new ThreeWayMergeHeaderView(leftHeader, rightHeader); + toolbar = new ThreeWayMergeToolbar(); - scrollPane.setContent(mergeGridPane); - getChildren().addAll(mergeToolbox, headerView, scrollPane); + initializeColumnConstraints(); + initializeMergeGridPane(); + initializeScrollPane(); + initializeHeaderView(); + initializeToolbar(); this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); + + getChildren().addAll(toolbar, headerView, scrollPane); } public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry) { this(leftEntry, rightEntry, LEFT_DEFAULT_HEADER, RIGHT_DEFAULT_HEADER); } - private void initializeMergeGridPane() { - ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); - fieldNameColumnConstraints.setHgrow(Priority.NEVER); + private void initializeToolbar() { + toolbar.setOnSelectLeftEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectLeftValue)); + toolbar.setOnSelectRightEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectRightValue)); + } + + private void initializeHeaderView() { + headerView.getColumnConstraints().addAll(fieldNameColumnConstraints, + leftEntryColumnConstraints, + rightEntryColumnConstraints, + mergedEntryColumnConstraints); + } - ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); - ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); - ColumnConstraints mergedEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); + private void initializeScrollPane() { + scrollPane.setFitToWidth(true); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setContent(mergeGridPane); + } + private void initializeColumnConstraints() { + fieldNameColumnConstraints.setHgrow(Priority.NEVER); leftEntryColumnConstraints.setHgrow(Priority.ALWAYS); rightEntryColumnConstraints.setHgrow(Priority.ALWAYS); mergedEntryColumnConstraints.setHgrow(Priority.ALWAYS); + } + private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { @@ -80,6 +106,8 @@ private void addFieldRow(int index) { } FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, index); + fieldRowControllerList.add(fieldRow); + fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); From 5a3725915c5f812f9fa1348d9b30995cd73296e8 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:07:45 +0100 Subject: [PATCH 245/473] Style stuff --- src/main/java/org/jabref/gui/Base.css | 31 +++++++++++-- src/main/java/org/jabref/gui/Dark.css | 25 +++++++++++ .../newmergedialog/ThreeWayMergeView.css | 44 +++++++------------ 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 97a3f3ad295..733bed56dbb 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -2,13 +2,13 @@ .root { -jr-transparent-green: rgba(16, 172, 132, 0.12); - -jr-row-odd-background: -fx-control-inner-background; - -jr-row-even-background: -fx-control-inner-background-alt; + -jr-row-odd-background: -fx-control-inner-background-alt; + -jr-row-even-background: -fx-control-inner-background; /* On light theme, the text is hard to see when it's on top of the accent color. This is an alternative lighter accent color for better text visibility. */ - -jr-accent-alt: derive(-jr-accent, 10%); + -jr-accent-alt: derive(-jr-accent, 15%); /* The theme color and some derived colors from it are used for icons, tab-headers, marking of selected inputs and @@ -618,6 +618,31 @@ TextFlow > .tooltip-text-monospaced { -fx-background-insets: 0; } +.field-value .copy-icon { + -fx-icon-size: 15; + -fx-icon-color: -fx-text-background-color; + -fx-blend-mode: multiply ; + -fx-opacity: 69%; +} + +.field-value:disabled .copy-icon { + -fx-opacity: 0%; +} + +.field-value:selected .copy-icon { + +} + +.header-cell { + -fx-border-width: 0 0 1 0; + -fx-border-color: -jr-gray-1; + -fx-background-color: -jr-row-even-background; +} + +.merge-header { + -fx-background-color: -jr-row-even-background; +} + .table-view .groupColumnBackground { -fx-stroke: -jr-gray-2; } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index ec62b343c85..3b8b05c861c 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -84,6 +84,31 @@ .tree-table-row-cell:hover { -fx-background-color: -jr-hover; } +.field-value .copy-icon { + -fx-icon-size: 15; + -fx-icon-color: -fx-text-background-color; + -fx-blend-mode: inherit; + -fx-opacity: 100%; +} + +.field-value:disabled .copy-icon { + -fx-opacity: 0%; +} + +.field-value:selected .copy-icon { + -fx-icon-color: -fx-text-background-color; + -fx-opacity: 100%; +} + +.header-cell { + -fx-border-width: 0 0 1 0; + -fx-border-color: -fx-outer-border; + -fx-background-color: -jr-row-odd-background; +} + +.merge-header { + -fx-background-color: -jr-row-odd-background; +} .table-view .groupColumnBackground { -fx-stroke: -jr-gray-3; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index db916d9010a..815114bc7ae 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -1,13 +1,18 @@ .merged-field { - -fx-border-color: #dfdfdf; - -fx-border-width: 0 0 0 1.5; +/* -fx-border-color: #dfdfdf; + -fx-border-width: 0 0 0 1.5;*/ } .merged-field .styled-text-area { - -fx-background-radius: 3; - -fx-border-radius: 3; - -fx-border-color: #dfdfdf; - -fx-background-color: white; + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1; + -fx-prompt-text-fill: -fx-mid-text-color; +} +.merged-field .styled-text-area:focused { + -fx-highlight-fill: derive(-jr-accent, 20%); + -fx-background-color: -jr-accent, -fx-control-inner-background; + -fx-background-insets: 0, 2; + -fx-highlight-text-fill: -fx-text-inner-color; } .field-value:selected .selection-box { @@ -23,30 +28,10 @@ -fx-background-radius: 8; } -.field-value .styled-text-area .text{ +.styled-text-area .text{ -fx-fill: -fx-text-background-color; } -.field-value .text-area { - -fx-font-size: 13; -} - - -.field-value .copy-icon { - -fx-icon-size: 15; - -fx-icon-color: -fx-text-background-color; - -fx-opacity: 100%; -} - -.field-value:disabled .copy-icon { - -fx-opacity: 0%; -} - -.field-value:selected .copy-icon { - -fx-icon-color: -fx-text-background-color; - -fx-opacity: 100%; -} - .field-cell:odd { -fx-background-color: -jr-row-odd-background; } @@ -59,6 +44,11 @@ -fx-background-color: -jr-menu-background; } +.header-cell .label{ + -fx-font-weight: bold; + -fx-padding: 1, 0, 1, 0; +} + /* Diff Highlighting */ .unchanged { From 3a2f7c4c3552ba830577878454568850800dcae1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:31:58 +0100 Subject: [PATCH 246/473] Add DiffHighlighter - Implemented UnifiedDiffHighlighter --- .../diffhighlighter/DiffHighlighter.java | 69 +++++++++++ .../diffhighlighter/SplitDiffHighlighter.java | 24 ++++ .../UnifiedDiffHighlighter.java | 117 ++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java new file mode 100644 index 00000000000..e92a85e0a96 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java @@ -0,0 +1,69 @@ +package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.fxmisc.richtext.StyleClassedTextArea; + +public abstract sealed class DiffHighlighter permits SplitDiffHighlighter, UnifiedDiffHighlighter { + protected final StyleClassedTextArea sourceTextview; + protected final StyleClassedTextArea targetTextview; + + protected DiffMethod diffMethod; + + public DiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview, DiffMethod diffMethod) { + Objects.requireNonNull(sourceTextview, "source text view MUST NOT be null."); + Objects.requireNonNull(targetTextview, "target text view MUST NOT be null."); + + this.sourceTextview = sourceTextview; + this.targetTextview = targetTextview; + this.diffMethod = diffMethod; + } + + abstract void highlight(); + + protected List splitString(String str) { + return Arrays.asList(str.split(diffMethod.separator())); + } + + private void setDiffMethod(DiffMethod diffMethod) { + this.diffMethod = diffMethod; + } + + public DiffMethod getDiffMethod() { + return diffMethod; + } + + public String getSeparator() { + return diffMethod.separator(); + } + + enum DiffMethod { + WORDS(" "), CHARS(""); + + private final String separator; + + DiffMethod(String separator) { + this.separator = separator; + } + + public String separator() { + return separator; + } + } + + protected String join(List stringList) { + return String.join(" ", stringList); + } + + enum ChangeType { + ADDITION, DELETION, CHANGE_DELETION + } + + record Change( + int position, + int spanSize, + ChangeType type) { + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java new file mode 100644 index 00000000000..c24868e9a37 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -0,0 +1,24 @@ +package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; + +import com.github.difflib.patch.DeltaType; +import org.fxmisc.richtext.StyleClassedTextArea; + +/** + * A diff highlighter in which changes of type {@link DeltaType#CHANGE} are split between source and target + * text view. They are represented by an addition in the target text view and deletion in the source text view. + * Normal addition and deletion are kept as they are. + */ +public final class SplitDiffHighlighter extends DiffHighlighter { + + public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview, DiffMethod diffMethod) { + super(sourceTextview, targetTextview, diffMethod); + } + + public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { + this(sourceTextview, targetTextview, DiffMethod.WORDS); + } + + @Override + public void highlight() { + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java new file mode 100644 index 00000000000..216ba52369f --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java @@ -0,0 +1,117 @@ +package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.github.difflib.DiffUtils; +import com.github.difflib.patch.AbstractDelta; +import com.github.difflib.patch.DeltaType; +import org.fxmisc.richtext.StyleClassedTextArea; + +/** + * A diff highlighter in which differences of type {@link DeltaType#CHANGE} are unified and represented by an insertion + * and deletion in the target text view. Normal addition and deletion are kept as they are. + */ +public final class UnifiedDiffHighlighter extends DiffHighlighter { + + public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview, DiffMethod diffMethod) { + super(sourceTextview, targetTextview, diffMethod); + } + + public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { + this(sourceTextview, targetTextview, DiffMethod.WORDS); + } + + @SuppressWarnings({"checkstyle:RegexpMultiline", "checkstyle:EmptyBlock"}) + @Override + public void highlight() { + String sourceContent = sourceTextview.getText(); + String targetContent = targetTextview.getText(); + if (sourceContent.equals(targetContent)) { + return; + } + + List sourceWords = splitString(sourceContent); + List targetWords = splitString(targetContent); + List unifiedWords = new ArrayList<>(targetWords); + + List> deltaList = DiffUtils.diff(sourceWords, targetWords).getDeltas(); + + List changeList = new ArrayList<>(); + + int deletionCount = 0; + for (AbstractDelta delta : deltaList) { + switch (delta.getType()) { + case CHANGE -> { + int changePosition = delta.getTarget().getPosition(); + int deletionPoint = changePosition + deletionCount; + int insertionPoint = deletionPoint + 1; + List deltaSourceWords = delta.getSource().getLines(); + List deltaTargetWords = delta.getTarget().getLines(); + + unifiedWords.add(deletionPoint, join(deltaSourceWords)); + + changeList.add(new Change(deletionPoint, 1, ChangeType.CHANGE_DELETION)); + changeList.add(new Change(insertionPoint, deltaTargetWords.size(), ChangeType.ADDITION)); + deletionCount++; + } + case DELETE -> { + int deletionPoint = delta.getTarget().getPosition() + deletionCount; + unifiedWords.add(deletionPoint, join(delta.getSource().getLines())); + + changeList.add(new Change(deletionPoint, 1, ChangeType.DELETION)); + deletionCount++; + } + case INSERT -> { + int insertionPoint = delta.getTarget().getPosition() + deletionCount; + changeList.add(new Change(insertionPoint, delta.getTarget().getLines().size(), ChangeType.ADDITION)); + } + } + } + targetTextview.clear(); + + boolean changeInProgress = false; + for (int position = 0; position < unifiedWords.size(); position++) { + String word = unifiedWords.get(position); + Optional changeAtPosition = findChange(position, changeList); + if (changeAtPosition.isEmpty()) { + appendToTextArea(targetTextview, getSeparator() + word, "unchanged"); + } else { + Change change = changeAtPosition.get(); + List changeWords = unifiedWords.subList(change.position(), change.position() + change.spanSize()); + + if (change.type() == ChangeType.DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + } else if (change.type() == ChangeType.ADDITION) { + if (changeInProgress) { + appendToTextArea(targetTextview, join(changeWords), "addition"); + changeInProgress = false; + } else { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "addition"); + } + } else if (change.type() == ChangeType.CHANGE_DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + changeInProgress = true; + } + position = position + changeWords.size() - 1; + } + } + } + + private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { + if (text.isEmpty()) { + return; + } + // Append separator without styling it + if (text.startsWith(getSeparator())) { + textArea.appendText(getSeparator()); + } + int separatorIndex = text.indexOf(getSeparator()); + textArea.append(text.substring(separatorIndex != -1 ? separatorIndex + 1 : 0), styleClass); + } + + private Optional findChange(int position, List changeList) { + return changeList.stream().filter(change -> change.position() == position).findAny(); + } +} From 48f46c926b3e1a57490c8f3567fe85302e48e405 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:32:28 +0100 Subject: [PATCH 247/473] Create DiffHighlighter.css --- .../newmergedialog/diffhighlighter/DiffHighlighter.css | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css new file mode 100644 index 00000000000..e69de29bb2d From 6f8d19a1125bca541eccc61488ec082d9010fbcb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:33:23 +0100 Subject: [PATCH 248/473] Add left padding to HeaderCell --- .../jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 1bc003200ca..5a7c6a9ff71 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -1,5 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.geometry.Insets; import javafx.scene.control.Label; public class HeaderCell extends AbstractCell { @@ -19,5 +20,6 @@ private void initialize() { private void initializeLabel() { label.textProperty().bind(textProperty()); + label.setPadding(new Insets(getPadding().getTop(), getPadding().getRight(), getPadding().getBottom(), 16)); } } From d7f91c3f39b9f83ddf307532e5c87c9b3f523f87 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:34:45 +0100 Subject: [PATCH 249/473] Move diff highlighting styles to Dark.css - Just for testing --- src/main/java/org/jabref/gui/Dark.css | 13 +++++++++++++ .../newmergedialog/ThreeWayMergeView.css | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 3b8b05c861c..a3406f63f52 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -63,6 +63,19 @@ -js-summary-text-color-selected: derive( -fx-dark-text-color, 70%); } +.unchanged { + +} + +.addition { + -rtfx-background-color: #0B1935; +} + +.deletion { + -rtfx-background-color: #4E0A0D; + +} + #previewBody { background-color: #272b38; /* -fx-control-inner-background*/ color: #7d8591; /* -fx-mid-text-color*/ diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 815114bc7ae..5f4731c9f27 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -48,16 +48,3 @@ -fx-font-weight: bold; -fx-padding: 1, 0, 1, 0; } - -/* Diff Highlighting */ -.unchanged { - -} - -.addition { - -rtfx-background-color: rgba(35, 225, 96, 0.26); -} - -.deletion { - -rtfx-background-color: rgba(248, 62, 68, 0.26); -} From 4716f4b7141f102db07da7fa0cc4ec2eeac261be Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:35:53 +0100 Subject: [PATCH 250/473] Show differences between left and right values using a unified diff view - Just for testing --- .../gui/mergeentries/newmergedialog/FieldRowController.java | 6 ++++++ .../mergeentries/newmergedialog/cell/FieldValueCell.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 904ca57c390..f145ec1132d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -6,6 +6,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.model.strings.StringUtil; public class FieldRowController { @@ -52,6 +53,11 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } else if (StringUtil.isNullOrEmpty(rightValue)) { rightValueCell.setDisable(true); } + + // Debugging + if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel()).highlight(); + } } /** diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 8945cf688e5..440cf9e51a0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -191,4 +191,8 @@ public void setUserData(Object value) { public Object getUserData() { return super.getText(); } + + public StyleClassedTextArea getStyleClassedLabel() { + return label; + } } From e7817ebdb57ec501a94bd0b056172142fd375a63 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:36:09 +0100 Subject: [PATCH 251/473] Change MergeEntriesDialog stage style --- .../java/org/jabref/gui/mergeentries/MergeEntriesDialog.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 0a76be098a2..b70a2dc915e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -2,6 +2,7 @@ import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; +import javafx.stage.StageStyle; import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; @@ -22,6 +23,7 @@ public MergeEntriesDialog(BibEntry one, BibEntry two) { */ private void init() { this.getDialogPane().setContent(threeWayMergeView); + this.initStyle(StageStyle.UTILITY); // Create buttons ButtonType replaceEntries = new ButtonType(Localization.lang("Merge entries"), ButtonBar.ButtonData.OK_DONE); From a1f7ac123cac6016fe81ca1de15f5a851dc1356c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:38:40 +0100 Subject: [PATCH 252/473] Remove BackgroundTone from AbstractCell --- .../newmergedialog/cell/AbstractCell.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java index 10b13bd5b71..ffb1f536986 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java @@ -7,7 +7,6 @@ import javafx.css.PseudoClass; import javafx.geometry.Insets; import javafx.scene.layout.HBox; -import javafx.scene.paint.Color; /** * @@ -80,17 +79,4 @@ public StringProperty textProperty() { public void setText(String text) { textProperty().set(text); } - - public enum BackgroundTone { - LIGHT(Color.web("#FEFEFE")), DARK(Color.web("#EFEFEF")); - private final Color color; - - BackgroundTone(Color color) { - this.color = color; - } - - public Color color() { - return color; - } - } } From 17787f963a0629f0a43de20ee86ef17eb5019c11 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:39:09 +0100 Subject: [PATCH 253/473] Move CopyFieldValueCommand --- .../newmergedialog/{cell => }/CopyFieldValueCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{cell => }/CopyFieldValueCommand.java (92%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java similarity index 92% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java index e18a831933b..a3ef9024215 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java @@ -1,4 +1,4 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; +package org.jabref.gui.mergeentries.newmergedialog; import java.util.Objects; From 46fd34e06ba4b5c9d833df8c73c2ea795f042455 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:39:37 +0100 Subject: [PATCH 254/473] Make DiffMethod public --- .../newmergedialog/diffhighlighter/DiffHighlighter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java index e92a85e0a96..17149e368d6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.java @@ -39,7 +39,7 @@ public String getSeparator() { return diffMethod.separator(); } - enum DiffMethod { + public enum DiffMethod { WORDS(" "), CHARS(""); private final String separator; @@ -54,7 +54,7 @@ public String separator() { } protected String join(List stringList) { - return String.join(" ", stringList); + return String.join(getSeparator(), stringList); } enum ChangeType { From 980a85e3c134323790127bf95e77348391c340fe Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:40:54 +0100 Subject: [PATCH 255/473] Move CopyFieldValueCommand --- .../gui/mergeentries/newmergedialog/cell/FieldValueCell.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 440cf9e51a0..649d95e20d9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -24,6 +24,7 @@ import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.mergeentries.newmergedialog.CopyFieldValueCommand; import org.jabref.logic.l10n.Localization; import org.fxmisc.flowless.VirtualizedScrollPane; @@ -107,7 +108,7 @@ private void initializeLabel() { label.prefHeightProperty().bind(label.totalHeightEstimateProperty().orElseConst(-1d)); - // Fix text area consuming scroll events before they rich the outer scrollable + // Fix text area consuming scroll events before they reach the outer scrollable label.addEventFilter(ScrollEvent.SCROLL, e -> { e.consume(); FieldValueCell.this.fireEvent(e.copyFor(e.getSource(), FieldValueCell.this)); From 2ef153b7da6508d435b33d68e0c69c585406e006 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:41:34 +0100 Subject: [PATCH 256/473] Implement SplitDiffHighlighter --- src/main/java/org/jabref/gui/Base.css | 13 +++ src/main/java/org/jabref/gui/Dark.css | 5 +- .../diffhighlighter/SplitDiffHighlighter.java | 99 +++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 733bed56dbb..b6fadb6c1e4 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -256,6 +256,19 @@ -jr-header-height: 3em; } +.unchanged { + -rtfx-background-color:#0000; +} + +.addition { + -rtfx-background-color: rgba(29, 209, 161, 0.5); +} + +.deletion { + -rtfx-background-color: rgba(255, 107, 107, 0.55); +} + + #frame { -fx-background-color: -jr-background-alt; } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index a3406f63f52..8256314e86b 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -68,12 +68,11 @@ } .addition { - -rtfx-background-color: #0B1935; + -rtfx-background-color: -jr-green; } .deletion { - -rtfx-background-color: #4E0A0D; - + -rtfx-background-color: -jr-red; } #previewBody { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java index c24868e9a37..5e3ba6274c5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -1,5 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.github.difflib.DiffUtils; +import com.github.difflib.patch.AbstractDelta; import com.github.difflib.patch.DeltaType; import org.fxmisc.richtext.StyleClassedTextArea; @@ -20,5 +26,98 @@ public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTex @Override public void highlight() { + String sourceContent = sourceTextview.getText(); + String targetContent = targetTextview.getText(); + if (sourceContent.equals(targetContent)) { + return; + } + + List sourceWords = splitString(sourceContent); + List targetWords = splitString(targetContent); + List unifiedWords = new ArrayList<>(targetWords); + + List> deltaList = DiffUtils.diff(sourceWords, targetWords).getDeltas(); + + List changeList = new ArrayList<>(); + + int deletionCount = 0; + for (AbstractDelta delta : deltaList) { + switch (delta.getType()) { + case CHANGE -> { + int changePosition = delta.getTarget().getPosition(); + int deletionPoint = changePosition + deletionCount; + int insertionPoint = deletionPoint + 1; + List deltaSourceWords = delta.getSource().getLines(); + List deltaTargetWords = delta.getTarget().getLines(); + + unifiedWords.add(deletionPoint, join(deltaSourceWords)); + + changeList.add(new Change(deletionPoint, 1, ChangeType.CHANGE_DELETION)); + changeList.add(new Change(insertionPoint, deltaTargetWords.size(), ChangeType.ADDITION)); + deletionCount++; + } + case DELETE -> { + int deletionPoint = delta.getTarget().getPosition() + deletionCount; + unifiedWords.add(deletionPoint, join(delta.getSource().getLines())); + + changeList.add(new Change(deletionPoint, 1, ChangeType.DELETION)); + deletionCount++; + } + case INSERT -> { + int insertionPoint = delta.getTarget().getPosition() + deletionCount; + changeList.add(new Change(insertionPoint, delta.getTarget().getLines().size(), ChangeType.ADDITION)); + } + } + } + sourceTextview.clear(); + targetTextview.clear(); + + boolean changeInProgress = false; + for (int position = 0; position < unifiedWords.size(); position++) { + String word = unifiedWords.get(position); + Optional changeAtPosition = findChange(position, changeList); + if (changeAtPosition.isEmpty()) { + appendToTextArea(targetTextview, getSeparator() + word, "unchanged"); + } else { + Change change = changeAtPosition.get(); + List changeWords = unifiedWords.subList(change.position(), change.position() + change.spanSize()); + + if (change.type() == ChangeType.DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + } else if (change.type() == ChangeType.ADDITION) { + if (changeInProgress) { + appendToTextArea(targetTextview, join(changeWords), "addition"); + changeInProgress = false; + } else { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "addition"); + } + } else if (change.type() == ChangeType.CHANGE_DELETION) { + appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); + changeInProgress = true; + } + position = position + changeWords.size() - 1; + } + } + if (targetTextview.getLength() >= getSeparator().length()) { + // There always going to be an extra separator at the start + targetTextview.deleteText(0, getSeparator().length()); + } + } + + private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { + if (text.isEmpty()) { + return; + } + // Append separator without styling it + if (text.startsWith(getSeparator())) { + textArea.append(getSeparator(), "unchanged"); + textArea.append(text.substring(getSeparator().length()), styleClass); + } else { + textArea.append(text, styleClass); + } + } + + private Optional findChange(int position, List changeList) { + return changeList.stream().filter(change -> change.position() == position).findAny(); } } From ea5604758265b23e56a8a539a185d801ae6cbd62 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:44:12 +0100 Subject: [PATCH 257/473] Show diffs when user selects "Show Diff" in the toolbar UI - Only unified diff view will be shown for now --- .../newmergedialog/FieldRowController.java | 42 ++++++++++++++++--- .../newmergedialog/ShowDiffConfig.java | 6 +++ .../newmergedialog/ThreeWayMergeView.java | 14 +++++++ 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index f145ec1132d..64db8cf9fd0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -6,7 +6,9 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; public class FieldRowController { @@ -15,6 +17,10 @@ public class FieldRowController { private final FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; + private final String leftValue; + + private final String rightValue; + private final ToggleGroup toggleGroup = new ToggleGroup(); public FieldRowController(String fieldName, String leftValue, String rightValue, int rowIndex) { @@ -23,6 +29,9 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); + this.leftValue = leftValue; + this.rightValue = rightValue; + toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); toggleGroup.selectedToggleProperty().addListener(invalidated -> { @@ -53,11 +62,6 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } else if (StringUtil.isNullOrEmpty(rightValue)) { rightValueCell.setDisable(true); } - - // Debugging - if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel()).highlight(); - } } /** @@ -111,4 +115,32 @@ public boolean hasEqualLeftAndRightValues() { !StringUtil.isNullOrEmpty(rightValueCell.getText()) && leftValueCell.getText().equals(rightValueCell.getText()); } + + public void showDiffs(ShowDiffConfig diffConfig) { + // TODO: read this from diffConfig + if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { + if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { + hideDiffs(); + if (diffConfig.diffMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS) { + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.WORDS).highlight(); + } else { + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.CHARS).highlight(); + } + } + } + } + + public void hideDiffs() { + if (!StringUtil.isNullOrEmpty(leftValue)) { + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); + getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); + getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); + } + + if (!StringUtil.isNullOrEmpty(rightValue)) { + int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); + getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); + getRightValueCell().getStyleClassedLabel().replaceText(rightValue); + } + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java new file mode 100644 index 00000000000..e1de4e3fc9a --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java @@ -0,0 +1,6 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; + +public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, ThreeWayMergeToolbar.DiffHighlightMode diffMode) { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 4ec81f6d6f2..f741c1515ef 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -62,6 +62,20 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry) { private void initializeToolbar() { toolbar.setOnSelectLeftEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectLeftValue)); toolbar.setOnSelectRightEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectRightValue)); + + toolbar.showDiffProperty().addListener(e -> updateDiff()); + toolbar.diffViewProperty().addListener(e -> updateDiff()); + toolbar.diffHighlightModeProperty().addListener(e -> updateDiff()); + } + + private void updateDiff() { + if (toolbar.isShowDiffEnabled()) { + fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiffs( + new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightMode()) + )); + } else { + fieldRowControllerList.forEach(FieldRowController::hideDiffs); + } } private void initializeHeaderView() { From 8a5b534cb18c1408f8943bd3e93aecd4d89fae31 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:44:37 +0100 Subject: [PATCH 258/473] Fix bugs in UnifiedDiffHighlighter --- .../diffhighlighter/UnifiedDiffHighlighter.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java index 216ba52369f..38d6a92c389 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java @@ -20,10 +20,9 @@ public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedT } public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { - this(sourceTextview, targetTextview, DiffMethod.WORDS); + this(sourceTextview, targetTextview, DiffMethod.CHARS); } - @SuppressWarnings({"checkstyle:RegexpMultiline", "checkstyle:EmptyBlock"}) @Override public void highlight() { String sourceContent = sourceTextview.getText(); @@ -97,6 +96,10 @@ public void highlight() { position = position + changeWords.size() - 1; } } + if (targetTextview.getLength() >= getSeparator().length()) { + // There always going to be an extra separator at the start + targetTextview.deleteText(0, getSeparator().length()); + } } private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { @@ -105,10 +108,11 @@ private void appendToTextArea(StyleClassedTextArea textArea, String text, String } // Append separator without styling it if (text.startsWith(getSeparator())) { - textArea.appendText(getSeparator()); + textArea.append(getSeparator(), "unchanged"); + textArea.append(text.substring(getSeparator().length()), styleClass); + } else { + textArea.append(text, styleClass); } - int separatorIndex = text.indexOf(getSeparator()); - textArea.append(text.substring(separatorIndex != -1 ? separatorIndex + 1 : 0), styleClass); } private Optional findChange(int position, List changeList) { From 1a25db6b826e776e9f176de08d55d5a55d0c6892 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:45:14 +0100 Subject: [PATCH 259/473] Style css stuff --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 5f4731c9f27..27dc070635a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -16,16 +16,18 @@ } .field-value:selected .selection-box { - -fx-background-color: -jr-accent-alt; - -fx-border-color: -jr-accent-alt; + /* -fx-background-color: -jr-accent-alt; + -fx-border-color: -jr-accent-alt;*/ + -fx-background-color: rgba(163, 183, 230, 0.7); + -fx-border-color: -jr-accent; } .field-value .selection-box { -fx-background-color: #0000; - -fx-border-width: 1; -fx-border-color: #0000; -fx-border-radius: 8; -fx-background-radius: 8; + -fx-border-width: 2.5; } .styled-text-area .text{ From 0cf68c7d9063386d492f6bbbaee70eb68eb82c2f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:45:25 +0100 Subject: [PATCH 260/473] Fix typos --- .../mergeentries/newmergedialog/ThreeWayMergeHeaderView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index 9299c5f2ef9..4e9e15b3af5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -8,7 +8,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; /** - * I used a GridPane instead of a Hbox because Hbox allocates more space for cells + * GridPane was used instead of a Hbox because Hbox allocates more space for cells * with longer text, but I wanted all cells to have the same width */ public class ThreeWayMergeHeaderView extends GridPane { From 21421923bfc132ae0ea0cc046490f957be5aa947 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:50:09 +0100 Subject: [PATCH 261/473] Refactor SplitDiffHighlighter and fix bugs - Added "updated" style class for styling CHANGE diffs --- src/main/java/org/jabref/gui/Base.css | 4 + .../diffhighlighter/SplitDiffHighlighter.java | 118 ++++++------------ 2 files changed, 40 insertions(+), 82 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index b6fadb6c1e4..37b59e62c7c 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -260,6 +260,10 @@ -rtfx-background-color:#0000; } +.updated { + -rtfx-background-color: rgba(41, 166, 236, 0.66); +} + .addition { -rtfx-background-color: rgba(29, 209, 161, 0.5); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java index 5e3ba6274c5..5b7275220eb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -10,9 +10,8 @@ import org.fxmisc.richtext.StyleClassedTextArea; /** - * A diff highlighter in which changes of type {@link DeltaType#CHANGE} are split between source and target - * text view. They are represented by an addition in the target text view and deletion in the source text view. - * Normal addition and deletion are kept as they are. + * A diff highlighter in which changes are split between source and target text view. + * They are represented by an addition in the target text view and deletion in the source text view. */ public final class SplitDiffHighlighter extends DiffHighlighter { @@ -20,10 +19,6 @@ public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTex super(sourceTextview, targetTextview, diffMethod); } - public SplitDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { - this(sourceTextview, targetTextview, DiffMethod.WORDS); - } - @Override public void highlight() { String sourceContent = sourceTextview.getText(); @@ -32,92 +27,51 @@ public void highlight() { return; } - List sourceWords = splitString(sourceContent); - List targetWords = splitString(targetContent); - List unifiedWords = new ArrayList<>(targetWords); - - List> deltaList = DiffUtils.diff(sourceWords, targetWords).getDeltas(); + List sourceTokens = splitString(sourceContent); + List targetTokens = splitString(targetContent); - List changeList = new ArrayList<>(); + List> deltaList = DiffUtils.diff(sourceTokens, targetTokens).getDeltas(); - int deletionCount = 0; for (AbstractDelta delta : deltaList) { + int affectedSourceTokensPosition = delta.getSource().getPosition(); + int affectedTargetTokensPosition = delta.getTarget().getPosition(); + + List affectedTokensInSource = delta.getSource().getLines(); + List affectedTokensInTarget = delta.getTarget().getLines(); + int joinedSourceTokensLength = affectedTokensInSource.stream() + .map(String::length) + .reduce(Integer::sum) + .map(value -> value + (getSeparator().length() * (affectedTokensInSource.size() - 1))) + .orElse(0); + + int joinedTargetTokensLength = affectedTokensInTarget.stream() + .map(String::length) + .reduce(Integer::sum) + .map(value -> value + (getSeparator().length() * (affectedTokensInTarget.size() - 1))) + .orElse(0); + int affectedSourceTokensPositionInText = getPositionInText(affectedSourceTokensPosition, sourceTokens); + int affectedTargetTokensPositionInText = getPositionInText(affectedTargetTokensPosition, targetTokens); switch (delta.getType()) { case CHANGE -> { - int changePosition = delta.getTarget().getPosition(); - int deletionPoint = changePosition + deletionCount; - int insertionPoint = deletionPoint + 1; - List deltaSourceWords = delta.getSource().getLines(); - List deltaTargetWords = delta.getTarget().getLines(); - - unifiedWords.add(deletionPoint, join(deltaSourceWords)); - - changeList.add(new Change(deletionPoint, 1, ChangeType.CHANGE_DELETION)); - changeList.add(new Change(insertionPoint, deltaTargetWords.size(), ChangeType.ADDITION)); - deletionCount++; - } - case DELETE -> { - int deletionPoint = delta.getTarget().getPosition() + deletionCount; - unifiedWords.add(deletionPoint, join(delta.getSource().getLines())); - - changeList.add(new Change(deletionPoint, 1, ChangeType.DELETION)); - deletionCount++; - } - case INSERT -> { - int insertionPoint = delta.getTarget().getPosition() + deletionCount; - changeList.add(new Change(insertionPoint, delta.getTarget().getLines().size(), ChangeType.ADDITION)); - } - } - } - sourceTextview.clear(); - targetTextview.clear(); - - boolean changeInProgress = false; - for (int position = 0; position < unifiedWords.size(); position++) { - String word = unifiedWords.get(position); - Optional changeAtPosition = findChange(position, changeList); - if (changeAtPosition.isEmpty()) { - appendToTextArea(targetTextview, getSeparator() + word, "unchanged"); - } else { - Change change = changeAtPosition.get(); - List changeWords = unifiedWords.subList(change.position(), change.position() + change.spanSize()); - - if (change.type() == ChangeType.DELETION) { - appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); - } else if (change.type() == ChangeType.ADDITION) { - if (changeInProgress) { - appendToTextArea(targetTextview, join(changeWords), "addition"); - changeInProgress = false; - } else { - appendToTextArea(targetTextview, getSeparator() + join(changeWords), "addition"); - } - } else if (change.type() == ChangeType.CHANGE_DELETION) { - appendToTextArea(targetTextview, getSeparator() + join(changeWords), "deletion"); - changeInProgress = true; + sourceTextview.setStyleClass(affectedSourceTokensPositionInText, affectedSourceTokensPositionInText + joinedSourceTokensLength, "deletion"); + targetTextview.setStyleClass(affectedTargetTokensPositionInText, affectedTargetTokensPositionInText + joinedTargetTokensLength, "updated"); } - position = position + changeWords.size() - 1; + case DELETE -> + sourceTextview.setStyleClass(affectedSourceTokensPositionInText, affectedSourceTokensPositionInText + joinedSourceTokensLength, "deletion"); + case INSERT -> + targetTextview.setStyleClass(affectedTargetTokensPositionInText, affectedTargetTokensPositionInText + joinedTargetTokensLength, "addition"); } } - if (targetTextview.getLength() >= getSeparator().length()) { - // There always going to be an extra separator at the start - targetTextview.deleteText(0, getSeparator().length()); - } } - private void appendToTextArea(StyleClassedTextArea textArea, String text, String styleClass) { - if (text.isEmpty()) { - return; - } - // Append separator without styling it - if (text.startsWith(getSeparator())) { - textArea.append(getSeparator(), "unchanged"); - textArea.append(text.substring(getSeparator().length()), styleClass); + public int getPositionInText(int positionInTokenList, List tokenList) { + if (positionInTokenList == 0) { + return 0; } else { - textArea.append(text, styleClass); + return tokenList.stream().limit(positionInTokenList).map(String::length) + .reduce(Integer::sum) + .map(value -> value + (getSeparator().length() * positionInTokenList)) + .orElse(0); } } - - private Optional findChange(int position, List changeList) { - return changeList.stream().filter(change -> change.position() == position).findAny(); - } } From 868f314fee9ee741aab1602e3b3dc0f2558d32c5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:51:21 +0100 Subject: [PATCH 262/473] Remove redundant constructor from UnifiedDiffHighlighter --- .../diffhighlighter/UnifiedDiffHighlighter.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java index 38d6a92c389..54824f06d61 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/UnifiedDiffHighlighter.java @@ -19,10 +19,6 @@ public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedT super(sourceTextview, targetTextview, diffMethod); } - public UnifiedDiffHighlighter(StyleClassedTextArea sourceTextview, StyleClassedTextArea targetTextview) { - this(sourceTextview, targetTextview, DiffMethod.CHARS); - } - @Override public void highlight() { String sourceContent = sourceTextview.getText(); From a1fb60426ae5a50add86076b7ed39fad7926da4d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:53:14 +0100 Subject: [PATCH 263/473] Allow users to switch between split and unified diff view - Fixed some bugs --- .../newmergedialog/FieldRowController.java | 47 ++++++++++++------- .../newmergedialog/ShowDiffConfig.java | 3 +- .../newmergedialog/ThreeWayMergeView.java | 8 ++-- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 64db8cf9fd0..c599aebd81d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -6,7 +6,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; -import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; @@ -68,22 +68,32 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, * @return True if left value was selected, False otherwise */ public boolean selectLeftValue() { - if (!leftValueCell.isDisabled()) { + if (StringUtil.isNullOrEmpty(leftValue)) { + toggleGroup.selectToggle(null); + mergedValueCell.setText(""); + return false; + } else { toggleGroup.selectToggle(leftValueCell); return true; } - return false; } /** * @return True if left value was selected, False otherwise */ public boolean selectRightValue() { - if (!rightValueCell.isDisabled()) { - toggleGroup.selectToggle(rightValueCell); + if (StringUtil.isNullOrEmpty(rightValue)) { + toggleGroup.selectToggle(null); + mergedValueCell.setText(""); + return false; + } else { + if (hasEqualLeftAndRightValues()) { + toggleGroup.selectToggle(leftValueCell); + } else { + toggleGroup.selectToggle(rightValueCell); + } return true; } - return false; } public String getMergedValue() { @@ -116,21 +126,24 @@ public boolean hasEqualLeftAndRightValues() { leftValueCell.getText().equals(rightValueCell.getText()); } - public void showDiffs(ShowDiffConfig diffConfig) { - // TODO: read this from diffConfig + public void showDiff(ShowDiffConfig diffConfig) { + if (leftValueCell.isDisabled() || rightValueCell.isDisabled()) { + return; + } + // Clearing old diff styles + hideDiff(); if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { - if (!leftValueCell.isDisabled() && !rightValueCell.isDisabled()) { - hideDiffs(); - if (diffConfig.diffMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS) { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.WORDS).highlight(); - } else { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), rightValueCell.getStyleClassedLabel(), DiffHighlighter.DiffMethod.CHARS).highlight(); - } - } + new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), + rightValueCell.getStyleClassedLabel(), + diffConfig.diffMethod()).highlight(); + } else { + new SplitDiffHighlighter(leftValueCell.getStyleClassedLabel(), + rightValueCell.getStyleClassedLabel(), + diffConfig.diffMethod()).highlight(); } } - public void hideDiffs() { + public void hideDiff() { if (!StringUtil.isNullOrEmpty(leftValue)) { int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java index e1de4e3fc9a..05a4d0121a9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java @@ -1,6 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, ThreeWayMergeToolbar.DiffHighlightMode diffMode) { +public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, DiffHighlighter.DiffMethod diffMethod) { } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index f741c1515ef..efd7ea93316 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,6 +10,7 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -70,11 +71,10 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiffs( - new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightMode()) - )); + DiffHighlighter.DiffMethod diffMethod = toolbar.getDiffHighlightMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS ? DiffHighlighter.DiffMethod.WORDS : DiffHighlighter.DiffMethod.CHARS; + fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), diffMethod))); } else { - fieldRowControllerList.forEach(FieldRowController::hideDiffs); + fieldRowControllerList.forEach(FieldRowController::hideDiff); } } From 604330570acfe93b6d7830f863962b1e7f5824a0 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:53:58 +0100 Subject: [PATCH 264/473] Set left and right headers in MergeEntriesDialog --- .../org/jabref/gui/mergeentries/MergeEntriesDialog.java | 7 ++++--- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index b70a2dc915e..34dcba8b6db 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,5 +1,6 @@ package org.jabref.gui.mergeentries; +import javafx.geometry.Insets; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; import javafx.stage.StageStyle; @@ -23,7 +24,7 @@ public MergeEntriesDialog(BibEntry one, BibEntry two) { */ private void init() { this.getDialogPane().setContent(threeWayMergeView); - this.initStyle(StageStyle.UTILITY); + this.getDialogPane().setPadding(new Insets(0)); // Create buttons ButtonType replaceEntries = new ButtonType(Localization.lang("Merge entries"), ButtonBar.ButtonData.OK_DONE); @@ -38,10 +39,10 @@ private void init() { } public void setLeftHeaderText(String leftHeaderText) { - // mergeEntries.setLeftHeaderText(leftHeaderText); + threeWayMergeView.setLeftHeader(leftHeaderText); } public void setRightHeaderText(String rightHeaderText) { - // mergeEntries.setRightHeaderText(rightHeaderText); + threeWayMergeView.setRightHeader(rightHeaderText); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index efd7ea93316..506bdffcb3f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -148,4 +148,12 @@ private void addFieldRow(int index) { public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } + + public void setLeftHeader(String leftHeader) { + headerView.setLeftHeader(leftHeader); + } + + public void setRightHeader(String rightHeader) { + headerView.setRightHeader(rightHeader); + } } From d8d22466284488da29a3bdd1c0bbd05ac9f6d3c0 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:54:14 +0100 Subject: [PATCH 265/473] Refactor ThreeWayMergeHeaderView --- .../newmergedialog/ThreeWayMergeHeaderView.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index 4e9e15b3af5..05acddd5017 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -36,7 +36,10 @@ public ThreeWayMergeHeaderView(String leftHeader, String rightHeader) { setMaxHeight(Control.USE_PREF_SIZE); setMinHeight(Control.USE_PREF_SIZE); - bindHeaderWidthToFieldGridWidth(); + // The fields grid pane is contained within a scroll pane, thus it doesn't allocate the full available width. In + // fact, it uses the available width minus the size of the scrollbar which is 8. This leads to header columns being + // always wider than fields columns. This hack should fix it. + setPadding(new Insets(0, 8, 0, 0)); } public void setLeftHeader(String leftHeader) { @@ -46,13 +49,4 @@ public void setLeftHeader(String leftHeader) { public void setRightHeader(String rightHeader) { rightHeaderCell.setText(rightHeader); } - - /** - * The fields grid pane is contained within a scroll pane, thus it doesn't allocate the full available width. In - * fact, it uses the available width minus the size of the scrollbar which is 8. This leads to header columns being - * always larger than fields columns. This hack should fix it. - */ - private void bindHeaderWidthToFieldGridWidth() { - setPadding(new Insets(0, 8, 0, 0)); - } } From e27d8f917bc4b523959db6d503dc6101f00f0c64 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 28 Jun 2022 22:02:34 +0100 Subject: [PATCH 266/473] Remove wellbehavedfx module dependency --- src/main/java/module-info.java | 1 - .../newmergedialog/cell/FieldValueCell.java | 26 ++++++++----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index ab748522580..c05e10bda2b 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -116,7 +116,6 @@ requires net.harawata.appdirs; requires org.eclipse.jgit; - requires wellbehavedfx; uses org.eclipse.jgit.transport.SshSessionFactory; uses org.eclipse.jgit.lib.GpgSigner; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 649d95e20d9..e109c88caf2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -5,7 +5,6 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.PseudoClass; -import javafx.event.Event; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Cursor; @@ -29,15 +28,9 @@ import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.StyleClassedTextArea; -import org.fxmisc.wellbehaved.event.InputMap; -import org.fxmisc.wellbehaved.event.Nodes; import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.materialdesign2.MaterialDesignC; -import static org.fxmisc.wellbehaved.event.EventPattern.anyOf; -import static org.fxmisc.wellbehaved.event.EventPattern.eventType; -import static org.fxmisc.wellbehaved.event.EventPattern.mousePressed; - /** * A readonly, selectable field cell that contains the value of some field */ @@ -143,14 +136,17 @@ private void initializeScrollPane() { } private void preventTextSelectionViaMouseEvents() { - InputMap preventSelection = InputMap.consume( - anyOf(eventType(MouseEvent.MOUSE_DRAGGED), - eventType(MouseEvent.DRAG_DETECTED), - eventType(MouseEvent.MOUSE_ENTERED), - mousePressed().unless(e -> e.getClickCount() == 1) - ) - ); - Nodes.addInputMap(label, preventSelection); + label.addEventFilter(MouseEvent.ANY, e -> { + if (e.getEventType() == MouseEvent.MOUSE_DRAGGED || + e.getEventType() == MouseEvent.DRAG_DETECTED || + e.getEventType() == MouseEvent.MOUSE_ENTERED) { + e.consume(); + } else if (e.getEventType() == MouseEvent.MOUSE_PRESSED) { + if (e.getClickCount() > 1) { + e.consume(); + } + } + }); } @Override From 4891fdcabbf248e624b39c6cb7205d1912cf3a97 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:58:48 +0100 Subject: [PATCH 267/473] Delete EmptyCell.java - I might recreate it later, but for now, I'm choosing simplicity over performance --- .../newmergedialog/ThreeWayMergeHeaderView.java | 3 +-- .../mergeentries/newmergedialog/cell/EmptyCell.java | 13 ------------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index 05acddd5017..a3b33e99461 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -4,7 +4,6 @@ import javafx.scene.control.Control; import javafx.scene.layout.GridPane; -import org.jabref.gui.mergeentries.newmergedialog.cell.EmptyCell; import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; /** @@ -26,7 +25,7 @@ public ThreeWayMergeHeaderView(String leftHeader, String rightHeader) { this.mergedHeaderCell = new HeaderCell("Merged Entry"); addRow(0, - new EmptyCell(HeaderCell.DEFAULT_STYLE_CLASS), + new HeaderCell(""), leftHeaderCell, rightHeaderCell, mergedHeaderCell diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java deleted file mode 100644 index e52ada18b13..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/EmptyCell.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; - -public class EmptyCell extends AbstractCell { - public EmptyCell(String styleClass, int rowIndex) { - super("", rowIndex); - getStyleClass().add(styleClass); - setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); - } - - public EmptyCell(String styleClass) { - this(styleClass, AbstractCell.NO_ROW_NUMBER); - } -} From 3f571639ee7794deb9a61b3cf501c98fb0af5622 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 04:59:46 +0100 Subject: [PATCH 268/473] Refactor FieldValueCell --- .../newmergedialog/cell/FieldValueCell.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index e109c88caf2..cde5ae3ec9a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -116,18 +116,23 @@ private void initializeSelectionBox() { labelBox.setPadding(new Insets(8)); labelBox.setCursor(Cursor.HAND); + checkmarkLayout.getChildren().setAll(createCopyButton()); + checkmarkLayout.setAlignment(Pos.TOP_CENTER); + checkmarkLayout.setPrefWidth(28); + + } + + private Button createCopyButton() { FontIcon copyIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); + copyIcon.getStyleClass().add("copy-icon"); + Button copyButton = factory.createIconButton(() -> Localization.lang("Copy"), new CopyFieldValueCommand(Globals.prefs, getText())); copyButton.setGraphic(copyIcon); copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); - - copyIcon.getStyleClass().add("copy-icon"); - checkmarkLayout.getChildren().setAll(copyButton); - checkmarkLayout.setAlignment(Pos.TOP_CENTER); - checkmarkLayout.setPrefWidth(28); - copyButton.setMaxHeight(Double.MAX_VALUE); VBox.setVgrow(copyButton, Priority.ALWAYS); + + return copyButton; } private void initializeScrollPane() { From fb3509efcda98a27c4ec3b7da034d5170f97d9b9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:00:34 +0100 Subject: [PATCH 269/473] Use the new merge UI in DuplicateResolverDialog --- .../DuplicateResolverDialog.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index 1dad9cae973..822c63bf77f 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -11,6 +11,7 @@ import org.jabref.gui.duplicationFinder.DuplicateResolverDialog.DuplicateResolverResult; import org.jabref.gui.help.HelpAction; import org.jabref.gui.mergeentries.MergeEntries; +import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.DialogWindowState; import org.jabref.logic.help.HelpFile; @@ -39,7 +40,7 @@ public enum DuplicateResolverResult { BREAK } - private MergeEntries mergeEntries; + private ThreeWayMergeView threeWayMerge; private final DialogService dialogService; public DuplicateResolverDialog(BibEntry one, BibEntry two, DuplicateResolverType type, BibDatabaseContext database, StateManager stateManager, DialogService dialogService) { @@ -69,14 +70,14 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { 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); - mergeEntries = new MergeEntries(one, two); + threeWayMerge = new ThreeWayMergeView(one, two); 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); - mergeEntries = new MergeEntries(one, two, Localization.lang("Old entry"), - Localization.lang("From import")); + threeWayMerge = new ThreeWayMergeView(one, two, Localization.lang("Old entry"), + Localization.lang("From import")); break; case DUPLICATE_SEARCH_WITH_EXACT: first = new ButtonType(Localization.lang("Keep left"), ButtonData.APPLY); @@ -85,14 +86,14 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { removeExactVisible = true; - mergeEntries = new MergeEntries(one, two); + threeWayMerge = new ThreeWayMergeView(one, two); 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); - mergeEntries = new MergeEntries(one, two, Localization.lang("Old entry"), - Localization.lang("From import")); + threeWayMerge = new ThreeWayMergeView(one, two, Localization.lang("Old entry"), + Localization.lang("From import")); break; } if (removeExactVisible) { @@ -109,7 +110,7 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { this.setY(state.getY()); } - BorderPane borderPane = new BorderPane(mergeEntries); + BorderPane borderPane = new BorderPane(threeWayMerge); borderPane.setBottom(options); this.setResultConverter(button -> { @@ -136,6 +137,6 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { } public BibEntry getMergedEntry() { - return mergeEntries.getMergedEntry(); + return threeWayMerge.getMergedEntry(); } } From 6bb8f2c02a7219be1875714674808c42a47f169f Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:04:43 +0100 Subject: [PATCH 270/473] Expose an API to change diff view and highlight method from outside the merge toolbar --- .../newmergedialog/cell/FieldValueCell.java | 1 - .../toolbar/ThreeWayMergeToolbar.java | 42 ++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index cde5ae3ec9a..d511d57d427 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -119,7 +119,6 @@ private void initializeSelectionBox() { checkmarkLayout.getChildren().setAll(createCopyButton()); checkmarkLayout.setAlignment(Pos.TOP_CENTER); checkmarkLayout.setPrefWidth(28); - } private Button createCopyButton() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 0703f49f7c2..d0f13f1d95f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -1,7 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog.toolbar; import java.util.Arrays; -import java.util.function.Consumer; +import java.util.Objects; import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; @@ -12,13 +12,17 @@ import javafx.scene.control.ComboBox; import javafx.scene.control.RadioButton; import javafx.scene.control.ToggleGroup; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import javafx.util.StringConverter; +import org.jabref.gui.mergeentries.DiffHighlighting; +import org.jabref.gui.mergeentries.DiffMode; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; + import com.airhacks.afterburner.views.ViewLoader; import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; +import org.apache.commons.lang3.builder.Diff; public class ThreeWayMergeToolbar extends AnchorPane { @FXML @@ -98,7 +102,7 @@ public DiffView fromString(String string) { diffHighlightModeToggleGroup.selectToggle(highlightWordsRadioButton); } - public ReadOnlyObjectProperty diffViewProperty() { + public ObjectProperty diffViewProperty() { return diffViewComboBox.valueProperty(); } @@ -106,18 +110,26 @@ public DiffView getDiffView() { return diffViewProperty().get(); } + public void setDiffView(DiffView diffView) { + diffViewProperty().set(diffView); + } + public EasyBinding showDiffProperty() { return showDiff; } + public void setShowDiff(boolean showDiff) { + plainTextOrDiffComboBox.valueProperty().set(showDiff ? PlainTextOrDiff.Diff : PlainTextOrDiff.PLAIN_TEXT); + } + /** - * Convince method used to disable diff related views when diff is not selected. + * Convenience method used to disable diff related views when diff is not selected. * *

* This method is required because {@link EasyBinding} class doesn't have a method to invert a boolean property, * like {@link BooleanExpression#not()} *

- * */ + */ public EasyBinding notShowDiffProperty() { return showDiffProperty().map(showDiff -> !showDiff); } @@ -134,12 +146,16 @@ public DiffHighlightMode getDiffHighlightMode() { return diffHighlightModeProperty().get(); } - public void setOnSelectLeftEntryValuesButtonClicked(Consumer onClick) { - selectLeftEntryValuesButton.setOnMouseClicked(onClick::accept); + public void setDiffHighlightMode(DiffHighlightMode diffHighlightMode) { + diffHighlightModeProperty().set(diffHighlightMode); } - public void setOnSelectRightEntryValuesButtonClicked(Consumer onClick) { - selectRightEntryValuesButton.setOnMouseClicked(onClick::accept); + public void setOnSelectLeftEntryValuesButtonClicked(Runnable onClick) { + selectLeftEntryValuesButton.setOnMouseClicked(e -> onClick.run()); + } + + public void setOnSelectRightEntryValuesButtonClicked(Runnable onClick) { + selectRightEntryValuesButton.setOnMouseClicked(e -> onClick.run()); } public enum PlainTextOrDiff { @@ -184,7 +200,13 @@ public static DiffView fromString(String str) { } } + // TODO: remove this and use DiffMethod public enum DiffHighlightMode { - WORDS, CHARS + WORDS, CHARS; + + public static DiffHighlightMode from(DiffHighlighter.DiffMethod diffMethod) { + Objects.requireNonNull(diffMethod, "Diff method is required"); + return diffMethod == DiffHighlighter.DiffMethod.WORDS ? WORDS : CHARS; + } } } From a9f3254b7a1119a837886db23cf233daa068e352 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:05:27 +0100 Subject: [PATCH 271/473] Use the new merge UI when an entry is changed from external --- .../gui/collab/EntryChangeViewModel.java | 22 +++++++++++-------- .../newmergedialog/ThreeWayMergeView.java | 20 ++++++++++++++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java index 3ebed73f187..421e4c1fcd9 100644 --- a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java @@ -5,8 +5,10 @@ import javafx.scene.control.Label; import javafx.scene.layout.VBox; -import org.jabref.gui.mergeentries.MergeEntries; -import org.jabref.gui.mergeentries.MergeEntries.DefaultRadioButtonSelectionMode; +import org.jabref.gui.mergeentries.newmergedialog.ShowDiffConfig; +import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; +import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertEntries; import org.jabref.logic.l10n.Localization; @@ -17,7 +19,7 @@ class EntryChangeViewModel extends DatabaseChangeViewModel { private final BibEntry oldEntry; private final BibEntry newEntry; - private MergeEntries mergePanel; + private ThreeWayMergeView threeWayMergeView; public EntryChangeViewModel(BibEntry entry, BibEntry newEntry) { super(); @@ -37,9 +39,9 @@ public EntryChangeViewModel(BibEntry entry, BibEntry newEntry) { public void setAccepted(boolean accepted) { super.setAccepted(accepted); if (accepted) { - mergePanel.selectAllRightRadioButtons(); + threeWayMergeView.selectRightEntryValues(); } else { - mergePanel.selectAllLeftRadioButtons(); + threeWayMergeView.selectLeftEntryValues(); } } @@ -47,7 +49,7 @@ public void setAccepted(boolean accepted) { public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { this.description(); // Init dialog to prevent NPE database.getDatabase().removeEntry(oldEntry); - BibEntry mergedEntry = mergePanel.getMergedEntry(); + BibEntry mergedEntry = threeWayMergeView.getMergedEntry(); mergedEntry.setId(oldEntry.getId()); // Keep ID database.getDatabase().insertEntry(mergedEntry); undoEdit.addEdit(new UndoableInsertEntries(database.getDatabase(), oldEntry)); @@ -56,13 +58,15 @@ public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { @Override public Node description() { - mergePanel = new MergeEntries(oldEntry, newEntry, Localization.lang("In JabRef"), Localization.lang("On disk"), DefaultRadioButtonSelectionMode.LEFT); + threeWayMergeView = new ThreeWayMergeView(oldEntry, newEntry, Localization.lang("In JabRef"), Localization.lang("On disk")); + threeWayMergeView.selectLeftEntryValues(); + threeWayMergeView.showDiff(new ShowDiffConfig(ThreeWayMergeToolbar.DiffView.SPLIT, DiffHighlighter.DiffMethod.WORDS)); VBox container = new VBox(10); Label header = new Label(name); header.getStyleClass().add("sectionHeader"); container.getChildren().add(header); - container.getChildren().add(mergePanel); - VBox.setMargin(mergePanel, new Insets(5, 5, 5, 5)); + container.getChildren().add(threeWayMergeView); + VBox.setMargin(threeWayMergeView, new Insets(5, 5, 5, 5)); return container; } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 506bdffcb3f..ae7aa604904 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -50,7 +50,7 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea initializeHeaderView(); initializeToolbar(); - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.75); this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); getChildren().addAll(toolbar, headerView, scrollPane); @@ -61,8 +61,8 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry) { } private void initializeToolbar() { - toolbar.setOnSelectLeftEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectLeftValue)); - toolbar.setOnSelectRightEntryValuesButtonClicked(e -> fieldRowControllerList.forEach(FieldRowController::selectRightValue)); + toolbar.setOnSelectLeftEntryValuesButtonClicked(this::selectLeftEntryValues); + toolbar.setOnSelectRightEntryValuesButtonClicked(this::selectRightEntryValues); toolbar.showDiffProperty().addListener(e -> updateDiff()); toolbar.diffViewProperty().addListener(e -> updateDiff()); @@ -156,4 +156,18 @@ public void setLeftHeader(String leftHeader) { public void setRightHeader(String rightHeader) { headerView.setRightHeader(rightHeader); } + + public void selectLeftEntryValues() { + fieldRowControllerList.forEach(FieldRowController::selectLeftValue); + } + + public void selectRightEntryValues() { + fieldRowControllerList.forEach(FieldRowController::selectRightValue); + } + + public void showDiff(ShowDiffConfig diffConfig) { + toolbar.setDiffView(diffConfig.diffView()); + toolbar.setDiffHighlightMode(ThreeWayMergeToolbar.DiffHighlightMode.from(diffConfig.diffMethod())); + toolbar.setShowDiff(true); + } } From 30b4f74c8e510d8a3386c4fbd91599f8af61062c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 29 Jun 2022 17:51:51 +0100 Subject: [PATCH 272/473] Minor styling --- .../org/jabref/gui/mergeentries/MergeEntriesDialog.java | 6 +++--- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 2 +- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 34dcba8b6db..3486a9702d2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,9 +1,7 @@ package org.jabref.gui.mergeentries; -import javafx.geometry.Insets; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; -import javafx.stage.StageStyle; import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; @@ -23,8 +21,10 @@ public MergeEntriesDialog(BibEntry one, BibEntry two) { * Sets up the dialog */ private void init() { + this.setX(20); + this.setY(20); + this.getDialogPane().setContent(threeWayMergeView); - this.getDialogPane().setPadding(new Insets(0)); // Create buttons ButtonType replaceEntries = new ButtonType(Localization.lang("Merge entries"), ButtonBar.ButtonData.OK_DONE); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 27dc070635a..b776ff345c6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -18,7 +18,7 @@ .field-value:selected .selection-box { /* -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent-alt;*/ - -fx-background-color: rgba(163, 183, 230, 0.7); + -fx-background-color: rgba(163, 183, 230, 0.80); -fx-border-color: -jr-accent; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index ae7aa604904..1474fc249b6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -50,8 +50,8 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea initializeHeaderView(); initializeToolbar(); - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.75); - this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.95); + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); + this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.97); getChildren().addAll(toolbar, headerView, scrollPane); } From 7022b741f25d182a31948f73f1bcdcf762edeabf Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:06:43 +0100 Subject: [PATCH 273/473] Remove DiffHighlighter.css stylesheet - You can find diff styles in Base.css and Dark.css --- .../newmergedialog/diffhighlighter/DiffHighlighter.css | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/DiffHighlighter.css deleted file mode 100644 index e69de29bb2d..00000000000 From 6fee209f1c2bb8390be39b3145fefec5d8019ad1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:08:14 +0100 Subject: [PATCH 274/473] Remove unused dependencies --- .../newmergedialog/toolbar/ThreeWayMergeToolbar.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index d0f13f1d95f..5c37e61a837 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -5,7 +5,6 @@ import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -15,14 +14,11 @@ import javafx.scene.layout.AnchorPane; import javafx.util.StringConverter; -import org.jabref.gui.mergeentries.DiffHighlighting; -import org.jabref.gui.mergeentries.DiffMode; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import com.airhacks.afterburner.views.ViewLoader; import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; -import org.apache.commons.lang3.builder.Diff; public class ThreeWayMergeToolbar extends AnchorPane { @FXML From 23223de832741da38224cf5722f9e6c5fec7fcc6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:08:49 +0100 Subject: [PATCH 275/473] Allow selecting empty field values --- .../newmergedialog/FieldRowController.java | 84 ++++++------------- .../newmergedialog/ThreeWayMergeView.java | 3 +- 2 files changed, 28 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index c599aebd81d..24a949b230e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -11,6 +11,8 @@ import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; +import org.fxmisc.richtext.StyleClassedTextArea; + public class FieldRowController { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; @@ -41,58 +43,31 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, }); mergedValueCell.textProperty().addListener((observable, old, mergedValue) -> { - if (!StringUtil.isNullOrEmpty(mergedValue)) { - if (mergedValue.equals(leftValue)) { - toggleGroup.selectToggle(leftValueCell); - } else if (mergedValue.equals(rightValue)) { - toggleGroup.selectToggle(rightValueCell); - } else { - // deselect all toggles because left and right values don't equal the merged value - toggleGroup.selectToggle(null); - } + if (mergedValue.equals(leftValue)) { + toggleGroup.selectToggle(leftValueCell); + } else if (mergedValue.equals(rightValue)) { + toggleGroup.selectToggle(rightValueCell); } else { - // deselect all toggles because empty toggles cannot be selected + // deselect all toggles because left and right values don't equal the merged value toggleGroup.selectToggle(null); } }); - // empty toggles are disabled and cannot be selected - if (StringUtil.isNullOrEmpty(leftValue)) { - leftValueCell.setDisable(true); - } else if (StringUtil.isNullOrEmpty(rightValue)) { + // Because when both left and right have the same values, then only left value will be shown + if (hasEqualLeftAndRightValues()) { rightValueCell.setDisable(true); } } - /** - * @return True if left value was selected, False otherwise - */ - public boolean selectLeftValue() { - if (StringUtil.isNullOrEmpty(leftValue)) { - toggleGroup.selectToggle(null); - mergedValueCell.setText(""); - return false; - } else { - toggleGroup.selectToggle(leftValueCell); - return true; - } + public void selectLeftValue() { + toggleGroup.selectToggle(leftValueCell); } - /** - * @return True if left value was selected, False otherwise - */ - public boolean selectRightValue() { - if (StringUtil.isNullOrEmpty(rightValue)) { - toggleGroup.selectToggle(null); - mergedValueCell.setText(""); - return false; + public void selectRightValue() { + if (rightValueCell.isDisabled()) { + selectLeftValue(); } else { - if (hasEqualLeftAndRightValues()) { - toggleGroup.selectToggle(leftValueCell); - } else { - toggleGroup.selectToggle(rightValueCell); - } - return true; + toggleGroup.selectToggle(rightValueCell); } } @@ -130,30 +105,25 @@ public void showDiff(ShowDiffConfig diffConfig) { if (leftValueCell.isDisabled() || rightValueCell.isDisabled()) { return; } - // Clearing old diff styles + + StyleClassedTextArea leftLabel = leftValueCell.getStyleClassedLabel(); + StyleClassedTextArea rightLabel = rightValueCell.getStyleClassedLabel(); + // Clearing old diff styles based on previous diffConfig hideDiff(); if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { - new UnifiedDiffHighlighter(leftValueCell.getStyleClassedLabel(), - rightValueCell.getStyleClassedLabel(), - diffConfig.diffMethod()).highlight(); + new UnifiedDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); } else { - new SplitDiffHighlighter(leftValueCell.getStyleClassedLabel(), - rightValueCell.getStyleClassedLabel(), - diffConfig.diffMethod()).highlight(); + new SplitDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); } } public void hideDiff() { - if (!StringUtil.isNullOrEmpty(leftValue)) { - int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); - getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); - getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); - } + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); + getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); + getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); - if (!StringUtil.isNullOrEmpty(rightValue)) { - int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); - getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); - getRightValueCell().getStyleClassedLabel().replaceText(rightValue); - } + int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); + getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); + getRightValueCell().getStyleClassedLabel().replaceText(rightValue); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 1474fc249b6..fe77ea972c5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -50,7 +50,7 @@ public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHea initializeHeaderView(); initializeToolbar(); - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.80); + this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.76); this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.97); getChildren().addAll(toolbar, headerView, scrollPane); @@ -139,7 +139,6 @@ private void addFieldRow(int index) { mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index, 1, 1); - fieldRow.getRightValueCell().setDisable(true); } else { mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); } From f9c4a185436347f79511e952d255eb23aa3abea1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:15:37 +0100 Subject: [PATCH 276/473] Fix readme :( --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08b68588cfb..23cc6f637f6 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,6 @@ For IntelliJ IDEA, just import the project via a Gradle Import by pointing at th ## Sponsoring -JabRef development is by powered YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) +JabRef development is powered by YourKit Java Profiler [![YourKit Java Profiler](https://www.yourkit.com/images/yk_logo.png)](https://www.yourkit.com/java/profiler/) [JabRef]: https://www.jabref.org From a5bc68948c58243d4803e9802a1a8638128eccbc Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 2 Jul 2022 05:31:03 +0100 Subject: [PATCH 277/473] Use a theme color for selection box background --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index b776ff345c6..59963812688 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -18,7 +18,7 @@ .field-value:selected .selection-box { /* -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent-alt;*/ - -fx-background-color: rgba(163, 183, 230, 0.80); + -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent; } From 4bd99c20ce3049b07087ded5bb729807eb38199e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 18:33:48 +0100 Subject: [PATCH 278/473] Refactor FieldValueCell --- .../newmergedialog/cell/FieldValueCell.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index d511d57d427..08ad2b33ff4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -65,7 +65,7 @@ protected void invalidated() { } }; private final HBox selectionBox = new HBox(); - private final VBox checkmarkLayout = new VBox(); + private final HBox actionsContainer = new HBox(); public FieldValueCell(String text, int rowIndex) { super(text, rowIndex); @@ -84,7 +84,7 @@ private void initialize() { } }); - selectionBox.getChildren().addAll(labelBox, checkmarkLayout); + selectionBox.getChildren().addAll(labelBox, actionsContainer); getChildren().setAll(selectionBox); } @@ -116,9 +116,9 @@ private void initializeSelectionBox() { labelBox.setPadding(new Insets(8)); labelBox.setCursor(Cursor.HAND); - checkmarkLayout.getChildren().setAll(createCopyButton()); - checkmarkLayout.setAlignment(Pos.TOP_CENTER); - checkmarkLayout.setPrefWidth(28); + actionsContainer.getChildren().setAll(createCopyButton()); + actionsContainer.setAlignment(Pos.TOP_CENTER); + actionsContainer.setPrefWidth(28); } private Button createCopyButton() { @@ -129,7 +129,6 @@ private Button createCopyButton() { copyButton.setGraphic(copyIcon); copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); copyButton.setMaxHeight(Double.MAX_VALUE); - VBox.setVgrow(copyButton, Priority.ALWAYS); return copyButton; } From e2d4f767790dc12884b2a9af6f8654039aeca866 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 19:40:16 +0100 Subject: [PATCH 279/473] Add an action to FieldValueCell for opening Urls --- src/main/java/org/jabref/gui/Base.css | 8 ++-- src/main/java/org/jabref/gui/Dark.css | 8 ++-- .../{ => cell}/CopyFieldValueCommand.java | 2 +- .../newmergedialog/cell/FieldValueCell.java | 43 ++++++++++++++++--- .../cell/OpenExternalLinkAction.java | 32 ++++++++++++++ 5 files changed, 77 insertions(+), 16 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ => cell}/CopyFieldValueCommand.java (92%) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 37b59e62c7c..4417f822d8e 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -635,18 +635,18 @@ TextFlow > .tooltip-text-monospaced { -fx-background-insets: 0; } -.field-value .copy-icon { - -fx-icon-size: 15; +.field-value .action-icon { + -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; -fx-blend-mode: multiply ; -fx-opacity: 69%; } -.field-value:disabled .copy-icon { +.field-value:disabled .action-icon { -fx-opacity: 0%; } -.field-value:selected .copy-icon { +.field-value:selected .action-icon { } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 8256314e86b..c2fb6e76b88 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -96,18 +96,18 @@ .tree-table-row-cell:hover { -fx-background-color: -jr-hover; } -.field-value .copy-icon { - -fx-icon-size: 15; +.field-value .action-icon { + -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; -fx-blend-mode: inherit; -fx-opacity: 100%; } -.field-value:disabled .copy-icon { +.field-value:disabled .action-icon { -fx-opacity: 0%; } -.field-value:selected .copy-icon { +.field-value:selected .action-icon { -fx-icon-color: -fx-text-background-color; -fx-opacity: 100%; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java similarity index 92% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java index a3ef9024215..e18a831933b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/CopyFieldValueCommand.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/CopyFieldValueCommand.java @@ -1,4 +1,4 @@ -package org.jabref.gui.mergeentries.newmergedialog; +package org.jabref.gui.mergeentries.newmergedialog.cell; import java.util.Objects; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 08ad2b33ff4..acb1cb4d600 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -3,11 +3,13 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanPropertyBase; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.PseudoClass; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Cursor; +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ContentDisplay; import javafx.scene.control.ScrollPane; @@ -18,23 +20,29 @@ import javafx.scene.layout.Background; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; -import org.jabref.gui.mergeentries.newmergedialog.CopyFieldValueCommand; +import org.jabref.gui.fieldeditors.URLUtil; +import org.jabref.gui.icon.IconTheme; import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; +import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.StyleClassedTextArea; import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.materialdesign2.MaterialDesignC; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A readonly, selectable field cell that contains the value of some field */ public class FieldValueCell extends AbstractCell implements Toggle { + public static final Logger LOGGER = LoggerFactory.getLogger(FieldValueCell.class); + public static final String DEFAULT_STYLE_CLASS = "field-value"; public static final String SELECTION_BOX_STYLE_CLASS = "selection-box"; @@ -67,6 +75,8 @@ protected void invalidated() { private final HBox selectionBox = new HBox(); private final HBox actionsContainer = new HBox(); + private final BooleanProperty isUrl = new SimpleBooleanProperty(); + public FieldValueCell(String text, int rowIndex) { super(text, rowIndex); initialize(); @@ -77,6 +87,7 @@ private void initialize() { initializeScrollPane(); initializeLabel(); initializeSelectionBox(); + initializeActions(); textProperty().addListener(invalidated -> setUserData(getText())); setOnMouseClicked(e -> { if (!isDisabled()) { @@ -108,6 +119,12 @@ private void initializeLabel() { }); } + private void initializeActions() { + actionsContainer.getChildren().setAll(createOpenLinkButton(), createCopyButton()); + actionsContainer.setAlignment(Pos.TOP_CENTER); + actionsContainer.setPrefWidth(28); + } + private void initializeSelectionBox() { selectionBox.getStyleClass().add(SELECTION_BOX_STYLE_CLASS); HBox.setHgrow(selectionBox, Priority.ALWAYS); @@ -115,24 +132,36 @@ private void initializeSelectionBox() { HBox.setHgrow(labelBox, Priority.ALWAYS); labelBox.setPadding(new Insets(8)); labelBox.setCursor(Cursor.HAND); - - actionsContainer.getChildren().setAll(createCopyButton()); - actionsContainer.setAlignment(Pos.TOP_CENTER); - actionsContainer.setPrefWidth(28); } private Button createCopyButton() { FontIcon copyIcon = FontIcon.of(MaterialDesignC.CONTENT_COPY); - copyIcon.getStyleClass().add("copy-icon"); + copyIcon.getStyleClass().add("action-icon"); Button copyButton = factory.createIconButton(() -> Localization.lang("Copy"), new CopyFieldValueCommand(Globals.prefs, getText())); copyButton.setGraphic(copyIcon); copyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); copyButton.setMaxHeight(Double.MAX_VALUE); + copyButton.visibleProperty().bind(textProperty().isEmpty().not()); return copyButton; } + public Button createOpenLinkButton() { + Node openLinkIcon = IconTheme.JabRefIcons.OPEN_LINK.getGraphicNode(); + openLinkIcon.getStyleClass().add("action-icon"); + + Button openLinkButton = factory.createIconButton(() -> Localization.lang("Open Link"), new OpenExternalLinkAction(getText())); + openLinkButton.setGraphic(openLinkIcon); + openLinkButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + openLinkButton.setMaxHeight(Double.MAX_VALUE); + + isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && URLUtil.isURL(input))); + openLinkButton.visibleProperty().bind(isUrl); + + return openLinkButton; + } + private void initializeScrollPane() { HBox.setHgrow(scrollPane, Priority.ALWAYS); scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java new file mode 100644 index 00000000000..6651be0d530 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java @@ -0,0 +1,32 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import java.io.IOException; + +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.model.strings.StringUtil; + +/** + * This action can open an Url and DOI + * */ +public class OpenExternalLinkAction extends SimpleCommand { + private final String urlOrDoi; + + public OpenExternalLinkAction(String urlOrDoi) { + this.urlOrDoi = urlOrDoi; + } + + @Override + public void execute() { + if (StringUtil.isBlank(urlOrDoi)) { + return; + } + + try { + JabRefDesktop.openBrowser(urlOrDoi); + } catch ( + IOException ex) { + // TODO: Do something + } + } +} From b8a357574d6f1f2eb1a00b67109cba98689c354e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 19:55:19 +0100 Subject: [PATCH 280/473] Add the ability to open DOI identifier --- .../newmergedialog/cell/FieldValueCell.java | 3 ++- .../newmergedialog/cell/OpenExternalLinkAction.java | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index acb1cb4d600..9e86ab58e15 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -27,6 +27,7 @@ import org.jabref.gui.fieldeditors.URLUtil; import org.jabref.gui.icon.IconTheme; import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.identifier.DOI; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -156,7 +157,7 @@ public Button createOpenLinkButton() { openLinkButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); openLinkButton.setMaxHeight(Double.MAX_VALUE); - isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && URLUtil.isURL(input))); + isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && (URLUtil.isURL(input) || DOI.isValid(input)))); openLinkButton.visibleProperty().bind(isUrl); return openLinkButton; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java index 6651be0d530..102b192458a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java @@ -1,9 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; import java.io.IOException; +import java.net.URI; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.model.entry.identifier.DOI; import org.jabref.model.strings.StringUtil; /** @@ -23,7 +25,14 @@ public void execute() { } try { - JabRefDesktop.openBrowser(urlOrDoi); + String url; + if (DOI.isValid(urlOrDoi)) { + url = DOI.parse(urlOrDoi).flatMap(DOI::getExternalURI).map(URI::toString).orElse(""); + } else { + url = urlOrDoi; + } + + JabRefDesktop.openBrowser(url); } catch ( IOException ex) { // TODO: Do something From 28fbefbcea0b420ac173a6085d2223b5a47350f0 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 20:07:02 +0100 Subject: [PATCH 281/473] Cleanup --- .../mergeentries/newmergedialog/cell/FieldValueCell.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 9e86ab58e15..82ca6b0c235 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -3,7 +3,6 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanPropertyBase; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.PseudoClass; import javafx.geometry.Insets; @@ -76,8 +75,6 @@ protected void invalidated() { private final HBox selectionBox = new HBox(); private final HBox actionsContainer = new HBox(); - private final BooleanProperty isUrl = new SimpleBooleanProperty(); - public FieldValueCell(String text, int rowIndex) { super(text, rowIndex); initialize(); @@ -157,8 +154,7 @@ public Button createOpenLinkButton() { openLinkButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); openLinkButton.setMaxHeight(Double.MAX_VALUE); - isUrl.bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && (URLUtil.isURL(input) || DOI.isValid(input)))); - openLinkButton.visibleProperty().bind(isUrl); + openLinkButton.visibleProperty().bind(EasyBind.map(textProperty(), input -> StringUtil.isNotBlank(input) && (URLUtil.isURL(input) || DOI.isValid(input)))); return openLinkButton; } From a471e20d4f867623eb3ce70f039dd5640a1a35eb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 3 Jul 2022 20:12:01 +0100 Subject: [PATCH 282/473] Checkstyle --- .../jabref/gui/duplicationFinder/DuplicateResolverDialog.java | 1 - .../newmergedialog/diffhighlighter/SplitDiffHighlighter.java | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index 822c63bf77f..cec54b0d192 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -10,7 +10,6 @@ import org.jabref.gui.StateManager; import org.jabref.gui.duplicationFinder.DuplicateResolverDialog.DuplicateResolverResult; import org.jabref.gui.help.HelpAction; -import org.jabref.gui.mergeentries.MergeEntries; import org.jabref.gui.mergeentries.newmergedialog.ThreeWayMergeView; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.DialogWindowState; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java index 5b7275220eb..14570f6b2a8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/diffhighlighter/SplitDiffHighlighter.java @@ -1,12 +1,9 @@ package org.jabref.gui.mergeentries.newmergedialog.diffhighlighter; -import java.util.ArrayList; import java.util.List; -import java.util.Optional; import com.github.difflib.DiffUtils; import com.github.difflib.patch.AbstractDelta; -import com.github.difflib.patch.DeltaType; import org.fxmisc.richtext.StyleClassedTextArea; /** From 03ee8c0e42271eaf132d30ef89ab0ce8c8f32108 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 4 Jul 2022 21:29:07 +0100 Subject: [PATCH 283/473] Improve URL validation logic --- src/main/java/org/jabref/gui/fieldeditors/URLUtil.java | 7 ++++++- src/test/java/org/jabref/logic/net/URLUtilTest.java | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java b/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java index bb73b95a6d9..1ee8e8b2652 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java +++ b/src/main/java/org/jabref/gui/fieldeditors/URLUtil.java @@ -74,7 +74,12 @@ public static String cleanGoogleSearchURL(String url) { * @return true if url contains a valid URL */ public static boolean isURL(String url) { - return url.contains("://"); + try { + new URL(url); + return true; + } catch (MalformedURLException e) { + return false; + } } /** diff --git a/src/test/java/org/jabref/logic/net/URLUtilTest.java b/src/test/java/org/jabref/logic/net/URLUtilTest.java index 04ed0e99a94..d69d7a1df7e 100644 --- a/src/test/java/org/jabref/logic/net/URLUtilTest.java +++ b/src/test/java/org/jabref/logic/net/URLUtilTest.java @@ -73,4 +73,9 @@ void isURLshouldRejectInvalidURL() { assertFalse(URLUtil.isURL("www.google.com")); assertFalse(URLUtil.isURL("google.com")); } + + @Test + void isURLshouldRejectEmbeddedURL() { + assertFalse(URLUtil.isURL("dblp computer science bibliography, http://dblp.org")); + } } From 06df19e9348406efcc1bafb3b20e2894ffac9b99 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 4 Jul 2022 21:42:18 +0100 Subject: [PATCH 284/473] Use DiffMethod in merge toolbar for consistency --- .../newmergedialog/FieldRowController.java | 6 +-- .../newmergedialog/ShowDiffConfig.java | 8 ++-- .../newmergedialog/ThreeWayMergeView.java | 8 ++-- .../toolbar/ThreeWayMergeToolbar.fxml | 4 +- .../toolbar/ThreeWayMergeToolbar.java | 39 +++++++------------ 5 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 24a949b230e..d1fb3b248a9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -53,7 +53,7 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } }); - // Because when both left and right have the same values, then only left value will be shown + // When left and right have the same value, only the left value will be shown if (hasEqualLeftAndRightValues()) { rightValueCell.setDisable(true); } @@ -111,9 +111,9 @@ public void showDiff(ShowDiffConfig diffConfig) { // Clearing old diff styles based on previous diffConfig hideDiff(); if (diffConfig.diffView() == ThreeWayMergeToolbar.DiffView.UNIFIED) { - new UnifiedDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); + new UnifiedDiffHighlighter(leftLabel, rightLabel, diffConfig.diffHighlightingMethod()).highlight(); } else { - new SplitDiffHighlighter(leftLabel, rightLabel, diffConfig.diffMethod()).highlight(); + new SplitDiffHighlighter(leftLabel, rightLabel, diffConfig.diffHighlightingMethod()).highlight(); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java index 05a4d0121a9..62697e3119b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ShowDiffConfig.java @@ -1,7 +1,9 @@ package org.jabref.gui.mergeentries.newmergedialog; -import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; -import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import static org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter.DiffMethod; +import static org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar.DiffView; -public record ShowDiffConfig(ThreeWayMergeToolbar.DiffView diffView, DiffHighlighter.DiffMethod diffMethod) { +public record ShowDiffConfig( + DiffView diffView, + DiffMethod diffHighlightingMethod) { } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index fe77ea972c5..0c6221450f4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,7 +10,6 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -66,13 +65,12 @@ private void initializeToolbar() { toolbar.showDiffProperty().addListener(e -> updateDiff()); toolbar.diffViewProperty().addListener(e -> updateDiff()); - toolbar.diffHighlightModeProperty().addListener(e -> updateDiff()); + toolbar.diffHighlightingMethodProperty().addListener(e -> updateDiff()); } private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - DiffHighlighter.DiffMethod diffMethod = toolbar.getDiffHighlightMode() == ThreeWayMergeToolbar.DiffHighlightMode.WORDS ? DiffHighlighter.DiffMethod.WORDS : DiffHighlighter.DiffMethod.CHARS; - fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), diffMethod))); + fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { fieldRowControllerList.forEach(FieldRowController::hideDiff); } @@ -166,7 +164,7 @@ public void selectRightEntryValues() { public void showDiff(ShowDiffConfig diffConfig) { toolbar.setDiffView(diffConfig.diffView()); - toolbar.setDiffHighlightMode(ThreeWayMergeToolbar.DiffHighlightMode.from(diffConfig.diffMethod())); + toolbar.setDiffHighlightingMethod(diffConfig.diffHighlightingMethod()); toolbar.setShowDiff(true); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml index 39df997c47b..2361c686981 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml @@ -38,10 +38,10 @@ - + - + diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 5c37e61a837..6efadffa2bf 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -1,7 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog.toolbar; import java.util.Arrays; -import java.util.Objects; import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; @@ -20,6 +19,8 @@ import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.EasyBinding; +import static org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter.DiffMethod; + public class ThreeWayMergeToolbar extends AnchorPane { @FXML private RadioButton highlightCharactersRadioButtons; @@ -28,7 +29,7 @@ public class ThreeWayMergeToolbar extends AnchorPane { private RadioButton highlightWordsRadioButton; @FXML - private ToggleGroup diffHighlightModeToggleGroup; + private ToggleGroup diffHighlightingMethodToggleGroup; @FXML private ComboBox diffViewComboBox; @@ -42,7 +43,7 @@ public class ThreeWayMergeToolbar extends AnchorPane { @FXML private Button selectRightEntryValuesButton; - private final ObjectProperty diffHighlightMode = new SimpleObjectProperty<>(); + private final ObjectProperty diffHighlightingMethod = new SimpleObjectProperty<>(); private EasyBinding showDiff; public ThreeWayMergeToolbar() { @@ -87,15 +88,15 @@ public DiffView fromString(String string) { highlightWordsRadioButton.disableProperty().bind(notShowDiffProperty()); highlightCharactersRadioButtons.disableProperty().bind(notShowDiffProperty()); - diffHighlightModeToggleGroup.selectedToggleProperty().addListener((observable -> { - if (diffHighlightModeToggleGroup.getSelectedToggle().equals(highlightCharactersRadioButtons)) { - diffHighlightMode.set(DiffHighlightMode.CHARS); + diffHighlightingMethodToggleGroup.selectedToggleProperty().addListener((observable -> { + if (diffHighlightingMethodToggleGroup.getSelectedToggle().equals(highlightCharactersRadioButtons)) { + diffHighlightingMethod.set(DiffMethod.CHARS); } else { - diffHighlightMode.set(DiffHighlightMode.WORDS); + diffHighlightingMethod.set(DiffMethod.WORDS); } })); - diffHighlightModeToggleGroup.selectToggle(highlightWordsRadioButton); + diffHighlightingMethodToggleGroup.selectToggle(highlightWordsRadioButton); } public ObjectProperty diffViewProperty() { @@ -134,16 +135,16 @@ public Boolean isShowDiffEnabled() { return showDiffProperty().get(); } - public ObjectProperty diffHighlightModeProperty() { - return diffHighlightMode; + public ObjectProperty diffHighlightingMethodProperty() { + return diffHighlightingMethod; } - public DiffHighlightMode getDiffHighlightMode() { - return diffHighlightModeProperty().get(); + public DiffMethod getDiffHighlightingMethod() { + return diffHighlightingMethodProperty().get(); } - public void setDiffHighlightMode(DiffHighlightMode diffHighlightMode) { - diffHighlightModeProperty().set(diffHighlightMode); + public void setDiffHighlightingMethod(DiffMethod diffHighlightingMethod) { + diffHighlightingMethodProperty().set(diffHighlightingMethod); } public void setOnSelectLeftEntryValuesButtonClicked(Runnable onClick) { @@ -195,14 +196,4 @@ public static DiffView fromString(String str) { .orElseThrow(IllegalArgumentException::new); } } - - // TODO: remove this and use DiffMethod - public enum DiffHighlightMode { - WORDS, CHARS; - - public static DiffHighlightMode from(DiffHighlighter.DiffMethod diffMethod) { - Objects.requireNonNull(diffMethod, "Diff method is required"); - return diffMethod == DiffHighlighter.DiffMethod.WORDS ? WORDS : CHARS; - } - } } From ddee09c7983b69ef4eec824b1272dab8e226f5d7 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Wed, 3 Aug 2022 20:19:03 +0200 Subject: [PATCH 285/473] i18n # Conflicts: # src/main/resources/l10n/JabRef_en.properties --- src/main/resources/l10n/JabRef_en.properties | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index dc9d31a3e5b..23b141ee9b7 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2512,6 +2512,4 @@ Swap\ content=Swap content Copy\ or\ move\ the\ content\ of\ one\ field\ to\ another=Copy or move the content of one field to another Automatic\ field\ editor=Automatic field editor -(Note\:\ If\ original\ entries\ lack\ keywords\ to\ qualify\ for\ the\ new\ group\ configuration,\ confirming\ here\ will\ add\ them)=(Note: If original entries lack keywords to qualify for the new group configuration, confirming here will add them) -Assign=Assign -Do\ not\ assign=Do not assign +Open\ Link=Open Link From f69c76cd656eef03c56bd977756e856b7278cc1e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:19:42 +0100 Subject: [PATCH 286/473] Cleanup css --- src/main/java/org/jabref/gui/Base.css | 3 +-- src/main/java/org/jabref/gui/Dark.css | 2 +- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 7 ------- .../gui/mergeentries/newmergedialog/cell/HeaderCell.java | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 4417f822d8e..2e127b538c9 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -1,7 +1,6 @@ .root { - -jr-transparent-green: rgba(16, 172, 132, 0.12); -jr-row-odd-background: -fx-control-inner-background-alt; -jr-row-even-background: -fx-control-inner-background; /* @@ -650,7 +649,7 @@ TextFlow > .tooltip-text-monospaced { } -.header-cell { +.merge-header-cell { -fx-border-width: 0 0 1 0; -fx-border-color: -jr-gray-1; -fx-background-color: -jr-row-even-background; diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index c2fb6e76b88..c1605d15ca7 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -112,7 +112,7 @@ -fx-opacity: 100%; } -.header-cell { +.merge-header-cell { -fx-border-width: 0 0 1 0; -fx-border-color: -fx-outer-border; -fx-background-color: -jr-row-odd-background; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 59963812688..5686b37d855 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -1,8 +1,3 @@ -.merged-field { -/* -fx-border-color: #dfdfdf; - -fx-border-width: 0 0 0 1.5;*/ -} - .merged-field .styled-text-area { -fx-background-color: -fx-outer-border, -fx-control-inner-background; -fx-background-insets: 0, 1; @@ -16,8 +11,6 @@ } .field-value:selected .selection-box { - /* -fx-background-color: -jr-accent-alt; - -fx-border-color: -jr-accent-alt;*/ -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 5a7c6a9ff71..2fd82afd38b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -4,7 +4,7 @@ import javafx.scene.control.Label; public class HeaderCell extends AbstractCell { - public static final String DEFAULT_STYLE_CLASS = "header-cell"; + public static final String DEFAULT_STYLE_CLASS = "merge-header-cell"; private final Label label = new Label(); public HeaderCell(String text) { From 4f6d227d77ccd4f350f4b51c69389acdcd38f02e Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:35:00 +0100 Subject: [PATCH 287/473] Remove redundant icon style --- src/main/java/org/jabref/gui/Base.css | 8 ++------ src/main/java/org/jabref/gui/Dark.css | 16 +++------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 2e127b538c9..5c681a697d1 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -635,20 +635,16 @@ TextFlow > .tooltip-text-monospaced { } .field-value .action-icon { + -fx-blend-mode: multiply; + -fx-opacity: 69%; -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; - -fx-blend-mode: multiply ; - -fx-opacity: 69%; } .field-value:disabled .action-icon { -fx-opacity: 0%; } -.field-value:selected .action-icon { - -} - .merge-header-cell { -fx-border-width: 0 0 1 0; -fx-border-color: -jr-gray-1; diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index c1605d15ca7..32e618f9b5c 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -96,20 +96,10 @@ .tree-table-row-cell:hover { -fx-background-color: -jr-hover; } -.field-value .action-icon { - -fx-icon-size: 14; - -fx-icon-color: -fx-text-background-color; - -fx-blend-mode: inherit; - -fx-opacity: 100%; -} -.field-value:disabled .action-icon { - -fx-opacity: 0%; -} - -.field-value:selected .action-icon { - -fx-icon-color: -fx-text-background-color; - -fx-opacity: 100%; +.field-value .action-icon { + -fx-blend-mode: none; + -fx-opacity: 90%; } .merge-header-cell { From baeb1dc586e92099dcbfe79fb2f0c39b19a66da2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:38:22 +0100 Subject: [PATCH 288/473] Rename style class field-value to merge-field-value - Since it is used in Base.css and Dark.css, it is critical to distinguish the field cell used is related to the merge UI. --- src/main/java/org/jabref/gui/Base.css | 4 ++-- src/main/java/org/jabref/gui/Dark.css | 2 +- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 4 ++-- .../gui/mergeentries/newmergedialog/cell/FieldValueCell.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 5c681a697d1..b4bb5c12cc3 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -634,14 +634,14 @@ TextFlow > .tooltip-text-monospaced { -fx-background-insets: 0; } -.field-value .action-icon { +.merge-field-value .action-icon { -fx-blend-mode: multiply; -fx-opacity: 69%; -fx-icon-size: 14; -fx-icon-color: -fx-text-background-color; } -.field-value:disabled .action-icon { +.merge-field-value:disabled .action-icon { -fx-opacity: 0%; } diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css index 32e618f9b5c..11e74ef6d1d 100644 --- a/src/main/java/org/jabref/gui/Dark.css +++ b/src/main/java/org/jabref/gui/Dark.css @@ -97,7 +97,7 @@ -fx-background-color: -jr-hover; } -.field-value .action-icon { +.merge-field-value .action-icon { -fx-blend-mode: none; -fx-opacity: 90%; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 5686b37d855..fbfdf859411 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -10,12 +10,12 @@ -fx-highlight-text-fill: -fx-text-inner-color; } -.field-value:selected .selection-box { +.merge-field-value:selected .selection-box { -fx-background-color: -jr-accent-alt; -fx-border-color: -jr-accent; } -.field-value .selection-box { +.merge-field-value .selection-box { -fx-background-color: #0000; -fx-border-color: #0000; -fx-border-radius: 8; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 82ca6b0c235..f31639ccc25 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -43,7 +43,7 @@ public class FieldValueCell extends AbstractCell implements Toggle { public static final Logger LOGGER = LoggerFactory.getLogger(FieldValueCell.class); - public static final String DEFAULT_STYLE_CLASS = "field-value"; + public static final String DEFAULT_STYLE_CLASS = "merge-field-value"; public static final String SELECTION_BOX_STYLE_CLASS = "selection-box"; private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected"); From 9905fe0c8a2d6050911ac06c7bab2fe44afee147 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:43:17 +0100 Subject: [PATCH 289/473] Remove old Merge entries UI --- .../jabref/gui/mergeentries/MergeEntries.css | 12 - .../jabref/gui/mergeentries/MergeEntries.java | 417 ------------------ 2 files changed, 429 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeEntries.css delete mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeEntries.java diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.css b/src/main/java/org/jabref/gui/mergeentries/MergeEntries.css deleted file mode 100644 index 82f5ca6d3ee..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.css +++ /dev/null @@ -1,12 +0,0 @@ -.text-changed { - -fx-fill: darkgreen; -} - -.text-added { - -fx-fill: #54A3F2; -} - -.text-removed { - -fx-fill: #FA5B68; -} - diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java deleted file mode 100644 index 99472efdd89..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntries.java +++ /dev/null @@ -1,417 +0,0 @@ -package org.jabref.gui.mergeentries; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; - -import javafx.collections.FXCollections; -import javafx.geometry.HPos; -import javafx.geometry.Insets; -import javafx.scene.control.Button; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.ToggleGroup; -import javafx.scene.control.Tooltip; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.text.Text; -import javafx.scene.text.TextFlow; -import javafx.stage.Screen; - -import org.jabref.gui.Globals; -import org.jabref.gui.icon.IconTheme.JabRefIcons; -import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.gui.util.component.DiffHighlightingTextPane; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.FieldFactory; - -import com.tobiasdiez.easybind.EasyBind; - -public class MergeEntries extends BorderPane { - - private static final int NUMBER_OF_COLUMNS = 6; - private static final int LEFT_RADIOBUTTON_INDEX = 0; - private static final int RIGHT_RADIOBUTTON_INDEX = 2; - private final ComboBox diffMode = new ComboBox<>(); - - // Headings - private final List columnHeadings = Arrays.asList( - Localization.lang("Field"), - Localization.lang("Left entry"), - "left icon", - Localization.lang("None"), - "right icon", - Localization.lang("Right entry")); - private final Set identicalFields = new HashSet<>(); - private final Set differentFields = new HashSet<>(); - private final BibEntry mergedEntry = new BibEntry(); - private final BibEntry leftEntry; - private final BibEntry rightEntry; - private final Map leftTextPanes = new HashMap<>(); - private final Set allFields = new TreeSet<>(Comparator.comparing(Field::getName)); - private final Map rightTextPanes = new HashMap<>(); - private final Map> radioButtons = new HashMap<>(); - private Boolean identicalTypes; - private List typeRadioButtons; - private final DefaultRadioButtonSelectionMode defaultRadioButtonSelectionMode; - private final List leftRadioButtons = new ArrayList<>(); - private final List rightRadioButtons = new ArrayList<>(); - - /** - * Constructor with optional column captions for the two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - * @param headingLeft Heading for left entry - * @param headingRight Heading for right entry - * @param defaultRadioButtonSelectionMode If the left or the right side of the radio button should be preselected - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight, String headingLeft, String headingRight, DefaultRadioButtonSelectionMode defaultRadioButtonSelectionMode) { - this.leftEntry = entryLeft; - this.rightEntry = entryRight; - this.defaultRadioButtonSelectionMode = defaultRadioButtonSelectionMode; - - initialize(); - setLeftHeaderText(headingLeft); - setRightHeaderText(headingRight); - } - - /** - * Constructor with optional column captions for the two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - * @param headingLeft Heading for left entry - * @param headingRight Heading for right entry - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight, String headingLeft, String headingRight) { - this(entryLeft, entryRight, headingLeft, headingRight, DefaultRadioButtonSelectionMode.LEFT); - } - - /** - * Constructor taking two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - * @param defaultRadioButtonSelectionMode If the left or the right side of the radio button should be preselected - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight, DefaultRadioButtonSelectionMode defaultRadioButtonSelectionMode) { - leftEntry = entryLeft; - rightEntry = entryRight; - this.defaultRadioButtonSelectionMode = defaultRadioButtonSelectionMode; - initialize(); - } - - /** - * Constructor taking two entries - * - * @param entryLeft Left entry - * @param entryRight Right entry - */ - public MergeEntries(BibEntry entryLeft, BibEntry entryRight) { - this(entryLeft, entryRight, DefaultRadioButtonSelectionMode.LEFT); - } - - private static String getDisplayText(DiffMode mode) { - return switch (mode) { - case PLAIN -> Localization.lang("Plain text"); - case WORD -> Localization.lang("Show diff") + " - " + Localization.lang("word"); - case CHARACTER -> Localization.lang("Show diff") + " - " + Localization.lang("character"); - case WORD_SYMMETRIC -> Localization.lang("Show symmetric diff") + " - " + Localization.lang("word"); - case CHARACTER_SYMMETRIC -> Localization.lang("Show symmetric diff") + " - " + Localization.lang("character"); - }; - } - - /** - * Main function for building the merge entry JPanel - */ - private void initialize() { - this.setPrefHeight(Screen.getPrimary().getBounds().getHeight() * 0.75); - this.setPrefWidth(Screen.getPrimary().getBounds().getWidth() * 0.75); - - setupFields(); - - fillDiffModes(); - - GridPane mergePanel = new GridPane(); - mergePanel.setVgap(10); - mergePanel.setHgap(15); - ColumnConstraints columnLabel = new ColumnConstraints(); - columnLabel.setHgrow(Priority.ALWAYS); - ColumnConstraints columnValues = new ColumnConstraints(); - columnValues.setHgrow(Priority.NEVER); - columnValues.setPercentWidth(40); - ColumnConstraints columnSelect = new ColumnConstraints(); - columnSelect.setHgrow(Priority.NEVER); - columnSelect.setHalignment(HPos.CENTER); - // See columnHeadings variable for the headings: 1) field, 2) left content, 3) left arrow, 4) "none", 5) right arrow, 6) right content - mergePanel.getColumnConstraints().setAll(columnLabel, columnValues, columnSelect, columnSelect, columnSelect, columnValues); - - setupHeadingRows(mergePanel); - setupEntryTypeRow(mergePanel); - setupFieldRows(mergePanel); - - ScrollPane scrollPane = new ScrollPane(mergePanel); - scrollPane.setFitToWidth(true); - setCenter(scrollPane); - - updateFieldValues(allFields); - - updateMergedEntry(); - - getStylesheets().add(0, MergeEntries.class.getResource("MergeEntries.css").toExternalForm()); - } - - private void setupFieldRows(GridPane mergePanel) { - // For all fields in joint add a row and possibly radio buttons - int row = 2; - for (Field field : allFields) { - Label label = new Label(field.getDisplayName()); - label.setMinWidth(USE_PREF_SIZE); - mergePanel.add(label, 0, row); - Optional leftString = leftEntry.getField(field); - Optional rightString = rightEntry.getField(field); - if (leftString.equals(rightString)) { - identicalFields.add(field); - } else { - differentFields.add(field); - } - - // Left text pane - if (leftString.isPresent()) { - TextFlow tf = new DiffHighlightingTextPane(); - mergePanel.add(tf, 1, row); - leftTextPanes.put(field, tf); - } - - // Add radio buttons if the two entries do not have identical fields - if (identicalFields.contains(field)) { - mergedEntry.setField(field, leftString.get()); // Will only happen if both entries have the field and the content is identical - } else { - ToggleGroup group = new ToggleGroup(); - List list = new ArrayList<>(3); - for (int k = 0; k < 3; k++) { - RadioButton button = new RadioButton(); - EasyBind.subscribe(button.selectedProperty(), selected -> updateMergedEntry()); - group.getToggles().add(button); - mergePanel.add(button, 2 + k, row); - list.add(button); - } - radioButtons.put(field, list); - if (leftString.isPresent()) { - leftRadioButtons.add(list.get(LEFT_RADIOBUTTON_INDEX)); - list.get(LEFT_RADIOBUTTON_INDEX).setSelected(true); - if (rightString.isEmpty()) { - list.get(RIGHT_RADIOBUTTON_INDEX).setDisable(true); - } else if (this.defaultRadioButtonSelectionMode == DefaultRadioButtonSelectionMode.RIGHT) { - list.get(RIGHT_RADIOBUTTON_INDEX).setSelected(true); - rightRadioButtons.add(list.get(RIGHT_RADIOBUTTON_INDEX)); - } else { - rightRadioButtons.add(list.get(RIGHT_RADIOBUTTON_INDEX)); - } - } else { - list.get(LEFT_RADIOBUTTON_INDEX).setDisable(true); - list.get(RIGHT_RADIOBUTTON_INDEX).setSelected(true); - rightRadioButtons.add(list.get(RIGHT_RADIOBUTTON_INDEX)); - } - } - - // Right text pane - if (rightString.isPresent()) { - TextFlow tf = new DiffHighlightingTextPane(); - mergePanel.add(tf, 5, row); - rightTextPanes.put(field, tf); - } - row++; - } - } - - private void setupEntryTypeRow(GridPane mergePanel) { - // Start with entry type - int rowIndex = 1; - mergePanel.add(new Label(Localization.lang("Entry type")), 0, rowIndex); - if (leftEntry.getType().equals(rightEntry.getType())) { - mergePanel.add(DiffHighlighting.forUnchanged(leftEntry.getType().getDisplayName()), 1, rowIndex); - mergePanel.add(DiffHighlighting.forUnchanged(rightEntry.getType().getDisplayName()), 5, rowIndex); - identicalTypes = true; - } else { - mergePanel.add(DiffHighlighting.forChanged(leftEntry.getType().getDisplayName()), 1, rowIndex); - mergePanel.add(DiffHighlighting.forChanged(rightEntry.getType().getDisplayName()), 5, rowIndex); - identicalTypes = false; - ToggleGroup group = new ToggleGroup(); - typeRadioButtons = new ArrayList<>(2); - - for (int k = 0; k < 3; k += 2) { - RadioButton button = new RadioButton(); - EasyBind.subscribe(button.selectedProperty(), selected -> updateMergedEntry()); - typeRadioButtons.add(button); - group.getToggles().add(button); - mergePanel.add(button, 2 + k, rowIndex); - } - if (defaultRadioButtonSelectionMode == DefaultRadioButtonSelectionMode.RIGHT) { - typeRadioButtons.get(1).setSelected(true); // This Radio Button list does not have a third option as compared to the fields, so do not use the constants here - rightRadioButtons.add(typeRadioButtons.get(1)); - } else { - typeRadioButtons.get(0).setSelected(true); - leftRadioButtons.add(typeRadioButtons.get(0)); - } - } - } - - private void setupHeadingRows(GridPane mergePanel) { - // Set headings - for (int i = 0; i < NUMBER_OF_COLUMNS; i++) { - if (i == 2) { - Button selectAllLeft = new Button(); - selectAllLeft.setGraphic(JabRefIcons.LEFT.getGraphicNode()); - selectAllLeft.setOnAction(evt -> this.selectAllLeftRadioButtons()); - selectAllLeft.setTooltip(new Tooltip(Localization.lang("Select all changes on the left"))); - mergePanel.add(selectAllLeft, i, 0); - } else if (i == 4) { - Button selectAllRight = new Button(); - selectAllRight.setOnAction(evt -> this.selectAllRightRadioButtons()); - selectAllRight.setGraphic(JabRefIcons.RIGHT.getGraphicNode()); - selectAllRight.setTooltip(new Tooltip(Localization.lang("Select all changes on the right"))); - mergePanel.add(selectAllRight, i, 0); - } else { - Label colHeading = new Label(columnHeadings.get(i)); - colHeading.setMinWidth(USE_PREF_SIZE); - mergePanel.add(colHeading, i, 0); - } - } - } - - private void fillDiffModes() { - diffMode.setItems(FXCollections.observableList(Arrays.asList(DiffMode.values()))); - new ViewModelListCellFactory() - .withText(MergeEntries::getDisplayText) - .install(diffMode); - DiffMode diffModePref = Globals.prefs.getGuiPreferences().getMergeDiffMode(); - diffMode.setValue(diffModePref); - EasyBind.subscribe(this.diffMode.valueProperty(), mode -> { - updateFieldValues(differentFields); - Globals.prefs.getGuiPreferences().setMergeDiffMode(mode); - }); - - HBox heading = new HBox(10); - heading.getChildren().setAll(this.diffMode); - setTop(heading); - BorderPane.setMargin(heading, new Insets(0, 0, 10, 0)); - } - - private void setupFields() { - allFields.addAll(leftEntry.getFields()); - allFields.addAll(rightEntry.getFields()); - - // Do not show internal fields - Set internalFields = allFields.stream().filter(FieldFactory::isInternalField).collect(Collectors.toSet()); - allFields.removeAll(internalFields); - } - - private void updateFieldValues(Collection fields) { - for (Field field : fields) { - String leftString = leftEntry.getField(field).orElse(""); - String rightString = rightEntry.getField(field).orElse(""); - List leftText = leftString.isEmpty() ? Collections.emptyList() : Collections.singletonList(DiffHighlighting.forUnchanged(leftString)); - List rightText = rightString.isEmpty() ? Collections.emptyList() : Collections.singletonList(DiffHighlighting.forUnchanged(rightString)); - switch (diffMode.getValue()) { - case PLAIN: - break; - case WORD: - rightText = DiffHighlighting.generateDiffHighlighting(leftString, rightString, " "); - break; - case CHARACTER: - rightText = DiffHighlighting.generateDiffHighlighting(leftString, rightString, ""); - break; - case WORD_SYMMETRIC: - leftText = DiffHighlighting.generateSymmetricHighlighting(leftString, rightString, " "); - rightText = DiffHighlighting.generateSymmetricHighlighting(rightString, leftString, " "); - break; - case CHARACTER_SYMMETRIC: - leftText = DiffHighlighting.generateSymmetricHighlighting(leftString, rightString, ""); - rightText = DiffHighlighting.generateSymmetricHighlighting(rightString, leftString, ""); - break; - default: - throw new UnsupportedOperationException("Not implemented " + diffMode.getValue()); - } - if (!leftText.isEmpty() && leftTextPanes.containsKey(field)) { - leftTextPanes.get(field).getChildren().setAll(leftText); - } - if (!rightText.isEmpty() && rightTextPanes.containsKey(field)) { - rightTextPanes.get(field).getChildren().setAll(rightText); - } - } - } - - public void selectAllRightRadioButtons() { - for (RadioButton radioButton : rightRadioButtons) { - radioButton.setSelected(true); - } - } - - public void selectAllLeftRadioButtons() { - for (RadioButton radioButton : leftRadioButtons) { - radioButton.setSelected(true); - } - } - - public BibEntry getMergedEntry() { - return mergedEntry; - } - - private void updateMergedEntry() { - // Check if the type has changed - if (!identicalTypes && !typeRadioButtons.isEmpty() && typeRadioButtons.get(0).isSelected()) { - mergedEntry.setType(leftEntry.getType()); - } else { - mergedEntry.setType(rightEntry.getType()); - } - - // Check the potentially different fields - for (Field field : differentFields) { - if (!radioButtons.containsKey(field)) { - // May happen during initialization -> just ignore - continue; - } - if (radioButtons.get(field).get(LEFT_RADIOBUTTON_INDEX).isSelected()) { - mergedEntry.setField(field, leftEntry.getField(field).get()); // Will only happen if field exists - } else if (radioButtons.get(field).get(RIGHT_RADIOBUTTON_INDEX).isSelected()) { - mergedEntry.setField(field, rightEntry.getField(field).get()); // Will only happen if field exists - } else { - mergedEntry.clearField(field); - } - } - } - - public void setLeftHeaderText(String leftHeaderText) { - columnHeadings.set(1, leftHeaderText); - initialize(); - } - - public void setRightHeaderText(String rightHeaderText) { - columnHeadings.set(5, rightHeaderText); - initialize(); - } - - public enum DefaultRadioButtonSelectionMode { - LEFT, - RIGHT - } -} From c37fbd371513df447e8f8aefa6f498240c8c3f7c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Jul 2022 00:56:28 +0100 Subject: [PATCH 290/473] Fix missing header styles --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index fbfdf859411..416b55b308a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -39,7 +39,7 @@ -fx-background-color: -jr-menu-background; } -.header-cell .label{ +.merge-header-cell .label{ -fx-font-weight: bold; -fx-padding: 1, 0, 1, 0; } From 7dcc34830196a20d5f5ddf0d5c7d5d1e5c5b8fd1 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Wed, 3 Aug 2022 20:20:09 +0200 Subject: [PATCH 291/473] i18n # Conflicts: # src/main/resources/l10n/JabRef_en.properties --- .../ThreeWayMergeHeaderView.java | 3 ++- .../newmergedialog/ThreeWayMergeView.java | 5 ++-- .../toolbar/ThreeWayMergeToolbar.fxml | 6 ++--- .../toolbar/ThreeWayMergeToolbar.java | 7 +++--- src/main/resources/l10n/JabRef_en.properties | 23 +++++++++++-------- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java index a3b33e99461..bf896f4b8a5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeHeaderView.java @@ -5,6 +5,7 @@ import javafx.scene.layout.GridPane; import org.jabref.gui.mergeentries.newmergedialog.cell.HeaderCell; +import org.jabref.logic.l10n.Localization; /** * GridPane was used instead of a Hbox because Hbox allocates more space for cells @@ -22,7 +23,7 @@ public ThreeWayMergeHeaderView(String leftHeader, String rightHeader) { this.leftHeaderCell = new HeaderCell(leftHeader); this.rightHeaderCell = new HeaderCell(rightHeader); - this.mergedHeaderCell = new HeaderCell("Merged Entry"); + this.mergedHeaderCell = new HeaderCell(Localization.lang("Merged Entry")); addRow(0, new HeaderCell(""), diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 0c6221450f4..7ab42c83d2f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -11,6 +11,7 @@ import javafx.stage.Screen; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; @@ -19,8 +20,8 @@ public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; - public static final String LEFT_DEFAULT_HEADER = "Left Entry"; - public static final String RIGHT_DEFAULT_HEADER = "Right Entry"; + public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); + public static final String RIGHT_DEFAULT_HEADER = Localization.lang("Right Entry"); private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml index 2361c686981..59fde5d824b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.fxml @@ -30,18 +30,18 @@ - + - + - + diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java index 6efadffa2bf..08189a7647b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/toolbar/ThreeWayMergeToolbar.java @@ -14,6 +14,7 @@ import javafx.util.StringConverter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.DiffHighlighter; +import org.jabref.logic.l10n.Localization; import com.airhacks.afterburner.views.ViewLoader; import com.tobiasdiez.easybind.EasyBind; @@ -156,7 +157,7 @@ public void setOnSelectRightEntryValuesButtonClicked(Runnable onClick) { } public enum PlainTextOrDiff { - PLAIN_TEXT("Plain Text"), Diff("Show Diff"); + PLAIN_TEXT(Localization.lang("Plain Text")), Diff(Localization.lang("Show Diff")); private final String value; @@ -177,8 +178,8 @@ public static PlainTextOrDiff fromString(String str) { } public enum DiffView { - UNIFIED("Unified View"), - SPLIT("Split View"); + UNIFIED(Localization.lang("Unified View")), + SPLIT(Localization.lang("Split View")); private final String value; DiffView(String value) { diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 23b141ee9b7..d9d14074508 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -323,7 +323,6 @@ Entry\ preview=Entry preview Entry\ table=Entry table Entry\ table\ columns=Entry table columns Entry\ Title\ (Required\ to\ deliver\ recommendations.)=Entry Title (Required to deliver recommendations.) -Entry\ type=Entry type Error=Error Error\ occurred\ when\ parsing\ entry=Error occurred when parsing entry Error\ opening\ file=Error opening file @@ -1311,8 +1310,8 @@ Help\ on\ Name\ Formatting=Help on Name Formatting Add\ new\ file\ type=Add new file type -Left\ entry=Left entry -Right\ entry=Right entry +Left\ Entry=Left Entry +Right\ Entry=Right Entry Original\ entry=Original entry No\ information\ added=No information added Select\ at\ least\ one\ entry\ to\ manage\ keywords.=Select at least one entry to manage keywords. @@ -1557,11 +1556,7 @@ Verse=Verse change\ entries\ of\ group=change entries of group odd\ number\ of\ unescaped\ '\#'=odd number of unescaped '#' -Plain\ text=Plain text Show\ diff=Show diff -character=character -word=word -Show\ symmetric\ diff=Show symmetric diff Copy\ Version=Copy Version Maintainers=Maintainers Contributors=Contributors @@ -2086,8 +2081,6 @@ Linked\ identifiers=Linked identifiers insert\ entries=insert entries In\ JabRef=In JabRef On\ disk=On disk -Select\ all\ changes\ on\ the\ left=Select all changes on the left -Select\ all\ changes\ on\ the\ right=Select all changes on the right Dismiss=Dismiss Mark\ all\ changes\ as\ accepted=Mark all changes as accepted Unmark\ all\ changes=Unmark all changes @@ -2513,3 +2506,15 @@ Copy\ or\ move\ the\ content\ of\ one\ field\ to\ another=Copy or move the conte Automatic\ field\ editor=Automatic field editor Open\ Link=Open Link +Highlight\ words=Highlight words +Highlight\ characters=Highlight characters +Unified\ View=Unified View +Split\ View=Split View +Plain\ Text=Plain Text +Show\ Diff=Show Diff +Merged\ Entry=Merged Entry + +(Note\:\ If\ original\ entries\ lack\ keywords\ to\ qualify\ for\ the\ new\ group\ configuration,\ confirming\ here\ will\ add\ them)=(Note: If original entries lack keywords to qualify for the new group configuration, confirming here will add them) +Assign=Assign +Do\ not\ assign=Do not assign + From 04346878f5cd1e4417a87d415510b634496cda3d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 6 Jul 2022 02:08:39 +0100 Subject: [PATCH 292/473] Garbage collect right cell when it's invisible - When both the left and right cells have the same value, only the left value is displayed, making it unnecessary to keep allocating memory for the right cell. --- .../newmergedialog/FieldRowController.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index d1fb3b248a9..38d02467e13 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -16,7 +16,7 @@ public class FieldRowController { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; - private final FieldValueCell rightValueCell; + private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; private final String leftValue; @@ -53,9 +53,11 @@ public FieldRowController(String fieldName, String leftValue, String rightValue, } }); - // When left and right have the same value, only the left value will be shown + // When both the left and right cells have the same value, only the left value is displayed, + // making it unnecessary to keep allocating memory for the right cell. if (hasEqualLeftAndRightValues()) { - rightValueCell.setDisable(true); + // Setting this to null so the GC release the memory allocated to the right cell. + this.rightValueCell = null; } } @@ -64,7 +66,7 @@ public void selectLeftValue() { } public void selectRightValue() { - if (rightValueCell.isDisabled()) { + if (rightValueCell == null) { selectLeftValue(); } else { toggleGroup.selectToggle(rightValueCell); @@ -96,13 +98,13 @@ public MergedFieldCell getMergedValueCell() { } public boolean hasEqualLeftAndRightValues() { - return !StringUtil.isNullOrEmpty(leftValueCell.getText()) && + return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && !StringUtil.isNullOrEmpty(rightValueCell.getText()) && - leftValueCell.getText().equals(rightValueCell.getText()); + leftValueCell.getText().equals(rightValueCell.getText())); } public void showDiff(ShowDiffConfig diffConfig) { - if (leftValueCell.isDisabled() || rightValueCell.isDisabled()) { + if (isRightValueCellHidden()) { return; } @@ -118,6 +120,10 @@ public void showDiff(ShowDiffConfig diffConfig) { } public void hideDiff() { + if (isRightValueCellHidden()) { + return; + } + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); @@ -126,4 +132,8 @@ public void hideDiff() { getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); getRightValueCell().getStyleClassedLabel().replaceText(rightValue); } + + private boolean isRightValueCellHidden() { + return rightValueCell == null; + } } From a4049ba84fd94fbe9e8d051fc294d8202269bb0b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 6 Jul 2022 02:12:15 +0100 Subject: [PATCH 293/473] Fix typo --- .../gui/mergeentries/newmergedialog/FieldRowController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java index 38d02467e13..8f2411d89cf 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java @@ -66,7 +66,7 @@ public void selectLeftValue() { } public void selectRightValue() { - if (rightValueCell == null) { + if (isRightValueCellHidden()) { selectLeftValue(); } else { toggleGroup.selectToggle(rightValueCell); From 516ca2f76122f45c84388e3bd2a8a779a6d35e63 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:55:26 +0100 Subject: [PATCH 294/473] Create GroupsFieldNameCell --- .../newmergedialog/cell/FieldNameCell.java | 2 ++ .../cell/GroupsFieldNameCell.java | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 7ad435d59b1..93b0b20d84e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -2,6 +2,8 @@ import javafx.scene.control.Label; +import org.jabref.gui.actions.Action; + /** * A non-editable cell that contains the name of some field */ diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java new file mode 100644 index 00000000000..b20c1ffcb11 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java @@ -0,0 +1,33 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +public class GroupsFieldNameCell extends FieldNameCell { + private Runnable onMergeGroups; + private Runnable onUnmergeGroups; + private boolean isMerged = false; + + public GroupsFieldNameCell(String text, int rowIndex, boolean groupsMerged) { + super(text, rowIndex); + isMerged = groupsMerged; + setOnMouseClicked(e -> { + if (isMerged) { + if (onUnmergeGroups != null) { + onUnmergeGroups.run(); + isMerged = false; + } + } else { + if (onMergeGroups != null) { + onMergeGroups.run(); + isMerged = true; + } + } + }); + } + + public void setOnMergeGroups(Runnable mergeGroups) { + this.onMergeGroups = mergeGroups; + } + + public void setOnUnmergeGroups(Runnable unmergeGroups) { + this.onUnmergeGroups = unmergeGroups; + } +} From c4ff603dc06b0a0832013b14a82084e8c0ddd780 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:56:21 +0100 Subject: [PATCH 295/473] Create MergedGroups to record the state of the groups before and after the merge --- .../gui/mergeentries/newmergedialog/MergedGroups.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java new file mode 100644 index 00000000000..f2b1e03da70 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java @@ -0,0 +1,6 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +public record MergedGroups( + String leftEntryGroups, String rightEntryGroups, String mergedGroups +) { +} From 8bd1ccb2076d41f93f3365197931c4ed902e036d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:57:26 +0100 Subject: [PATCH 296/473] Create a factory class for creating field name cells --- ...ldRowController.java => ThreeFieldValues.java} | 11 ++++++++--- .../newmergedialog/cell/FieldNameCellFactory.java | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{FieldRowController.java => ThreeFieldValues.java} (92%) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java similarity index 92% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 8f2411d89cf..45f34afe920 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowController.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -4,16 +4,18 @@ import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; import org.fxmisc.richtext.StyleClassedTextArea; -public class FieldRowController { +public class ThreeFieldValues { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; @@ -23,16 +25,19 @@ public class FieldRowController { private final String rightValue; + private final String fieldName; + private final ToggleGroup toggleGroup = new ToggleGroup(); - public FieldRowController(String fieldName, String leftValue, String rightValue, int rowIndex) { - fieldNameCell = new FieldNameCell(fieldName, rowIndex); + public ThreeFieldValues(Field field, String leftValue, String rightValue, int rowIndex, boolean groupsMerged) { + fieldNameCell = FieldNameCellFactory.create(field, rowIndex, groupsMerged); leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); this.leftValue = leftValue; this.rightValue = rightValue; + this.fieldName = field.getDisplayName(); toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java new file mode 100644 index 00000000000..4a87c2645cf --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -0,0 +1,15 @@ +package org.jabref.gui.mergeentries.newmergedialog.cell; + +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.StandardField; + +public class FieldNameCellFactory { + + public static FieldNameCell create(Field field, int rowIndex, boolean groupsMerged) { + if (field.equals(StandardField.GROUPS)) { + return new GroupsFieldNameCell("Groups", rowIndex, groupsMerged); + } else { + return new FieldNameCell(field.getDisplayName(), rowIndex); + } + } +} From 6ace5040b12c7382d237da69e1e610e7e49320af Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:59:25 +0100 Subject: [PATCH 297/473] Perform experiments for implementing groups merging --- .../newmergedialog/ThreeWayMergeView.java | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 7ab42c83d2f..8aa1b9dc5ce 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,11 +10,13 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { @@ -33,7 +35,9 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List fieldRowControllerList = new ArrayList<>(); + private final List threeFieldValuesList = new ArrayList<>(); + + private MergedGroups mergedGroupsRecord; public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); @@ -71,9 +75,9 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - fieldRowControllerList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); + threeFieldValuesList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - fieldRowControllerList.forEach(FieldRowController::hideDiff); + threeFieldValuesList.forEach(ThreeFieldValues::hideDiff); } } @@ -101,13 +105,19 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - addFieldRow(fieldIndex); + addFieldValues(viewModel.allFields().get(fieldIndex), fieldIndex); } } - private void addFieldRow(int index) { - Field field = viewModel.allFields().get(index); + private void addFieldName(Field field, int rowIndex) { + + } + + private Field getFieldAtIndex(int index) { + return viewModel.allFields().get(index); + } + private void addFieldValues(Field field, int index) { String leftEntryValue; String rightEntryValue; if (field.equals(InternalField.TYPE_HEADER)) { @@ -118,8 +128,38 @@ private void addFieldRow(int index) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - FieldRowController fieldRow = new FieldRowController(field.getDisplayName(), leftEntryValue, rightEntryValue, index); - fieldRowControllerList.add(fieldRow); + ThreeFieldValues fieldRow = new ThreeFieldValues(field, leftEntryValue, rightEntryValue, index, mergedGroupsRecord != null); + threeFieldValuesList.add(fieldRow); + + if (field.equals(StandardField.GROUPS)) { + // attach listener + GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldRow.getFieldNameCell(); + groupsField.setOnMergeGroups(() -> { + if (!fieldRow.hasEqualLeftAndRightValues()) { + removeRow(index); + String mergedGroups = mergeEntryGroups(); + viewModel.getLeftEntry().setField(field, mergedGroups); + viewModel.getRightEntry().setField(field, mergedGroups); + addFieldValues(field, index); + System.out.println("Groups merged: " + mergedGroups); + mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); + } else { + System.out.println("Groups already have the same value"); + } + }); + + groupsField.setOnUnmergeGroups(() -> { + if (fieldRow.hasEqualLeftAndRightValues()) { + if (mergedGroupsRecord != null) { + viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); + removeRow(index); + addFieldValues(field, index); + mergedGroupsRecord = null; + } + } + }); + } fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { @@ -143,6 +183,17 @@ private void addFieldRow(int index) { } } + public void removeRow(int index) { + threeFieldValuesList.remove(index); + mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index); + } + + private String mergeEntryGroups() { + // TODO: Update the merging logic + return viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("") + + viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + } + public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } @@ -156,11 +207,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - fieldRowControllerList.forEach(FieldRowController::selectLeftValue); + threeFieldValuesList.forEach(ThreeFieldValues::selectLeftValue); } public void selectRightEntryValues() { - fieldRowControllerList.forEach(FieldRowController::selectRightValue); + threeFieldValuesList.forEach(ThreeFieldValues::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 6187c26e446e715dad1b54c0ad9bec7d83951d49 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:08:01 +0100 Subject: [PATCH 298/473] Delegate field name cells creation to ThreeWayMergeView - Seperated field values and field name cells because now it's easier to update field values cells without touching the field name cell --- .../newmergedialog/ThreeFieldValues.java | 13 +---------- .../newmergedialog/ThreeWayMergeView.java | 22 +++++++++++-------- .../cell/FieldNameCellFactory.java | 4 ++-- .../cell/GroupsFieldNameCell.java | 3 +-- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 45f34afe920..57e2a21f4a7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -4,19 +4,16 @@ import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; import org.fxmisc.richtext.StyleClassedTextArea; public class ThreeFieldValues { - private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; @@ -25,19 +22,15 @@ public class ThreeFieldValues { private final String rightValue; - private final String fieldName; - private final ToggleGroup toggleGroup = new ToggleGroup(); - public ThreeFieldValues(Field field, String leftValue, String rightValue, int rowIndex, boolean groupsMerged) { - fieldNameCell = FieldNameCellFactory.create(field, rowIndex, groupsMerged); + public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); this.leftValue = leftValue; this.rightValue = rightValue; - this.fieldName = field.getDisplayName(); toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); @@ -86,10 +79,6 @@ public ReadOnlyStringProperty mergedValueProperty() { return mergedValueCell.textProperty(); } - public FieldNameCell getFieldNameCell() { - return fieldNameCell; - } - public FieldValueCell getLeftValueCell() { return leftValueCell; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 8aa1b9dc5ce..647221b71b7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -10,7 +10,8 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -105,12 +106,14 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - addFieldValues(viewModel.allFields().get(fieldIndex), fieldIndex); + addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); + addFieldValues(getFieldAtIndex(fieldIndex), fieldIndex); } } private void addFieldName(Field field, int rowIndex) { - + FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, rowIndex); + mergeGridPane.add(fieldNameCell, 0, rowIndex); } private Field getFieldAtIndex(int index) { @@ -128,10 +131,10 @@ private void addFieldValues(Field field, int index) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldRow = new ThreeFieldValues(field, leftEntryValue, rightEntryValue, index, mergedGroupsRecord != null); + ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, index); threeFieldValuesList.add(fieldRow); - if (field.equals(StandardField.GROUPS)) { +/* if (field.equals(StandardField.GROUPS)) { // attach listener GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldRow.getFieldNameCell(); groupsField.setOnMergeGroups(() -> { @@ -159,7 +162,7 @@ private void addFieldValues(Field field, int index) { } } }); - } + }*/ fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { @@ -175,11 +178,12 @@ private void addFieldValues(Field field, int index) { } if (fieldRow.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldRow.getFieldNameCell(), 0, index, 1, 1); mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index, 1, 1); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); } else { - mergeGridPane.addRow(index, fieldRow.getFieldNameCell(), fieldRow.getLeftValueCell(), fieldRow.getRightValueCell(), fieldRow.getMergedValueCell()); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index); + mergeGridPane.add(fieldRow.getRightValueCell(), 1, index); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index 4a87c2645cf..ecc352af4c0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -5,9 +5,9 @@ public class FieldNameCellFactory { - public static FieldNameCell create(Field field, int rowIndex, boolean groupsMerged) { + public static FieldNameCell create(Field field, int rowIndex) { if (field.equals(StandardField.GROUPS)) { - return new GroupsFieldNameCell("Groups", rowIndex, groupsMerged); + return new GroupsFieldNameCell("Groups", rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java index b20c1ffcb11..f70a7e79b1a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java @@ -5,9 +5,8 @@ public class GroupsFieldNameCell extends FieldNameCell { private Runnable onUnmergeGroups; private boolean isMerged = false; - public GroupsFieldNameCell(String text, int rowIndex, boolean groupsMerged) { + public GroupsFieldNameCell(String text, int rowIndex) { super(text, rowIndex); - isMerged = groupsMerged; setOnMouseClicked(e -> { if (isMerged) { if (onUnmergeGroups != null) { From 8580d3572a6ec34fdeaaf88620f923198d6d1299 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:09:56 +0100 Subject: [PATCH 299/473] Improve groups merging function --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 647221b71b7..999fc29a982 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -198,6 +198,14 @@ private String mergeEntryGroups() { viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); } + private String mergeLeftAndRightEntryGroups() { + List leftGroups = new ArrayList<>(Arrays.stream(viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList()); + List rightGroups = Arrays.stream(viewModel.getRightEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList(); + leftGroups.addAll(rightGroups); + + return String.join(", ", leftGroups); + } + public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } From 5703cd46c571478fddd661c7f40896d64fb10523 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:12:08 +0100 Subject: [PATCH 300/473] Implement updateFieldValues to redraw the field row when left or right entry changes --- .../newmergedialog/ThreeWayMergeView.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 999fc29a982..8ed0268df2b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -1,6 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javafx.scene.control.ScrollPane; @@ -12,6 +13,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; +import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -23,9 +25,11 @@ public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; + public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); public static final String RIGHT_DEFAULT_HEADER = Localization.lang("Right Entry"); + private static final int FIELD_NAME_COLUMN = 0; private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); private final ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); @@ -120,7 +124,8 @@ private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } - private void addFieldValues(Field field, int index) { + private void addFieldValues(int fieldIndex) { + Field field = getFieldAtIndex(fieldIndex); String leftEntryValue; String rightEntryValue; if (field.equals(InternalField.TYPE_HEADER)) { @@ -178,24 +183,23 @@ private void addFieldValues(Field field, int index) { } if (fieldRow.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index, 2, 1); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex, 2, 1); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); } else { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, index); - mergeGridPane.add(fieldRow.getRightValueCell(), 1, index); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, index); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldRow.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); } } - public void removeRow(int index) { - threeFieldValuesList.remove(index); - mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index); + public void updateFieldValues(int fieldIndex) { + removeFieldValues(fieldIndex); + addFieldValues(fieldIndex); } - private String mergeEntryGroups() { - // TODO: Update the merging logic - return viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("") + - viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + public void removeFieldValues(int index) { + threeFieldValuesList.remove(index); + mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } private String mergeLeftAndRightEntryGroups() { From 4043a6d9b08cdba0c3cdd0353d79ca461331094d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:14:07 +0100 Subject: [PATCH 301/473] Write a draft version of the logic to merge groups --- .../newmergedialog/ThreeWayMergeView.java | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 8ed0268df2b..3096ddaef9c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -111,13 +111,39 @@ private void initializeMergeGridPane() { for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); - addFieldValues(getFieldAtIndex(fieldIndex), fieldIndex); + addFieldValues(fieldIndex); } } - private void addFieldName(Field field, int rowIndex) { - FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, rowIndex); - mergeGridPane.add(fieldNameCell, 0, rowIndex); + private void addFieldName(Field field, int fieldIndex) { + FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, fieldIndex); + mergeGridPane.add(fieldNameCell, FIELD_NAME_COLUMN, fieldIndex); + + if (field.equals(StandardField.GROUPS)) { + GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; + groupsField.setOnMergeGroups(() -> { + if (mergedGroupsRecord == null) { + String leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); + String rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); + + String mergedGroups = mergeLeftAndRightEntryGroups(); + viewModel.getLeftEntry().setField(field, mergedGroups); + viewModel.getRightEntry().setField(field, mergedGroups); + System.out.println("Groups merged: " + mergedGroups); + mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); + updateFieldValues(fieldIndex); + } + }); + + groupsField.setOnUnmergeGroups(() -> { + if (mergedGroupsRecord != null) { + viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); + updateFieldValues(fieldIndex); + mergedGroupsRecord = null; + } + }); + } } private Field getFieldAtIndex(int index) { @@ -136,39 +162,9 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, index); + ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); threeFieldValuesList.add(fieldRow); -/* if (field.equals(StandardField.GROUPS)) { - // attach listener - GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldRow.getFieldNameCell(); - groupsField.setOnMergeGroups(() -> { - if (!fieldRow.hasEqualLeftAndRightValues()) { - removeRow(index); - String mergedGroups = mergeEntryGroups(); - viewModel.getLeftEntry().setField(field, mergedGroups); - viewModel.getRightEntry().setField(field, mergedGroups); - addFieldValues(field, index); - System.out.println("Groups merged: " + mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); - } else { - System.out.println("Groups already have the same value"); - } - }); - - groupsField.setOnUnmergeGroups(() -> { - if (fieldRow.hasEqualLeftAndRightValues()) { - if (mergedGroupsRecord != null) { - viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); - removeRow(index); - addFieldValues(field, index); - mergedGroupsRecord = null; - } - } - }); - }*/ - fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); From 9c152c6c3c81bebcbfdfc195e3a492c85b71bbe4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:15:25 +0100 Subject: [PATCH 302/473] Refactoring --- .../newmergedialog/ThreeFieldValues.java | 4 +- .../newmergedialog/ThreeWayMergeView.java | 48 +++++++++++-------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 57e2a21f4a7..74bf76fe8b2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -3,7 +3,6 @@ import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; @@ -13,6 +12,9 @@ import org.fxmisc.richtext.StyleClassedTextArea; +/** + * A controller class to control left, right and merged field values + */ public class ThreeFieldValues { private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 3096ddaef9c..5a3f3b16ae7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -121,31 +121,39 @@ private void addFieldName(Field field, int fieldIndex) { if (field.equals(StandardField.GROUPS)) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setOnMergeGroups(() -> { - if (mergedGroupsRecord == null) { - String leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); - String rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); - - String mergedGroups = mergeLeftAndRightEntryGroups(); - viewModel.getLeftEntry().setField(field, mergedGroups); - viewModel.getRightEntry().setField(field, mergedGroups); - System.out.println("Groups merged: " + mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryValue, rightEntryValue, mergedGroups); - updateFieldValues(fieldIndex); - } - }); - - groupsField.setOnUnmergeGroups(() -> { - if (mergedGroupsRecord != null) { - viewModel.getLeftEntry().setField(field, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(field, mergedGroupsRecord.rightEntryGroups()); - updateFieldValues(fieldIndex); - mergedGroupsRecord = null; + groupsField.setOnAction(() -> { + if (areGroupsMerged()) { + unmergeGroups(); + } else { + mergeGroups(); } }); } } + public void mergeGroups() { + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + + String mergedGroups = mergeLeftAndRightEntryGroups(); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + } + + public void unmergeGroups() { + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + mergedGroupsRecord = null; + } + + private boolean areGroupsMerged() { + return mergedGroupsRecord != null; + } + private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } From 4bf7b2e0ea51523970b4bb624052e11ad19b2cba Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:19:11 +0100 Subject: [PATCH 303/473] More Refactoring --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 5a3f3b16ae7..efe45679d0b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -135,7 +135,7 @@ public void mergeGroups() { String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - String mergedGroups = mergeLeftAndRightEntryGroups(); + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); @@ -206,9 +206,9 @@ public void removeFieldValues(int index) { mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } - private String mergeLeftAndRightEntryGroups() { - List leftGroups = new ArrayList<>(Arrays.stream(viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList()); - List rightGroups = Arrays.stream(viewModel.getRightEntry().getField(StandardField.GROUPS).orElse("").split(", ")).toList(); + private String mergeLeftAndRightEntryGroups(String left, String right) { + List leftGroups = new ArrayList<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); leftGroups.addAll(rightGroups); return String.join(", ", leftGroups); From 4dceb2e053740bd6f57a162772fd64b37c3d82e4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:51:57 +0100 Subject: [PATCH 304/473] Merge groups only when left and right entries have different groups --- .../newmergedialog/ThreeWayMergeView.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index efe45679d0b..a6f93197779 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -135,12 +135,14 @@ public void mergeGroups() { String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + if (!leftEntryGroups.equals(rightEntryGroups)) { + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + } } public void unmergeGroups() { From 8cf5bc4fe65dc2d0ab8d9111d6d11a78fdcac0ca Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 10:53:44 +0100 Subject: [PATCH 305/473] Add row constraints to fix UI lagging when updating field values --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index a6f93197779..77d78663be6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -8,6 +8,7 @@ import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.Priority; +import javafx.scene.layout.RowConstraints; import javafx.scene.layout.VBox; import javafx.stage.Screen; @@ -112,6 +113,12 @@ private void initializeMergeGridPane() { for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); + + if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { + mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); + } else { + mergeGridPane.getRowConstraints().add(new RowConstraints()); + } } } From ffe4f04dee109c3c94797134bc4b47561e499a61 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 11:01:07 +0100 Subject: [PATCH 306/473] Minor refactoring --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 77d78663be6..c7604ecca2c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -114,6 +114,7 @@ private void initializeMergeGridPane() { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); + // Removing this will cause a UI lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); } else { @@ -205,12 +206,12 @@ private void addFieldValues(int fieldIndex) { } } - public void updateFieldValues(int fieldIndex) { + private void updateFieldValues(int fieldIndex) { removeFieldValues(fieldIndex); addFieldValues(fieldIndex); } - public void removeFieldValues(int index) { + private void removeFieldValues(int index) { threeFieldValuesList.remove(index); mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } From c7edbe30dbf447d20fab288c4dacd60092764d10 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 11:06:55 +0100 Subject: [PATCH 307/473] Don't merge common groups between left and right entries --- .../newmergedialog/ThreeWayMergeView.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index c7604ecca2c..684a09dcad4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -2,7 +2,9 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; @@ -41,7 +43,7 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List threeFieldValuesList = new ArrayList<>(); + private final List fieldValuesList = new ArrayList<>(); private MergedGroups mergedGroupsRecord; @@ -81,9 +83,9 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - threeFieldValuesList.forEach(fieldRow -> fieldRow.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); + fieldValuesList.forEach(fieldValues -> fieldValues.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - threeFieldValuesList.forEach(ThreeFieldValues::hideDiff); + fieldValuesList.forEach(ThreeFieldValues::hideDiff); } } @@ -114,7 +116,7 @@ private void initializeMergeGridPane() { addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); - // Removing this will cause a UI lag when updating field values + // Removing this will cause UI to lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); } else { @@ -181,7 +183,7 @@ private void addFieldValues(int fieldIndex) { } ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); - threeFieldValuesList.add(fieldRow); + fieldValuesList.add(fieldRow); fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { @@ -212,12 +214,12 @@ private void updateFieldValues(int fieldIndex) { } private void removeFieldValues(int index) { - threeFieldValuesList.remove(index); + fieldValuesList.remove(index); mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } private String mergeLeftAndRightEntryGroups(String left, String right) { - List leftGroups = new ArrayList<>(Arrays.stream(left.split(", ")).toList()); + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); List rightGroups = Arrays.stream(right.split(", ")).toList(); leftGroups.addAll(rightGroups); @@ -237,11 +239,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - threeFieldValuesList.forEach(ThreeFieldValues::selectLeftValue); + fieldValuesList.forEach(ThreeFieldValues::selectLeftValue); } public void selectRightEntryValues() { - threeFieldValuesList.forEach(ThreeFieldValues::selectRightValue); + fieldValuesList.forEach(ThreeFieldValues::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 2f59a6978f98f81aad452fcdc54752a289c21eb3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:17:35 +0100 Subject: [PATCH 308/473] Refactor GroupsFieldNameCell constructor --- .../mergeentries/newmergedialog/cell/FieldNameCellFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index ecc352af4c0..01a2fa90aff 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -7,7 +7,7 @@ public class FieldNameCellFactory { public static FieldNameCell create(Field field, int rowIndex) { if (field.equals(StandardField.GROUPS)) { - return new GroupsFieldNameCell("Groups", rowIndex); + return new GroupsFieldNameCell(rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); } From 5ba051bdfb1343c9ffa2b9b78fa9569c5642bf83 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:20:05 +0100 Subject: [PATCH 309/473] Allow groups field row to grow in height --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 684a09dcad4..37ba0212e69 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -118,7 +118,7 @@ private void initializeMergeGridPane() { // Removing this will cause UI to lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { - mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, 56)); + mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, Double.MAX_VALUE)); } else { mergeGridPane.getRowConstraints().add(new RowConstraints()); } From fcc066720dabed2dd7908a78da7958b50eb5d63a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:25:09 +0100 Subject: [PATCH 310/473] Fix select all left/right not working properly --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 37ba0212e69..61401763dcd 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -183,7 +183,7 @@ private void addFieldValues(int fieldIndex) { } ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); - fieldValuesList.add(fieldRow); + fieldValuesList.add(fieldIndex, fieldRow); fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { From 99dd8623df83e6932085fb4891c7b2723a4e9a50 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 22:29:39 +0100 Subject: [PATCH 311/473] Update diff when a field value changes --- .../newmergedialog/ThreeWayMergeView.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 61401763dcd..331a2a4e970 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -182,10 +182,10 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldRow = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); - fieldValuesList.add(fieldIndex, fieldRow); + ThreeFieldValues fieldValues = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); + fieldValuesList.add(fieldIndex, fieldValues); - fieldRow.mergedValueProperty().addListener((observable, old, mergedValue) -> { + fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { if (field.equals(InternalField.TYPE_HEADER)) { getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); } else { @@ -193,24 +193,25 @@ private void addFieldValues(int fieldIndex) { } }); if (field.equals(InternalField.TYPE_HEADER)) { - getMergedEntry().setType(EntryTypeFactory.parse(fieldRow.getMergedValue())); + getMergedEntry().setType(EntryTypeFactory.parse(fieldValues.getMergedValue())); } else { - getMergedEntry().setField(field, fieldRow.getMergedValue()); + getMergedEntry().setField(field, fieldValues.getMergedValue()); } - if (fieldRow.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex, 2, 1); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); + if (fieldValues.hasEqualLeftAndRightValues()) { + mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex, 2, 1); + mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } else { - mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex); - mergeGridPane.add(fieldRow.getRightValueCell(), 2, fieldIndex); - mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); + mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } } private void updateFieldValues(int fieldIndex) { removeFieldValues(fieldIndex); addFieldValues(fieldIndex); + updateDiff(); } private void removeFieldValues(int index) { From 754d20fe1131e1daa3aa7ba51f8a77d5cd0153e9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 23:16:18 +0100 Subject: [PATCH 312/473] Add the merge icon and style css --- .../java/org/jabref/gui/icon/IconTheme.java | 4 ++- .../newmergedialog/ThreeWayMergeView.css | 6 ++++ .../newmergedialog/cell/FieldNameCell.java | 29 +++++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/icon/IconTheme.java b/src/main/java/org/jabref/gui/icon/IconTheme.java index 8ef3ed5d490..80eb1824a9b 100644 --- a/src/main/java/org/jabref/gui/icon/IconTheme.java +++ b/src/main/java/org/jabref/gui/icon/IconTheme.java @@ -343,7 +343,9 @@ public enum JabRefIcons implements JabRefIcon { ACCEPT_LEFT(MaterialDesignS.SUBDIRECTORY_ARROW_LEFT), - ACCEPT_RIGHT(MaterialDesignS.SUBDIRECTORY_ARROW_RIGHT); + ACCEPT_RIGHT(MaterialDesignS.SUBDIRECTORY_ARROW_RIGHT), + + MERGE_GROUPS(MaterialDesignS.SOURCE_MERGE); private final JabRefIcon icon; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css index 416b55b308a..ac73d7593f0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.css @@ -43,3 +43,9 @@ -fx-font-weight: bold; -fx-padding: 1, 0, 1, 0; } + +.field-name .glyph-icon, +.field-name .ikonli-font-icon { + -fx-icon-size: 17; + -fx-icon-color: -jr-theme-text; +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 93b0b20d84e..95664eb7566 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -1,16 +1,30 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; -import org.jabref.gui.actions.Action; +import org.jabref.gui.Globals; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.icon.IconTheme; +import org.jabref.logic.l10n.Localization; + +import de.saxsys.mvvmfx.utils.commands.Command; /** * A non-editable cell that contains the name of some field */ public class FieldNameCell extends AbstractCell { public static final String DEFAULT_STYLE_CLASS = "field-name"; + protected final HBox actionLayout = new HBox(); private final Label label = new Label(); + private final HBox labelBox = new HBox(label); + private final ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + public FieldNameCell(String text, int rowIndex) { super(text, rowIndex); initialize(); @@ -19,10 +33,21 @@ public FieldNameCell(String text, int rowIndex) { private void initialize() { getStyleClass().add(DEFAULT_STYLE_CLASS); initializeLabel(); - getChildren().add(label); + getChildren().addAll(labelBox, actionLayout); } private void initializeLabel() { label.textProperty().bind(textProperty()); + HBox.setHgrow(labelBox, Priority.ALWAYS); + } + + protected void addAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + Node iconNode = icon.getGraphicNode(); + Button actionButton = factory.createIconButton(() -> Localization.lang(actionName), command); + actionButton.setGraphic(iconNode); + actionButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + actionButton.setMaxHeight(Double.MAX_VALUE); + + actionLayout.getChildren().add(actionButton); } } From 9561db2fd6cf890d340b7c452a95ae9cdb0d15f6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 8 Jul 2022 23:31:31 +0100 Subject: [PATCH 313/473] Extract merge and unmerge commands into their own classes --- .../newmergedialog/ThreeWayMergeView.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 331a2a4e970..ab1cd97b6d1 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -14,6 +14,7 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; @@ -131,37 +132,11 @@ private void addFieldName(Field field, int fieldIndex) { if (field.equals(StandardField.GROUPS)) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setOnAction(() -> { - if (areGroupsMerged()) { - unmergeGroups(); - } else { - mergeGroups(); - } - }); - } - } - - public void mergeGroups() { - String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - - if (!leftEntryGroups.equals(rightEntryGroups)) { - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + groupsField.setMergeGroupsCommand(new MergeGroupsCommand()); + groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand()); } } - public void unmergeGroups() { - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - mergedGroupsRecord = null; - } - private boolean areGroupsMerged() { return mergedGroupsRecord != null; } @@ -252,4 +227,36 @@ public void showDiff(ShowDiffConfig diffConfig) { toolbar.setDiffHighlightingMethod(diffConfig.diffHighlightingMethod()); toolbar.setShowDiff(true); } + + public class MergeGroupsCommand extends SimpleCommand { + @Override + public void execute() { + if (!areGroupsMerged()) { + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + + if (!leftEntryGroups.equals(rightEntryGroups)) { + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + } + } + } + } + + public class UnmergeGroupsCommand extends SimpleCommand { + + @Override + public void execute() { + if (areGroupsMerged()) { + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + mergedGroupsRecord = null; + } + } + } } From b161536b1b0ccd98879820f8080831aab5eaf49a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 02:36:10 +0100 Subject: [PATCH 314/473] Refactoring --- .../newmergedialog/ThreeWayMergeView.java | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index ab1cd97b6d1..c69695f36fa 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -6,6 +6,9 @@ import java.util.List; import java.util.Set; +import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -48,6 +51,9 @@ public class ThreeWayMergeView extends VBox { private MergedGroups mergedGroupsRecord; + private final BooleanProperty areGroupsMerged = new SimpleBooleanProperty(); + + public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); @@ -132,8 +138,8 @@ private void addFieldName(Field field, int fieldIndex) { if (field.equals(StandardField.GROUPS)) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setMergeGroupsCommand(new MergeGroupsCommand()); - groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand()); + groupsField.setMergeGroupsCommand(new MergeGroupsCommand(groupsField)); + groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand(groupsField)); } } @@ -229,34 +235,61 @@ public void showDiff(ShowDiffConfig diffConfig) { } public class MergeGroupsCommand extends SimpleCommand { + private final GroupsFieldNameCell groupsFieldNameCell; + + public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + this.groupsFieldNameCell = groupsFieldCell; + + this.executable.bind(Bindings.and(areGroupsMerged.not(), Bindings.createBooleanBinding(() -> { + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + + return !leftEntryGroups.equals(rightEntryGroups); + }))); + } + @Override public void execute() { - if (!areGroupsMerged()) { + assert !areGroupsMerged(); + String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - if (!leftEntryGroups.equals(rightEntryGroups)) { - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + assert !leftEntryGroups.equals(rightEntryGroups); - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - } - } + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + + mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + groupsFieldNameCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.UNMERGE); } } public class UnmergeGroupsCommand extends SimpleCommand { + private final GroupsFieldNameCell groupsFieldCell; + + public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + this.groupsFieldCell = groupsFieldCell; + } @Override public void execute() { - if (areGroupsMerged()) { + assert areGroupsMerged(); viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); mergedGroupsRecord = null; - } + groupsFieldCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.MERGE); } } + + /* + * Notes + * 1. Left and Right could have the same value + * + * Merge Button Clicked: + * 1. + * */ } From 1519bb115387bb866d49ead02db186ffc1e580d7 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 02:59:39 +0100 Subject: [PATCH 315/473] Record groups merging operation using CompoundEdit - Exposed a public API to be able to cancel groups merge --- .../newmergedialog/ThreeWayMergeView.java | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index c69695f36fa..5d29549d8ef 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -6,6 +6,8 @@ import java.util.List; import java.util.Set; +import javax.swing.undo.CompoundEdit; + import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -22,6 +24,7 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -49,10 +52,9 @@ public class ThreeWayMergeView extends VBox { private final ThreeWayMergeViewModel viewModel; private final List fieldValuesList = new ArrayList<>(); - private MergedGroups mergedGroupsRecord; - private final BooleanProperty areGroupsMerged = new SimpleBooleanProperty(); + private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); @@ -143,10 +145,6 @@ private void addFieldName(Field field, int fieldIndex) { } } - private boolean areGroupsMerged() { - return mergedGroupsRecord != null; - } - private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } @@ -234,6 +232,12 @@ public void showDiff(ShowDiffConfig diffConfig) { toolbar.setShowDiff(true); } + public void cancelGroupsMerge() { + if (mergeGroupsEdit.canUndo()) { + mergeGroupsEdit.undo(); + } + } + public class MergeGroupsCommand extends SimpleCommand { private final GroupsFieldNameCell groupsFieldNameCell; @@ -250,20 +254,28 @@ public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { @Override public void execute() { - assert !areGroupsMerged(); + BibEntry leftEntry = viewModel.getLeftEntry(); + BibEntry rightEntry = viewModel.getRightEntry(); - String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); + String leftEntryGroups = leftEntry.getField(StandardField.GROUPS).orElse(""); + String rightEntryGroups = rightEntry.getField(StandardField.GROUPS).orElse(""); - assert !leftEntryGroups.equals(rightEntryGroups); + assert !leftEntryGroups.equals(rightEntryGroups); - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); + viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - mergedGroupsRecord = new MergedGroups(leftEntryGroups, rightEntryGroups, mergedGroups); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.UNMERGE); + if (mergeGroupsEdit.canRedo()) { + mergeGroupsEdit.redo(); + } else { + mergeGroupsEdit.addEdit(new UndoableFieldChange(leftEntry, StandardField.GROUPS, leftEntryGroups, mergedGroups)); + mergeGroupsEdit.addEdit(new UndoableFieldChange(rightEntry, StandardField.GROUPS, rightEntryGroups, mergedGroups)); + mergeGroupsEdit.end(); + } + + updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); + groupsFieldNameCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.UNMERGE); } } @@ -272,24 +284,16 @@ public class UnmergeGroupsCommand extends SimpleCommand { public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { this.groupsFieldCell = groupsFieldCell; + this.executable.bind(Bindings.createBooleanBinding(mergeGroupsEdit::canUndo)); } @Override public void execute() { - assert areGroupsMerged(); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroupsRecord.leftEntryGroups()); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroupsRecord.rightEntryGroups()); + if (mergeGroupsEdit.canUndo()) { + mergeGroupsEdit.undo(); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - mergedGroupsRecord = null; - groupsFieldCell.toggleMergeProperty().set(GroupsFieldNameCell.ToggleMerge.MERGE); + groupsFieldCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.MERGE); + } } } - - /* - * Notes - * 1. Left and Right could have the same value - * - * Merge Button Clicked: - * 1. - * */ } From 228f56e3affd00b267714ea2eb5f22e55301528d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:25:57 +0100 Subject: [PATCH 316/473] Cancel groups merge when user choose 'Cancel' in the merge entries dialog --- .../java/org/jabref/gui/mergeentries/MergeEntriesDialog.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 3486a9702d2..4c2f5ace0ec 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -33,6 +33,7 @@ private void init() { if (buttonType.equals(replaceEntries)) { return threeWayMergeView.getMergedEntry(); } else { + threeWayMergeView.cancelGroupsMerge(); return null; } }); From a9d7a7f3c16e92ad5866596e467d8d1e757bb152 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:28:38 +0100 Subject: [PATCH 317/473] Make FieldNameCell take only one action --- .../gui/mergeentries/newmergedialog/cell/FieldNameCell.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 95664eb7566..5391b0f0b4c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -41,7 +41,8 @@ private void initializeLabel() { HBox.setHgrow(labelBox, Priority.ALWAYS); } - protected void addAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + protected void setAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + actionLayout.getChildren().clear(); Node iconNode = icon.getGraphicNode(); Button actionButton = factory.createIconButton(() -> Localization.lang(actionName), command); actionButton.setGraphic(iconNode); From 2bf5f669a4f4a8aabd45b833d4576d43782538fb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:46:43 +0100 Subject: [PATCH 318/473] Set groups merge action to MERGE by default --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 5d29549d8ef..eba9651eba7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -142,6 +142,7 @@ private void addFieldName(Field field, int fieldIndex) { GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; groupsField.setMergeGroupsCommand(new MergeGroupsCommand(groupsField)); groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand(groupsField)); + groupsField.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); } } From 7e25fe50655d52f9c79f6d73f5da95912e476282 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:50:08 +0100 Subject: [PATCH 319/473] Fix Unmerge button always disabled --- .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index eba9651eba7..7e94f06bd4e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -285,7 +285,6 @@ public class UnmergeGroupsCommand extends SimpleCommand { public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { this.groupsFieldCell = groupsFieldCell; - this.executable.bind(Bindings.createBooleanBinding(mergeGroupsEdit::canUndo)); } @Override From 1af0bc4defcee1ce16a1bddf2bcfc20728f93a2d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 03:52:35 +0100 Subject: [PATCH 320/473] Cleanup --- .../newmergedialog/ThreeWayMergeView.java | 20 +++++++++---------- .../newmergedialog/cell/FieldNameCell.java | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 7e94f06bd4e..2194dd19c08 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -199,14 +199,6 @@ private void removeFieldValues(int index) { mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); } - private String mergeLeftAndRightEntryGroups(String left, String right) { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); - - return String.join(", ", leftGroups); - } - public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } @@ -276,7 +268,15 @@ public void execute() { } updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.UNMERGE); + groupsFieldNameCell.setMergeAction(GroupsFieldNameCell.MergeAction.UNMERGE); + } + + private String mergeLeftAndRightEntryGroups(String left, String right) { + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); + leftGroups.addAll(rightGroups); + + return String.join(", ", leftGroups); } } @@ -292,7 +292,7 @@ public void execute() { if (mergeGroupsEdit.canUndo()) { mergeGroupsEdit.undo(); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldCell.mergeActionProperty().set(GroupsFieldNameCell.MergeAction.MERGE); + groupsFieldCell.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 5391b0f0b4c..c00d55ba4aa 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -44,7 +44,7 @@ private void initializeLabel() { protected void setAction(String actionName, IconTheme.JabRefIcons icon, Command command) { actionLayout.getChildren().clear(); Node iconNode = icon.getGraphicNode(); - Button actionButton = factory.createIconButton(() -> Localization.lang(actionName), command); + Button actionButton = factory.createIconButton(() -> actionName, command); actionButton.setGraphic(iconNode); actionButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); actionButton.setMaxHeight(Double.MAX_VALUE); From 43f8aca2e614cc429b33e56d0777e599ed731a45 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:31:28 +0100 Subject: [PATCH 321/473] Almost f**** everything up. I deleted GroupsFieldNameCell content by mistake, it's all ok now - I did a rebase and then when resolving conflicts, I chose "Accept Theirs" all the way but that didn't go well, now I have no history of GroupsFieldNameCell --- .../cell/GroupsFieldNameCell.java | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java index f70a7e79b1a..94a232cf3d2 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java @@ -1,32 +1,48 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import org.jabref.gui.icon.IconTheme; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.field.StandardField; + +import de.saxsys.mvvmfx.utils.commands.Command; + public class GroupsFieldNameCell extends FieldNameCell { - private Runnable onMergeGroups; - private Runnable onUnmergeGroups; - private boolean isMerged = false; - - public GroupsFieldNameCell(String text, int rowIndex) { - super(text, rowIndex); - setOnMouseClicked(e -> { - if (isMerged) { - if (onUnmergeGroups != null) { - onUnmergeGroups.run(); - isMerged = false; - } + private Command mergeGroupsCommand; + private Command unmergeGroupsCommand; + + private final ObjectProperty mergeAction = new SimpleObjectProperty<>(); + + public GroupsFieldNameCell(int rowIndex) { + super(StandardField.GROUPS.getDisplayName(), rowIndex); + mergeActionProperty().addListener((obs, old, newValue) -> { + if (newValue == MergeAction.MERGE) { + setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeGroupsCommand); } else { - if (onMergeGroups != null) { - onMergeGroups.run(); - isMerged = true; - } + setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeGroupsCommand); } }); } - public void setOnMergeGroups(Runnable mergeGroups) { - this.onMergeGroups = mergeGroups; + public void setMergeGroupsCommand(Command mergeGroupsCommand) { + this.mergeGroupsCommand = mergeGroupsCommand; + } + + public void setUnmergeGroupsCommand(Command unmergeGroupsCommand) { + this.unmergeGroupsCommand = unmergeGroupsCommand; + } + + public ObjectProperty mergeActionProperty() { + return mergeAction; + } + + public void setMergeAction(MergeAction mergeAction) { + mergeActionProperty().set(mergeAction); } - public void setOnUnmergeGroups(Runnable unmergeGroups) { - this.onUnmergeGroups = unmergeGroups; + public enum MergeAction { + MERGE, UNMERGE } } From 9faebb6a100e278fcd3c1c233bc11f68ee0331ea Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 9 Jul 2022 04:59:32 +0100 Subject: [PATCH 322/473] Checkstyle --- .../gui/mergeentries/newmergedialog/cell/FieldNameCell.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index c00d55ba4aa..0f82beac6c6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -10,7 +10,6 @@ import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.icon.IconTheme; -import org.jabref.logic.l10n.Localization; import de.saxsys.mvvmfx.utils.commands.Command; From 650fddfee17fcb40c9702702b114b937ceee3a15 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 10 Jul 2022 08:02:10 +0100 Subject: [PATCH 323/473] Remove unused MergedGroups class - Because now groups merge history is kept in a compound Edit --- .../gui/mergeentries/newmergedialog/MergedGroups.java | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java deleted file mode 100644 index f2b1e03da70..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/MergedGroups.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog; - -public record MergedGroups( - String leftEntryGroups, String rightEntryGroups, String mergedGroups -) { -} From 1a599f59505f0a7ba0edc98554d1345d024bebbe Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 10 Jul 2022 23:42:15 +0100 Subject: [PATCH 324/473] Register groups merge edit into UndoManager --- .../DuplicateResolverDialog.java | 6 ++++++ .../gui/duplicationFinder/DuplicateSearch.java | 18 ++++++++++++++++++ .../gui/mergeentries/FetchAndMergeEntry.java | 4 ++++ .../gui/mergeentries/MergeEntriesAction.java | 1 + .../gui/mergeentries/MergeEntriesDialog.java | 6 ++++++ .../newmergedialog/ThreeWayMergeView.java | 4 ++++ 6 files changed, 39 insertions(+) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index cec54b0d192..f25b680b936 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -1,5 +1,7 @@ package org.jabref.gui.duplicationFinder; +import javax.swing.undo.CompoundEdit; + import javafx.scene.control.Button; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar.ButtonData; @@ -138,4 +140,8 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { public BibEntry getMergedEntry() { return threeWayMerge.getMergedEntry(); } + + public CompoundEdit getMergeGroupsEdit() { + return threeWayMerge.getMergeGroupsEdit(); + } } diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java index 7ccc1b19402..50bce360ff9 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java @@ -5,12 +5,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import javax.swing.undo.CompoundEdit; + import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; @@ -163,6 +166,10 @@ private void askResolveStrategy(DuplicateSearchResult result, BibEntry first, Bi } else if (resolverResult == DuplicateResolverResult.KEEP_MERGE) { result.replace(first, second, dialog.getMergedEntry()); } + + if (dialog.getMergeGroupsEdit().canUndo()) { + result.setMergeGroupsEdit(dialog.getMergeGroupsEdit()); + } } private void handleDuplicates(DuplicateSearchResult result) { @@ -184,6 +191,7 @@ private void handleDuplicates(DuplicateSearchResult result) { libraryTab.getDatabase().insertEntries(result.getToAdd()); libraryTab.markBaseChanged(); } + result.getMergedGroupsEdit().ifPresent(compoundEdit::addEdit); duplicateProgress.set(0); @@ -203,6 +211,8 @@ static class DuplicateSearchResult { private final Map toRemove = new HashMap<>(); private final List toAdd = new ArrayList<>(); + private CompoundEdit mergeGroupsEdit; + private int duplicates = 0; public synchronized List getToRemove() { @@ -232,5 +242,13 @@ public synchronized boolean isToRemove(BibEntry entry) { public synchronized int getDuplicateCount() { return duplicates; } + + public synchronized void setMergeGroupsEdit(CompoundEdit mergeGroupsEdit) { + this.mergeGroupsEdit = mergeGroupsEdit; + } + + public Optional getMergedGroupsEdit() { + return Optional.ofNullable(mergeGroupsEdit); + } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index 7c1a9e127ba..fe6ffd80283 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -133,6 +133,10 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF edited = true; } } + if (dialog.getMergeGroupsEdit().canUndo()) { + ce.addEdit(dialog.getMergeGroupsEdit()); + edited = true; + } if (edited) { ce.end(); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index 3a24e84246b..ca0feb50de4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -81,6 +81,7 @@ public void execute() { ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergedEntry.get())); List entriesToRemove = Arrays.asList(one, two); ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); + ce.addEdit(dlg.getMergeGroupsEdit()); databaseContext.getDatabase().removeEntries(entriesToRemove); ce.end(); Globals.undoManager.addEdit(ce); // ToDo: Rework UndoManager and extract Globals diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 4c2f5ace0ec..30255f6c7eb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,5 +1,7 @@ package org.jabref.gui.mergeentries; +import javax.swing.undo.CompoundEdit; + import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; @@ -46,4 +48,8 @@ public void setLeftHeaderText(String leftHeaderText) { public void setRightHeaderText(String rightHeaderText) { threeWayMergeView.setRightHeader(rightHeaderText); } + + public CompoundEdit getMergeGroupsEdit() { + return threeWayMergeView.getMergeGroupsEdit(); + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 2194dd19c08..3262797f2d7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -231,6 +231,10 @@ public void cancelGroupsMerge() { } } + public CompoundEdit getMergeGroupsEdit() { + return mergeGroupsEdit; + } + public class MergeGroupsCommand extends SimpleCommand { private final GroupsFieldNameCell groupsFieldNameCell; From fde0bb7214815909b8c27c22f63d3479bf41463b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 10 Jul 2022 09:00:42 +0100 Subject: [PATCH 325/473] Cancel merge groups edit in the DuplicateResolverDialog when user choose 'Cancel' button --- .../jabref/gui/duplicationFinder/DuplicateResolverDialog.java | 1 + .../gui/mergeentries/newmergedialog/ThreeWayMergeView.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index f25b680b936..0bfd6cf4ed3 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -129,6 +129,7 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { } else if (button.equals(removeExact)) { return DuplicateResolverResult.AUTOREMOVE_EXACT; } + threeWayMerge.cancelGroupsMerge(); return null; }); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 3262797f2d7..1104d47ac73 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -33,7 +33,7 @@ import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { - + public static final String GROUPS_SEPARATOR = ", "; public static final int GRID_COLUMN_MIN_WIDTH = 250; public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); @@ -280,7 +280,7 @@ private String mergeLeftAndRightEntryGroups(String left, String right) { List rightGroups = Arrays.stream(right.split(", ")).toList(); leftGroups.addAll(rightGroups); - return String.join(", ", leftGroups); + return String.join(GROUPS_SEPARATOR, leftGroups); } } From 008e7ea24b6f519ceba7f98d24b4f2bf31630147 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Wed, 3 Aug 2022 20:20:50 +0200 Subject: [PATCH 326/473] i18n # Conflicts: # src/main/resources/l10n/JabRef_en.properties --- src/main/resources/l10n/JabRef_en.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index d9d14074508..be6f674b56a 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2518,3 +2518,5 @@ Merged\ Entry=Merged Entry Assign=Assign Do\ not\ assign=Do not assign +Merge\ Groups=Merge Groups +Unmerge\ Groups=Unmerge Groups From 5bf4ad9af7c6095b0de7a53dba144d77081e4d6a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 13:18:53 +0100 Subject: [PATCH 327/473] Introduce ThreeFieldValuesViewModel --- .../newmergedialog/ThreeFieldValues.java | 6 +++ .../ThreeFieldValuesViewModel.java | 47 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 74bf76fe8b2..98f97bde8fe 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -1,6 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog; +import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; @@ -26,11 +28,15 @@ public class ThreeFieldValues { private final ToggleGroup toggleGroup = new ToggleGroup(); + private final ThreeFieldValuesViewModel viewModel; + public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); + viewModel = new ThreeFieldValuesViewModel(); + this.leftValue = leftValue; this.rightValue = rightValue; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java new file mode 100644 index 00000000000..e965ab8e729 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -0,0 +1,47 @@ +package org.jabref.gui.mergeentries.newmergedialog; + +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import org.jabref.model.strings.StringUtil; + +public class ThreeFieldValuesViewModel { + public enum Selection { + LEFT, RIGHT, MERGED + } + + private final ObjectProperty selectedCell = new SimpleObjectProperty<>(); + + private final StringProperty leftFieldValue = new SimpleStringProperty(); + private final StringProperty rightFieldValue = new SimpleStringProperty(); + private final StringProperty mergedFieldValue = new SimpleStringProperty(); + + private final BooleanBinding hasEqualLeftAndRight; + + public ThreeFieldValuesViewModel() { + hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + } + + public boolean hasEqualLeftAndRightValues() { + return (!StringUtil.isNullOrEmpty(leftFieldValue.get()) && + !StringUtil.isNullOrEmpty(rightFieldValue.get()) && + leftFieldValue.get().equals(rightFieldValue.get())); + } + + public void selectLeftValue() { + selectedCell.set(Selection.LEFT); + mergedFieldValue.set(leftFieldValue.getValue()); + } + + public void merge() { + selectedCell.set(Selection.MERGED); + } + + public BooleanBinding hasEqualLeftAndRightBinding() { + return hasEqualLeftAndRight; + } +} From 73ddbc8bd2e8bde4f0468d3bb30c0dc70733aba8 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 12:52:21 +0100 Subject: [PATCH 328/473] Merge clones of left & right entry rather than the original ones --- .../gui/mergeentries/FetchAndMergeEntry.java | 6 +---- .../gui/mergeentries/MergeEntriesAction.java | 23 ++++++++----------- .../gui/mergeentries/MergeEntriesDialog.java | 10 ++------ .../jabref/gui/mergeentries/MergeResult.java | 8 +++++++ .../newmergedialog/ThreeWayMergeView.java | 10 +++++++- .../gui/shared/SharedDatabaseUIManager.java | 3 ++- 6 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeResult.java diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index fe6ffd80283..542788431cc 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -91,7 +91,7 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF 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 mergedEntry = dialogService.showCustomDialogAndWait(dialog); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); if (mergedEntry.isPresent()) { NamedCompound ce = new NamedCompound(Localization.lang("Merge entry with %0 information", fetcher.getName())); @@ -133,10 +133,6 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF edited = true; } } - if (dialog.getMergeGroupsEdit().canUndo()) { - ce.addEdit(dialog.getMergeGroupsEdit()); - edited = true; - } if (edited) { ce.end(); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index ca0feb50de4..7820cd95c92 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -66,29 +66,24 @@ public void execute() { second = one; } - MergeEntriesDialog dlg = new MergeEntriesDialog(first, second); - dlg.setTitle(Localization.lang("Merge entries")); - Optional mergedEntry = dialogService.showCustomDialogAndWait(dlg); - if (mergedEntry.isPresent()) { - // ToDo: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark + MergeEntriesDialog dialog = new MergeEntriesDialog(first, second); + dialog.setTitle(Localization.lang("Merge entries")); + Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); + mergeResultOpt.ifPresentOrElse(mergeResult -> { + // TODO: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark // entries with a timestamp, only BasePanel::insertEntry does. Workaround for the moment is to get the // BasePanel from the constructor injected JabRefFrame. Should be refactored and extracted! - frame.getCurrentLibraryTab().insertEntry(mergedEntry.get()); + frame.getCurrentLibraryTab().insertEntry(mergeResult.mergedEntry()); - // Create a new entry and add it to the undo stack - // Remove the other two entries and add them to the undo stack (which is not working...) NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); - ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergedEntry.get())); + ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergeResult.mergedEntry())); List entriesToRemove = Arrays.asList(one, two); ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); - ce.addEdit(dlg.getMergeGroupsEdit()); databaseContext.getDatabase().removeEntries(entriesToRemove); ce.end(); - Globals.undoManager.addEdit(ce); // ToDo: Rework UndoManager and extract Globals + Globals.undoManager.addEdit(ce); dialogService.notify(Localization.lang("Merged entries")); - } else { - dialogService.notify(Localization.lang("Canceled merging entries")); - } + }, () -> dialogService.notify(Localization.lang("Canceled merging entries"))); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 30255f6c7eb..adaea1a0c46 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -1,7 +1,5 @@ package org.jabref.gui.mergeentries; -import javax.swing.undo.CompoundEdit; - import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; @@ -10,7 +8,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; -public class MergeEntriesDialog extends BaseDialog { +public class MergeEntriesDialog extends BaseDialog { private final ThreeWayMergeView threeWayMergeView; public MergeEntriesDialog(BibEntry one, BibEntry two) { @@ -33,7 +31,7 @@ private void init() { this.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, replaceEntries); this.setResultConverter(buttonType -> { if (buttonType.equals(replaceEntries)) { - return threeWayMergeView.getMergedEntry(); + return new MergeResult(threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); } else { threeWayMergeView.cancelGroupsMerge(); return null; @@ -48,8 +46,4 @@ public void setLeftHeaderText(String leftHeaderText) { public void setRightHeaderText(String rightHeaderText) { threeWayMergeView.setRightHeader(rightHeaderText); } - - public CompoundEdit getMergeGroupsEdit() { - return threeWayMergeView.getMergeGroupsEdit(); - } } diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeResult.java b/src/main/java/org/jabref/gui/mergeentries/MergeResult.java new file mode 100644 index 00000000000..6db5a7a60e5 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/MergeResult.java @@ -0,0 +1,8 @@ +package org.jabref.gui.mergeentries; + +import org.jabref.model.entry.BibEntry; + +public record MergeResult( + BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry +) { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 1104d47ac73..4552c654db5 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -58,7 +58,7 @@ public class ThreeWayMergeView extends VBox { public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); - viewModel = new ThreeWayMergeViewModel(leftEntry, rightEntry, leftHeader, rightHeader); + viewModel = new ThreeWayMergeViewModel((BibEntry) leftEntry.clone(), (BibEntry) rightEntry.clone(), leftHeader, rightHeader); mergeGridPane = new GridPane(); scrollPane = new ScrollPane(); @@ -235,6 +235,14 @@ public CompoundEdit getMergeGroupsEdit() { return mergeGroupsEdit; } + public BibEntry getLeftEntry() { + return viewModel.getLeftEntry(); + } + + public BibEntry getRightEntry() { + return viewModel.getRightEntry(); + } + public class MergeGroupsCommand extends SimpleCommand { private final GroupsFieldNameCell groupsFieldNameCell; diff --git a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java index 055ea30a983..e5c2a0e9732 100644 --- a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java +++ b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java @@ -16,6 +16,7 @@ import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.gui.mergeentries.MergeEntriesDialog; +import org.jabref.gui.mergeentries.MergeResult; import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; @@ -99,7 +100,7 @@ public void listen(UpdateRefusedEvent updateRefusedEvent) { if (response.isPresent() && response.get().equals(merge)) { MergeEntriesDialog dialog = new MergeEntriesDialog(localBibEntry, sharedBibEntry); - Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); mergedEntry.ifPresent(mergedBibEntry -> { mergedBibEntry.getSharedBibEntryData().setSharedID(sharedBibEntry.getSharedBibEntryData().getSharedID()); From d05373b36039d682ebe55b6750312cca71c43d2d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 12:52:40 +0100 Subject: [PATCH 329/473] Optimize imports --- .../gui/mergeentries/newmergedialog/ThreeFieldValues.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 98f97bde8fe..369c8e4de41 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -1,8 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog; -import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; From 6522f940b9debb02127df7ef8050b602e2469d00 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 13:16:37 +0100 Subject: [PATCH 330/473] Refactor DuplicateResolverDialog to merge clones of left and right entry --- .../DuplicateResolverDialog.java | 10 ++++--- .../duplicationFinder/DuplicateSearch.java | 28 +++++++------------ .../newmergedialog/ThreeWayMergeView.java | 4 --- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index 0bfd6cf4ed3..d3c70e06bfe 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -1,7 +1,5 @@ package org.jabref.gui.duplicationFinder; -import javax.swing.undo.CompoundEdit; - import javafx.scene.control.Button; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar.ButtonData; @@ -142,7 +140,11 @@ public BibEntry getMergedEntry() { return threeWayMerge.getMergedEntry(); } - public CompoundEdit getMergeGroupsEdit() { - return threeWayMerge.getMergeGroupsEdit(); + public BibEntry getNewLeftEntry() { + return threeWayMerge.getLeftEntry(); + } + + public BibEntry getNewRightEntry() { + return threeWayMerge.getRightEntry(); } } diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java index 50bce360ff9..46ddfaf6f3b 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java @@ -5,15 +5,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import javax.swing.undo.CompoundEdit; - import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; @@ -155,20 +152,21 @@ private void askResolveStrategy(DuplicateSearchResult result, BibEntry first, Bi if ((resolverResult == DuplicateResolverResult.KEEP_LEFT) || (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT)) { result.remove(second); + result.replace(first, dialog.getNewLeftEntry()); if (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT) { autoRemoveExactDuplicates.set(true); // Remember choice } } else if (resolverResult == DuplicateResolverResult.KEEP_RIGHT) { result.remove(first); + result.replace(second, dialog.getNewRightEntry()); } else if (resolverResult == DuplicateResolverResult.BREAK) { libraryAnalyzed.set(true); duplicates.clear(); } else if (resolverResult == DuplicateResolverResult.KEEP_MERGE) { result.replace(first, second, dialog.getMergedEntry()); - } - - if (dialog.getMergeGroupsEdit().canUndo()) { - result.setMergeGroupsEdit(dialog.getMergeGroupsEdit()); + } else if (resolverResult == DuplicateResolverResult.KEEP_BOTH) { + result.replace(first, dialog.getNewLeftEntry()); + result.replace(second, dialog.getNewRightEntry()); } } @@ -191,7 +189,6 @@ private void handleDuplicates(DuplicateSearchResult result) { libraryTab.getDatabase().insertEntries(result.getToAdd()); libraryTab.markBaseChanged(); } - result.getMergedGroupsEdit().ifPresent(compoundEdit::addEdit); duplicateProgress.set(0); @@ -211,8 +208,6 @@ static class DuplicateSearchResult { private final Map toRemove = new HashMap<>(); private final List toAdd = new ArrayList<>(); - private CompoundEdit mergeGroupsEdit; - private int duplicates = 0; public synchronized List getToRemove() { @@ -235,6 +230,11 @@ public synchronized void replace(BibEntry first, BibEntry second, BibEntry repla duplicates++; } + public synchronized void replace(BibEntry entry, BibEntry replacement) { + remove(entry); + getToAdd().add(replacement); + } + public synchronized boolean isToRemove(BibEntry entry) { return toRemove.containsKey(System.identityHashCode(entry)); } @@ -242,13 +242,5 @@ public synchronized boolean isToRemove(BibEntry entry) { public synchronized int getDuplicateCount() { return duplicates; } - - public synchronized void setMergeGroupsEdit(CompoundEdit mergeGroupsEdit) { - this.mergeGroupsEdit = mergeGroupsEdit; - } - - public Optional getMergedGroupsEdit() { - return Optional.ofNullable(mergeGroupsEdit); - } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 4552c654db5..eb90ba14fbb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -231,10 +231,6 @@ public void cancelGroupsMerge() { } } - public CompoundEdit getMergeGroupsEdit() { - return mergeGroupsEdit; - } - public BibEntry getLeftEntry() { return viewModel.getLeftEntry(); } From b7ab2350fc75e215ce3b78f77aabee8c195bb0bf Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sat, 16 Jul 2022 13:37:15 +0100 Subject: [PATCH 331/473] Select the other entry groups when one entry has no group --- .../newmergedialog/ThreeWayMergeView.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index eb90ba14fbb..90c8616e3cf 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -31,6 +31,7 @@ import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.EntryTypeFactory; +import org.jabref.model.strings.StringUtil; public class ThreeWayMergeView extends VBox { public static final String GROUPS_SEPARATOR = ", "; @@ -280,11 +281,17 @@ public void execute() { } private String mergeLeftAndRightEntryGroups(String left, String right) { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); + if (StringUtil.isBlank(left)) { + return right; + } else if (StringUtil.isBlank(right)) { + return left; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); + leftGroups.addAll(rightGroups); - return String.join(GROUPS_SEPARATOR, leftGroups); + return String.join(GROUPS_SEPARATOR, leftGroups); + } } } From 4212cc7ecdaa54e21d30ac0628bdf564060d15e1 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 17 Jul 2022 18:42:37 +0100 Subject: [PATCH 332/473] Remove unused property --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 90c8616e3cf..515a45d7648 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -9,8 +9,6 @@ import javax.swing.undo.CompoundEdit; import javafx.beans.binding.Bindings; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -53,8 +51,6 @@ public class ThreeWayMergeView extends VBox { private final ThreeWayMergeViewModel viewModel; private final List fieldValuesList = new ArrayList<>(); - private final BooleanProperty areGroupsMerged = new SimpleBooleanProperty(); - private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { @@ -246,12 +242,12 @@ public class MergeGroupsCommand extends SimpleCommand { public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { this.groupsFieldNameCell = groupsFieldCell; - this.executable.bind(Bindings.and(areGroupsMerged.not(), Bindings.createBooleanBinding(() -> { + this.executable.bind(Bindings.createBooleanBinding(() -> { String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); return !leftEntryGroups.equals(rightEntryGroups); - }))); + })); } @Override From c8d47b4aebcd2ccde883684454509641584bcf99 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Sun, 17 Jul 2022 19:47:49 +0100 Subject: [PATCH 333/473] [WIP] Convert ThreeFieldValues to MVVM - Together with my mentors, we decided to convert ThreeFieldValues to MVVM in order to maintain the codebase consistency and facilitate testing. The view is ThreeFieldValues, and it has a view model. --- .../newmergedialog/ThreeFieldValues.java | 28 ++++-- .../ThreeFieldValuesViewModel.java | 86 +++++++++++++++++-- 2 files changed, 103 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 369c8e4de41..836027073d7 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -1,5 +1,6 @@ package org.jabref.gui.mergeentries.newmergedialog; +import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; @@ -12,6 +13,8 @@ import org.fxmisc.richtext.StyleClassedTextArea; +import static org.jabref.gui.mergeentries.newmergedialog.ThreeFieldValuesViewModel.Selection; + /** * A controller class to control left, right and merged field values */ @@ -57,6 +60,19 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); + mergedValueCell.textProperty().bindBidirectional(viewModel.mergedFieldValueProperty()); + + viewModel.selectionProperty().addListener(obs -> { + Selection selection = viewModel.getSelection(); + if (selection == Selection.LEFT) { + toggleGroup.selectToggle(leftValueCell); + } else if (selection == Selection.RIGHT) { + toggleGroup.selectToggle(rightValueCell); + } else if (selection == Selection.NONE) { + toggleGroup.selectToggle(null); + } + }); + // When both the left and right cells have the same value, only the left value is displayed, // making it unnecessary to keep allocating memory for the right cell. if (hasEqualLeftAndRightValues()) { @@ -66,15 +82,11 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } public void selectLeftValue() { - toggleGroup.selectToggle(leftValueCell); + viewModel.selectLeftValue(); } public void selectRightValue() { - if (isRightValueCellHidden()) { - selectLeftValue(); - } else { - toggleGroup.selectToggle(rightValueCell); - } + viewModel.selectRightValue(); } public String getMergedValue() { @@ -136,4 +148,8 @@ public void hideDiff() { private boolean isRightValueCellHidden() { return rightValueCell == null; } + + private ObjectProperty selectionProperty() { + return viewModel.selectionProperty(); + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index e965ab8e729..2ae5f7129a6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -2,7 +2,9 @@ import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -11,10 +13,19 @@ public class ThreeFieldValuesViewModel { public enum Selection { - LEFT, RIGHT, MERGED + LEFT, + RIGHT, + /** + * When the user types something into the merged field value and neither the left nor + * right values match it, NONE is selected + * */ + NONE } - private final ObjectProperty selectedCell = new SimpleObjectProperty<>(); + + private final BooleanProperty isFieldsMerged = new SimpleBooleanProperty(Boolean.FALSE); + + private final ObjectProperty selection = new SimpleObjectProperty<>(); private final StringProperty leftFieldValue = new SimpleStringProperty(); private final StringProperty rightFieldValue = new SimpleStringProperty(); @@ -33,15 +44,80 @@ public boolean hasEqualLeftAndRightValues() { } public void selectLeftValue() { - selectedCell.set(Selection.LEFT); - mergedFieldValue.set(leftFieldValue.getValue()); + setSelection(Selection.LEFT); + setMergedFieldValue(getLeftFieldValue()); + } + + public void selectRightValue() { + if (isIsFieldsMerged()) { + selectLeftValue(); + } else { + setSelection(Selection.RIGHT); + setMergedFieldValue(getRightFieldValue()); + } + } + + public void setMergedFieldValue(String mergedFieldValue) { + mergedFieldValueProperty().set(mergedFieldValue); + } + + public StringProperty mergedFieldValueProperty() { + return mergedFieldValue; } public void merge() { - selectedCell.set(Selection.MERGED); + setIsFieldsMerged(true); } public BooleanBinding hasEqualLeftAndRightBinding() { return hasEqualLeftAndRight; } + + public ObjectProperty selectionProperty() { + return selection; + } + + public void setSelection(Selection select) { + selectionProperty().set(select); + } + + public Selection getSelection() { + return selectionProperty().get(); + } + + public boolean isIsFieldsMerged() { + return isFieldsMerged.get(); + } + + public BooleanProperty isFieldsMergedProperty() { + return isFieldsMerged; + } + + public void setIsFieldsMerged(boolean isFieldsMerged) { + this.isFieldsMerged.set(isFieldsMerged); + } + + public String getLeftFieldValue() { + return leftFieldValue.get(); + } + + public StringProperty leftFieldValueProperty() { + return leftFieldValue; + } + + public void setLeftFieldValue(String leftFieldValue) { + this.leftFieldValue.set(leftFieldValue); + } + + public String getRightFieldValue() { + return rightFieldValue.get(); + } + + public StringProperty rightFieldValueProperty() { + return rightFieldValue; + } + + public void setRightFieldValue(String rightFieldValue) { + this.rightFieldValue.set(rightFieldValue); + } } From 884aa53e458f8db068a6dbf89264a79a98ee3d6d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 13:38:24 +0100 Subject: [PATCH 334/473] Move business logic to the view-model and update UI via binding --- .../newmergedialog/ThreeFieldValues.java | 49 ++++++++++--------- .../ThreeFieldValuesViewModel.java | 47 +++++++++++++++--- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 836027073d7..739d2842089 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -2,6 +2,7 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; +import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; @@ -36,31 +37,16 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); - viewModel = new ThreeFieldValuesViewModel(); + viewModel = new ThreeFieldValuesViewModel(leftValue, rightValue); this.leftValue = leftValue; this.rightValue = rightValue; toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); - toggleGroup.selectToggle(StringUtil.isNullOrEmpty(leftValue) ? rightValueCell : leftValueCell); - toggleGroup.selectedToggleProperty().addListener(invalidated -> { - if (toggleGroup.getSelectedToggle() != null) { - mergedValueCell.setText((String) toggleGroup.getSelectedToggle().getUserData()); - } - }); - - mergedValueCell.textProperty().addListener((observable, old, mergedValue) -> { - if (mergedValue.equals(leftValue)) { - toggleGroup.selectToggle(leftValueCell); - } else if (mergedValue.equals(rightValue)) { - toggleGroup.selectToggle(rightValueCell); - } else { - // deselect all toggles because left and right values don't equal the merged value - toggleGroup.selectToggle(null); - } - }); mergedValueCell.textProperty().bindBidirectional(viewModel.mergedFieldValueProperty()); + leftValueCell.textProperty().bindBidirectional(viewModel.leftFieldValueProperty()); + rightValueCell.textProperty().bindBidirectional(viewModel.rightFieldValueProperty()); viewModel.selectionProperty().addListener(obs -> { Selection selection = viewModel.getSelection(); @@ -73,6 +59,23 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); + toggleGroup.selectedToggleProperty().addListener(obs -> { + Toggle selectedToggle = toggleGroup.getSelectedToggle(); + if (selectedToggle == leftValueCell) { + selectLeftValue(); + } else if (selectedToggle == rightValueCell) { + selectRightValue(); + } else { + selectNone(); + } + }); + + if (StringUtil.isNullOrEmpty(leftValue)) { + selectRightValue(); + } else { + selectLeftValue(); + } + // When both the left and right cells have the same value, only the left value is displayed, // making it unnecessary to keep allocating memory for the right cell. if (hasEqualLeftAndRightValues()) { @@ -89,12 +92,16 @@ public void selectRightValue() { viewModel.selectRightValue(); } + public void selectNone() { + viewModel.selectNone(); + } + public String getMergedValue() { return mergedValueProperty().getValue(); } public ReadOnlyStringProperty mergedValueProperty() { - return mergedValueCell.textProperty(); + return viewModel.mergedFieldValueProperty(); } public FieldValueCell getLeftValueCell() { @@ -110,9 +117,7 @@ public MergedFieldCell getMergedValueCell() { } public boolean hasEqualLeftAndRightValues() { - return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && - !StringUtil.isNullOrEmpty(rightValueCell.getText()) && - leftValueCell.getText().equals(rightValueCell.getText())); + return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && !StringUtil.isNullOrEmpty(rightValueCell.getText()) && leftValueCell.getText().equals(rightValueCell.getText())); } public void showDiff(ShowDiffConfig diffConfig) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 2ae5f7129a6..5a501f7d618 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -27,14 +27,31 @@ public enum Selection { private final ObjectProperty selection = new SimpleObjectProperty<>(); - private final StringProperty leftFieldValue = new SimpleStringProperty(); - private final StringProperty rightFieldValue = new SimpleStringProperty(); - private final StringProperty mergedFieldValue = new SimpleStringProperty(); + private final StringProperty leftFieldValue = new SimpleStringProperty(""); + private final StringProperty rightFieldValue = new SimpleStringProperty(""); + private final StringProperty mergedFieldValue = new SimpleStringProperty(""); private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel() { + public ThreeFieldValuesViewModel(String leftValue, String rightValue) { + leftFieldValueProperty().set(leftValue); + rightFieldValueProperty().set(rightValue); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + selectionProperty().addListener((obs, old, newVal) -> { + switch (newVal) { + case LEFT -> onLeftSelected(); + case RIGHT -> onRightSelected(); + } + }); + mergedFieldValueProperty().addListener(obs -> { + if (getMergedFieldValue().equals(getLeftFieldValue())) { + selectLeftValue(); + } else if (getMergedFieldValue().equals(getRightFieldValue())) { + selectRightValue(); + } else { + selectNone(); + } + }); } public boolean hasEqualLeftAndRightValues() { @@ -43,9 +60,20 @@ public boolean hasEqualLeftAndRightValues() { leftFieldValue.get().equals(rightFieldValue.get())); } + private void onLeftSelected() { + setMergedFieldValue(getLeftFieldValue()); + } + + private void onRightSelected() { + if (isIsFieldsMerged()) { + onLeftSelected(); + } else { + setMergedFieldValue(getRightFieldValue()); + } + } + public void selectLeftValue() { setSelection(Selection.LEFT); - setMergedFieldValue(getLeftFieldValue()); } public void selectRightValue() { @@ -53,10 +81,13 @@ public void selectRightValue() { selectLeftValue(); } else { setSelection(Selection.RIGHT); - setMergedFieldValue(getRightFieldValue()); } } + public void selectNone() { + setSelection(Selection.NONE); + } + public void setMergedFieldValue(String mergedFieldValue) { mergedFieldValueProperty().set(mergedFieldValue); } @@ -65,6 +96,10 @@ public StringProperty mergedFieldValueProperty() { return mergedFieldValue; } + public String getMergedFieldValue() { + return mergedFieldValue.get(); + } + public void merge() { setIsFieldsMerged(true); } From ae6babd04221cc6012d822fb07a4052061903230 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 13:55:57 +0100 Subject: [PATCH 335/473] Consider equal left and right fields as merged --- .../ThreeFieldValuesViewModel.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 5a501f7d618..27b2ed57ebc 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -37,12 +37,14 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { leftFieldValueProperty().set(leftValue); rightFieldValueProperty().set(rightValue); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + selectionProperty().addListener((obs, old, newVal) -> { switch (newVal) { - case LEFT -> onLeftSelected(); - case RIGHT -> onRightSelected(); + case LEFT -> setMergedFieldValue(getLeftFieldValue()); + case RIGHT -> setMergedFieldValue(getRightFieldValue()); } }); + mergedFieldValueProperty().addListener(obs -> { if (getMergedFieldValue().equals(getLeftFieldValue())) { selectLeftValue(); @@ -52,6 +54,20 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { selectNone(); } }); + + if (StringUtil.isNullOrEmpty(leftValue)) { + selectRightValue(); + } else { + selectLeftValue(); + } + + if (hasEqualLeftAndRight.get()) { + setIsFieldsMerged(true); + } + + hasEqualLeftAndRight.addListener(obs -> { + setIsFieldsMerged(true); + }); } public boolean hasEqualLeftAndRightValues() { @@ -60,18 +76,6 @@ public boolean hasEqualLeftAndRightValues() { leftFieldValue.get().equals(rightFieldValue.get())); } - private void onLeftSelected() { - setMergedFieldValue(getLeftFieldValue()); - } - - private void onRightSelected() { - if (isIsFieldsMerged()) { - onLeftSelected(); - } else { - setMergedFieldValue(getRightFieldValue()); - } - } - public void selectLeftValue() { setSelection(Selection.LEFT); } From f0c1f1cfb4e0ea65d464ee62d0c4fd9666891b14 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:18:52 +0100 Subject: [PATCH 336/473] Move initial selection code to the view model - Replaced addListener() with EasyBind#subscribe --- .../newmergedialog/ThreeFieldValues.java | 24 ++++----------- .../ThreeFieldValuesViewModel.java | 30 ++++++++----------- 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 739d2842089..1ebbd84de74 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -12,6 +12,7 @@ import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.strings.StringUtil; +import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; import static org.jabref.gui.mergeentries.newmergedialog.ThreeFieldValuesViewModel.Selection; @@ -48,8 +49,7 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { leftValueCell.textProperty().bindBidirectional(viewModel.leftFieldValueProperty()); rightValueCell.textProperty().bindBidirectional(viewModel.rightFieldValueProperty()); - viewModel.selectionProperty().addListener(obs -> { - Selection selection = viewModel.getSelection(); + EasyBind.subscribe(viewModel.selectionProperty(), selection -> { if (selection == Selection.LEFT) { toggleGroup.selectToggle(leftValueCell); } else if (selection == Selection.RIGHT) { @@ -59,29 +59,15 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); - toggleGroup.selectedToggleProperty().addListener(obs -> { - Toggle selectedToggle = toggleGroup.getSelectedToggle(); - if (selectedToggle == leftValueCell) { + EasyBind.subscribe(toggleGroup.selectedToggleProperty(), val -> { + if (val == leftValueCell) { selectLeftValue(); - } else if (selectedToggle == rightValueCell) { + } else if (val == rightValueCell) { selectRightValue(); } else { selectNone(); } }); - - if (StringUtil.isNullOrEmpty(leftValue)) { - selectRightValue(); - } else { - selectLeftValue(); - } - - // When both the left and right cells have the same value, only the left value is displayed, - // making it unnecessary to keep allocating memory for the right cell. - if (hasEqualLeftAndRightValues()) { - // Setting this to null so the GC release the memory allocated to the right cell. - this.rightValueCell = null; - } } public void selectLeftValue() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 27b2ed57ebc..acd2bc94c57 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -11,6 +11,8 @@ import org.jabref.model.strings.StringUtil; +import com.tobiasdiez.easybind.EasyBind; + public class ThreeFieldValuesViewModel { public enum Selection { LEFT, @@ -38,15 +40,21 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { rightFieldValueProperty().set(rightValue); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); - selectionProperty().addListener((obs, old, newVal) -> { - switch (newVal) { + if (StringUtil.isNullOrEmpty(leftValue)) { + selectRightValue(); + } else { + selectLeftValue(); + } + + EasyBind.subscribe(selectionProperty(), selection -> { + switch (selection) { case LEFT -> setMergedFieldValue(getLeftFieldValue()); case RIGHT -> setMergedFieldValue(getRightFieldValue()); } }); - mergedFieldValueProperty().addListener(obs -> { - if (getMergedFieldValue().equals(getLeftFieldValue())) { + EasyBind.subscribe(mergedFieldValueProperty(), mergedValue -> { + if (mergedValue.equals(getLeftFieldValue())) { selectLeftValue(); } else if (getMergedFieldValue().equals(getRightFieldValue())) { selectRightValue(); @@ -55,19 +63,7 @@ public ThreeFieldValuesViewModel(String leftValue, String rightValue) { } }); - if (StringUtil.isNullOrEmpty(leftValue)) { - selectRightValue(); - } else { - selectLeftValue(); - } - - if (hasEqualLeftAndRight.get()) { - setIsFieldsMerged(true); - } - - hasEqualLeftAndRight.addListener(obs -> { - setIsFieldsMerged(true); - }); + EasyBind.subscribe(hasEqualLeftAndRightBinding(), this::setIsFieldsMerged); } public boolean hasEqualLeftAndRightValues() { From ae99ef436e70fcfc78045e60837888c4b8e09736 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:20:22 +0100 Subject: [PATCH 337/473] Refactor --- .../mergeentries/newmergedialog/ThreeFieldValues.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index 1ebbd84de74..ffa294f3c4c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -2,7 +2,6 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; -import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; @@ -59,10 +58,10 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { } }); - EasyBind.subscribe(toggleGroup.selectedToggleProperty(), val -> { - if (val == leftValueCell) { + EasyBind.subscribe(toggleGroup.selectedToggleProperty(), selectedToggle -> { + if (selectedToggle == leftValueCell) { selectLeftValue(); - } else if (val == rightValueCell) { + } else if (selectedToggle == rightValueCell) { selectRightValue(); } else { selectNone(); @@ -103,7 +102,7 @@ public MergedFieldCell getMergedValueCell() { } public boolean hasEqualLeftAndRightValues() { - return isRightValueCellHidden() || (!StringUtil.isNullOrEmpty(leftValueCell.getText()) && !StringUtil.isNullOrEmpty(rightValueCell.getText()) && leftValueCell.getText().equals(rightValueCell.getText())); + return viewModel.hasEqualLeftAndRightValues(); } public void showDiff(ShowDiffConfig diffConfig) { From e16ae4740538f48e2c54c51209ef85615e0f518d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:31:20 +0100 Subject: [PATCH 338/473] Hide rightValueCell and extend leftValueCell to 2 columns when fields are merged --- .../newmergedialog/ThreeFieldValues.java | 12 ++++++++++++ .../newmergedialog/ThreeWayMergeView.java | 11 +++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java index ffa294f3c4c..561b6c03608 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java @@ -3,6 +3,7 @@ import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.GridPane; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; @@ -67,6 +68,17 @@ public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { selectNone(); } }); + + // Hide rightValueCell and extend leftValueCell to 2 columns when fields are merged + EasyBind.subscribe(viewModel.isFieldsMergedProperty(), isFieldsMerged -> { + if (isFieldsMerged) { + rightValueCell.setVisible(false); + GridPane.setColumnSpan(leftValueCell, 2); + } else { + rightValueCell.setVisible(true); + GridPane.setColumnSpan(leftValueCell, 1); + } + }); } public void selectLeftValue() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 515a45d7648..4c359a36970 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -175,14 +175,9 @@ private void addFieldValues(int fieldIndex) { getMergedEntry().setField(field, fieldValues.getMergedValue()); } - if (fieldValues.hasEqualLeftAndRightValues()) { - mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex, 2, 1); - mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); - } else { - mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); - mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); - mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); - } + mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } private void updateFieldValues(int fieldIndex) { From 737045addc9d3687c1fdcfd4d98f64e9cab2a7ce Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:41:23 +0100 Subject: [PATCH 339/473] Prepare for adding the ability to merge fields other than groups --- .../newmergedialog/ThreeWayMergeView.java | 24 +++++++++---------- .../cell/FieldNameCellFactory.java | 8 +++++-- ...dNameCell.java => MergeableFieldCell.java} | 24 +++++++++---------- 3 files changed, 30 insertions(+), 26 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/{GroupsFieldNameCell.java => MergeableFieldCell.java} (59%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 4c359a36970..b64dae403a9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -20,7 +20,7 @@ import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; -import org.jabref.gui.mergeentries.newmergedialog.cell.GroupsFieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; @@ -135,11 +135,11 @@ private void addFieldName(Field field, int fieldIndex) { FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, fieldIndex); mergeGridPane.add(fieldNameCell, FIELD_NAME_COLUMN, fieldIndex); - if (field.equals(StandardField.GROUPS)) { - GroupsFieldNameCell groupsField = (GroupsFieldNameCell) fieldNameCell; - groupsField.setMergeGroupsCommand(new MergeGroupsCommand(groupsField)); - groupsField.setUnmergeGroupsCommand(new UnmergeGroupsCommand(groupsField)); - groupsField.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); + if (FieldNameCellFactory.isMergeableField(field)) { + MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; + mergeableFieldCell.setMergeCommand(new MergeGroupsCommand(mergeableFieldCell)); + mergeableFieldCell.setUnmergeCommand(new UnmergeGroupsCommand(mergeableFieldCell)); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } @@ -232,9 +232,9 @@ public BibEntry getRightEntry() { } public class MergeGroupsCommand extends SimpleCommand { - private final GroupsFieldNameCell groupsFieldNameCell; + private final MergeableFieldCell groupsFieldNameCell; - public MergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + public MergeGroupsCommand(MergeableFieldCell groupsFieldCell) { this.groupsFieldNameCell = groupsFieldCell; this.executable.bind(Bindings.createBooleanBinding(() -> { @@ -268,7 +268,7 @@ public void execute() { } updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.setMergeAction(GroupsFieldNameCell.MergeAction.UNMERGE); + groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } private String mergeLeftAndRightEntryGroups(String left, String right) { @@ -287,9 +287,9 @@ private String mergeLeftAndRightEntryGroups(String left, String right) { } public class UnmergeGroupsCommand extends SimpleCommand { - private final GroupsFieldNameCell groupsFieldCell; + private final MergeableFieldCell groupsFieldCell; - public UnmergeGroupsCommand(GroupsFieldNameCell groupsFieldCell) { + public UnmergeGroupsCommand(MergeableFieldCell groupsFieldCell) { this.groupsFieldCell = groupsFieldCell; } @@ -298,7 +298,7 @@ public void execute() { if (mergeGroupsEdit.canUndo()) { mergeGroupsEdit.undo(); updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldCell.setMergeAction(GroupsFieldNameCell.MergeAction.MERGE); + groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index 01a2fa90aff..b30245014f4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -5,9 +5,13 @@ public class FieldNameCellFactory { + public static boolean isMergeableField(Field field) { + return field == StandardField.GROUPS; + } + public static FieldNameCell create(Field field, int rowIndex) { - if (field.equals(StandardField.GROUPS)) { - return new GroupsFieldNameCell(rowIndex); + if (isMergeableField(field)) { + return new MergeableFieldCell(field, rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java similarity index 59% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 94a232cf3d2..519c65d50ad 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/GroupsFieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -5,33 +5,33 @@ import org.jabref.gui.icon.IconTheme; import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.field.Field; import de.saxsys.mvvmfx.utils.commands.Command; -public class GroupsFieldNameCell extends FieldNameCell { - private Command mergeGroupsCommand; - private Command unmergeGroupsCommand; +public class MergeableFieldCell extends FieldNameCell { + private Command mergeCommand; + private Command unmergeCommand; private final ObjectProperty mergeAction = new SimpleObjectProperty<>(); - public GroupsFieldNameCell(int rowIndex) { - super(StandardField.GROUPS.getDisplayName(), rowIndex); + public MergeableFieldCell(Field field, int rowIndex) { + super(field.getDisplayName(), rowIndex); mergeActionProperty().addListener((obs, old, newValue) -> { if (newValue == MergeAction.MERGE) { - setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeGroupsCommand); + setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); } else { - setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeGroupsCommand); + setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeCommand); } }); } - public void setMergeGroupsCommand(Command mergeGroupsCommand) { - this.mergeGroupsCommand = mergeGroupsCommand; + public void setMergeCommand(Command mergeCommand) { + this.mergeCommand = mergeCommand; } - public void setUnmergeGroupsCommand(Command unmergeGroupsCommand) { - this.unmergeGroupsCommand = unmergeGroupsCommand; + public void setUnmergeCommand(Command unmergeCommand) { + this.unmergeCommand = unmergeCommand; } public ObjectProperty mergeActionProperty() { From acf63ee0b9aab649d15c154ceab5778e106415b5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:44:28 +0100 Subject: [PATCH 340/473] Rename ThreeFieldValues to ThreeFieldValuesView --- ...ThreeFieldValues.java => ThreeFieldValuesView.java} | 4 ++-- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ThreeFieldValues.java => ThreeFieldValuesView.java} (97%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java similarity index 97% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 561b6c03608..3f27db4b092 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValues.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -20,7 +20,7 @@ /** * A controller class to control left, right and merged field values */ -public class ThreeFieldValues { +public class ThreeFieldValuesView { private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; @@ -33,7 +33,7 @@ public class ThreeFieldValues { private final ThreeFieldValuesViewModel viewModel; - public ThreeFieldValues(String leftValue, String rightValue, int rowIndex) { + public ThreeFieldValuesView(String leftValue, String rightValue, int rowIndex) { leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index b64dae403a9..3b8bcd05b32 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -49,7 +49,7 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List fieldValuesList = new ArrayList<>(); + private final List fieldValuesList = new ArrayList<>(); private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); @@ -91,7 +91,7 @@ private void updateDiff() { if (toolbar.isShowDiffEnabled()) { fieldValuesList.forEach(fieldValues -> fieldValues.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - fieldValuesList.forEach(ThreeFieldValues::hideDiff); + fieldValuesList.forEach(ThreeFieldValuesView::hideDiff); } } @@ -159,7 +159,7 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValues fieldValues = new ThreeFieldValues(leftEntryValue, rightEntryValue, fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(leftEntryValue, rightEntryValue, fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { @@ -204,11 +204,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - fieldValuesList.forEach(ThreeFieldValues::selectLeftValue); + fieldValuesList.forEach(ThreeFieldValuesView::selectLeftValue); } public void selectRightEntryValues() { - fieldValuesList.forEach(ThreeFieldValues::selectRightValue); + fieldValuesList.forEach(ThreeFieldValuesView::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 1dfe8a4f7a96b38d5a08335517cd547c6ec9b304 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 14:56:03 +0100 Subject: [PATCH 341/473] Delegate FieldNameCell creation to ThreeFieldValuesView --- .../newmergedialog/ThreeFieldValuesView.java | 11 ++++++++++- .../newmergedialog/ThreeWayMergeView.java | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 3f27db4b092..075fe81a45f 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -5,11 +5,14 @@ import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -21,6 +24,7 @@ * A controller class to control left, right and merged field values */ public class ThreeFieldValuesView { + private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; @@ -33,7 +37,8 @@ public class ThreeFieldValuesView { private final ThreeFieldValuesViewModel viewModel; - public ThreeFieldValuesView(String leftValue, String rightValue, int rowIndex) { + public ThreeFieldValuesView(Field field, String leftValue, String rightValue, int rowIndex) { + fieldNameCell = FieldNameCellFactory.create(field, rowIndex); leftValueCell = new FieldValueCell(leftValue, rowIndex); rightValueCell = new FieldValueCell(rightValue, rowIndex); mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); @@ -101,6 +106,10 @@ public ReadOnlyStringProperty mergedValueProperty() { return viewModel.mergedFieldValueProperty(); } + public FieldNameCell getFieldNameCell() { + return fieldNameCell; + } + public FieldValueCell getLeftValueCell() { return leftValueCell; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 3b8bcd05b32..93721d19745 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -119,7 +119,7 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); + // addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addFieldValues(fieldIndex); // Removing this will cause UI to lag when updating field values @@ -159,7 +159,7 @@ private void addFieldValues(int fieldIndex) { rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); } - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(leftEntryValue, rightEntryValue, fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, leftEntryValue, rightEntryValue, fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { @@ -175,6 +175,7 @@ private void addFieldValues(int fieldIndex) { getMergedEntry().setField(field, fieldValues.getMergedValue()); } + mergeGridPane.add(fieldValues.getFieldNameCell(), 0, fieldIndex); mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); From 0210d7128bc842a759cc73d6a9245848f29064f2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 19:01:10 +0100 Subject: [PATCH 342/473] Pass Bib entries to ThreeFieldValuesView rather than raw string - Because I want to add the merge/unmerge commands to ThreeFieldValuesView and I need to have a reference to left and right bib entries --- .../newmergedialog/ThreeFieldValuesView.java | 25 ++++------- .../ThreeFieldValuesViewModel.java | 41 +++++++++++++++---- .../newmergedialog/ThreeWayMergeView.java | 11 +---- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 075fe81a45f..3717a4068e8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -12,8 +12,8 @@ import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; @@ -29,24 +29,17 @@ public class ThreeFieldValuesView { private FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; - private final String leftValue; - - private final String rightValue; - private final ToggleGroup toggleGroup = new ToggleGroup(); private final ThreeFieldValuesViewModel viewModel; - public ThreeFieldValuesView(Field field, String leftValue, String rightValue, int rowIndex) { - fieldNameCell = FieldNameCellFactory.create(field, rowIndex); - leftValueCell = new FieldValueCell(leftValue, rowIndex); - rightValueCell = new FieldValueCell(rightValue, rowIndex); - mergedValueCell = new MergedFieldCell(StringUtil.isNullOrEmpty(leftValue) ? rightValue : leftValue, rowIndex); + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, int rowIndex) { + viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry); - viewModel = new ThreeFieldValuesViewModel(leftValue, rightValue); - - this.leftValue = leftValue; - this.rightValue = rightValue; + fieldNameCell = FieldNameCellFactory.create(field, rowIndex); + leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); + rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); + mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); @@ -149,11 +142,11 @@ public void hideDiff() { int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); - getLeftValueCell().getStyleClassedLabel().replaceText(leftValue); + getLeftValueCell().getStyleClassedLabel().replaceText(viewModel.getLeftFieldValue()); int rightValueLength = getRightValueCell().getStyleClassedLabel().getLength(); getRightValueCell().getStyleClassedLabel().clearStyle(0, rightValueLength); - getRightValueCell().getStyleClassedLabel().replaceText(rightValue); + getRightValueCell().getStyleClassedLabel().replaceText(viewModel.getRightFieldValue()); } private boolean isRightValueCellHidden() { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index acd2bc94c57..b8fe4bef004 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -9,6 +9,9 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.InternalField; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -33,14 +36,30 @@ public enum Selection { private final StringProperty rightFieldValue = new SimpleStringProperty(""); private final StringProperty mergedFieldValue = new SimpleStringProperty(""); + private final Field field; + + private final BibEntry leftEntry; + + private final BibEntry rightEntry; + private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel(String leftValue, String rightValue) { - leftFieldValueProperty().set(leftValue); - rightFieldValueProperty().set(rightValue); - hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValue, rightFieldValue); + public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry) { + this.field = field; + this.leftEntry = leftEntry; + this.rightEntry = rightEntry; + + if (field.equals(InternalField.TYPE_HEADER)) { + setLeftFieldValue(leftEntry.getType().getDisplayName()); + setRightFieldValue(rightEntry.getType().getDisplayName()); + } else { + setLeftFieldValue(leftEntry.getField(field).orElse("")); + setRightFieldValue(rightEntry.getField(field).orElse("")); + } - if (StringUtil.isNullOrEmpty(leftValue)) { + hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); + + if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { selectRightValue(); } else { selectLeftValue(); @@ -140,7 +159,7 @@ public StringProperty leftFieldValueProperty() { return leftFieldValue; } - public void setLeftFieldValue(String leftFieldValue) { + private void setLeftFieldValue(String leftFieldValue) { this.leftFieldValue.set(leftFieldValue); } @@ -152,7 +171,15 @@ public StringProperty rightFieldValueProperty() { return rightFieldValue; } - public void setRightFieldValue(String rightFieldValue) { + private void setRightFieldValue(String rightFieldValue) { this.rightFieldValue.set(rightFieldValue); } + + public BibEntry getLeftEntry() { + return leftEntry; + } + + public BibEntry getRightEntry() { + return rightEntry; + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 93721d19745..a56098f7e30 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -149,17 +149,8 @@ private Field getFieldAtIndex(int index) { private void addFieldValues(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - String leftEntryValue; - String rightEntryValue; - if (field.equals(InternalField.TYPE_HEADER)) { - leftEntryValue = viewModel.getLeftEntry().getType().getDisplayName(); - rightEntryValue = viewModel.getRightEntry().getType().getDisplayName(); - } else { - leftEntryValue = viewModel.getLeftEntry().getField(field).orElse(""); - rightEntryValue = viewModel.getRightEntry().getField(field).orElse(""); - } - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, leftEntryValue, rightEntryValue, fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { From 6a768eb9c0e40b57cec5d0d56a4e2eba5c5e0cc8 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 19:31:07 +0100 Subject: [PATCH 343/473] Move merge/unmerge commands to ThreeFieldValuesView --- .../newmergedialog/ThreeFieldValuesView.java | 93 +++++++++++++++ .../ThreeFieldValuesViewModel.java | 4 + .../newmergedialog/ThreeWayMergeView.java | 107 ------------------ 3 files changed, 97 insertions(+), 107 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 3717a4068e8..45e432528b0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -1,19 +1,31 @@ package org.jabref.gui.mergeentries.newmergedialog; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.undo.CompoundEdit; + +import javafx.beans.binding.Bindings; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; +import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; +import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; @@ -33,6 +45,8 @@ public class ThreeFieldValuesView { private final ThreeFieldValuesViewModel viewModel; + private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, int rowIndex) { viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry); @@ -41,6 +55,13 @@ public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); + if (FieldNameCellFactory.isMergeableField(field)) { + MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; + mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell)); + mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + } + toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); mergedValueCell.textProperty().bindBidirectional(viewModel.mergedFieldValueProperty()); @@ -156,4 +177,76 @@ private boolean isRightValueCellHidden() { private ObjectProperty selectionProperty() { return viewModel.selectionProperty(); } + + public class MergeCommand extends SimpleCommand { + private final MergeableFieldCell groupsFieldNameCell; + + public MergeCommand(MergeableFieldCell groupsFieldCell) { + this.groupsFieldNameCell = groupsFieldCell; + + this.executable.bind(Bindings.createBooleanBinding(() -> { + String leftEntryGroups = viewModel.getLeftEntry().getField(viewModel.getField()).orElse(""); + String rightEntryGroups = viewModel.getRightEntry().getField(viewModel.getField()).orElse(""); + + return !leftEntryGroups.equals(rightEntryGroups); + })); + } + + @Override + public void execute() { + BibEntry leftEntry = viewModel.getLeftEntry(); + BibEntry rightEntry = viewModel.getRightEntry(); + + String leftEntryGroups = leftEntry.getField(viewModel.getField()).orElse(""); + String rightEntryGroups = rightEntry.getField(viewModel.getField()).orElse(""); + + assert !leftEntryGroups.equals(rightEntryGroups); + + String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); + viewModel.getLeftEntry().setField(viewModel.getField(), mergedGroups); + viewModel.getRightEntry().setField(viewModel.getField(), mergedGroups); + + if (fieldsMergedEdit.canRedo()) { + fieldsMergedEdit.redo(); + } else { + fieldsMergedEdit.addEdit(new UndoableFieldChange(leftEntry, viewModel.getField(), leftEntryGroups, mergedGroups)); + fieldsMergedEdit.addEdit(new UndoableFieldChange(rightEntry, viewModel.getField(), rightEntryGroups, mergedGroups)); + fieldsMergedEdit.end(); + } + + groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); + viewModel.setIsFieldsMerged(true); + } + + private String mergeLeftAndRightEntryGroups(String left, String right) { + if (StringUtil.isBlank(left)) { + return right; + } else if (StringUtil.isBlank(right)) { + return left; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); + List rightGroups = Arrays.stream(right.split(", ")).toList(); + leftGroups.addAll(rightGroups); + + return String.join(", ", leftGroups); + } + } + } + + public class UnmergeCommand extends SimpleCommand { + private final MergeableFieldCell groupsFieldCell; + + public UnmergeCommand(MergeableFieldCell groupsFieldCell) { + this.groupsFieldCell = groupsFieldCell; + } + + @Override + public void execute() { + if (fieldsMergedEdit.canUndo()) { + fieldsMergedEdit.undo(); + groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + viewModel.setIsFieldsMerged(false); + } + } + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index b8fe4bef004..6bb1f195e34 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -175,6 +175,10 @@ private void setRightFieldValue(String rightFieldValue) { this.rightFieldValue.set(rightFieldValue); } + public Field getField() { + return field; + } + public BibEntry getLeftEntry() { return leftEntry; } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index a56098f7e30..5b6695bce0e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -1,14 +1,10 @@ package org.jabref.gui.mergeentries.newmergedialog; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; import javax.swing.undo.CompoundEdit; -import javafx.beans.binding.Bindings; import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -17,28 +13,20 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; -import org.jabref.gui.actions.SimpleCommand; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; -import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.EntryTypeFactory; -import org.jabref.model.strings.StringUtil; public class ThreeWayMergeView extends VBox { - public static final String GROUPS_SEPARATOR = ", "; public static final int GRID_COLUMN_MIN_WIDTH = 250; public static final String LEFT_DEFAULT_HEADER = Localization.lang("Left Entry"); public static final String RIGHT_DEFAULT_HEADER = Localization.lang("Right Entry"); - private static final int FIELD_NAME_COLUMN = 0; private final ColumnConstraints fieldNameColumnConstraints = new ColumnConstraints(150); private final ColumnConstraints leftEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); private final ColumnConstraints rightEntryColumnConstraints = new ColumnConstraints(GRID_COLUMN_MIN_WIDTH, 256, Double.MAX_VALUE); @@ -131,18 +119,6 @@ private void initializeMergeGridPane() { } } - private void addFieldName(Field field, int fieldIndex) { - FieldNameCell fieldNameCell = FieldNameCellFactory.create(field, fieldIndex); - mergeGridPane.add(fieldNameCell, FIELD_NAME_COLUMN, fieldIndex); - - if (FieldNameCellFactory.isMergeableField(field)) { - MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setMergeCommand(new MergeGroupsCommand(mergeableFieldCell)); - mergeableFieldCell.setUnmergeCommand(new UnmergeGroupsCommand(mergeableFieldCell)); - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); - } - } - private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } @@ -172,17 +148,6 @@ private void addFieldValues(int fieldIndex) { mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); } - private void updateFieldValues(int fieldIndex) { - removeFieldValues(fieldIndex); - addFieldValues(fieldIndex); - updateDiff(); - } - - private void removeFieldValues(int index) { - fieldValuesList.remove(index); - mergeGridPane.getChildren().removeIf(node -> GridPane.getRowIndex(node) == index && GridPane.getColumnIndex(node) > FIELD_NAME_COLUMN); - } - public BibEntry getMergedEntry() { return viewModel.getMergedEntry(); } @@ -222,76 +187,4 @@ public BibEntry getLeftEntry() { public BibEntry getRightEntry() { return viewModel.getRightEntry(); } - - public class MergeGroupsCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldNameCell; - - public MergeGroupsCommand(MergeableFieldCell groupsFieldCell) { - this.groupsFieldNameCell = groupsFieldCell; - - this.executable.bind(Bindings.createBooleanBinding(() -> { - String leftEntryGroups = viewModel.getLeftEntry().getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(StandardField.GROUPS).orElse(""); - - return !leftEntryGroups.equals(rightEntryGroups); - })); - } - - @Override - public void execute() { - BibEntry leftEntry = viewModel.getLeftEntry(); - BibEntry rightEntry = viewModel.getRightEntry(); - - String leftEntryGroups = leftEntry.getField(StandardField.GROUPS).orElse(""); - String rightEntryGroups = rightEntry.getField(StandardField.GROUPS).orElse(""); - - assert !leftEntryGroups.equals(rightEntryGroups); - - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(StandardField.GROUPS, mergedGroups); - viewModel.getRightEntry().setField(StandardField.GROUPS, mergedGroups); - - if (mergeGroupsEdit.canRedo()) { - mergeGroupsEdit.redo(); - } else { - mergeGroupsEdit.addEdit(new UndoableFieldChange(leftEntry, StandardField.GROUPS, leftEntryGroups, mergedGroups)); - mergeGroupsEdit.addEdit(new UndoableFieldChange(rightEntry, StandardField.GROUPS, rightEntryGroups, mergedGroups)); - mergeGroupsEdit.end(); - } - - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); - } - - private String mergeLeftAndRightEntryGroups(String left, String right) { - if (StringUtil.isBlank(left)) { - return right; - } else if (StringUtil.isBlank(right)) { - return left; - } else { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); - - return String.join(GROUPS_SEPARATOR, leftGroups); - } - } - } - - public class UnmergeGroupsCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldCell; - - public UnmergeGroupsCommand(MergeableFieldCell groupsFieldCell) { - this.groupsFieldCell = groupsFieldCell; - } - - @Override - public void execute() { - if (mergeGroupsEdit.canUndo()) { - mergeGroupsEdit.undo(); - updateFieldValues(viewModel.allFields().indexOf(StandardField.GROUPS)); - groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); - } - } - } } From e48bcbe75f3d07440c5c0b233d04bd8f17bfe76d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:38:49 +0100 Subject: [PATCH 344/473] Bind field value cell text property --- .../gui/mergeentries/newmergedialog/cell/FieldValueCell.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index f31639ccc25..4019c8f9a21 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -100,7 +100,7 @@ private void initialize() { private void initializeLabel() { label.setEditable(false); label.setBackground(Background.fill(Color.TRANSPARENT)); - label.appendText(textProperty().get()); + EasyBind.subscribe(textProperty(), label::replaceText); label.setAutoHeight(true); label.setWrapText(true); label.setStyle("-fx-cursor: hand"); From 12e6f40a45458881c0d46bbde3e75e9c35644020 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:45:05 +0100 Subject: [PATCH 345/473] Create an undoable edit for undoing fields merging --- .../newmergedialog/ThreeFieldValuesView.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 45e432528b0..654c17e64b8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -5,6 +5,9 @@ import java.util.List; import java.util.Set; +import javax.swing.undo.AbstractUndoableEdit; +import javax.swing.undo.CannotRedoException; +import javax.swing.undo.CannotUndoException; import javax.swing.undo.CompoundEdit; import javafx.beans.binding.Bindings; @@ -249,4 +252,30 @@ public void execute() { } } } + + class MergeFieldsUndo extends AbstractUndoableEdit { + private final String oldLeft; + private final String oldRight; + private final String mergedFields; + + MergeFieldsUndo(String oldLeft, String oldRight, String mergedFields) { + this.oldLeft = oldLeft; + this.oldRight = oldRight; + this.mergedFields = mergedFields; + } + + @Override + public void undo() throws CannotUndoException { + super.undo(); + viewModel.setLeftFieldValue(oldLeft); + viewModel.setRightFieldValue(oldRight); + } + + @Override + public void redo() throws CannotRedoException { + super.redo(); + viewModel.setLeftFieldValue(mergedFields); + viewModel.setRightFieldValue(mergedFields); + } + } } From 75260de9d94ee0f0d57c91c950d5b864fedf7099 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:48:36 +0100 Subject: [PATCH 346/473] Update bib entries when left and right field value properties change --- .../newmergedialog/ThreeFieldValuesViewModel.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 6bb1f195e34..28fbe18d062 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -57,6 +57,9 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right setRightFieldValue(rightEntry.getField(field).orElse("")); } + EasyBind.listen(leftFieldValueProperty(), (obs, old, leftValue) -> leftEntry.setField(field, leftValue)); + EasyBind.listen(rightFieldValueProperty(), (obs, old, rightValue) -> rightEntry.setField(field, rightValue)); + hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { @@ -67,8 +70,8 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right EasyBind.subscribe(selectionProperty(), selection -> { switch (selection) { - case LEFT -> setMergedFieldValue(getLeftFieldValue()); - case RIGHT -> setMergedFieldValue(getRightFieldValue()); + case LEFT -> mergedFieldValueProperty().bind(leftFieldValueProperty()); + case RIGHT -> mergedFieldValueProperty().bind(rightFieldValueProperty()); } }); @@ -159,7 +162,7 @@ public StringProperty leftFieldValueProperty() { return leftFieldValue; } - private void setLeftFieldValue(String leftFieldValue) { + public void setLeftFieldValue(String leftFieldValue) { this.leftFieldValue.set(leftFieldValue); } @@ -171,7 +174,7 @@ public StringProperty rightFieldValueProperty() { return rightFieldValue; } - private void setRightFieldValue(String rightFieldValue) { + public void setRightFieldValue(String rightFieldValue) { this.rightFieldValue.set(rightFieldValue); } From f3efc40df4eb24d826ab57de0b00450cbfe756db Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:49:16 +0100 Subject: [PATCH 347/473] Update left and right field value properties when merging fields rather than the bib entries --- .../newmergedialog/ThreeFieldValuesView.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 654c17e64b8..00967908671 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -25,7 +25,6 @@ import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; -import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.strings.StringUtil; @@ -197,23 +196,19 @@ public MergeCommand(MergeableFieldCell groupsFieldCell) { @Override public void execute() { - BibEntry leftEntry = viewModel.getLeftEntry(); - BibEntry rightEntry = viewModel.getRightEntry(); + assert !viewModel.getLeftFieldValue().equals(viewModel.getRightFieldValue()); - String leftEntryGroups = leftEntry.getField(viewModel.getField()).orElse(""); - String rightEntryGroups = rightEntry.getField(viewModel.getField()).orElse(""); + String oldLeftFieldValue = viewModel.getLeftFieldValue(); + String oldRightFieldValue = viewModel.getRightFieldValue(); - assert !leftEntryGroups.equals(rightEntryGroups); - - String mergedGroups = mergeLeftAndRightEntryGroups(leftEntryGroups, rightEntryGroups); - viewModel.getLeftEntry().setField(viewModel.getField(), mergedGroups); - viewModel.getRightEntry().setField(viewModel.getField(), mergedGroups); + String mergedGroups = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); + viewModel.setLeftFieldValue(mergedGroups); + viewModel.setRightFieldValue(mergedGroups); if (fieldsMergedEdit.canRedo()) { fieldsMergedEdit.redo(); } else { - fieldsMergedEdit.addEdit(new UndoableFieldChange(leftEntry, viewModel.getField(), leftEntryGroups, mergedGroups)); - fieldsMergedEdit.addEdit(new UndoableFieldChange(rightEntry, viewModel.getField(), rightEntryGroups, mergedGroups)); + fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedGroups)); fieldsMergedEdit.end(); } From 6d3e7cd1b98e84f740547c61c18212fc9adac986 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 22:58:35 +0100 Subject: [PATCH 348/473] Unbind MergedFieldValue property because it can't be edited when bound --- .../newmergedialog/ThreeFieldValuesViewModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 28fbe18d062..15bb5981b82 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -70,8 +70,8 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right EasyBind.subscribe(selectionProperty(), selection -> { switch (selection) { - case LEFT -> mergedFieldValueProperty().bind(leftFieldValueProperty()); - case RIGHT -> mergedFieldValueProperty().bind(rightFieldValueProperty()); + case LEFT -> EasyBind.subscribe(leftFieldValueProperty(), this::setMergedFieldValue); + case RIGHT -> EasyBind.subscribe(rightFieldValueProperty(), this::setMergedFieldValue); } }); From 184cd1ac6db270aee57f0b12a26229b8af99f186 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 23:01:18 +0100 Subject: [PATCH 349/473] Cleanup --- .../newmergedialog/ThreeFieldValuesView.java | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 00967908671..12898acf3af 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -11,7 +11,6 @@ import javax.swing.undo.CompoundEdit; import javafx.beans.binding.Bindings; -import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; @@ -40,7 +39,7 @@ public class ThreeFieldValuesView { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; - private FieldValueCell rightValueCell; + private final FieldValueCell rightValueCell; private final MergedFieldCell mergedValueCell; private final ToggleGroup toggleGroup = new ToggleGroup(); @@ -138,12 +137,8 @@ public MergedFieldCell getMergedValueCell() { return mergedValueCell; } - public boolean hasEqualLeftAndRightValues() { - return viewModel.hasEqualLeftAndRightValues(); - } - public void showDiff(ShowDiffConfig diffConfig) { - if (isRightValueCellHidden()) { + if (!rightValueCell.isVisible()) { return; } @@ -159,7 +154,7 @@ public void showDiff(ShowDiffConfig diffConfig) { } public void hideDiff() { - if (isRightValueCellHidden()) { + if (!rightValueCell.isVisible()) { return; } @@ -172,14 +167,6 @@ public void hideDiff() { getRightValueCell().getStyleClassedLabel().replaceText(viewModel.getRightFieldValue()); } - private boolean isRightValueCellHidden() { - return rightValueCell == null; - } - - private ObjectProperty selectionProperty() { - return viewModel.selectionProperty(); - } - public class MergeCommand extends SimpleCommand { private final MergeableFieldCell groupsFieldNameCell; @@ -201,19 +188,18 @@ public void execute() { String oldLeftFieldValue = viewModel.getLeftFieldValue(); String oldRightFieldValue = viewModel.getRightFieldValue(); - String mergedGroups = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); - viewModel.setLeftFieldValue(mergedGroups); - viewModel.setRightFieldValue(mergedGroups); + String mergedFields = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); + viewModel.setLeftFieldValue(mergedFields); + viewModel.setRightFieldValue(mergedFields); if (fieldsMergedEdit.canRedo()) { fieldsMergedEdit.redo(); } else { - fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedGroups)); + fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedFields)); fieldsMergedEdit.end(); } groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); - viewModel.setIsFieldsMerged(true); } private String mergeLeftAndRightEntryGroups(String left, String right) { @@ -243,7 +229,6 @@ public void execute() { if (fieldsMergedEdit.canUndo()) { fieldsMergedEdit.undo(); groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); - viewModel.setIsFieldsMerged(false); } } } From 874952eaac704c531c4c012e88bb430c97e9d674 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 18 Jul 2022 23:09:29 +0100 Subject: [PATCH 350/473] Move merged entry update logic to ThreeFieldValuesViewModel --- .../newmergedialog/ThreeFieldValuesView.java | 4 ++-- .../ThreeFieldValuesViewModel.java | 17 ++++++++++++++++- .../newmergedialog/ThreeWayMergeView.java | 18 ++---------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 12898acf3af..54f264cfd7d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -48,8 +48,8 @@ public class ThreeFieldValuesView { private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); - public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, int rowIndex) { - viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry); + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, int rowIndex) { + viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry, mergedEntry); fieldNameCell = FieldNameCellFactory.create(field, rowIndex); leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 15bb5981b82..5a88a9ec447 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -12,6 +12,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.InternalField; +import org.jabref.model.entry.types.EntryTypeFactory; import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; @@ -42,12 +43,15 @@ public enum Selection { private final BibEntry rightEntry; + private final BibEntry mergedEntry; + private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry) { + public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry) { this.field = field; this.leftEntry = leftEntry; this.rightEntry = rightEntry; + this.mergedEntry = mergedEntry; if (field.equals(InternalField.TYPE_HEADER)) { setLeftFieldValue(leftEntry.getType().getDisplayName()); @@ -59,6 +63,13 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right EasyBind.listen(leftFieldValueProperty(), (obs, old, leftValue) -> leftEntry.setField(field, leftValue)); EasyBind.listen(rightFieldValueProperty(), (obs, old, rightValue) -> rightEntry.setField(field, rightValue)); + EasyBind.listen(mergedFieldValueProperty(), (obs, old, mergedFieldValue) -> { + if (field.equals(InternalField.TYPE_HEADER)) { + getMergedEntry().setType(EntryTypeFactory.parse(mergedFieldValue)); + } else { + getMergedEntry().setField(field, mergedFieldValue); + } + }); hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); @@ -189,4 +200,8 @@ public BibEntry getLeftEntry() { public BibEntry getRightEntry() { return rightEntry; } + + public BibEntry getMergedEntry() { + return mergedEntry; + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 5b6695bce0e..85475213092 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -17,9 +17,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.InternalField; import org.jabref.model.entry.field.StandardField; -import org.jabref.model.entry.types.EntryTypeFactory; public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; @@ -126,21 +124,9 @@ private Field getFieldAtIndex(int index) { private void addFieldValues(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), fieldIndex); - fieldValuesList.add(fieldIndex, fieldValues); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldIndex); - fieldValues.mergedValueProperty().addListener((observable, old, mergedValue) -> { - if (field.equals(InternalField.TYPE_HEADER)) { - getMergedEntry().setType(EntryTypeFactory.parse(mergedValue)); - } else { - getMergedEntry().setField(field, mergedValue); - } - }); - if (field.equals(InternalField.TYPE_HEADER)) { - getMergedEntry().setType(EntryTypeFactory.parse(fieldValues.getMergedValue())); - } else { - getMergedEntry().setField(field, fieldValues.getMergedValue()); - } + fieldValuesList.add(fieldIndex, fieldValues); mergeGridPane.add(fieldValues.getFieldNameCell(), 0, fieldIndex); mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); From 3541cd589a17e73cec087aebccb2fbb4d274b5e5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:21:56 +0100 Subject: [PATCH 351/473] Implement algorithms for merging groups and keywords --- .../fieldsmerger/FieldMerger.java | 9 +++++ .../fieldsmerger/FieldMergerFactory.java | 23 +++++++++++ .../fieldsmerger/GroupMerger.java | 29 ++++++++++++++ .../fieldsmerger/KeywordMerger.java | 38 +++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java new file mode 100644 index 00000000000..8119a892abb --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMerger.java @@ -0,0 +1,9 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +/** + * This class is responsible for taking two values for some field and merging them to into one value + * */ +@FunctionalInterface +public interface FieldMerger { + String merge(String fieldValueA, String fieldValueB); +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java new file mode 100644 index 00000000000..d5da07e06e7 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -0,0 +1,23 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.StandardField; +import org.jabref.preferences.PreferencesService; + +public class FieldMergerFactory { + private final PreferencesService preferencesService; + + public FieldMergerFactory(PreferencesService preferencesService) { + this.preferencesService = preferencesService; + } + + public FieldMerger create(Field field) { + if (field.equals(StandardField.GROUPS)) { + return new GroupMerger(); + } else if (field.equals(StandardField.KEYWORDS)) { + return new KeywordMerger(preferencesService); + } else { + throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); + } + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java new file mode 100644 index 00000000000..e6580b948d0 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java @@ -0,0 +1,29 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jabref.model.strings.StringUtil; + +public class GroupMerger implements FieldMerger { + public static final String GROUPS_SEPARATOR = ", "; + + @Override + public String merge(String groupsA, String groupsB) { + if (StringUtil.isBlank(groupsA) && StringUtil.isBlank(groupsB)) { + return ""; + } else if (StringUtil.isBlank(groupsA)) { + return groupsB; + } else if (StringUtil.isBlank(groupsB)) { + return groupsA; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(groupsA.split(GROUPS_SEPARATOR)).toList()); + List rightGroups = Arrays.stream(groupsB.split(GROUPS_SEPARATOR)).toList(); + leftGroups.addAll(rightGroups); + + return String.join(GROUPS_SEPARATOR, leftGroups); + } + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java new file mode 100644 index 00000000000..6535a2774f9 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -0,0 +1,38 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.jabref.model.strings.StringUtil; +import org.jabref.preferences.PreferencesService; + +public class KeywordMerger implements FieldMerger { + private final PreferencesService preferencesService; + + public KeywordMerger(PreferencesService preferencesService) { + Objects.requireNonNull(preferencesService); + this.preferencesService = preferencesService; + } + + @Override + public String merge(String keywordsA, String keywordsB) { + String keywordSeparator = " " + preferencesService.getGroupsPreferences().getKeywordSeparator(); + + if (StringUtil.isBlank(keywordsA) && StringUtil.isBlank(keywordsB)) { + return ""; + } else if (StringUtil.isBlank(keywordsA)) { + return keywordsB; + } else if (StringUtil.isBlank(keywordsB)) { + return keywordsA; + } else { + Set leftGroups = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); + List rightGroups = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); + leftGroups.addAll(rightGroups); + + return String.join(keywordSeparator, leftGroups); + } + } +} From 075da2bcb95d4160da65b3e2984eacd2f7c0d58c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:30:18 +0100 Subject: [PATCH 352/473] Pass FieldMergerFactory to ThreeFieldValuesView --- .../newmergedialog/ThreeFieldValuesView.java | 32 +++++-------------- .../newmergedialog/ThreeWayMergeView.java | 8 ++++- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index 54f264cfd7d..a7fb369a0b6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -1,10 +1,5 @@ package org.jabref.gui.mergeentries.newmergedialog; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; @@ -23,10 +18,11 @@ import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMerger; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; @@ -48,7 +44,7 @@ public class ThreeFieldValuesView { private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); - public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, int rowIndex) { + public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry, mergedEntry); fieldNameCell = FieldNameCellFactory.create(field, rowIndex); @@ -58,7 +54,7 @@ public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry if (FieldNameCellFactory.isMergeableField(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell)); + mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field))); mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } @@ -169,9 +165,11 @@ public void hideDiff() { public class MergeCommand extends SimpleCommand { private final MergeableFieldCell groupsFieldNameCell; + private final FieldMerger fieldMerger; - public MergeCommand(MergeableFieldCell groupsFieldCell) { + public MergeCommand(MergeableFieldCell groupsFieldCell, FieldMerger fieldMerger) { this.groupsFieldNameCell = groupsFieldCell; + this.fieldMerger = fieldMerger; this.executable.bind(Bindings.createBooleanBinding(() -> { String leftEntryGroups = viewModel.getLeftEntry().getField(viewModel.getField()).orElse(""); @@ -188,7 +186,7 @@ public void execute() { String oldLeftFieldValue = viewModel.getLeftFieldValue(); String oldRightFieldValue = viewModel.getRightFieldValue(); - String mergedFields = mergeLeftAndRightEntryGroups(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); + String mergedFields = fieldMerger.merge(viewModel.getLeftFieldValue(), viewModel.getRightFieldValue()); viewModel.setLeftFieldValue(mergedFields); viewModel.setRightFieldValue(mergedFields); @@ -201,20 +199,6 @@ public void execute() { groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } - - private String mergeLeftAndRightEntryGroups(String left, String right) { - if (StringUtil.isBlank(left)) { - return right; - } else if (StringUtil.isBlank(right)) { - return left; - } else { - Set leftGroups = new HashSet<>(Arrays.stream(left.split(", ")).toList()); - List rightGroups = Arrays.stream(right.split(", ")).toList(); - leftGroups.addAll(rightGroups); - - return String.join(", ", leftGroups); - } - } } public class UnmergeCommand extends SimpleCommand { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 85475213092..26f2068824b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -13,6 +13,8 @@ import javafx.scene.layout.VBox; import javafx.stage.Screen; +import org.jabref.gui.Globals; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -39,9 +41,13 @@ public class ThreeWayMergeView extends VBox { private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); + private final FieldMergerFactory fieldMergerFactory; + public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { getStylesheets().add(ThreeWayMergeView.class.getResource("ThreeWayMergeView.css").toExternalForm()); viewModel = new ThreeWayMergeViewModel((BibEntry) leftEntry.clone(), (BibEntry) rightEntry.clone(), leftHeader, rightHeader); + // TODO: Inject 'preferenceService' into the constructor + this.fieldMergerFactory = new FieldMergerFactory(Globals.prefs); mergeGridPane = new GridPane(); scrollPane = new ScrollPane(); @@ -124,7 +130,7 @@ private Field getFieldAtIndex(int index) { private void addFieldValues(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldIndex); + ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldMergerFactory, fieldIndex); fieldValuesList.add(fieldIndex, fieldValues); From b2ddc8a30da88bd76a2296302fa396ea026acbb3 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:34:08 +0100 Subject: [PATCH 353/473] Move isMergeableField method to FieldMergerFactory --- .../newmergedialog/ThreeFieldValuesView.java | 2 +- .../newmergedialog/cell/FieldNameCellFactory.java | 9 ++------- .../newmergedialog/fieldsmerger/FieldMergerFactory.java | 4 ++++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java index a7fb369a0b6..fa9a31183ad 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java @@ -52,7 +52,7 @@ public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); - if (FieldNameCellFactory.isMergeableField(field)) { + if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field))); mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java index b30245014f4..ee038e53eca 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java @@ -1,16 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.StandardField; public class FieldNameCellFactory { - - public static boolean isMergeableField(Field field) { - return field == StandardField.GROUPS; - } - public static FieldNameCell create(Field field, int rowIndex) { - if (isMergeableField(field)) { + if (FieldMergerFactory.canMerge(field)) { return new MergeableFieldCell(field, rowIndex); } else { return new FieldNameCell(field.getDisplayName(), rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java index d5da07e06e7..63777a514fb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -20,4 +20,8 @@ public FieldMerger create(Field field) { throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); } } + + public static boolean canMerge(Field field) { + return field == StandardField.GROUPS || field == StandardField.KEYWORDS; + } } From fb40879f2e2408e93e9c092591dc2f55bd95add8 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:35:31 +0100 Subject: [PATCH 354/473] Delete cancelGroupsEdit() --- .../gui/duplicationFinder/DuplicateResolverDialog.java | 1 - .../jabref/gui/mergeentries/MergeEntriesDialog.java | 1 - .../mergeentries/newmergedialog/ThreeWayMergeView.java | 10 ---------- 3 files changed, 12 deletions(-) diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index d3c70e06bfe..6a89a239500 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -127,7 +127,6 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { } else if (button.equals(removeExact)) { return DuplicateResolverResult.AUTOREMOVE_EXACT; } - threeWayMerge.cancelGroupsMerge(); return null; }); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index adaea1a0c46..a93598494b0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -33,7 +33,6 @@ private void init() { if (buttonType.equals(replaceEntries)) { return new MergeResult(threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); } else { - threeWayMergeView.cancelGroupsMerge(); return null; } }); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 26f2068824b..0b1f01a6803 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.List; -import javax.swing.undo.CompoundEdit; - import javafx.scene.control.ScrollPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; @@ -39,8 +37,6 @@ public class ThreeWayMergeView extends VBox { private final ThreeWayMergeViewModel viewModel; private final List fieldValuesList = new ArrayList<>(); - private final CompoundEdit mergeGroupsEdit = new CompoundEdit(); - private final FieldMergerFactory fieldMergerFactory; public ThreeWayMergeView(BibEntry leftEntry, BibEntry rightEntry, String leftHeader, String rightHeader) { @@ -166,12 +162,6 @@ public void showDiff(ShowDiffConfig diffConfig) { toolbar.setShowDiff(true); } - public void cancelGroupsMerge() { - if (mergeGroupsEdit.canUndo()) { - mergeGroupsEdit.undo(); - } - } - public BibEntry getLeftEntry() { return viewModel.getLeftEntry(); } From 2c7339a9ce591863c38b9e45257859dd92e75d0b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 10:47:55 +0100 Subject: [PATCH 355/473] Fix KeywordMerger implementation --- .../newmergedialog/fieldsmerger/KeywordMerger.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java index 6535a2774f9..af73dab692a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -19,7 +19,7 @@ public KeywordMerger(PreferencesService preferencesService) { @Override public String merge(String keywordsA, String keywordsB) { - String keywordSeparator = " " + preferencesService.getGroupsPreferences().getKeywordSeparator(); + String keywordSeparator = preferencesService.getGroupsPreferences().getKeywordSeparator() + " "; if (StringUtil.isBlank(keywordsA) && StringUtil.isBlank(keywordsB)) { return ""; @@ -28,11 +28,11 @@ public String merge(String keywordsA, String keywordsB) { } else if (StringUtil.isBlank(keywordsB)) { return keywordsA; } else { - Set leftGroups = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); - List rightGroups = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); - leftGroups.addAll(rightGroups); + Set keywordsASet = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); + List keywordsBList = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); + keywordsASet.addAll(keywordsBList); - return String.join(keywordSeparator, leftGroups); + return String.join(keywordSeparator, keywordsASet); } } } From 11fb4f1066d95d413138e8c2ed99c76c4883cecb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:04:51 +0100 Subject: [PATCH 356/473] Fix a bug that deselects both fields after they are unmerged --- .../newmergedialog/ThreeFieldValuesViewModel.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java index 5a88a9ec447..17ae31b0eee 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java @@ -100,9 +100,7 @@ public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry right } public boolean hasEqualLeftAndRightValues() { - return (!StringUtil.isNullOrEmpty(leftFieldValue.get()) && - !StringUtil.isNullOrEmpty(rightFieldValue.get()) && - leftFieldValue.get().equals(rightFieldValue.get())); + return leftFieldValue.get().equals(rightFieldValue.get()); } public void selectLeftValue() { From ef212c097e14ea067845dfd8fbf519e8b826936c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:16:22 +0100 Subject: [PATCH 357/473] Rename 'ThreeFieldValues' to 'FieldRow' --- ...FieldValuesView.java => FieldRowView.java} | 10 +++---- ...sViewModel.java => FieldRowViewModel.java} | 4 +-- .../newmergedialog/ThreeWayMergeView.java | 26 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ThreeFieldValuesView.java => FieldRowView.java} (95%) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/{ThreeFieldValuesViewModel.java => FieldRowViewModel.java} (97%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java similarity index 95% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index fa9a31183ad..75fda80810c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -27,12 +27,12 @@ import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; -import static org.jabref.gui.mergeentries.newmergedialog.ThreeFieldValuesViewModel.Selection; +import static org.jabref.gui.mergeentries.newmergedialog.FieldRowViewModel.Selection; /** * A controller class to control left, right and merged field values */ -public class ThreeFieldValuesView { +public class FieldRowView { private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private final FieldValueCell rightValueCell; @@ -40,12 +40,12 @@ public class ThreeFieldValuesView { private final ToggleGroup toggleGroup = new ToggleGroup(); - private final ThreeFieldValuesViewModel viewModel; + private final FieldRowViewModel viewModel; private final CompoundEdit fieldsMergedEdit = new CompoundEdit(); - public ThreeFieldValuesView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { - viewModel = new ThreeFieldValuesViewModel(field, leftEntry, rightEntry, mergedEntry); + public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { + viewModel = new FieldRowViewModel(field, leftEntry, rightEntry, mergedEntry); fieldNameCell = FieldNameCellFactory.create(field, rowIndex); leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java similarity index 97% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java index 17ae31b0eee..94959d8a1fb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeFieldValuesViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java @@ -17,7 +17,7 @@ import com.tobiasdiez.easybind.EasyBind; -public class ThreeFieldValuesViewModel { +public class FieldRowViewModel { public enum Selection { LEFT, RIGHT, @@ -47,7 +47,7 @@ public enum Selection { private final BooleanBinding hasEqualLeftAndRight; - public ThreeFieldValuesViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry) { + public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry) { this.field = field; this.leftEntry = leftEntry; this.rightEntry = rightEntry; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index 0b1f01a6803..b417bf2ca0a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -35,7 +35,7 @@ public class ThreeWayMergeView extends VBox { private final GridPane mergeGridPane; private final ThreeWayMergeViewModel viewModel; - private final List fieldValuesList = new ArrayList<>(); + private final List fieldRows = new ArrayList<>(); private final FieldMergerFactory fieldMergerFactory; @@ -77,9 +77,9 @@ private void initializeToolbar() { private void updateDiff() { if (toolbar.isShowDiffEnabled()) { - fieldValuesList.forEach(fieldValues -> fieldValues.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); + fieldRows.forEach(row -> row.showDiff(new ShowDiffConfig(toolbar.getDiffView(), toolbar.getDiffHighlightingMethod()))); } else { - fieldValuesList.forEach(ThreeFieldValuesView::hideDiff); + fieldRows.forEach(FieldRowView::hideDiff); } } @@ -108,7 +108,7 @@ private void initializeMergeGridPane() { for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { // addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); - addFieldValues(fieldIndex); + addRow(fieldIndex); // Removing this will cause UI to lag when updating field values if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { @@ -123,17 +123,17 @@ private Field getFieldAtIndex(int index) { return viewModel.allFields().get(index); } - private void addFieldValues(int fieldIndex) { + private void addRow(int fieldIndex) { Field field = getFieldAtIndex(fieldIndex); - ThreeFieldValuesView fieldValues = new ThreeFieldValuesView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldMergerFactory, fieldIndex); + FieldRowView fieldRow = new FieldRowView(field, getLeftEntry(), getRightEntry(), getMergedEntry(), fieldMergerFactory, fieldIndex); - fieldValuesList.add(fieldIndex, fieldValues); + fieldRows.add(fieldIndex, fieldRow); - mergeGridPane.add(fieldValues.getFieldNameCell(), 0, fieldIndex); - mergeGridPane.add(fieldValues.getLeftValueCell(), 1, fieldIndex); - mergeGridPane.add(fieldValues.getRightValueCell(), 2, fieldIndex); - mergeGridPane.add(fieldValues.getMergedValueCell(), 3, fieldIndex); + mergeGridPane.add(fieldRow.getFieldNameCell(), 0, fieldIndex); + mergeGridPane.add(fieldRow.getLeftValueCell(), 1, fieldIndex); + mergeGridPane.add(fieldRow.getRightValueCell(), 2, fieldIndex); + mergeGridPane.add(fieldRow.getMergedValueCell(), 3, fieldIndex); } public BibEntry getMergedEntry() { @@ -149,11 +149,11 @@ public void setRightHeader(String rightHeader) { } public void selectLeftEntryValues() { - fieldValuesList.forEach(ThreeFieldValuesView::selectLeftValue); + fieldRows.forEach(FieldRowView::selectLeftValue); } public void selectRightEntryValues() { - fieldValuesList.forEach(ThreeFieldValuesView::selectRightValue); + fieldRows.forEach(FieldRowView::selectRightValue); } public void showDiff(ShowDiffConfig diffConfig) { From 3752f160a8dcd8b03ca35368c8d6695a8d9f92bc Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:17:49 +0100 Subject: [PATCH 358/473] Cleanup --- .../mergeentries/newmergedialog/ThreeWayMergeView.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java index b417bf2ca0a..a61833456f8 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/ThreeWayMergeView.java @@ -17,7 +17,6 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.StandardField; public class ThreeWayMergeView extends VBox { public static final int GRID_COLUMN_MIN_WIDTH = 250; @@ -107,15 +106,9 @@ private void initializeMergeGridPane() { mergeGridPane.getColumnConstraints().addAll(fieldNameColumnConstraints, leftEntryColumnConstraints, rightEntryColumnConstraints, mergedEntryColumnConstraints); for (int fieldIndex = 0; fieldIndex < viewModel.allFieldsSize(); fieldIndex++) { - // addFieldName(getFieldAtIndex(fieldIndex), fieldIndex); addRow(fieldIndex); - // Removing this will cause UI to lag when updating field values - if (getFieldAtIndex(fieldIndex).equals(StandardField.GROUPS)) { - mergeGridPane.getRowConstraints().add(fieldIndex, new RowConstraints(56, 56, Double.MAX_VALUE)); - } else { - mergeGridPane.getRowConstraints().add(new RowConstraints()); - } + mergeGridPane.getRowConstraints().add(new RowConstraints()); } } From 0a8f9d7653b98b7e4a144cd5668822ed55e9b9f6 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 19 Jul 2022 11:21:05 +0100 Subject: [PATCH 359/473] Hide diffs when both values are equal --- .../gui/mergeentries/newmergedialog/FieldRowView.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 75fda80810c..a7a09631e90 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -95,6 +95,12 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt GridPane.setColumnSpan(leftValueCell, 1); } }); + + EasyBind.listen(viewModel.hasEqualLeftAndRightBinding(), (obs, old, isEqual) -> { + if (isEqual) { + hideDiff(); + } + }); } public void selectLeftValue() { From 6eea335a7b0c25a982d1389528b404d29fb125c4 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 15:54:27 +0100 Subject: [PATCH 360/473] Fix typos --- .../newmergedialog/FieldRowView.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index a7a09631e90..0e1b62b91a4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -5,7 +5,6 @@ import javax.swing.undo.CannotUndoException; import javax.swing.undo.CompoundEdit; -import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyStringProperty; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; @@ -170,19 +169,14 @@ public void hideDiff() { } public class MergeCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldNameCell; + private final MergeableFieldCell mergeableFieldCell; private final FieldMerger fieldMerger; - public MergeCommand(MergeableFieldCell groupsFieldCell, FieldMerger fieldMerger) { - this.groupsFieldNameCell = groupsFieldCell; + public MergeCommand(MergeableFieldCell mergeableFieldCell, FieldMerger fieldMerger) { + this.mergeableFieldCell = mergeableFieldCell; this.fieldMerger = fieldMerger; - this.executable.bind(Bindings.createBooleanBinding(() -> { - String leftEntryGroups = viewModel.getLeftEntry().getField(viewModel.getField()).orElse(""); - String rightEntryGroups = viewModel.getRightEntry().getField(viewModel.getField()).orElse(""); - - return !leftEntryGroups.equals(rightEntryGroups); - })); + this.executable.bind(viewModel.hasEqualLeftAndRightBinding().not()); } @Override @@ -203,22 +197,22 @@ public void execute() { fieldsMergedEdit.end(); } - groupsFieldNameCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } } public class UnmergeCommand extends SimpleCommand { - private final MergeableFieldCell groupsFieldCell; + private final MergeableFieldCell mergeableFieldCell; - public UnmergeCommand(MergeableFieldCell groupsFieldCell) { - this.groupsFieldCell = groupsFieldCell; + public UnmergeCommand(MergeableFieldCell mergeableFieldCell) { + this.mergeableFieldCell = mergeableFieldCell; } @Override public void execute() { if (fieldsMergedEdit.canUndo()) { fieldsMergedEdit.undo(); - groupsFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } } From e1667d95d8cfaa52e518e6310e59e70f5fe73463 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 16:01:48 +0100 Subject: [PATCH 361/473] Select LEFT value after merging fields --- .../newmergedialog/FieldRowViewModel.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java index 94959d8a1fb..2fc07acd282 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java @@ -73,11 +73,15 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B hasEqualLeftAndRight = Bindings.createBooleanBinding(this::hasEqualLeftAndRightValues, leftFieldValueProperty(), rightFieldValueProperty()); - if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { - selectRightValue(); - } else { - selectLeftValue(); - } + selectNonEmptyValue(); + + EasyBind.listen(isFieldsMergedProperty(), (obs, old, areFieldsMerged) -> { + if (areFieldsMerged) { + selectLeftValue(); + } else { + selectNonEmptyValue(); + } + }); EasyBind.subscribe(selectionProperty(), selection -> { switch (selection) { @@ -99,6 +103,14 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B EasyBind.subscribe(hasEqualLeftAndRightBinding(), this::setIsFieldsMerged); } + public void selectNonEmptyValue() { + if (StringUtil.isNullOrEmpty(leftFieldValue.get())) { + selectRightValue(); + } else { + selectLeftValue(); + } + } + public boolean hasEqualLeftAndRightValues() { return leftFieldValue.get().equals(rightFieldValue.get()); } From 383dd76e639346b9c23ef93cae990b828572765b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 17:12:01 +0100 Subject: [PATCH 362/473] Logging --- .../gui/mergeentries/newmergedialog/FieldRowViewModel.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java index 2fc07acd282..06356de4177 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowViewModel.java @@ -16,6 +16,8 @@ import org.jabref.model.strings.StringUtil; import com.tobiasdiez.easybind.EasyBind; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FieldRowViewModel { public enum Selection { @@ -28,7 +30,7 @@ public enum Selection { NONE } - + private final Logger LOGGER = LoggerFactory.getLogger(FieldRowViewModel.class); private final BooleanProperty isFieldsMerged = new SimpleBooleanProperty(Boolean.FALSE); private final ObjectProperty selection = new SimpleObjectProperty<>(); @@ -76,6 +78,7 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B selectNonEmptyValue(); EasyBind.listen(isFieldsMergedProperty(), (obs, old, areFieldsMerged) -> { + LOGGER.debug("Field are merged: {}", areFieldsMerged); if (areFieldsMerged) { selectLeftValue(); } else { @@ -84,6 +87,7 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B }); EasyBind.subscribe(selectionProperty(), selection -> { + LOGGER.debug("Selecting {}' value for field {}", selection, field.getDisplayName()); switch (selection) { case LEFT -> EasyBind.subscribe(leftFieldValueProperty(), this::setMergedFieldValue); case RIGHT -> EasyBind.subscribe(rightFieldValueProperty(), this::setMergedFieldValue); @@ -91,6 +95,7 @@ public FieldRowViewModel(Field field, BibEntry leftEntry, BibEntry rightEntry, B }); EasyBind.subscribe(mergedFieldValueProperty(), mergedValue -> { + LOGGER.debug("Merged value is {} for field {}", mergedValue, field.getDisplayName()); if (mergedValue.equals(getLeftFieldValue())) { selectLeftValue(); } else if (getMergedFieldValue().equals(getRightFieldValue())) { From 2f58d9bb5ce9b5707ecb774d2415fe6484cc509c Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 19:56:57 +0100 Subject: [PATCH 363/473] Implement merging comments --- .../newmergedialog/fieldsmerger/CommentMerger.java | 10 ++++++++++ .../fieldsmerger/FieldMergerFactory.java | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java new file mode 100644 index 00000000000..5599bfb2470 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java @@ -0,0 +1,10 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import org.jabref.logic.util.OS; + +public class CommentMerger implements FieldMerger { + @Override + public String merge(String fieldValueA, String fieldValueB) { + return fieldValueA + OS.NEWLINE + fieldValueB; + } +} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java index 63777a514fb..e794830ba26 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -16,12 +16,14 @@ public FieldMerger create(Field field) { return new GroupMerger(); } else if (field.equals(StandardField.KEYWORDS)) { return new KeywordMerger(preferencesService); + } else if (field == StandardField.COMMENT) { + return new CommentMerger(); } else { throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); } } public static boolean canMerge(Field field) { - return field == StandardField.GROUPS || field == StandardField.KEYWORDS; + return field == StandardField.GROUPS || field == StandardField.KEYWORDS || field == StandardField.COMMENT; } } From 4aaabf0f6fc0cf61fa1cc5551e579df38d4a58bb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 20 Jul 2022 19:57:28 +0100 Subject: [PATCH 364/473] Improve groups and keywords merger implementation --- .../newmergedialog/fieldsmerger/GroupMerger.java | 12 ++++-------- .../newmergedialog/fieldsmerger/KeywordMerger.java | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java index e6580b948d0..8af126aac61 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java @@ -1,9 +1,7 @@ package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.stream.Collectors; import org.jabref.model.strings.StringUtil; @@ -19,11 +17,9 @@ public String merge(String groupsA, String groupsB) { } else if (StringUtil.isBlank(groupsB)) { return groupsA; } else { - Set leftGroups = new HashSet<>(Arrays.stream(groupsA.split(GROUPS_SEPARATOR)).toList()); - List rightGroups = Arrays.stream(groupsB.split(GROUPS_SEPARATOR)).toList(); - leftGroups.addAll(rightGroups); - - return String.join(GROUPS_SEPARATOR, leftGroups); + return Arrays.stream((groupsA + GROUPS_SEPARATOR + groupsB).split(GROUPS_SEPARATOR)) + .distinct() + .collect(Collectors.joining(GROUPS_SEPARATOR)); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java index af73dab692a..62b5ca2bb11 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -1,10 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; import java.util.Objects; -import java.util.Set; +import java.util.stream.Collectors; import org.jabref.model.strings.StringUtil; import org.jabref.preferences.PreferencesService; @@ -28,11 +26,9 @@ public String merge(String keywordsA, String keywordsB) { } else if (StringUtil.isBlank(keywordsB)) { return keywordsA; } else { - Set keywordsASet = new HashSet<>(Arrays.stream(keywordsA.split(keywordSeparator)).toList()); - List keywordsBList = Arrays.stream(keywordsB.split(keywordSeparator)).toList(); - keywordsASet.addAll(keywordsBList); - - return String.join(keywordSeparator, keywordsASet); + return Arrays.stream((keywordsA + keywordSeparator + keywordsB).split(keywordSeparator)) + .distinct() + .collect(Collectors.joining(keywordSeparator)); } } } From ecf1eeb1102e9160a0b365af91d4b29e66f90231 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Fri, 22 Jul 2022 16:03:29 +0100 Subject: [PATCH 365/473] Change merge/unmerge buttons tooltip text based on the field to merge --- .../mergeentries/newmergedialog/cell/MergeableFieldCell.java | 4 ++-- src/main/resources/l10n/JabRef_en.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 519c65d50ad..d9cab3a38ed 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -19,9 +19,9 @@ public MergeableFieldCell(Field field, int rowIndex) { super(field.getDisplayName(), rowIndex); mergeActionProperty().addListener((obs, old, newValue) -> { if (newValue == MergeAction.MERGE) { - setAction(Localization.lang("Merge Groups"), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); + setAction(Localization.lang("Merge %0", field.getDisplayName()), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); } else { - setAction(Localization.lang("Unmerge Groups"), IconTheme.JabRefIcons.UNDO, unmergeCommand); + setAction(Localization.lang("Unmerge %0", field.getDisplayName()), IconTheme.JabRefIcons.UNDO, unmergeCommand); } }); } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index be6f674b56a..ab98eefe526 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2518,5 +2518,5 @@ Merged\ Entry=Merged Entry Assign=Assign Do\ not\ assign=Do not assign -Merge\ Groups=Merge Groups -Unmerge\ Groups=Unmerge Groups +Merge\ %0=Merge %0 +Unmerge\ %0=Unmerge %0 From b1e2951270cb78da450ac2fd159c2b4e1cab043d Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 12:13:44 +0100 Subject: [PATCH 366/473] Implement file merging --- .../fieldsmerger/FieldMergerFactory.java | 4 ++- .../fieldsmerger/FileMerger.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java index e794830ba26..3c275dfcb7d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FieldMergerFactory.java @@ -18,12 +18,14 @@ public FieldMerger create(Field field) { return new KeywordMerger(preferencesService); } else if (field == StandardField.COMMENT) { return new CommentMerger(); + } else if (field == StandardField.FILE) { + return new FileMerger(); } else { throw new IllegalArgumentException("No implementation found for merging the given field: " + field.getDisplayName()); } } public static boolean canMerge(Field field) { - return field == StandardField.GROUPS || field == StandardField.KEYWORDS || field == StandardField.COMMENT; + return field == StandardField.GROUPS || field == StandardField.KEYWORDS || field == StandardField.COMMENT || field == StandardField.FILE; } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java new file mode 100644 index 00000000000..c8fb940870b --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java @@ -0,0 +1,29 @@ +package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.jabref.logic.importer.util.FileFieldParser; +import org.jabref.model.entry.LinkedFile; +import org.jabref.model.strings.StringUtil; + +public class FileMerger implements FieldMerger { + @Override + public String merge(String filesA, String filesB) { + if (StringUtil.isBlank(filesA + filesB)) { + return ""; + } else if (StringUtil.isBlank(filesA)) { + return filesB; + } else if (StringUtil.isBlank(filesB)) { + return filesA; + } else { + List linkedFilesA = FileFieldParser.parse(filesA); + List linkedFilesB = FileFieldParser.parse(filesB); + // TODO: If one of the linked files list is empty then the its string value is malformed. + return Stream.concat(linkedFilesA.stream(), linkedFilesB.stream()) + .map(LinkedFile::getLink) + .collect(Collectors.joining(";")); + } + } +} From dd8457cc4ba7d8d5ea537d7aeae78b57a337b104 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 12:37:34 +0100 Subject: [PATCH 367/473] Encode the resulting string from merging files --- .../mergeentries/newmergedialog/fieldsmerger/FileMerger.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java index c8fb940870b..3033fe32dfd 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java @@ -4,6 +4,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jabref.logic.bibtex.FileFieldWriter; import org.jabref.logic.importer.util.FileFieldParser; import org.jabref.model.entry.LinkedFile; import org.jabref.model.strings.StringUtil; @@ -22,8 +23,8 @@ public String merge(String filesA, String filesB) { List linkedFilesB = FileFieldParser.parse(filesB); // TODO: If one of the linked files list is empty then the its string value is malformed. return Stream.concat(linkedFilesA.stream(), linkedFilesB.stream()) - .map(LinkedFile::getLink) - .collect(Collectors.joining(";")); + .map(FileFieldWriter::getStringRepresentation) + .collect(Collectors.joining()); } } } From 8c3a1e0d781c771cf9ca5aca6e1d930deb7a7f3b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 15:48:03 +0100 Subject: [PATCH 368/473] Refactor merge/unmerge fields command handling --- .../newmergedialog/FieldRowView.java | 13 +-- .../newmergedialog/cell/FieldNameCell.java | 16 +--- .../cell/MergeableFieldCell.java | 94 ++++++++++++++----- 3 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 0e1b62b91a4..233c34ba9fb 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -53,9 +53,13 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setMergeCommand(new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field))); - mergeableFieldCell.setUnmergeCommand(new UnmergeCommand(mergeableFieldCell)); - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); + EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { + if (fieldState == MergeableFieldCell.FieldState.MERGED) { + new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field)).execute(); + } else { + new UnmergeCommand(mergeableFieldCell).execute(); + } + })); } toggleGroup.getToggles().addAll(leftValueCell, rightValueCell); @@ -196,8 +200,6 @@ public void execute() { fieldsMergedEdit.addEdit(new MergeFieldsUndo(oldLeftFieldValue, oldRightFieldValue, mergedFields)); fieldsMergedEdit.end(); } - - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.UNMERGE); } } @@ -212,7 +214,6 @@ public UnmergeCommand(MergeableFieldCell mergeableFieldCell) { public void execute() { if (fieldsMergedEdit.canUndo()) { fieldsMergedEdit.undo(); - mergeableFieldCell.setMergeAction(MergeableFieldCell.MergeAction.MERGE); } } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 0f82beac6c6..9eb133c267b 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -1,17 +1,12 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; -import javafx.scene.Node; import javafx.scene.control.Button; -import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import org.jabref.gui.Globals; import org.jabref.gui.actions.ActionFactory; -import org.jabref.gui.icon.IconTheme; - -import de.saxsys.mvvmfx.utils.commands.Command; /** * A non-editable cell that contains the name of some field @@ -40,14 +35,9 @@ private void initializeLabel() { HBox.setHgrow(labelBox, Priority.ALWAYS); } - protected void setAction(String actionName, IconTheme.JabRefIcons icon, Command command) { + protected void addSideButton(Button sideButton) { + // TODO: Allow adding more than one side button actionLayout.getChildren().clear(); - Node iconNode = icon.getGraphicNode(); - Button actionButton = factory.createIconButton(() -> actionName, command); - actionButton.setGraphic(iconNode); - actionButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); - actionButton.setMaxHeight(Double.MAX_VALUE); - - actionLayout.getChildren().add(actionButton); + actionLayout.getChildren().setAll(sideButton); } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index d9cab3a38ed..3c367b30917 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -1,48 +1,100 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import java.util.Optional; + import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.control.Button; +import org.jabref.gui.Globals; +import org.jabref.gui.actions.Action; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.icon.JabRefIcon; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; -import de.saxsys.mvvmfx.utils.commands.Command; - public class MergeableFieldCell extends FieldNameCell { - private Command mergeCommand; - private Command unmergeCommand; + private final ObjectProperty fieldState = new SimpleObjectProperty<>(FieldState.UNMERGED); + + private Button toggleMergeUnmergeButton; - private final ObjectProperty mergeAction = new SimpleObjectProperty<>(); + private final ActionFactory actionFactory = new ActionFactory(Globals.getKeyPrefs()); + + private final Field field; public MergeableFieldCell(Field field, int rowIndex) { super(field.getDisplayName(), rowIndex); - mergeActionProperty().addListener((obs, old, newValue) -> { - if (newValue == MergeAction.MERGE) { - setAction(Localization.lang("Merge %0", field.getDisplayName()), IconTheme.JabRefIcons.MERGE_GROUPS, mergeCommand); - } else { - setAction(Localization.lang("Unmerge %0", field.getDisplayName()), IconTheme.JabRefIcons.UNDO, unmergeCommand); + this.field = field; + + configureMergeButton(); + addSideButton(toggleMergeUnmergeButton); + } + + private void configureMergeButton() { + Action mergeAction = new Action() { + @Override + public String getText() { + return Localization.lang("Merge %", field.getDisplayName()); + } + + @Override + public Optional getIcon() { + return Optional.of(IconTheme.JabRefIcons.MERGE_GROUPS); } - }); + }; + + if (toggleMergeUnmergeButton == null) { + toggleMergeUnmergeButton = actionFactory.createIconButton(mergeAction, new ToggleMergeUnmergeAction()); + toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); + } + actionFactory.configureIconButton(mergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); } - public void setMergeCommand(Command mergeCommand) { - this.mergeCommand = mergeCommand; + private void configureUnmergeButton() { + Action unmergeAction = new Action() { + @Override + public String getText() { + return Localization.lang("Unmerge %", field.getDisplayName()); + } + + @Override + public Optional getIcon() { + return Optional.of(IconTheme.JabRefIcons.UNDO); + } + }; + + if (toggleMergeUnmergeButton == null) { + toggleMergeUnmergeButton = actionFactory.createIconButton(unmergeAction, new ToggleMergeUnmergeAction()); + toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); + } + actionFactory.configureIconButton(unmergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); } - public void setUnmergeCommand(Command unmergeCommand) { - this.unmergeCommand = unmergeCommand; + public ObjectProperty fieldStateProperty() { + return fieldState; } - public ObjectProperty mergeActionProperty() { - return mergeAction; + private void setFieldState(FieldState fieldState) { + fieldStateProperty().set(fieldState); } - public void setMergeAction(MergeAction mergeAction) { - mergeActionProperty().set(mergeAction); + private class ToggleMergeUnmergeAction extends SimpleCommand { + + @Override + public void execute() { + if (fieldStateProperty().get() == FieldState.MERGED) { + setFieldState(FieldState.UNMERGED); + configureMergeButton(); + } else { + setFieldState(FieldState.MERGED); + configureUnmergeButton(); + } + } } - public enum MergeAction { - MERGE, UNMERGE + public enum FieldState { + MERGED, UNMERGED } } From 15f3de3527d28d33c3e3cd14b89fa6b0e4a84a7a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 15:57:34 +0100 Subject: [PATCH 369/473] Declare Actions with the builder design pattern --- .../java/org/jabref/gui/actions/Action.java | 68 +++++++++++++++++++ .../cell/MergeableFieldCell.java | 29 ++------ 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/jabref/gui/actions/Action.java b/src/main/java/org/jabref/gui/actions/Action.java index e6ccfe487b2..28859e00225 100644 --- a/src/main/java/org/jabref/gui/actions/Action.java +++ b/src/main/java/org/jabref/gui/actions/Action.java @@ -1,5 +1,6 @@ package org.jabref.gui.actions; +import java.util.Objects; import java.util.Optional; import org.jabref.gui.icon.JabRefIcon; @@ -19,4 +20,71 @@ default Optional getKeyBinding() { default String getDescription() { return ""; } + + class Builder { + private final ActionImpl actionImpl; + + public Builder(String text) { + this.actionImpl = new ActionImpl(); + setText(text); + } + + public Builder() { + this(""); + } + + public Action setIcon(JabRefIcon icon) { + Objects.requireNonNull(icon); + actionImpl.icon = icon; + return actionImpl; + } + + public Action setText(String text) { + Objects.requireNonNull(text); + actionImpl.text = text; + return actionImpl; + } + + public Action setKeyBinding(KeyBinding keyBinding) { + Objects.requireNonNull(keyBinding); + actionImpl.keyBinding = keyBinding; + return actionImpl; + } + + public Action setDescription(String description) { + Objects.requireNonNull(description); + actionImpl.description = description; + return actionImpl; + } + } + + class ActionImpl implements Action { + private JabRefIcon icon; + private KeyBinding keyBinding; + private String text; + private String description; + + private ActionImpl() { + } + + @Override + public Optional getIcon() { + return Optional.ofNullable(icon); + } + + @Override + public Optional getKeyBinding() { + return Optional.ofNullable(keyBinding); + } + + @Override + public String getText() { + return text != null ? text : ""; + } + + @Override + public String getDescription() { + return description != null ? description : ""; + } + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 3c367b30917..2556de991c0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -1,7 +1,5 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; -import java.util.Optional; - import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.Button; @@ -11,7 +9,6 @@ import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.icon.IconTheme; -import org.jabref.gui.icon.JabRefIcon; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; @@ -33,17 +30,8 @@ public MergeableFieldCell(Field field, int rowIndex) { } private void configureMergeButton() { - Action mergeAction = new Action() { - @Override - public String getText() { - return Localization.lang("Merge %", field.getDisplayName()); - } - - @Override - public Optional getIcon() { - return Optional.of(IconTheme.JabRefIcons.MERGE_GROUPS); - } - }; + Action mergeAction = new Action.Builder(Localization.lang("Merge %", field.getDisplayName())) + .setIcon(IconTheme.JabRefIcons.MERGE_GROUPS); if (toggleMergeUnmergeButton == null) { toggleMergeUnmergeButton = actionFactory.createIconButton(mergeAction, new ToggleMergeUnmergeAction()); @@ -53,17 +41,8 @@ public Optional getIcon() { } private void configureUnmergeButton() { - Action unmergeAction = new Action() { - @Override - public String getText() { - return Localization.lang("Unmerge %", field.getDisplayName()); - } - - @Override - public Optional getIcon() { - return Optional.of(IconTheme.JabRefIcons.UNDO); - } - }; + Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %", field.getDisplayName())) + .setIcon(IconTheme.JabRefIcons.UNDO); if (toggleMergeUnmergeButton == null) { toggleMergeUnmergeButton = actionFactory.createIconButton(unmergeAction, new ToggleMergeUnmergeAction()); From eb8429c61265493123b536939b9996344a3f4ef9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:01:08 +0100 Subject: [PATCH 370/473] Remove MergeableFieldCell dependency from the merge/unmerge commands - Thus commands can be moved to the view model --- .../mergeentries/newmergedialog/FieldRowView.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 233c34ba9fb..b41f4dfc98e 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -55,9 +55,9 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { if (fieldState == MergeableFieldCell.FieldState.MERGED) { - new MergeCommand(mergeableFieldCell, fieldMergerFactory.create(field)).execute(); + new MergeCommand(fieldMergerFactory.create(field)).execute(); } else { - new UnmergeCommand(mergeableFieldCell).execute(); + new UnmergeCommand().execute(); } })); } @@ -173,11 +173,9 @@ public void hideDiff() { } public class MergeCommand extends SimpleCommand { - private final MergeableFieldCell mergeableFieldCell; private final FieldMerger fieldMerger; - public MergeCommand(MergeableFieldCell mergeableFieldCell, FieldMerger fieldMerger) { - this.mergeableFieldCell = mergeableFieldCell; + public MergeCommand(FieldMerger fieldMerger) { this.fieldMerger = fieldMerger; this.executable.bind(viewModel.hasEqualLeftAndRightBinding().not()); @@ -204,10 +202,8 @@ public void execute() { } public class UnmergeCommand extends SimpleCommand { - private final MergeableFieldCell mergeableFieldCell; - public UnmergeCommand(MergeableFieldCell mergeableFieldCell) { - this.mergeableFieldCell = mergeableFieldCell; + public UnmergeCommand() { } @Override From 09b6073798d44e90ebda15dbb1e2117c5092efae Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:09:12 +0100 Subject: [PATCH 371/473] Add logs --- .../gui/mergeentries/newmergedialog/FieldRowView.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index b41f4dfc98e..783fdcb89c1 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -25,6 +25,8 @@ import com.tobiasdiez.easybind.EasyBind; import org.fxmisc.richtext.StyleClassedTextArea; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.jabref.gui.mergeentries.newmergedialog.FieldRowViewModel.Selection; @@ -32,6 +34,7 @@ * A controller class to control left, right and merged field values */ public class FieldRowView { + private static final Logger LOGGER = LoggerFactory.getLogger(FieldRowView.class); private final FieldNameCell fieldNameCell; private final FieldValueCell leftValueCell; private final FieldValueCell rightValueCell; @@ -54,6 +57,7 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { + LOGGER.debug("Field merge state is {} for field {}", fieldState, field); if (fieldState == MergeableFieldCell.FieldState.MERGED) { new MergeCommand(fieldMergerFactory.create(field)).execute(); } else { @@ -100,7 +104,9 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt }); EasyBind.listen(viewModel.hasEqualLeftAndRightBinding(), (obs, old, isEqual) -> { + if (isEqual) { + LOGGER.debug("Left and right values are equal, LEFT==RIGHT=={}", viewModel.getLeftFieldValue()); hideDiff(); } }); @@ -146,6 +152,7 @@ public void showDiff(ShowDiffConfig diffConfig) { if (!rightValueCell.isVisible()) { return; } + LOGGER.debug("Showing diffs..."); StyleClassedTextArea leftLabel = leftValueCell.getStyleClassedLabel(); StyleClassedTextArea rightLabel = rightValueCell.getStyleClassedLabel(); @@ -163,6 +170,8 @@ public void hideDiff() { return; } + LOGGER.debug("Hiding diffs..."); + int leftValueLength = getLeftValueCell().getStyleClassedLabel().getLength(); getLeftValueCell().getStyleClassedLabel().clearStyle(0, leftValueLength); getLeftValueCell().getStyleClassedLabel().replaceText(viewModel.getLeftFieldValue()); From 2ef9a52fc75aabd8906fe30430a32f7f706f2363 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:25:27 +0100 Subject: [PATCH 372/473] Disable field's merge button when field values are equal --- .../newmergedialog/FieldRowView.java | 3 ++- .../cell/MergeableFieldCell.java | 25 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index 783fdcb89c1..dc1add53c31 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -56,6 +56,8 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt if (FieldMergerFactory.canMerge(field)) { MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; + mergeableFieldCell.setCanMerge(!viewModel.hasEqualLeftAndRightValues()); + EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { LOGGER.debug("Field merge state is {} for field {}", fieldState, field); if (fieldState == MergeableFieldCell.FieldState.MERGED) { @@ -104,7 +106,6 @@ public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEnt }); EasyBind.listen(viewModel.hasEqualLeftAndRightBinding(), (obs, old, isEqual) -> { - if (isEqual) { LOGGER.debug("Left and right values are equal, LEFT==RIGHT=={}", viewModel.getLeftFieldValue()); hideDiff(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 2556de991c0..097ccd15569 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -1,6 +1,8 @@ package org.jabref.gui.mergeentries.newmergedialog.cell; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.Button; @@ -14,6 +16,7 @@ public class MergeableFieldCell extends FieldNameCell { private final ObjectProperty fieldState = new SimpleObjectProperty<>(FieldState.UNMERGED); + private final BooleanProperty canMerge = new SimpleBooleanProperty(Boolean.TRUE); private Button toggleMergeUnmergeButton; @@ -26,7 +29,8 @@ public MergeableFieldCell(Field field, int rowIndex) { this.field = field; configureMergeButton(); - addSideButton(toggleMergeUnmergeButton); + super.addSideButton(toggleMergeUnmergeButton); + toggleMergeUnmergeButton.disableProperty().bind(canMergeProperty().not()); } private void configureMergeButton() { @@ -59,6 +63,25 @@ private void setFieldState(FieldState fieldState) { fieldStateProperty().set(fieldState); } + public FieldState getFieldState() { + return fieldState.get(); + } + + public BooleanProperty canMergeProperty() { + return canMerge; + } + + public boolean canMerge() { + return canMerge.get(); + } + + /** + * Setting {@code canMerge} to {@code false} will disable the merge/unmerge button + * */ + public void setCanMerge(boolean value) { + canMergeProperty().set(value); + } + private class ToggleMergeUnmergeAction extends SimpleCommand { @Override From c3c76cb43893b180497ad324630fd868580723e5 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:51:18 +0100 Subject: [PATCH 373/473] Update code documentation --- .../gui/mergeentries/newmergedialog/cell/FieldNameCell.java | 6 +----- .../gui/mergeentries/newmergedialog/cell/HeaderCell.java | 3 +++ .../newmergedialog/cell/OpenExternalLinkAction.java | 2 +- .../newmergedialog/fieldsmerger/CommentMerger.java | 4 ++++ .../newmergedialog/fieldsmerger/FileMerger.java | 4 ++++ .../newmergedialog/fieldsmerger/GroupMerger.java | 4 ++++ .../newmergedialog/fieldsmerger/KeywordMerger.java | 4 ++++ 7 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 9eb133c267b..43e0a19f053 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -5,11 +5,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import org.jabref.gui.Globals; -import org.jabref.gui.actions.ActionFactory; - /** - * A non-editable cell that contains the name of some field + * A readonly cell used to display the name of some field. */ public class FieldNameCell extends AbstractCell { public static final String DEFAULT_STYLE_CLASS = "field-name"; @@ -17,7 +14,6 @@ public class FieldNameCell extends AbstractCell { private final Label label = new Label(); private final HBox labelBox = new HBox(label); - private final ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); public FieldNameCell(String text, int rowIndex) { super(text, rowIndex); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 2fd82afd38b..65f89f13713 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -3,6 +3,9 @@ import javafx.geometry.Insets; import javafx.scene.control.Label; +/** + * A readonly cell used to display the header of the ThreeWayMerge UI at the top of the layout. + * */ public class HeaderCell extends AbstractCell { public static final String DEFAULT_STYLE_CLASS = "merge-header-cell"; private final Label label = new Label(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java index 102b192458a..1b5087b413a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/OpenExternalLinkAction.java @@ -9,7 +9,7 @@ import org.jabref.model.strings.StringUtil; /** - * This action can open an Url and DOI + * A command for opening DOIs and URLs. This was created primarily for simplifying {@link FieldValueCell}. * */ public class OpenExternalLinkAction extends SimpleCommand { private final String urlOrDoi; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java index 5599bfb2470..9beb1819423 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/CommentMerger.java @@ -1,7 +1,11 @@ package org.jabref.gui.mergeentries.newmergedialog.fieldsmerger; import org.jabref.logic.util.OS; +import org.jabref.model.entry.field.StandardField; +/** + * A merger for the {@link StandardField#COMMENT} field + * */ public class CommentMerger implements FieldMerger { @Override public String merge(String fieldValueA, String fieldValueB) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java index 3033fe32dfd..4b4e2034226 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/FileMerger.java @@ -7,8 +7,12 @@ import org.jabref.logic.bibtex.FileFieldWriter; import org.jabref.logic.importer.util.FileFieldParser; import org.jabref.model.entry.LinkedFile; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.strings.StringUtil; +/** + * A merger for the {@link StandardField#FILE} field + * */ public class FileMerger implements FieldMerger { @Override public String merge(String filesA, String filesB) { diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java index 8af126aac61..fdbbddbb268 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/GroupMerger.java @@ -3,8 +3,12 @@ import java.util.Arrays; import java.util.stream.Collectors; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.strings.StringUtil; +/** + * A merger for the {@link StandardField#GROUPS} field + * */ public class GroupMerger implements FieldMerger { public static final String GROUPS_SEPARATOR = ", "; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java index 62b5ca2bb11..22d1479e3d4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/fieldsmerger/KeywordMerger.java @@ -4,9 +4,13 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.strings.StringUtil; import org.jabref.preferences.PreferencesService; +/** + * A merger for the {@link StandardField#KEYWORDS} field + * */ public class KeywordMerger implements FieldMerger { private final PreferencesService preferencesService; From 4829168f6b60834cd7e2d4fed27a66bc4b0e339a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Mon, 25 Jul 2022 16:52:07 +0100 Subject: [PATCH 374/473] Rename 'AbstractCell' to 'ThreeWayMergeCell' --- .../mergeentries/newmergedialog/cell/FieldNameCell.java | 2 +- .../mergeentries/newmergedialog/cell/FieldValueCell.java | 2 +- .../gui/mergeentries/newmergedialog/cell/HeaderCell.java | 4 ++-- .../mergeentries/newmergedialog/cell/MergedFieldCell.java | 2 +- .../cell/{AbstractCell.java => ThreeWayMergeCell.java} | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/{AbstractCell.java => ThreeWayMergeCell.java} (91%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index 43e0a19f053..a93e6b23308 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -8,7 +8,7 @@ /** * A readonly cell used to display the name of some field. */ -public class FieldNameCell extends AbstractCell { +public class FieldNameCell extends ThreeWayMergeCell { public static final String DEFAULT_STYLE_CLASS = "field-name"; protected final HBox actionLayout = new HBox(); private final Label label = new Label(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java index 4019c8f9a21..04fda36975d 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldValueCell.java @@ -40,7 +40,7 @@ /** * A readonly, selectable field cell that contains the value of some field */ -public class FieldValueCell extends AbstractCell implements Toggle { +public class FieldValueCell extends ThreeWayMergeCell implements Toggle { public static final Logger LOGGER = LoggerFactory.getLogger(FieldValueCell.class); public static final String DEFAULT_STYLE_CLASS = "merge-field-value"; diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java index 65f89f13713..76d3fceff0a 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/HeaderCell.java @@ -6,12 +6,12 @@ /** * A readonly cell used to display the header of the ThreeWayMerge UI at the top of the layout. * */ -public class HeaderCell extends AbstractCell { +public class HeaderCell extends ThreeWayMergeCell { public static final String DEFAULT_STYLE_CLASS = "merge-header-cell"; private final Label label = new Label(); public HeaderCell(String text) { - super(text, AbstractCell.NO_ROW_NUMBER); + super(text, ThreeWayMergeCell.NO_ROW_NUMBER); initialize(); } diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java index 77f170541d6..89c591ee0ac 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergedFieldCell.java @@ -10,7 +10,7 @@ import org.fxmisc.richtext.StyleClassedTextArea; -public class MergedFieldCell extends AbstractCell { +public class MergedFieldCell extends ThreeWayMergeCell { private static final String DEFAULT_STYLE_CLASS = "merged-field"; private final StyleClassedTextArea textArea = new StyleClassedTextArea(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/ThreeWayMergeCell.java similarity index 91% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/ThreeWayMergeCell.java index ffb1f536986..c3496fcecb6 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/AbstractCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/ThreeWayMergeCell.java @@ -11,7 +11,7 @@ /** * */ -public abstract class AbstractCell extends HBox { +public abstract class ThreeWayMergeCell extends HBox { public static final String ODD_PSEUDO_CLASS = "odd"; public static final String EVEN_PSEUDO_CLASS = "even"; public static final int NO_ROW_NUMBER = -1; @@ -20,7 +20,7 @@ public abstract class AbstractCell extends HBox { private final BooleanProperty odd = new BooleanPropertyBase() { @Override public Object getBean() { - return AbstractCell.this; + return ThreeWayMergeCell.this; } @Override @@ -38,7 +38,7 @@ protected void invalidated() { private final BooleanProperty even = new BooleanPropertyBase() { @Override public Object getBean() { - return AbstractCell.this; + return ThreeWayMergeCell.this; } @Override @@ -53,7 +53,7 @@ protected void invalidated() { } }; - public AbstractCell(String text, int rowIndex) { + public ThreeWayMergeCell(String text, int rowIndex) { getStyleClass().add(DEFAULT_STYLE_CLASS); if (rowIndex != NO_ROW_NUMBER) { if (rowIndex % 2 == 1) { From fa3927def2a65a6da9d86c6bc8bdac15b76a47fb Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 27 Jul 2022 14:58:49 +0100 Subject: [PATCH 375/473] Pass arguments to Localization.lang using '%0' not '%' --- .../mergeentries/newmergedialog/cell/MergeableFieldCell.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java index 097ccd15569..61afc11cd91 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java @@ -34,7 +34,7 @@ public MergeableFieldCell(Field field, int rowIndex) { } private void configureMergeButton() { - Action mergeAction = new Action.Builder(Localization.lang("Merge %", field.getDisplayName())) + Action mergeAction = new Action.Builder(Localization.lang("Merge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.MERGE_GROUPS); if (toggleMergeUnmergeButton == null) { @@ -45,7 +45,7 @@ private void configureMergeButton() { } private void configureUnmergeButton() { - Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %", field.getDisplayName())) + Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.UNDO); if (toggleMergeUnmergeButton == null) { From d707561d058f465ce7f1aae003d24dface96be4a Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Wed, 27 Jul 2022 15:14:55 +0100 Subject: [PATCH 376/473] Decompose the ToggleMergeUnmergeButton into its own class (or component) - Removed FieldNameCellFactory.java and MergeableFieldCell.java - Made it easier to add more side buttons in the future --- .../newmergedialog/FieldRowView.java | 14 +++++----- .../newmergedialog/cell/FieldNameCell.java | 2 +- .../cell/FieldNameCellFactory.java | 14 ---------- .../ToggleMergeUnmergeButton.java} | 27 ++++++------------- 4 files changed, 16 insertions(+), 41 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java rename src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/{MergeableFieldCell.java => sidebuttons/ToggleMergeUnmergeButton.java} (72%) diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java index dc1add53c31..51ced825162 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/FieldRowView.java @@ -11,10 +11,9 @@ import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.FieldNameCellFactory; import org.jabref.gui.mergeentries.newmergedialog.cell.FieldValueCell; -import org.jabref.gui.mergeentries.newmergedialog.cell.MergeableFieldCell; import org.jabref.gui.mergeentries.newmergedialog.cell.MergedFieldCell; +import org.jabref.gui.mergeentries.newmergedialog.cell.sidebuttons.ToggleMergeUnmergeButton; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.SplitDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.diffhighlighter.UnifiedDiffHighlighter; import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMerger; @@ -49,18 +48,19 @@ public class FieldRowView { public FieldRowView(Field field, BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry, FieldMergerFactory fieldMergerFactory, int rowIndex) { viewModel = new FieldRowViewModel(field, leftEntry, rightEntry, mergedEntry); - fieldNameCell = FieldNameCellFactory.create(field, rowIndex); + fieldNameCell = new FieldNameCell(field.getDisplayName(), rowIndex); leftValueCell = new FieldValueCell(viewModel.getLeftFieldValue(), rowIndex); rightValueCell = new FieldValueCell(viewModel.getRightFieldValue(), rowIndex); mergedValueCell = new MergedFieldCell(viewModel.getMergedFieldValue(), rowIndex); if (FieldMergerFactory.canMerge(field)) { - MergeableFieldCell mergeableFieldCell = (MergeableFieldCell) fieldNameCell; - mergeableFieldCell.setCanMerge(!viewModel.hasEqualLeftAndRightValues()); + ToggleMergeUnmergeButton toggleMergeUnmergeButton = new ToggleMergeUnmergeButton(field); + toggleMergeUnmergeButton.setCanMerge(!viewModel.hasEqualLeftAndRightValues()); + fieldNameCell.addSideButton(toggleMergeUnmergeButton); - EasyBind.listen(mergeableFieldCell.fieldStateProperty(), ((observableValue, old, fieldState) -> { + EasyBind.listen(toggleMergeUnmergeButton.fieldStateProperty(), ((observableValue, old, fieldState) -> { LOGGER.debug("Field merge state is {} for field {}", fieldState, field); - if (fieldState == MergeableFieldCell.FieldState.MERGED) { + if (fieldState == ToggleMergeUnmergeButton.FieldState.MERGED) { new MergeCommand(fieldMergerFactory.create(field)).execute(); } else { new UnmergeCommand().execute(); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java index a93e6b23308..a435f623187 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCell.java @@ -31,7 +31,7 @@ private void initializeLabel() { HBox.setHgrow(labelBox, Priority.ALWAYS); } - protected void addSideButton(Button sideButton) { + public void addSideButton(Button sideButton) { // TODO: Allow adding more than one side button actionLayout.getChildren().clear(); actionLayout.getChildren().setAll(sideButton); diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java deleted file mode 100644 index ee038e53eca..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/FieldNameCellFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; - -import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory; -import org.jabref.model.entry.field.Field; - -public class FieldNameCellFactory { - public static FieldNameCell create(Field field, int rowIndex) { - if (FieldMergerFactory.canMerge(field)) { - return new MergeableFieldCell(field, rowIndex); - } else { - return new FieldNameCell(field.getDisplayName(), rowIndex); - } - } -} diff --git a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/sidebuttons/ToggleMergeUnmergeButton.java similarity index 72% rename from src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java rename to src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/sidebuttons/ToggleMergeUnmergeButton.java index 61afc11cd91..de958837778 100644 --- a/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/MergeableFieldCell.java +++ b/src/main/java/org/jabref/gui/mergeentries/newmergedialog/cell/sidebuttons/ToggleMergeUnmergeButton.java @@ -1,4 +1,4 @@ -package org.jabref.gui.mergeentries.newmergedialog.cell; +package org.jabref.gui.mergeentries.newmergedialog.cell.sidebuttons; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; @@ -14,45 +14,34 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; -public class MergeableFieldCell extends FieldNameCell { +public class ToggleMergeUnmergeButton extends Button { private final ObjectProperty fieldState = new SimpleObjectProperty<>(FieldState.UNMERGED); private final BooleanProperty canMerge = new SimpleBooleanProperty(Boolean.TRUE); - private Button toggleMergeUnmergeButton; - private final ActionFactory actionFactory = new ActionFactory(Globals.getKeyPrefs()); private final Field field; - public MergeableFieldCell(Field field, int rowIndex) { - super(field.getDisplayName(), rowIndex); + public ToggleMergeUnmergeButton(Field field) { this.field = field; + setMaxHeight(Double.MAX_VALUE); + setFocusTraversable(false); configureMergeButton(); - super.addSideButton(toggleMergeUnmergeButton); - toggleMergeUnmergeButton.disableProperty().bind(canMergeProperty().not()); + this.disableProperty().bind(canMergeProperty().not()); } private void configureMergeButton() { Action mergeAction = new Action.Builder(Localization.lang("Merge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.MERGE_GROUPS); - if (toggleMergeUnmergeButton == null) { - toggleMergeUnmergeButton = actionFactory.createIconButton(mergeAction, new ToggleMergeUnmergeAction()); - toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); - } - actionFactory.configureIconButton(mergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); + actionFactory.configureIconButton(mergeAction, new ToggleMergeUnmergeAction(), this); } private void configureUnmergeButton() { Action unmergeAction = new Action.Builder(Localization.lang("Unmerge %0", field.getDisplayName())) .setIcon(IconTheme.JabRefIcons.UNDO); - - if (toggleMergeUnmergeButton == null) { - toggleMergeUnmergeButton = actionFactory.createIconButton(unmergeAction, new ToggleMergeUnmergeAction()); - toggleMergeUnmergeButton.setMaxHeight(Double.MAX_VALUE); - } - actionFactory.configureIconButton(unmergeAction, new ToggleMergeUnmergeAction(), toggleMergeUnmergeButton); + actionFactory.configureIconButton(unmergeAction, new ToggleMergeUnmergeAction(), this); } public ObjectProperty fieldStateProperty() { From 94626dc9c87e9d707421c0c69591fa04b0cf6d63 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 16:31:44 +0100 Subject: [PATCH 377/473] Include original left and right entries in EntriesMergeResult --- .../jabref/gui/mergeentries/EntriesMergeResult.java | 8 ++++++++ .../jabref/gui/mergeentries/FetchAndMergeEntry.java | 2 +- .../jabref/gui/mergeentries/MergeEntriesAction.java | 10 +++++----- .../jabref/gui/mergeentries/MergeEntriesDialog.java | 8 ++++++-- .../java/org/jabref/gui/mergeentries/MergeResult.java | 8 -------- .../org/jabref/gui/shared/SharedDatabaseUIManager.java | 4 ++-- 6 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java delete mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeResult.java diff --git a/src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java b/src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java new file mode 100644 index 00000000000..b134b11688a --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/EntriesMergeResult.java @@ -0,0 +1,8 @@ +package org.jabref.gui.mergeentries; + +import org.jabref.model.entry.BibEntry; + +public record EntriesMergeResult( + BibEntry originalLeftEntry, BibEntry originalRightEntry, BibEntry newLeftEntry, BibEntry newRightEntry, BibEntry mergedEntry +) { +} diff --git a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java index 542788431cc..04eda76e077 100644 --- a/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java +++ b/src/main/java/org/jabref/gui/mergeentries/FetchAndMergeEntry.java @@ -91,7 +91,7 @@ private void showMergeDialog(BibEntry originalEntry, BibEntry fetchedEntry, WebF 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 mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(EntriesMergeResult::mergedEntry); if (mergedEntry.isPresent()) { NamedCompound ce = new NamedCompound(Localization.lang("Merge entry with %0 information", fetcher.getName())); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index 7820cd95c92..0bf58e4f65c 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -68,16 +68,16 @@ public void execute() { MergeEntriesDialog dialog = new MergeEntriesDialog(first, second); dialog.setTitle(Localization.lang("Merge entries")); - Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); - mergeResultOpt.ifPresentOrElse(mergeResult -> { + Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); + mergeResultOpt.ifPresentOrElse(entriesMergeResult -> { // TODO: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark // entries with a timestamp, only BasePanel::insertEntry does. Workaround for the moment is to get the // BasePanel from the constructor injected JabRefFrame. Should be refactored and extracted! - frame.getCurrentLibraryTab().insertEntry(mergeResult.mergedEntry()); + frame.getCurrentLibraryTab().insertEntry(entriesMergeResult.mergedEntry()); NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); - ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), mergeResult.mergedEntry())); - List entriesToRemove = Arrays.asList(one, two); + ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), entriesMergeResult.mergedEntry())); + List entriesToRemove = Arrays.asList(entriesMergeResult.originalLeftEntry(), entriesMergeResult.originalRightEntry()); ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); databaseContext.getDatabase().removeEntries(entriesToRemove); ce.end(); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index a93598494b0..4d9c06c4ef9 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -8,11 +8,15 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; -public class MergeEntriesDialog extends BaseDialog { +public class MergeEntriesDialog extends BaseDialog { private final ThreeWayMergeView threeWayMergeView; + private final BibEntry one; + private final BibEntry two; public MergeEntriesDialog(BibEntry one, BibEntry two) { threeWayMergeView = new ThreeWayMergeView(one, two); + this.one = one; + this.two = two; init(); } @@ -31,7 +35,7 @@ private void init() { this.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, replaceEntries); this.setResultConverter(buttonType -> { if (buttonType.equals(replaceEntries)) { - return new MergeResult(threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); + return new EntriesMergeResult(one, two, threeWayMergeView.getLeftEntry(), threeWayMergeView.getRightEntry(), threeWayMergeView.getMergedEntry()); } else { return null; } diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeResult.java b/src/main/java/org/jabref/gui/mergeentries/MergeResult.java deleted file mode 100644 index 6db5a7a60e5..00000000000 --- a/src/main/java/org/jabref/gui/mergeentries/MergeResult.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.jabref.gui.mergeentries; - -import org.jabref.model.entry.BibEntry; - -public record MergeResult( - BibEntry leftEntry, BibEntry rightEntry, BibEntry mergedEntry -) { -} diff --git a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java index e5c2a0e9732..6b87d7c620a 100644 --- a/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java +++ b/src/main/java/org/jabref/gui/shared/SharedDatabaseUIManager.java @@ -15,8 +15,8 @@ import org.jabref.gui.LibraryTab; import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.exporter.SaveDatabaseAction; +import org.jabref.gui.mergeentries.EntriesMergeResult; import org.jabref.gui.mergeentries.MergeEntriesDialog; -import org.jabref.gui.mergeentries.MergeResult; import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; @@ -100,7 +100,7 @@ public void listen(UpdateRefusedEvent updateRefusedEvent) { if (response.isPresent() && response.get().equals(merge)) { MergeEntriesDialog dialog = new MergeEntriesDialog(localBibEntry, sharedBibEntry); - Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(MergeResult::mergedEntry); + Optional mergedEntry = dialogService.showCustomDialogAndWait(dialog).map(EntriesMergeResult::mergedEntry); mergedEntry.ifPresent(mergedBibEntry -> { mergedBibEntry.getSharedBibEntryData().setSharedID(sharedBibEntry.getSharedBibEntryData().getSharedID()); From dc9293d3900f68535cdb7953001b027d265c3c0b Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 16:52:21 +0100 Subject: [PATCH 378/473] Make entries merging logic reusable --- .../gui/mergeentries/MergeEntriesAction.java | 20 +------- .../mergeentries/MergeTwoEntriesAction.java | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java index 0bf58e4f65c..82652a75fb4 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesAction.java @@ -1,21 +1,15 @@ package org.jabref.gui.mergeentries; -import java.util.Arrays; import java.util.List; import java.util.Optional; import org.jabref.gui.DialogService; -import org.jabref.gui.Globals; import org.jabref.gui.JabRefFrame; import org.jabref.gui.StateManager; import org.jabref.gui.actions.ActionHelper; import org.jabref.gui.actions.SimpleCommand; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableInsertEntries; -import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.logic.bibtex.comparator.EntryComparator; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.InternalField; @@ -38,7 +32,6 @@ public void execute() { if (stateManager.getActiveDatabase().isEmpty()) { return; } - BibDatabaseContext databaseContext = stateManager.getActiveDatabase().get(); // Check if there are two entries selected List selectedEntries = stateManager.getSelectedEntries(); @@ -70,18 +63,7 @@ public void execute() { dialog.setTitle(Localization.lang("Merge entries")); Optional mergeResultOpt = dialogService.showCustomDialogAndWait(dialog); mergeResultOpt.ifPresentOrElse(entriesMergeResult -> { - // TODO: BibDatabase::insertEntry does not contain logic to mark the BasePanel as changed and to mark - // entries with a timestamp, only BasePanel::insertEntry does. Workaround for the moment is to get the - // BasePanel from the constructor injected JabRefFrame. Should be refactored and extracted! - frame.getCurrentLibraryTab().insertEntry(entriesMergeResult.mergedEntry()); - - NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); - ce.addEdit(new UndoableInsertEntries(databaseContext.getDatabase(), entriesMergeResult.mergedEntry())); - List entriesToRemove = Arrays.asList(entriesMergeResult.originalLeftEntry(), entriesMergeResult.originalRightEntry()); - ce.addEdit(new UndoableRemoveEntries(databaseContext.getDatabase(), entriesToRemove)); - databaseContext.getDatabase().removeEntries(entriesToRemove); - ce.end(); - Globals.undoManager.addEdit(ce); + new MergeTwoEntriesAction(entriesMergeResult, frame, stateManager).execute(); dialogService.notify(Localization.lang("Merged entries")); }, () -> dialogService.notify(Localization.lang("Canceled merging entries"))); diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java b/src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java new file mode 100644 index 00000000000..e494e1966b5 --- /dev/null +++ b/src/main/java/org/jabref/gui/mergeentries/MergeTwoEntriesAction.java @@ -0,0 +1,46 @@ +package org.jabref.gui.mergeentries; + +import java.util.Arrays; +import java.util.List; + +import org.jabref.gui.Globals; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.undo.NamedCompound; +import org.jabref.gui.undo.UndoableInsertEntries; +import org.jabref.gui.undo.UndoableRemoveEntries; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; + +public class MergeTwoEntriesAction extends SimpleCommand { + private final EntriesMergeResult entriesMergeResult; + private final JabRefFrame frame; + private final StateManager stateManager; + + public MergeTwoEntriesAction(EntriesMergeResult entriesMergeResult, JabRefFrame frame, StateManager stateManager) { + this.entriesMergeResult = entriesMergeResult; + this.frame = frame; + this.stateManager = stateManager; + } + + @Override + public void execute() { + if (stateManager.getActiveDatabase().isEmpty()) { + return; + } + + BibDatabase database = stateManager.getActiveDatabase().get().getDatabase(); + + frame.getCurrentLibraryTab().insertEntry(entriesMergeResult.mergedEntry()); + + NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); + ce.addEdit(new UndoableInsertEntries(stateManager.getActiveDatabase().get().getDatabase(), entriesMergeResult.mergedEntry())); + List entriesToRemove = Arrays.asList(entriesMergeResult.originalLeftEntry(), entriesMergeResult.originalRightEntry()); + ce.addEdit(new UndoableRemoveEntries(database, entriesToRemove)); + database.removeEntries(entriesToRemove); + ce.end(); + Globals.undoManager.addEdit(ce); + } +} From a984a97312b51206fc879ba6c9330e3ea7f5c584 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 18:20:16 +0100 Subject: [PATCH 379/473] Rename ChangeDisplayDialog.java to ExternalChangesResolverDialog.java --- .../java/org/jabref/gui/collab/DatabaseChangeMonitor.java | 2 +- ...eDisplayDialog.java => ExternalChangesResolverDialog.java} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/org/jabref/gui/collab/{ChangeDisplayDialog.java => ExternalChangesResolverDialog.java} (96%) diff --git a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java index 575307bcda8..20263b36ab6 100644 --- a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java +++ b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java @@ -67,7 +67,7 @@ public DatabaseChangeMonitor(BibDatabaseContext database, Localization.lang("The library has been modified by another program."), List.of(new Action(Localization.lang("Dismiss changes"), event -> notificationPane.hide()), new Action(Localization.lang("Review changes"), event -> { - dialogService.showCustomDialogAndWait(new ChangeDisplayDialog(database, changes)); + dialogService.showCustomDialogAndWait(new ExternalChangesResolverDialog(database, changes)); notificationPane.hide(); })), Duration.ZERO)); diff --git a/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.java similarity index 96% rename from src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java rename to src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.java index e9f0751cc07..aa9b802da73 100644 --- a/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java +++ b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.java @@ -23,13 +23,13 @@ import com.tobiasdiez.easybind.EasyBind; -class ChangeDisplayDialog extends BaseDialog { +class ExternalChangesResolverDialog extends BaseDialog { private final ListView changesList; private final BorderPane infoPanel = new BorderPane(); private final CheckBox cb = new CheckBox(Localization.lang("Accept change")); - public ChangeDisplayDialog(BibDatabaseContext database, List changes) { + public ExternalChangesResolverDialog(BibDatabaseContext database, List changes) { this.setTitle(Localization.lang("External changes")); this.getDialogPane().setPrefSize(800, 600); From fce5ff9ab2ba116846b2097138dc8f0cfdbd4cd2 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 18:21:21 +0100 Subject: [PATCH 380/473] Create ExternalChangesResolverViewModel --- .../jabref/gui/collab/ExternalChangesResolverViewModel.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java diff --git a/src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java new file mode 100644 index 00000000000..1453a9cf033 --- /dev/null +++ b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverViewModel.java @@ -0,0 +1,6 @@ +package org.jabref.gui.collab; + +import org.jabref.gui.AbstractViewModel; + +public class ExternalChangesResolverViewModel extends AbstractViewModel { +} From b9d7bc1ed2cb47a4af5ed8f4fb22ccef1ae71276 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 2 Aug 2022 19:18:47 +0100 Subject: [PATCH 381/473] Design the ExternalChangesResolverDialog --- .../collab/ExternalChangesResolverDialog.fxml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml diff --git a/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml new file mode 100644 index 00000000000..e532d7a055c --- /dev/null +++ b/src/main/java/org/jabref/gui/collab/ExternalChangesResolverDialog.fxml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + +