From 137fddf7916aebc3ec82c5186fd84a186ac3973f Mon Sep 17 00:00:00 2001 From: Akanksha Date: Sat, 6 Sep 2025 10:30:35 -0700 Subject: [PATCH 01/10] Automatic field editor: Add Clear content tab + viewmodel --- .../AutomaticFieldEditorViewModel.java | 2 + .../clearcontent/ClearContentTabView.java | 73 +++++++++++++++++++ .../clearcontent/ClearContentViewModel.java | 69 ++++++++++++++++++ .../EditFieldContentTabView.java | 7 -- .../editfieldcontent/EditFieldContentTab.fxml | 5 -- .../main/resources/l10n/JabRef_en.properties | 3 + 6 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java create mode 100644 jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java diff --git a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/AutomaticFieldEditorViewModel.java b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/AutomaticFieldEditorViewModel.java index 3f517a1dabd..3acf24c7428 100644 --- a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/AutomaticFieldEditorViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/AutomaticFieldEditorViewModel.java @@ -9,6 +9,7 @@ import org.jabref.gui.AbstractViewModel; import org.jabref.gui.StateManager; +import org.jabref.gui.edit.automaticfiededitor.clearcontent.ClearContentTabView; import org.jabref.gui.edit.automaticfiededitor.copyormovecontent.CopyOrMoveFieldContentTabView; import org.jabref.gui.edit.automaticfiededitor.editfieldcontent.EditFieldContentTabView; import org.jabref.gui.edit.automaticfiededitor.renamefield.RenameFieldTabView; @@ -28,6 +29,7 @@ public AutomaticFieldEditorViewModel(List selectedEntries, BibDatabase fieldEditorTabs.addAll( new EditFieldContentTabView(database, stateManager), new CopyOrMoveFieldContentTabView(database, stateManager), + new ClearContentTabView(stateManager), new RenameFieldTabView(database, stateManager) ); } diff --git a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java new file mode 100644 index 00000000000..94c7dfacc34 --- /dev/null +++ b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java @@ -0,0 +1,73 @@ +package org.jabref.gui.edit.automaticfiededitor.clearcontent; + +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +import org.jabref.gui.StateManager; +import org.jabref.gui.edit.automaticfiededitor.AbstractAutomaticFieldEditorTabView; +import org.jabref.gui.edit.automaticfiededitor.AutomaticFieldEditorTab; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.field.Field; + +public class ClearContentTabView extends AbstractAutomaticFieldEditorTabView implements AutomaticFieldEditorTab { + + private final ComboBox fieldCombo; + private final CheckBox showOnlySetFields; + private final Button clearButton; + private final ClearContentViewModel viewModel; + + public ClearContentTabView(StateManager stateManager) { + super(); + + this.viewModel = new ClearContentViewModel(stateManager); + + Label fieldLabel = new Label(Localization.lang("Field")); + fieldCombo = new ComboBox<>(); + showOnlySetFields = new CheckBox(Localization.lang("Show only set fields")); + clearButton = new Button(Localization.lang("Clear field content")); + + // populate initially with all fields + fieldCombo.getItems().setAll( + viewModel.getAllFields().stream().toList() + ); + + // toggle filtering when checkbox is clicked + showOnlySetFields.setOnAction(e -> { + if (showOnlySetFields.isSelected()) { + fieldCombo.getItems().setAll( + viewModel.getSetFieldsOnly().stream().toList() + ); + } else { + fieldCombo.getItems().setAll( + viewModel.getAllFields().stream().toList() + ); + } + }); + + VBox box = new VBox(10); + + Label title = new Label(Localization.lang("Clear field content for selected entries")); + title.getStyleClass().add("sectionHeader"); // match Edit tab styling + + HBox row = new HBox(10, fieldLabel, fieldCombo, showOnlySetFields); + box.getChildren().addAll(title, row, clearButton); + this.getChildren().add(box); + + clearButton.setOnAction(e -> { + Field chosen = fieldCombo.getValue(); // keep ComboBox + if (chosen != null) { + viewModel.clearField(chosen); // VM builds/publishes the undo compound + System.out.println("Cleared field: " + chosen.getName()); + } + }); + } + + @Override + public String getTabName() { + return Localization.lang("Clear content"); + } +} diff --git a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java new file mode 100644 index 00000000000..75f53bab99b --- /dev/null +++ b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java @@ -0,0 +1,69 @@ +package org.jabref.gui.edit.automaticfiededitor.clearcontent; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.jabref.gui.StateManager; +import org.jabref.gui.edit.automaticfiededitor.LastAutomaticFieldEditorEdit; +import org.jabref.gui.undo.NamedCompound; +import org.jabref.gui.undo.UndoableFieldChange; +import org.jabref.model.FieldChange; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldFactory; + +public class ClearContentViewModel { + + private final StateManager stateManager; + + public ClearContentViewModel(StateManager stateManager) { + this.stateManager = stateManager; + } + + /** all fields (without internal ones) */ + public Set getAllFields() { + return FieldFactory.getAllFieldsWithOutInternal(); + } + + /** only fields that are set in the selected entries */ + public Set getSetFieldsOnly() { + List selected = stateManager.getSelectedEntries(); + Set setFields = new LinkedHashSet<>(); + + for (BibEntry entry : selected) { + for (Field f : entry.getFields()) { + entry.getField(f).ifPresent(val -> { + if (!val.isBlank()) { + setFields.add(f); + } + }); + } + } + return setFields; + } + + public void clearField(Field field) { + if (field == null) { + return; + } + + NamedCompound edits = new NamedCompound("Clear field content"); + int affected = 0; + + List selected = stateManager.getSelectedEntries(); + for (BibEntry entry : selected) { + // clearField returns Optional + entry.clearField(field).ifPresent((FieldChange change) -> { + edits.addEdit(new UndoableFieldChange(change)); // Wrap into UndoableEdit + }); + } + + if (edits.hasEdits()) { + edits.end(); + stateManager.setLastAutomaticFieldEditorEdit( + new LastAutomaticFieldEditorEdit(selected.size(), 1, edits) + ); + } + } +} diff --git a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTabView.java b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTabView.java index 0c97b3f81e6..f85657edeb0 100644 --- a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTabView.java +++ b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTabView.java @@ -24,7 +24,6 @@ public class EditFieldContentTabView extends AbstractAutomaticFieldEditorTabView { public Button appendValueButton; - public Button clearFieldButton; public Button setValueButton; @FXML private ComboBox fieldComboBox; @@ -72,7 +71,6 @@ public void initialize() { appendValueButton.disableProperty().bind(viewModel.canAppendProperty().not()); setValueButton.disableProperty().bind(viewModel.fieldValidationStatus().validProperty().not()); - clearFieldButton.disableProperty().bind(viewModel.fieldValidationStatus().validProperty().not()); overwriteFieldContentCheckBox.disableProperty().bind(viewModel.fieldValidationStatus().validProperty().not()); Platform.runLater(() -> visualizer.initVisualization(viewModel.fieldValidationStatus(), fieldComboBox, true)); @@ -88,11 +86,6 @@ void appendToFieldValue() { viewModel.appendToFieldValue(); } - @FXML - void clearField() { - viewModel.clearSelectedField(); - } - @FXML void setFieldValue() { viewModel.setFieldValue(); diff --git a/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml b/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml index 2fb80b223b0..56f263119c0 100644 --- a/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml +++ b/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml @@ -42,11 +42,6 @@ diff --git a/jablib/src/main/resources/l10n/JabRef_en.properties b/jablib/src/main/resources/l10n/JabRef_en.properties index 391abcfd0b7..0ea694802bd 100644 --- a/jablib/src/main/resources/l10n/JabRef_en.properties +++ b/jablib/src/main/resources/l10n/JabRef_en.properties @@ -1474,6 +1474,7 @@ Show\ preferences=Show preferences Save\ actions=Save actions Other\ fields=Other fields Show\ remaining\ fields=Show remaining fields +Show\ only\ set\ fields=Show only set fields link\ should\ refer\ to\ a\ correct\ file\ path=link should refer to a correct file path abbreviation\ detected=abbreviation detected @@ -2587,6 +2588,8 @@ Overwrite\ field\ content=Overwrite field content Set=Set Append=Append Clear\ field\ content=Clear field content +Clear\ field\ content\ for\ selected\ entries=Clear field content for selected entries +Clear\ content=Clear content Set\ or\ append\ content=Set or append content Edit\ field\ content\ for\ selected\ entries=Edit field content for selected entries Rename=Rename From bb07ec4a3c94e86658fbd43f00583888ddf30ea6 Mon Sep 17 00:00:00 2001 From: Akanksha Date: Sat, 6 Sep 2025 12:16:47 -0700 Subject: [PATCH 02/10] Removing comments --- .../automaticfiededitor/clearcontent/ClearContentViewModel.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java index 75f53bab99b..083ca75b184 100644 --- a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java @@ -21,12 +21,10 @@ public ClearContentViewModel(StateManager stateManager) { this.stateManager = stateManager; } - /** all fields (without internal ones) */ public Set getAllFields() { return FieldFactory.getAllFieldsWithOutInternal(); } - /** only fields that are set in the selected entries */ public Set getSetFieldsOnly() { List selected = stateManager.getSelectedEntries(); Set setFields = new LinkedHashSet<>(); From 6c2e29a580013b94a180cf1326a644137f12b00a Mon Sep 17 00:00:00 2001 From: Akanksha Date: Wed, 10 Sep 2025 21:28:27 -0700 Subject: [PATCH 03/10] PR comment changes --- .../clearcontent/ClearContentTabView.java | 81 +++++++++---------- .../clearcontent/ClearContentViewModel.java | 21 ++--- .../clearcontent/ClearContentTab.fxml | 48 +++++++++++ 3 files changed, 94 insertions(+), 56 deletions(-) create mode 100644 jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTab.fxml diff --git a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java index 94c7dfacc34..75b4420fc3f 100644 --- a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java +++ b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTabView.java @@ -1,11 +1,10 @@ package org.jabref.gui.edit.automaticfiededitor.clearcontent; +import javafx.application.Platform; +import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; import org.jabref.gui.StateManager; import org.jabref.gui.edit.automaticfiededitor.AbstractAutomaticFieldEditorTabView; @@ -13,57 +12,57 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; +import com.airhacks.afterburner.views.ViewLoader; + +import static org.jabref.gui.util.FieldsUtil.FIELD_STRING_CONVERTER; + public class ClearContentTabView extends AbstractAutomaticFieldEditorTabView implements AutomaticFieldEditorTab { - private final ComboBox fieldCombo; - private final CheckBox showOnlySetFields; - private final Button clearButton; - private final ClearContentViewModel viewModel; + @FXML private ComboBox fieldComboBox; + @FXML private CheckBox showOnlySetFieldsCheckBox; + @FXML private Button clearButton; + private final StateManager stateManager; + private ClearContentViewModel viewModel; public ClearContentTabView(StateManager stateManager) { - super(); + this.stateManager = stateManager; + ViewLoader.view(this) + .root(this) + .load(); + } - this.viewModel = new ClearContentViewModel(stateManager); + @FXML + public void initialize() { + viewModel = new ClearContentViewModel(stateManager); - Label fieldLabel = new Label(Localization.lang("Field")); - fieldCombo = new ComboBox<>(); - showOnlySetFields = new CheckBox(Localization.lang("Show only set fields")); - clearButton = new Button(Localization.lang("Clear field content")); + fieldComboBox.setConverter(FIELD_STRING_CONVERTER); - // populate initially with all fields - fieldCombo.getItems().setAll( - viewModel.getAllFields().stream().toList() - ); + fieldComboBox.getItems().setAll(viewModel.getAllFields().stream().toList()); - // toggle filtering when checkbox is clicked - showOnlySetFields.setOnAction(e -> { - if (showOnlySetFields.isSelected()) { - fieldCombo.getItems().setAll( - viewModel.getSetFieldsOnly().stream().toList() - ); - } else { - fieldCombo.getItems().setAll( - viewModel.getAllFields().stream().toList() - ); + if (!fieldComboBox.getItems().isEmpty()) { + fieldComboBox.getSelectionModel().selectFirst(); + } + showOnlySetFieldsCheckBox.setOnAction(e -> { + var items = showOnlySetFieldsCheckBox.isSelected() + ? viewModel.getSetFieldsOnly().stream().toList() + : viewModel.getAllFields().stream().toList(); + fieldComboBox.getItems().setAll(items); + if (!items.isEmpty()) { + fieldComboBox.getSelectionModel().selectFirst(); } }); - VBox box = new VBox(10); - - Label title = new Label(Localization.lang("Clear field content for selected entries")); - title.getStyleClass().add("sectionHeader"); // match Edit tab styling + clearButton.disableProperty().bind(fieldComboBox.valueProperty().isNull()); - HBox row = new HBox(10, fieldLabel, fieldCombo, showOnlySetFields); - box.getChildren().addAll(title, row, clearButton); - this.getChildren().add(box); + Platform.runLater(fieldComboBox::requestFocus); + } - clearButton.setOnAction(e -> { - Field chosen = fieldCombo.getValue(); // keep ComboBox - if (chosen != null) { - viewModel.clearField(chosen); // VM builds/publishes the undo compound - System.out.println("Cleared field: " + chosen.getName()); - } - }); + @FXML + private void onClear() { + Field chosen = fieldComboBox.getValue(); + if (chosen != null) { + viewModel.clearField(chosen); + } } @Override diff --git a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java index 083ca75b184..abc0e8a1dcd 100644 --- a/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentViewModel.java @@ -3,6 +3,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.jabref.gui.StateManager; import org.jabref.gui.edit.automaticfiededitor.LastAutomaticFieldEditorEdit; @@ -26,19 +27,10 @@ public Set getAllFields() { } public Set getSetFieldsOnly() { - List selected = stateManager.getSelectedEntries(); - Set setFields = new LinkedHashSet<>(); - - for (BibEntry entry : selected) { - for (Field f : entry.getFields()) { - entry.getField(f).ifPresent(val -> { - if (!val.isBlank()) { - setFields.add(f); - } - }); - } - } - return setFields; + return stateManager.getSelectedEntries().stream() + .flatMap(entry -> entry.getFields().stream() + .filter(f -> entry.getField(f).isPresent() && !entry.getField(f).get().isBlank())) + .collect(Collectors.toCollection(LinkedHashSet::new)); } public void clearField(Field field) { @@ -51,9 +43,8 @@ public void clearField(Field field) { List selected = stateManager.getSelectedEntries(); for (BibEntry entry : selected) { - // clearField returns Optional entry.clearField(field).ifPresent((FieldChange change) -> { - edits.addEdit(new UndoableFieldChange(change)); // Wrap into UndoableEdit + edits.addEdit(new UndoableFieldChange(change)); }); } diff --git a/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTab.fxml b/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTab.fxml new file mode 100644 index 00000000000..2987ac0dc9a --- /dev/null +++ b/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/clearcontent/ClearContentTab.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml b/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml index 3b20e04ecfd..72ddd2de3f1 100644 --- a/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml +++ b/jabgui/src/main/resources/org/jabref/gui/edit/automaticfiededitor/editfieldcontent/EditFieldContentTab.fxml @@ -8,8 +8,8 @@ -