Skip to content

[WIP] Add toggle functionality for journal abbreviation lists #12912

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 28 commits into
base: main
Choose a base branch
from

Conversation

zikunz
Copy link

@zikunz zikunz commented Apr 8, 2025

Heads up! This PR is still a work in progress:

  • I am still refactoring some parts of the code.
  • The PR content regarding code changes is not yet up to date and will be revised soon.
  • I will also open an issue and a PR in the documentation (user guide) repo later on.
  • I anticipate these changes will be completed within the next 3 days. Thank you for your patience and guidance!

Toggle Functionality for Journal Abbreviation Lists

Closes #12468.

What

This feature is comprehensive and solves more than what is asked in #12468.

Specifially, this PR adds the ability to enable/disable any journal abbreviation lists in JabRef, including both the built-in list and external CSV files. Users can now toggle all types of journal abbreviation lists on/off to make them enabled/disabled.

We can disable the built-in list:
image

If the built-in list is disabled, journal names found in the built-in list will not be abbreviated:
image

Why

In the original codebase, all journal abbreviation lists were always active once loaded. Users had no way to temporarily disable specific abbreviation sources without completely removing them. This was particularly problematic with the built-in list, which could not be removed at all. Detailed reasons about why we want to disable built-in list sometimes can be found in the issue.

This feature improves workflow flexibility by allowing users to:

  • Temporarily disable specific sources during editing sessions
  • Manage potential conflicts between abbreviation lists
  • Enable/disable the built-in list when needed
  • Control which external lists are active without removing them

How

The implementation follows JabRef's existing architecture patterns:

Key Features

Filtering Logic

  • Only enabled abbreviation sources will apply changes during operations
  • Disabled abbreviation sources have no effect on journal name processing
  • The repository dynamically filters abbreviations based on source enabled state

Persistence

  • Toggle states are stored in preferences only upon clicking "Save"
  • If the user clicks "Cancel" or closes the dialog (X), previous states are restored
  • States persist between application restarts

UI Feedback

  • Visual indicators show enabled/disabled state for each list
  • Toggle button provides easy access to state change
  • Dropdown shows current state with clear visual indicators

Design Considerations

Performance Considerations

The implementation reloads the journal repository before each abbreviation operation to ensure it uses the latest toggle states. This approach has minimal performance impact because:

  1. Repository loading is very efficient as it only builds active abbreviation sets
  2. Abbreviation operations are typically infrequent user actions
  3. The benefits of having accurate, up-to-date toggle states outweigh the small overhead of reloading

I have also tested with fairly large abbreviation lists and observed no noticeable performance degradation.

Design Alternatives Considered

  1. Event-based updates: I considered using an event system to update the repository when toggle states change. While potentially more efficient, this approach would be more complex and error-prone, requiring careful synchronization between preference changes and repository state.

  2. Runtime filtering: Another approach was to keep all abbreviations loaded and filter at runtime during abbreviation operations. This would be slightly faster but would require more memory and complicate the core lookup methods.

  3. Separate repositories: I also considered maintaining separate repositories for each source, but this would diverge significantly from JabRef's existing architecture and complicate cross-source operations.

The chosen approach of reloading the repository provides the best balance of reliability, maintainability, and adherence to existing architecture patterns.

Proposed Code Changes

Frontend Changes (GUI)

  1. JournalAbbreviationsTab.java

    • Purpose: User interface tab for managing journal abbreviations
    • Changes:
      • Added toggle button next to journal list dropdown
      • Created custom ListCell displaying checkmarks (✓) or circles (○) to indicate enabled state
      • Implemented real-time UI refresh when toggling lists
    • Why: Provides the visual interface for users to see and change enabled states
  2. AbbreviationsFileViewModel.java

    • Purpose: View model for a single abbreviation file
    • Changes:
      • Added enabledProperty to track and bind state
      • Implemented getter/setter methods for state access
      • Added path handling for consistent preference storage
    • Why: Provides the model binding for UI components to reflect enabled state changes
  3. JournalAbbreviationsTabViewModel.java

    • Purpose: Manages the journal abbreviation tab's business logic
    • Changes:
      • Implemented state tracking with proper model update notification
      • Added event handling for toggle button click
      • Added methods to build file list with correct initial states
      • Connected UI state to persistence layer
    • Why: Connects the UI actions to the model and ensures proper state synchronization
  4. MainMenu.java

    • Purpose: Builds the application's main menu
    • Changes:
      • Updated constructor calls to accommodate new repository loading mechanism
    • Why: Required to accommodate the new repository loading approach in AbbreviateAction

