Skip to content

Show compound patterns in the dropdown for citation key patterns #12580

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jabref.gui.commonfxcontrols;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -16,9 +17,13 @@
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.Window;

import org.jabref.gui.DialogService;
import org.jabref.logic.citationkeypattern.CitationKeyPattern;
import org.jabref.logic.l10n.Localization;

import com.airhacks.afterburner.injection.Injector;
import jakarta.inject.Inject;

public class CitationKeyPatternSuggestionCell extends TextFieldTableCell<CitationKeyPatternsPanelItemModel, String> {
private final CitationKeyPatternSuggestionTextField searchField;

Expand Down Expand Up @@ -60,11 +65,22 @@ public void updateItem(String item, boolean empty) {
}

static class CitationKeyPatternSuggestionTextField extends TextField {
// Maximum number of entries that can be displayed in the popup menu.
private static final int MAX_ENTRIES = 7;

private final int ALL_PATTERNS_POSITION = 0;

private final List<String> citationKeyPatterns;
private final ContextMenu suggestionsList;
private int selectionCount = 0;
private int heightOfMenuItem;
private final StringBuilder selectedPatterns = new StringBuilder();
Copy link

Choose a reason for hiding this comment

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

StringBuilder is used for concatenating strings, which can be replaced with StringJoiner for better readability and maintainability.


@Inject private DialogService dialogService;

public CitationKeyPatternSuggestionTextField(List<String> citationKeyPatterns) {
Injector.registerExistingAndInject(this);

this.citationKeyPatterns = new ArrayList<>(citationKeyPatterns);
this.suggestionsList = new ContextMenu();
// Initial reasonable estimate before the menu items are populated. We overwrite this dynamically
Expand Down Expand Up @@ -93,11 +109,14 @@ private void setListener() {
} else {
suggestionsList.hide();
}
createCompoundPatternsSubMenu();
}
});

focusedProperty().addListener((observable, oldValue, newValue) -> {
suggestionsList.hide();
if (!newValue) {
suggestionsList.hide();
}
Comment on lines +117 to +119
Copy link

Choose a reason for hiding this comment

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

The code should follow the fail-fast principle by immediately handling invalid states and returning early instead of nesting logic inside else branches.

});
}

