Skip to content
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

Add drop down for citation key patterns #12516

Merged
merged 19 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.jabref.gui.commonfxcontrols;

import java.util.List;
import java.util.stream.Collectors;

import javafx.collections.FXCollections;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.Popup;

public class CitationKeyPatternSuggestionCell extends TextFieldTableCell<CitationKeyPatternsPanelItemModel, String> {
private final TextField searchField = new TextField();
private final ListView<String> suggestionList = new ListView<>();
private final Popup popup = new Popup();

private final List<String> fullData;

public CitationKeyPatternSuggestionCell(List<String> fullData) {
this.fullData = fullData;
popup.getContent().add(suggestionList);
popup.setAutoHide(true);

searchField.textProperty().addListener((obs, oldVal, newVal) -> {
List<String> filtered = fullData.stream()
.filter(item -> item.toLowerCase().contains(newVal.toLowerCase()))
.collect(Collectors.toList());

suggestionList.setItems(FXCollections.observableArrayList(filtered));
if (!filtered.isEmpty()) {
popup.show(searchField, searchField.localToScreen(0, searchField.getHeight()).getX(),
searchField.localToScreen(0, searchField.getHeight() * 2).getY());
} else {
popup.hide();
}
});

suggestionList.setOnMouseClicked(event -> {
String selected = suggestionList.getSelectionModel().getSelectedItem();
if (selected != null) {
searchField.setText(selected);
popup.hide();
}
});

searchField.setOnAction(event -> commitEdit(searchField.getText()));
}

@Override
public void startEdit() {
super.startEdit();
searchField.setText(getItem());
setGraphic(searchField);
searchField.requestFocus();
}

@Override
public void cancelEdit() {
super.cancelEdit();
setGraphic(null);
popup.hide();
}

@Override
public void commitEdit(String newValue) {
super.commitEdit(newValue);
getTableView().getItems().get(getIndex()).setPattern(newValue);
setGraphic(null);
}

@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
setText(null);
} else {
setText(item);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;

import org.jabref.gui.icon.IconTheme;
Expand All @@ -27,6 +30,8 @@ public class CitationKeyPatternsPanel extends TableView<CitationKeyPatternsPanel
@FXML public TableColumn<CitationKeyPatternsPanelItemModel, EntryType> entryTypeColumn;
@FXML public TableColumn<CitationKeyPatternsPanelItemModel, String> patternColumn;
@FXML public TableColumn<CitationKeyPatternsPanelItemModel, EntryType> actionsColumn;
@FXML private TextField searchField;
@FXML private ListView<String> suggestionList;

@Inject private CliPreferences preferences;

Expand Down Expand Up @@ -58,10 +63,15 @@ private void initialize() {
this.setOnSort(event ->
viewModel.patternListProperty().sort(CitationKeyPatternsPanelViewModel.defaultOnTopComparator));

ObservableList<String> fullData = FXCollections.observableArrayList(
"[auth]", "[authFirstFull]", "[authForeIni]", "[auth.etal]", "[authEtAl]",
"[auth.auth.ea]", "[authors]", "[authorsN]", "[authIniN]", "[authN]", "[authN_M]",
"[authorIni]", "[authshort]", "[authorsAlpha]");
Copy link
Member

@subhramit subhramit Feb 16, 2025

Choose a reason for hiding this comment

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

Also add [authorsAlphaLNI] (added in #12499).
Also, the issue asks for special field markers, which also includes Editor-related field markers, Title-related field markers, Other field markers and Bibentry fields apart from the author-related ones. Please add them as well.

Copy link
Member

Choose a reason for hiding this comment

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

We should either think how to auto-populate this list - or add a Java comment on how to populate the list manually.

Copy link
Member

@subhramit subhramit Feb 17, 2025

Choose a reason for hiding this comment

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

Yes, @priyanshu16095 - lets make this neat.
This is what I brainstormed, need a second opinion from @Siedlerchr and @koppor so that we know this is the best way and doesn't break things:
There is a record class, CitationKeyPatterns.java.

  1. Modify it to make it a final class.
  2. Hardcode the patterns as constants there. Leave proper comments with //region - citation key patterns offered. for any new pattern, add them here and // endregion below.
  3. Make a public static function getAllPatterns, see if this works (I chatgpt'd this snippet - make any modifications needed):
Arrays.stream(CitationKeyPatterns.class.getDeclaredFields())
             .filter(field -> {
                 int modifiers = field.getModifiers();
                 return Modifier.isPublic(modifiers) && 
                        Modifier.isStatic(modifiers) && 
                        Modifier.isFinal(modifiers) &&
                        field.getType() == CitationKeyPattern.class &&
                        field != CitationKeyPattern.NULL_CITATION_KEY_PATTERN;
             })
             .map(field -> {
                 try {
                     return (CitationKeyPattern) field.get(null);
                 } catch (IllegalAccessException e) {
                     throw new RuntimeException("Could not access field", e);
                 }
             })
             .collect(Collectors.toList());
  1. Use that list returned in your observable array list

This way, the developer has to just change one line when adding a new pattern, without the overhead of finding the list where patterns are populated, or just using raw strings or using constants (you have to put them everywhere otherwise).

Copy link
Member

Choose a reason for hiding this comment

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

Actually no need to even change the class type. You can add the method in the record itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure! Great suggestions, thanks!


patternColumn.setSortable(true);
patternColumn.setReorderable(false);
patternColumn.setCellValueFactory(cellData -> cellData.getValue().pattern());
patternColumn.setCellFactory(TextFieldTableCell.forTableColumn());
patternColumn.setCellFactory(column -> new CitationKeyPatternSuggestionCell(fullData));
patternColumn.setEditable(true);
patternColumn.setOnEditCommit(
(TableColumn.CellEditEvent<CitationKeyPatternsPanelItemModel, String> event) ->
Expand Down
Loading