Backend Changes (Logic)

  1. JournalAbbreviationRepository.java

    • Purpose: Central repository that stores and retrieves abbreviations
    • Changes:
      • Added source tracking with sourceToAbbreviations map to associate abbreviations with their sources
      • Added enabledSources map to track enabled/disabled state of each source
      • Modified core lookup methods to filter based on enabled state
      • Implemented proper updating of active abbreviations when toggling
    • Why: This is the core component where abbreviation filtering happens. When a source is disabled, its abbreviations shouldn't be used in operations
  2. JournalAbbreviationLoader.java

    • Purpose: Loads abbreviations from various sources into the repository
    • Changes:
      • Modified to respect enabled states from preferences
      • Implemented consistent key naming for external list identification
      • Added robust error handling for missing files
    • Why: The loader needed to initialize the repository with the correct enabled states and ensure proper source identification
  3. AbbreviateAction.java

    • Purpose: Handles abbreviation/unabbreviation commands from menu
    • Changes:
      • Implemented repository reload before abbreviation operations
      • Ensured operations use the latest toggle states
    • Why: Without reloading the repository, toggle state changes wouldn't affect already-running abbreviation operations
  4. JournalAbbreviationPreferences.java

    • Purpose: Stores user preferences for journal abbreviations
    • Changes:
      • Added enabledExternalLists map to store enabled/disabled states
      • Added methods to check if a specific source has an explicit enabled setting
      • Enhanced preference retrieval with multiple lookup strategies
    • Why: Provides the persistence mechanism for toggle states between application sessions
  5. JabRefCliPreferences.java

    • Purpose: Handles preference loading/saving at application level
    • Changes:
      • Added settings for journal abbreviation toggle states
      • Integrated with the overall preference system
    • Why: Ensures toggle states are properly saved/loaded at application level

Testing Strategy

Test Files and Coverage

  1. JournalAbbreviationRepositoryTest.java

    • Purpose: Tests the core backend functionality for source tracking and toggle behavior
    • Test Cases:
      • multipleSourcesCanBeToggled: Verifies that multiple sources can be independently enabled/disabled
      • disabledSourcesAreFilteredFromLookup: Ensures abbreviations from disabled sources aren't returned in lookups
      • builtInListCanBeToggled: Confirms the built-in list can be toggled like external sources
      • toggleStateAffectsAbbreviationSets: Tests that abbreviation sets are properly filtered by source state
  2. JournalAbbreviationsViewModelTabTest.java

    • Purpose: Tests the UI view model for toggle functionality
    • Test Cases:
      • addBuiltInListInitializesWithCorrectEnabledState: Verifies built-in list loaded with correct enabled state
      • enabledExternalListFiltersAbbreviationsWhenDisabled: Tests that UI reflects filtered abbreviations
      • storeSettingsPersistsEnabledStateToPreferences: Ensures toggle states are saved to preferences

Implementation Additions for Testing

The following methods and properties were added specifically to support testing:

  1. AbbreviationsFileViewModel.java

    • Added refreshAbbreviations() method to simulate UI updates when toggle state changes
    • Added thorough isEnabled(), setEnabled(), and enabledProperty() methods for test validation
  2. JournalAbbreviationsTabViewModel.java

    • Added markAsDirty() method to allow tests to mark files as needing to be saved
    • Enhanced storeSettings() to provide verification points for proper state persistence
  3. JournalAbbreviationRepository.java

    • Implemented addCustomAbbreviation(abbreviation, sourcePath, enabled) with source tracking for test scenarios
    • Added test-friendly mapping between abbreviations and their sources for verification
  4. JournalAbbreviationPreferences.java

    • Added hasExplicitEnabledSetting() method to improve testability of preference storage
    • Implemented clean getters/setters for toggle states to simplify test verification

These additions ensure the toggle functionality can be thoroughly tested while maintaining clean separation between the application code and test code.

Mandatory checks

  • I own the copyright of the code submitted and I license it under the MIT license
  • Change in CHANGELOG.md described in a way that is understandable for the average user (if change is visible to the user)
  • Tests created for changes (if applicable)
  • Manually tested changed features in running JabRef (always required)
  • Screenshots added in PR description (if change is visible to the user)
  • Checked developer's documentation: Is the information available and up to date? If not, I outlined it in this pull request.
  • Checked documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request to the documentation repository.

