Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv

### Added

- We added a per-library journal abbreviation preference to Library Properties, allowing automatic LTWA abbreviation on save. [#15495](https://github.com/JabRef/jabref/issues/15495)
- We fixed a glitch with the sidepane divider position on startup. [#15394](https://github.com/JabRef/jabref/issues/15394)
- We added a label to the Group dropdown in the Import Dialog. [#15567](https://github.com/JabRef/jabref/issues/15567)
- We added a related work text extractor, which finds and inserts the related work text into bib entries from references in the texts. [#9840](https://github.com/JabRef/jabref/issues/9840)
Expand Down
2 changes: 1 addition & 1 deletion jabgui/src/main/java/org/jabref/gui/LibraryTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ private boolean confirmClose() {

if (buttonType.equals(saveChanges)) {
try {
SaveDatabaseAction saveAction = new SaveDatabaseAction(this, dialogService, preferences, Injector.instantiateModelOrService(BibEntryTypesManager.class), stateManager);
SaveDatabaseAction saveAction = new SaveDatabaseAction(this, dialogService, preferences, Injector.instantiateModelOrService(BibEntryTypesManager.class), stateManager, Injector.instantiateModelOrService(JournalAbbreviationRepository.class));
if (saveAction.save()) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import org.jabref.gui.StateManager;
import org.jabref.gui.exporter.SaveDatabaseAction;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.model.database.event.AutosaveEvent;
import org.jabref.model.entry.BibEntryTypesManager;

import com.airhacks.afterburner.injection.Injector;
import com.google.common.eventbus.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -20,7 +22,7 @@ public class AutosaveUiManager {
private final SaveDatabaseAction saveDatabaseAction;

public AutosaveUiManager(LibraryTab libraryTab, DialogService dialogService, GuiPreferences preferences, BibEntryTypesManager entryTypesManager, StateManager stateManager) {
this.saveDatabaseAction = new SaveDatabaseAction(libraryTab, dialogService, preferences, entryTypesManager, stateManager);
this.saveDatabaseAction = new SaveDatabaseAction(libraryTab, dialogService, preferences, entryTypesManager, stateManager, Injector.instantiateModelOrService(JournalAbbreviationRepository.class));
}

@Subscribe
Expand Down
4 changes: 3 additions & 1 deletion jabgui/src/main/java/org/jabref/gui/exporter/SaveAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jabref.gui.actions.ActionHelper;
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.model.entry.BibEntryTypesManager;

import com.airhacks.afterburner.injection.Injector;
Expand Down Expand Up @@ -49,7 +50,8 @@ public void execute() {
dialogService,
preferences,
Injector.instantiateModelOrService(BibEntryTypesManager.class),
stateManager);
stateManager,
Injector.instantiateModelOrService(JournalAbbreviationRepository.class));

switch (saveMethod) {
case SAVE ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jabref.gui.StateManager;
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntryTypesManager;

Expand Down Expand Up @@ -35,7 +36,7 @@ public void execute() {
dialogService.notify(Localization.lang("Saving all libraries..."));

for (LibraryTab libraryTab : tabsSupplier.get()) {
SaveDatabaseAction saveDatabaseAction = new SaveDatabaseAction(libraryTab, dialogService, preferences, Injector.instantiateModelOrService(BibEntryTypesManager.class), stateManager);
SaveDatabaseAction saveDatabaseAction = new SaveDatabaseAction(libraryTab, dialogService, preferences, Injector.instantiateModelOrService(BibEntryTypesManager.class), stateManager, Injector.instantiateModelOrService(JournalAbbreviationRepository.class));
boolean saveResult = saveDatabaseAction.save();
if (!saveResult) {
dialogService.notify(Localization.lang("Could not save file."));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
Expand All @@ -27,18 +28,22 @@
import org.jabref.gui.maintable.columns.MainTableColumn;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.gui.util.FileDialogConfiguration;
import org.jabref.logic.cleanup.AbbreviateJournalCleanup;
import org.jabref.logic.exporter.AtomicFileWriter;
import org.jabref.logic.exporter.BibDatabaseWriter;
import org.jabref.logic.exporter.BibWriter;
import org.jabref.logic.exporter.SaveException;
import org.jabref.logic.exporter.SelfContainedSaveConfiguration;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.os.OS;
import org.jabref.logic.shared.DatabaseLocation;
import org.jabref.logic.shared.prefs.SharedDatabasePreferences;
import org.jabref.logic.util.StandardFileType;
import org.jabref.model.FieldChange;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.database.event.ChangePropagation;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.metadata.SaveOrder;
import org.jabref.model.metadata.SelfContainedSaveOrder;
Expand All @@ -59,6 +64,7 @@ public class SaveDatabaseAction {
private final GuiPreferences preferences;
private final BibEntryTypesManager entryTypesManager;
private final StateManager stateManager;
private final JournalAbbreviationRepository journalAbbreviationRepository;

public enum SaveDatabaseMode {
SILENT, NORMAL
Expand All @@ -68,12 +74,14 @@ public SaveDatabaseAction(LibraryTab libraryTab,
DialogService dialogService,
GuiPreferences preferences,
BibEntryTypesManager entryTypesManager,
StateManager stateManager) {
StateManager stateManager,
JournalAbbreviationRepository journalAbbreviationRepository) {
this.libraryTab = libraryTab;
this.dialogService = dialogService;
this.preferences = preferences;
this.entryTypesManager = entryTypesManager;
this.stateManager = stateManager;
this.journalAbbreviationRepository = journalAbbreviationRepository;
}

public boolean save() {
Expand Down Expand Up @@ -260,13 +268,29 @@ private boolean saveDatabase(Path file, boolean selectedOnly, Charset encoding,
preferences.getCitationKeyPatternPreferences(),
entryTypesManager);

List<BibEntry> entriesToAbbreviate = selectedOnly
? libraryTab.getSelectedEntries()
: bibDatabaseContext.getDatabase().getEntries();
List<FieldChange> abbreviationChanges = bibDatabaseContext.getMetaData()
.getLibraryAbbreviationType()
.map(abbreviationType -> {
boolean useFJournal = preferences.getJournalAbbreviationPreferences().shouldUseFJournalField();
AbbreviateJournalCleanup cleanup = new AbbreviateJournalCleanup(
bibDatabaseContext.getDatabase(), journalAbbreviationRepository, abbreviationType, useFJournal);
return entriesToAbbreviate.stream()
.flatMap(entry -> cleanup.cleanup(entry).stream())
.toList();
})
.orElse(List.of());

if (selectedOnly) {
databaseWriter.writePartOfDatabase(bibDatabaseContext, libraryTab.getSelectedEntries());
} else {
databaseWriter.writeDatabase(bibDatabaseContext);
}

libraryTab.registerUndoableChanges(databaseWriter.getSaveActionsFieldChanges());
libraryTab.registerUndoableChanges(
Stream.concat(databaseWriter.getSaveActionsFieldChanges().stream(), abbreviationChanges.stream()).toList());
Comment on lines +274 to +293
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Cleanup logic added to gui 📘 Rule violation ⚙ Maintainability

SaveDatabaseAction (GUI layer) now performs journal abbreviation cleanup over all entries, which
is non-GUI/business logic. This violates the layering guideline and makes the GUI responsible for
logic behavior.
Agent Prompt
## Issue description
GUI-layer `SaveDatabaseAction` now contains business logic for abbreviating journals on save.

## Issue Context
Layering rules require business logic to be implemented in `org.jabref.logic`, with GUI code acting as wiring/gateway.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java[276-288]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
if (fileWriter.hasEncodingProblems()) {
saveWithDifferentEncoding(file, selectedOnly, encoding, fileWriter.getEncodingProblems(), saveType, saveOrder);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package org.jabref.gui.libraryproperties.saving;

import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.util.StringConverter;

import org.jabref.gui.commonfxcontrols.FieldFormatterCleanupsPanel;
import org.jabref.gui.commonfxcontrols.SaveOrderConfigPanel;
import org.jabref.gui.libraryproperties.AbstractPropertiesTabView;
import org.jabref.gui.libraryproperties.PropertiesTab;
import org.jabref.logic.journals.AbbreviationType;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.model.database.BibDatabaseContext;
Expand All @@ -19,6 +23,7 @@ public class SavingPropertiesView extends AbstractPropertiesTabView<SavingProper
@FXML private CheckBox protect;
@FXML private SaveOrderConfigPanel saveOrderConfigPanel;
@FXML private FieldFormatterCleanupsPanel fieldFormatterCleanupsPanel;
@FXML private ComboBox<AbbreviationType> journalAbbreviationOnSave;

@Inject private CliPreferences preferences;

Expand Down Expand Up @@ -49,5 +54,33 @@ public void initialize() {

fieldFormatterCleanupsPanel.cleanupsDisableProperty().bindBidirectional(viewModel.cleanupsDisableProperty());
fieldFormatterCleanupsPanel.cleanupsProperty().bindBidirectional(viewModel.cleanupsProperty());

journalAbbreviationOnSave.setItems(FXCollections.observableArrayList(
null, AbbreviationType.DEFAULT, AbbreviationType.DOTLESS,
AbbreviationType.SHORTEST_UNIQUE, AbbreviationType.LTWA));
journalAbbreviationOnSave.setConverter(new StringConverter<>() {
@Override
public String toString(AbbreviationType type) {
if (type == null) {
return Localization.lang("None (use global setting)");
}
return switch (type) {
case DEFAULT ->
Localization.lang("Abbreviate (default)");
case DOTLESS ->
Localization.lang("Abbreviate (dotless)");
case SHORTEST_UNIQUE ->
Localization.lang("Abbreviate (shortest unique)");
case LTWA ->
Localization.lang("Abbreviate (LTWA)");
};
}
Comment on lines +67 to +77
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope these options sound correct.


@Override
public AbbreviationType fromString(String string) {
return null;
}
});
journalAbbreviationOnSave.valueProperty().bindBidirectional(viewModel.journalAbbreviationOnSaveProperty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;

import org.jabref.gui.commonfxcontrols.SortCriterionViewModel;
import org.jabref.gui.libraryproperties.PropertiesTabViewModel;
import org.jabref.logic.cleanup.CleanupPreferences;
import org.jabref.logic.cleanup.FieldFormatterCleanup;
import org.jabref.logic.cleanup.FieldFormatterCleanupActions;
import org.jabref.logic.journals.AbbreviationType;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.field.Field;
Expand Down Expand Up @@ -49,6 +52,9 @@ public class SavingPropertiesViewModel implements PropertiesTabViewModel {
private final BooleanProperty cleanupsDisableProperty = new SimpleBooleanProperty();
private final ListProperty<FieldFormatterCleanup> cleanupsProperty = new SimpleListProperty<>(FXCollections.emptyObservableList());

// Journal abbreviation on save
private final ObjectProperty<AbbreviationType> journalAbbreviationOnSaveProperty = new SimpleObjectProperty<>();

private final BibDatabaseContext databaseContext;
private final MetaData initialMetaData;
private final SaveOrder saveOrder;
Expand Down Expand Up @@ -101,6 +107,8 @@ public void setValues() {
cleanupsDisableProperty.setValue(!defaultPreset.getFieldFormatterCleanups().isEnabled());
cleanupsProperty.setValue(FXCollections.observableArrayList(defaultPreset.getFieldFormatterCleanups().getConfiguredActions()));
});

journalAbbreviationOnSaveProperty.setValue(initialMetaData.getLibraryAbbreviationType().orElse(null));
}

@Override
Expand Down Expand Up @@ -140,6 +148,13 @@ public void storeSettings() {
}
}

AbbreviationType abbreviationType = journalAbbreviationOnSaveProperty.getValue();
if (abbreviationType != null) {
newMetaData.setLibraryAbbreviationType(abbreviationType);
} else {
newMetaData.clearLibraryAbbreviationType();
}

databaseContext.setMetaData(newMetaData);
}

Expand Down Expand Up @@ -182,4 +197,8 @@ public BooleanProperty cleanupsDisableProperty() {
public ListProperty<FieldFormatterCleanup> cleanupsProperty() {
return cleanupsProperty;
}

public ObjectProperty<AbbreviationType> journalAbbreviationOnSaveProperty() {
return journalAbbreviationOnSaveProperty;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.jabref.gui.util.FileFilterConverter;
import org.jabref.logic.ai.AiService;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.shared.DBMSConnectionProperties;
import org.jabref.logic.shared.DBMSConnectionPropertiesBuilder;
Expand Down Expand Up @@ -213,7 +214,8 @@ private boolean openSharedDatabase(DBMSConnectionProperties connectionProperties
dialogService,
preferences,
Injector.instantiateModelOrService(BibEntryTypesManager.class),
stateManager
stateManager,
Injector.instantiateModelOrService(JournalAbbreviationRepository.class)
).saveAs(Path.of(folder.getValue()));
} catch (Throwable e) {
LOGGER.error("Error while saving the database", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

<?import javafx.geometry.Insets?>
<?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.commonfxcontrols.FieldFormatterCleanupsPanel?>
<?import org.jabref.gui.commonfxcontrols.SaveOrderConfigPanel?>
Expand All @@ -18,6 +20,12 @@

<Label styleClass="sectionHeader" text="%Save actions"/>
<FieldFormatterCleanupsPanel fx:id="fieldFormatterCleanupsPanel" />

<Label styleClass="sectionHeader" text="%Journal abbreviation on save"/>
<HBox spacing="8.0" alignment="CENTER_LEFT">
<Label text="%Abbreviation style"/>
<ComboBox fx:id="journalAbbreviationOnSave"/>
</HBox>
<padding>
<Insets bottom="12.0" />
</padding>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.jabref.logic.exporter.BibDatabaseWriter;
import org.jabref.logic.exporter.ExportPreferences;
import org.jabref.logic.exporter.SaveConfiguration;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.shared.DatabaseLocation;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.database.BibDatabaseContext;
Expand Down Expand Up @@ -64,7 +65,7 @@ void setUp() {
when(filePreferences.getWorkingDirectory()).thenReturn(Path.of(TEST_BIBTEX_LIBRARY_LOCATION));
when(preferences.getFilePreferences()).thenReturn(filePreferences);
when(preferences.getExportPreferences()).thenReturn(mock(ExportPreferences.class));
saveDatabaseAction = spy(new SaveDatabaseAction(libraryTab, dialogService, preferences, mock(BibEntryTypesManager.class), stateManager));
saveDatabaseAction = spy(new SaveDatabaseAction(libraryTab, dialogService, preferences, mock(BibEntryTypesManager.class), stateManager, mock(JournalAbbreviationRepository.class)));
}

@Test
Expand Down Expand Up @@ -133,7 +134,7 @@ private SaveDatabaseAction createSaveDatabaseActionForBibDatabase(BibDatabase da
when(libraryTab.getBibDatabaseContext()).thenReturn(dbContext);
when(libraryTab.getUndoManager()).thenReturn(mock(CountingUndoManager.class));
when(libraryTab.getBibDatabaseContext()).thenReturn(dbContext);
saveDatabaseAction = new SaveDatabaseAction(libraryTab, dialogService, preferences, mock(BibEntryTypesManager.class), stateManager);
saveDatabaseAction = new SaveDatabaseAction(libraryTab, dialogService, preferences, mock(BibEntryTypesManager.class), stateManager, mock(JournalAbbreviationRepository.class));
return saveDatabaseAction;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public static Map<String, String> getSerializedStringMap(MetaData metaData,
stringyMetaData.putAll(serializeCiteKeyPatterns(metaData, globalCiteKeyPatterns));
metaData.getMode().ifPresent(
mode -> stringyMetaData.put(MetaData.DATABASE_TYPE, List.of(mode.getAsString())));
metaData.getLibraryAbbreviationType().ifPresent(
abbreviationType -> stringyMetaData.put(MetaData.LIBRARY_ABBREVIATION_TYPE, List.of(abbreviationType.name())));
metaData.getLibrarySpecificFileDirectory().ifPresent(
path -> stringyMetaData.put(MetaData.FILE_DIRECTORY, List.of(path.trim())));
metaData.getUserFileDirectories().forEach((user, path) -> stringyMetaData
Expand Down
Loading
Loading