Expand All @@ -112,7 +131,6 @@ private void populatePopup(List<String> searchResult) {
for (int i = 0; i < count; i++) {
final String result = searchResult.get(i);
Label entryLabel = new Label(result);
entryLabel.setPrefWidth(getWidth());

CustomMenuItem item = new CustomMenuItem(entryLabel, true);
item.setHideOnClick(false);
Expand All @@ -131,7 +149,8 @@ private void populatePopup(List<String> searchResult) {
}

suggestionsList.getItems().clear();
suggestionsList.getItems().add(createPatternsSubMenu());
suggestionsList.getItems().add(ALL_PATTERNS_POSITION, createPatternsSubMenu());
Copy link

Choose a reason for hiding this comment

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

The use of magic numbers like ALL_PATTERNS_POSITION should be avoided. Consider using a more descriptive constant or comment.

suggestionsList.getItems().add(ALL_PATTERNS_POSITION + 1, createCompoundPatternsSubMenu());
suggestionsList.getItems().addAll(menuItems);

if (!menuItems.isEmpty()) {
Expand Down Expand Up @@ -163,13 +182,12 @@ private Menu createPatternsSubMenu() {
CitationKeyPattern.getAllPatterns().stream()
.collect(Collectors.groupingBy(CitationKeyPattern::getCategory));

Map<CitationKeyPattern.Category, String> categoryNames = Map.of(
CitationKeyPattern.Category.AUTHOR_RELATED, Localization.lang("Author related"),
CitationKeyPattern.Category.EDITOR_RELATED, Localization.lang("Editor related"),
CitationKeyPattern.Category.TITLE_RELATED, Localization.lang("Title related"),
CitationKeyPattern.Category.OTHER_FIELDS, Localization.lang("Other fields"),
CitationKeyPattern.Category.BIBENTRY_FIELDS, Localization.lang("Entry fields")
);
Map<CitationKeyPattern.Category, String> categoryNames = new LinkedHashMap<>();
categoryNames.put(CitationKeyPattern.Category.AUTHOR_RELATED, Localization.lang("Author related"));
Copy link

Choose a reason for hiding this comment

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

The localization strings should be prefixed with % for proper localization handling in JabRef.

categoryNames.put(CitationKeyPattern.Category.EDITOR_RELATED, Localization.lang("Editor related"));
categoryNames.put(CitationKeyPattern.Category.TITLE_RELATED, Localization.lang("Title related"));
categoryNames.put(CitationKeyPattern.Category.OTHER_FIELDS, Localization.lang("Other fields"));
categoryNames.put(CitationKeyPattern.Category.BIBENTRY_FIELDS, Localization.lang("Entry fields"));

for (Map.Entry<CitationKeyPattern.Category, String> entry : categoryNames.entrySet()) {
CitationKeyPattern.Category category = entry.getKey();
Expand All @@ -191,5 +209,62 @@ private Menu createPatternsSubMenu() {
}
return patternsSubMenu;
}

private Menu createCompoundPatternsSubMenu() {
Menu compoundPatternsSubMenu = new Menu(Localization.lang("Create compound pattern"));

Map<CitationKeyPattern.Category, List<CitationKeyPattern>> categorizedPatterns =
CitationKeyPattern.getAllPatterns().stream()
.collect(Collectors.groupingBy(CitationKeyPattern::getCategory));

Map<CitationKeyPattern.Category, String> categoryNames = new LinkedHashMap<>();
categoryNames.put(CitationKeyPattern.Category.AUTHOR_RELATED, Localization.lang("Author related"));
categoryNames.put(CitationKeyPattern.Category.EDITOR_RELATED, Localization.lang("Editor related"));
categoryNames.put(CitationKeyPattern.Category.TITLE_RELATED, Localization.lang("Title related"));
categoryNames.put(CitationKeyPattern.Category.OTHER_FIELDS, Localization.lang("Other fields"));
categoryNames.put(CitationKeyPattern.Category.BIBENTRY_FIELDS, Localization.lang("Entry fields"));

for (Map.Entry<CitationKeyPattern.Category, String> entry : categoryNames.entrySet()) {
CitationKeyPattern.Category category = entry.getKey();
String categoryName = entry.getValue();

Menu categoryMenu = new Menu(categoryName);
List<CitationKeyPattern> patterns = categorizedPatterns.getOrDefault(category, List.of());

for (CitationKeyPattern pattern : patterns) {
MenuItem menuItem = new MenuItem(pattern.stringRepresentation());
menuItem.setOnAction(event -> {
setText(pattern.stringRepresentation());
positionCaret(pattern.stringRepresentation().length());
suggestionsList.hide();

if (selectionCount == 0) {
selectionCount++;
selectedPatterns.append(pattern.stringRepresentation());
setText(selectedPatterns.toString());
positionCaret(selectedPatterns.length());
dialogService.notify(Localization.lang("Select one more item to create a compound pattern."));
if (getScene() != null) {
suggestionsList.getItems().remove(ALL_PATTERNS_POSITION);
double screenX = localToScreen(0, 0).getX();
double screenY = localToScreen(0, 0).getY() + getHeight();
suggestionsList.show(this, screenX, screenY);
}
} else if (selectionCount == 1) {
selectedPatterns.append("_").append(pattern.stringRepresentation());
Copy link
Member

Choose a reason for hiding this comment

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

Not sure how this whole things works. Somewhere, it should be explained, how selectedPatterns is inteded to be sued.

setText(selectedPatterns.toString());
positionCaret(selectedPatterns.length());
suggestionsList.hide();
selectionCount = 0;
selectedPatterns.setLength(0);
Copy link
Member

Choose a reason for hiding this comment

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

Not understandable at first sight - comment needed.

}
});
categoryMenu.getItems().add(menuItem);
}
compoundPatternsSubMenu.getItems().add(categoryMenu);
}

return compoundPatternsSubMenu;
}
}
}
2 changes: 2 additions & 0 deletions src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2874,11 +2874,13 @@ Entries\ copied\ successfully,\ without\ cross-references.=Entries copied succes
Ask\ whether\ to\ include\ cross-references\ when\ copying\ to\ another\ library=Ask whether to include cross-references when copying to another library

All\ patterns=All patterns
Create\ compound\ pattern=Create compound pattern
Author\ related=Author related
Editor\ related=Editor related
Title\ related=Title related
Entry\ fields=Entry fields

Select\ one\ more\ item\ to\ create\ a\ compound\ pattern.=Select one more item to create a compound pattern.
Add\ example\ entry=Add example entry
No\ content\ in\ table=No content in table
Import\ existing\ PDFs=Import existing PDFs
Expand Down