This feature allows users to enable/disable specific journal abbreviation lists, including both the built-in list and external CSV files, without removing them from configuration.

- Added toggle controls in UI with visual indicators for enabled/disabled states

- Implemented filtering of abbreviations based on source enabled state

- Ensured toggle states persist between application sessions

- Optimized performance with efficient repository loading

- Added comprehensive test coverage for new functionality

Closes JabRef#12468
@zikunz zikunz force-pushed the feature/journal-abbreviation-toggle branch from dd85326 to 37c8d2c Compare April 8, 2025 15:02
@subhramit subhramit marked this pull request as draft April 8, 2025 15:21
@subhramit
Copy link
Member

Please update your screenshots here as well.

@zikunz
Copy link
Author

zikunz commented Apr 8, 2025

@subhramit Got it, I will make sure all the screenshots will be updated in the PR content above :)

@zikunz
Copy link
Author

zikunz commented Apr 8, 2025

I tried to fix the two screenshots in the PR content, may I ask whether you are able to see them? @subhramit

@subhramit
Copy link
Member

I tried to fix the two screenshots in the PR content, may I ask whether you are able to see them? @subhramit

yes, they are fine now

@zikunz
Copy link
Author

zikunz commented Apr 8, 2025

Thank you! @subhramit

Journal abbreviations coming from sources that the user has disabled should neither be generated nor reversed.\n\nThis patch:\n
1. Makes UndoableUnabbreviator skip entries whose source is disabled\n2. Introduces AbbreviationWithSource to persist source metadata\n3. Filters candidates early in AbbreviateAction\n4. Refreshes repository state when a source is toggled in the UI
@zikunz
Copy link
Author

zikunz commented Apr 13, 2025

Update: the bug is now fixed and I proceed to refactor the code now. Afterwards, this PR will be ready for review :)

zikunz added 8 commits April 13, 2025 18:17
This commit fixes test failures that occurred after implementing the
journal abbreviation toggle feature. The changes include:

1. Ensuring the built-in list is always enabled by default in the
   JournalAbbreviationLoader for backward compatibility

2. Updating journal abbreviation tests to use controlled test data
   rather than depending on the built-in repository contents

3. Adding a more comprehensive test case for the abbreviation cycle
@jabref-machine
Copy link
Collaborator

Your pull request conflicts with the target branch.

Please merge upstream/main with your code. For a step-by-step guide to resolve merge conflicts, see https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line.

@jabref-machine
Copy link
Collaborator

Your pull request conflicts with the target branch.

Please merge upstream/main with your code. For a step-by-step guide to resolve merge conflicts, see https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line.

Integrate journal abbreviation toggle functionality (JabRef#12880) with the LTWA repository support from main branch. Resolve conflicts in JournalAbbreviationRepository, JournalAbbreviationLoader, and MainMenu to ensure both features work correctly together. The combined functionality allows users to enable/disable specific journal abbreviation sources while maintaining LTWA abbreviation support.
@zikunz
Copy link
Author

zikunz commented Apr 18, 2025

@koppor @Siedlerchr @subhramit

I have completed resolving the 6 merge conflicts between my PR and PR #12880 (which closed #12273). The resolved changes are reflected in my recent commit with the commit message of "feat: resolve merge conflicts with journal abbreviation toggle feature".

To properly test the combined functionality, I first proceeded to git checkout 1a4e1f38864e9bb1fc336a366ec24c3c0d48a94f in main branch to understand the behavior after merging #12880 to main (without my code changes).

During my local testing of the merged functionality, I observed some behavior that I would like to confirm is working as intended:

  1. When testing with the LTWA abbreviation mode, I noticed that the word "graph" does not get abbreviated to "gr." despite the csv file found in Add support for LTWA #12273 containing the entry -graph-;"-gr.";"eng".
Screen Shot 2025-04-19 at 2 39 11 AM Screen Shot 2025-04-19 at 2 39 21 AM
  1. I can successfully abbreviate "Journal of Polymer Science Part A" to "J. Polym. Sci. A" using LTWA mode (matching a test case in Add support for LTWA #12273), but when I try to unabbreviate it, it does not revert to the original text. In addition, "Journal of Polymer Science Part A" does not seem to be found in the the csv file found in Add support for LTWA #12273.
Screen Shot 2025-04-19 at 2 38 22 AM Screen Shot 2025-04-19 at 2 38 34 AM Screen Shot 2025-04-19 at 2 38 48 AM Screen Shot 2025-04-19 at 2 38 57 AM
  1. When attempting to abbreviate "Dem" (this is achieved by first abbreviating "Demonstration" using the shortest unique mode) using LTWA mode, the result is an empty string.
Screen Shot 2025-04-19 at 2 36 27 AM Screen Shot 2025-04-19 at 2 36 32 AM

I want to ensure that my merge conflict resolution is correct and that I am understanding the expected behavior of the LTWA abbreviation functionality properly. Could you please advise if these observations align with the intended functionality of the LTWA implementation, or if further adjustments are needed?

Thank you for your guidance.

@koppor
Copy link
Member

koppor commented Apr 19, 2025

@Yubo-Cao Can you look into #12912 (comment) maybe? I currently don't have the resources to properly answer.

@zikunz
Copy link
Author

zikunz commented Apr 19, 2025

@Yubo-Cao Can you look into #12912 (comment) maybe? I currently don't have the resources to properly answer.

@koppor Thank you!

@Yubo-Cao I look forward to your guidance. Thank you in advance!

@Test
void checkBasicAbbreviate() {
BibEntry entry = new BibEntry();
entry.setField(StandardField.JOURNAL, "TJ");
Copy link

Choose a reason for hiding this comment

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

When creating a new BibEntry object, 'withers' should be used instead of 'setField'. This improves code readability and follows modern Java practices.


@Test
void unabbreviateWithBothSourcesEnabled() {
assertTrue(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
Copy link

Choose a reason for hiding this comment

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

The test uses assertTrue to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

repository.setSourceEnabled(CUSTOM_SOURCE, false);

assertTrue(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
assertFalse(repository.isSourceEnabled(CUSTOM_SOURCE));
Copy link

Choose a reason for hiding this comment

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

The test uses assertFalse to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

@Test
void unabbreviateWithBothSourcesEnabled() {
assertTrue(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
assertTrue(repository.isSourceEnabled(CUSTOM_SOURCE));
Copy link

Choose a reason for hiding this comment

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

The test uses assertTrue to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

void unabbreviateWithOnlyCustomSourceEnabled() {
repository.setSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID, false);

assertFalse(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
Copy link

Choose a reason for hiding this comment

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

The test uses assertFalse to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

repository.setSourceEnabled(CUSTOM_SOURCE, false);

assertTrue(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
assertFalse(repository.isSourceEnabled(CUSTOM_SOURCE));
Copy link

Choose a reason for hiding this comment

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

The test uses assertFalse to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.


@Test
void unabbreviateWithBothSourcesEnabled() {
assertTrue(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
Copy link

Choose a reason for hiding this comment

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

The test uses assertTrue to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

@Test
void unabbreviateWithBothSourcesEnabled() {
assertTrue(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
assertTrue(repository.isSourceEnabled(CUSTOM_SOURCE));
Copy link

Choose a reason for hiding this comment

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

The test uses assertTrue to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

void unabbreviateWithOnlyCustomSourceEnabled() {
repository.setSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID, false);

assertFalse(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
Copy link

Choose a reason for hiding this comment

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

The test uses assertFalse to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

repository.setSourceEnabled(CUSTOM_SOURCE, false);

assertTrue(repository.isSourceEnabled(JournalAbbreviationRepository.BUILTIN_LIST_ID));
assertFalse(repository.isSourceEnabled(CUSTOM_SOURCE));
Copy link

Choose a reason for hiding this comment

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

The test uses assertFalse to check boolean conditions. It should assert the contents of objects using assertEquals for better clarity and debugging.

@Yubo-Cao
Copy link
Contributor

Yubo-Cao commented Apr 20, 2025

@Yubo-Cao Can you look into #12912 (comment) maybe? I currently don't have the resources to properly answer.

@koppor Thank you!

@Yubo-Cao I look forward to your guidance. Thank you in advance!

Apologies for the late reply. The behavior you found is as expected:

  1. When there is only one or two words in the journal title, LTWA suggests doing nothing with it, since it is typically a proper noun (e.g., The Lancet).
  2. In any other cases, we would break down the title into subsequences and match them with the LTWA list to perform the abbreviation. For example, Journal of Polymer Science Part A became [Journal] [stopwods are dropped] [Polymer] [Science] [A].
  3. Dem is recognized by the parser as a German article—currently, that has to be the expected behavior since we couldn't infer the language for which the journal belongs to.
  4. Unabbreviate is effectively impossible. Since LTWA removes all the stopwords, we couldn't magically reproduce of from the abbreviated version either. I thought the fjournal field would take care of that?

List<T> placeholder = new ArrayList<>(observableList);
Collections.swap(placeholder, i, j);
observableList.sort(Comparator.comparingInt(placeholder::indexOf));
if (i < 0 || j < 0 || i >= observableList.size() || j >= observableList.size()) {
Copy link

Choose a reason for hiding this comment

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

The code follows the fail-fast principle by returning early on invalid indices, which is a good practice. Ensure this is consistently applied throughout the codebase.

@zikunz zikunz force-pushed the feature/journal-abbreviation-toggle branch from 69e0d00 to 10491f5 Compare April 20, 2025 20:08

action.execute();

verify(dialogService).notify(eq(Localization.lang("Cannot unabbreviate: all journal lists are disabled.")));
Copy link

Choose a reason for hiding this comment

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

The notification message uses an exclamation mark, which should be avoided as per guidelines. Use a period instead to end the sentence.

action.execute();

verify(dialogService, never()).notify(eq(Localization.lang("Cannot unabbreviate: all journal lists are disabled.")));
verify(dialogService).notify(eq(Localization.lang("Unabbreviating...")));
Copy link

Choose a reason for hiding this comment

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

The notification message uses an exclamation mark, which should be avoided as per guidelines. Use a period instead to end the sentence.

@zikunz
Copy link
Author

zikunz commented Apr 21, 2025

@Yubo-Cao Can you look into #12912 (comment) maybe? I currently don't have the resources to properly answer.

@koppor Thank you!
@Yubo-Cao I look forward to your guidance. Thank you in advance!

Apologies for the late reply. The behavior you found is as expected:

  1. When there is only one or two words in the journal title, LTWA suggests doing nothing with it, since it is typically a proper noun (e.g., The Lancet).
  2. In any other cases, we would break down the title into subsequences and match them with the LTWA list to perform the abbreviation. For example, Journal of Polymer Science Part A became [Journal] [stopwods are dropped] [Polymer] [Science] [A].
  3. Dem is recognized by the parser as a German article—currently, that has to be the expected behavior since we couldn't infer the language for which the journal belongs to.
  4. Unabbreviate is effectively impossible. Since LTWA removes all the stopwords, we couldn't magically reproduce of from the abbreviated version either. I thought the fjournal field would take care of that?

Thank you so much for your reply! @Yubo-Cao I apologize for not noticing your response until just now.

I am very thankful for your confirmation that all the behaviors I described are expected. This is reassuring that my resolution of the merge conflicts appears to be on the right track because there is no change in LTWA functionalities you implemented after adding toggle functionality (I will also thoroughly double-check it later on again). Thank you also for explaining the detailed business logic, design choices and implementation details - this has been extremely helpful.

@koppor All my questions were answered, I will make this PR ready for review soon. I will update everyone in #12468 :)

Copy link
Member

@subhramit subhramit left a comment

Choose a reason for hiding this comment

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

The changes so far are looking good. How much more work do you estimate it'll take to get to a "ready" state?

See if you can get rid of Collectors and Collections wherever possible. I have left some hints in comments below and some miscellaneous code suggestions.

journalFilesBox.setCellFactory(listView -> new JournalFileListCell());
journalFilesBox.setButtonCell(new JournalFileListCell());

viewModel.journalFilesProperty().addListener((observable, oldValue, newValue) -> {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
viewModel.journalFilesProperty().addListener((observable, oldValue, newValue) -> {
viewModel.journalFilesProperty().addListener((_, _, newValue) -> {

return;
}
for (AbbreviationsFileViewModel fileViewModel : newValue) {
fileViewModel.enabledProperty().addListener((obs, oldVal, newVal) -> {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
fileViewModel.enabledProperty().addListener((obs, oldVal, newVal) -> {
fileViewModel.enabledProperty().addListener((_, _, _) -> {

Optional<Abbreviation> customMatch = findBestFuzzyMatched(customAbbreviations, input);
Collection<Abbreviation> enabledCustomAbbreviations = customAbbreviations.stream()
.filter(abbreviation -> isSourceEnabled(abbreviationSources.getOrDefault(abbreviation, BUILTIN_LIST_ID)))
.collect(Collectors.toList());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.collect(Collectors.toList());
.toList();

public List<Abbreviation> getAllAbbreviations() {
return getAllAbbreviationsWithSources().stream()
.map(AbbreviationWithSource::getAbbreviation)
.collect(Collectors.toList());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.collect(Collectors.toList());
.toList();

return;
}
try {
Collection<Abbreviation> abbreviationsFromFile = JournalAbbreviationLoader.readAbbreviationsFromCsvFile(filePath);
Copy link
Member

Choose a reason for hiding this comment

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

Can you use Set here? Refactor up the hierarchy, start by converting return type of:

public Collection<Abbreviation> getAbbreviations() {
return abbreviations;
}

To Set<Abbreviation> and then replace everywhere. I have left "some" suggestions as were visible to me in other comments.

* Adds multiple custom abbreviations to the repository
*
* @param abbreviationsToAdd The abbreviations to add
*/
public void addCustomAbbreviations(Collection<Abbreviation> abbreviationsToAdd) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public void addCustomAbbreviations(Collection<Abbreviation> abbreviationsToAdd) {
public void addCustomAbbreviations(Set<Abbreviation> abbreviationsToAdd) {

* @param sourceKey The key identifying the source of these abbreviations
* @param enabled Whether the source should be enabled initially
*/
public void addCustomAbbreviations(Collection<Abbreviation> abbreviationsToAdd, String sourceKey, boolean enabled) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public void addCustomAbbreviations(Collection<Abbreviation> abbreviationsToAdd, String sourceKey, boolean enabled) {
public void addCustomAbbreviations(Set<Abbreviation> abbreviationsToAdd, String sourceKey, boolean enabled) {

Adapt the javadoc too.

@@ -234,4 +356,76 @@ public Set<String> getFullNames() {
public Collection<Abbreviation> getAllLoaded() {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public Collection<Abbreviation> getAllLoaded() {
public Set<Abbreviation> getAllLoaded() {


String text = entry.getFieldLatexFree(journalField).orElse("");
List<JournalAbbreviationRepository.AbbreviationWithSource> possibleSources =
textToSourceMap.getOrDefault(text, Collections.emptyList());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
textToSourceMap.getOrDefault(text, Collections.emptyList());
textToSourceMap.getOrDefault(text, List.of());

public class JournalAbbreviationPreferences {

private final ObservableList<String> externalJournalLists;
private final BooleanProperty useFJournalField;

private final Map<String, Boolean> enabledExternalLists = new HashMap<>();
private final BooleanProperty enabledListsChanged = new SimpleBooleanProperty(false);
Copy link
Member

Choose a reason for hiding this comment

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

No need to initialize with false here.
Put the default in JabRefCliPreferences using defaults.put(ENABLED_EXTERNAL_JOURNAL_LISTS, false).
See other examples for reference.

@zikunz
Copy link
Author

zikunz commented Apr 21, 2025

The changes so far are looking good. How much more work do you estimate it'll take to get to a "ready" state?

See if you can get rid of Collectors and Collections wherever possible. I have left some hints in comments below and some miscellaneous code suggestions.

@subhramit Thank you so much for your thorough code review and feedback. I estimate I will need approximately 1 - 2 additional days to bring this PR to a "ready" state. Here is what remains on my task list (please let me know if I still miss any):

  1. Code Refactoring (most significant effort)

    • Address all remaining review comments by trag-bot
    • Implement your suggestions regarding Collectors and Collections alternatives
    • Conduct a final quality review to identify additional improvements
  2. PR Documentation Updates

    • Enhance the description with clear explanations of:
      • Modified files and rationale for changes
      • Implementation approach
      • Key design decisions and alternatives considered
      • ...
  3. Documentation Repo Updates

    • Open a corresponding issue in the documentation repo
    • Submit a PR with necessary documentation changes

I am really thankful for your guidance on reducing dependencies on Collectors and Collections - I will incorporate your suggestions in my upcoming changes. The hints you have provided in the comments are especially helpful.


List<BibEntry> filteredEntries = new ArrayList<>();

JournalAbbreviationRepository freshRepository = JournalAbbreviationLoader.loadRepository(journalAbbreviationPreferences);
Copy link
Member

Choose a reason for hiding this comment

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

We also had a question about this here - do you wish to create a new repository every time you want to call unabbreviate?
Or even more generally, should unabbreviate depend on preferences at all?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ability to disable the built-in JabRef journal abbreviation list
5 participants