Skip to content

Commit 0dc9d7d

Browse files
authored
Use a Tag Field for Resolve strings and Do not wrap (#12876)
* Use a Tag Field for Resolve strings and Do not wrap * Updating ChangeLog.md * Added the ability to use custom tags * Fixing a leftover comment & a mistake in change llog I had accidently duplicated a line in the change log, and had left commented out code. * Fixing line breaks * Custom tags now always show up in suggestions * Added Custom Tag Support I used the KeywordEditor classes implementation for custom tags, and renamed the fields to match the naming convention I see elsewhere in the project. * Added Line Wrapping Added wrapping for "Affected Fields" & "Do not wrap when saving" lables within the Entry tab of preferences.
1 parent d089f9f commit 0dc9d7d

File tree

4 files changed

+102
-22
lines changed

4 files changed

+102
-22
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
6262
- A tooltip now appears after 300ms (instead of 2s). [#12649](https://github.com/JabRef/jabref/issues/12649)
6363
- We improved search in preferences and keybindings. [#12647](https://github.com/JabRef/jabref/issues/12647)
6464
- We improved the performance of the LibreOffice integration when inserting CSL citations/bibliography. [#12851](https://github.com/JabRef/jabref/pull/12851)
65+
- 'Affected fields' and 'Do not wrap when saving' are now displayed as tags. [#12550](https://github.com/JabRef/jabref/issues/12550)
6566

6667
### Fixed
6768

src/main/java/org/jabref/gui/preferences/entry/EntryTab.fxml

+7-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<?import javafx.scene.control.Tooltip?>
99
<?import javafx.scene.layout.HBox?>
1010
<?import javafx.scene.layout.VBox?>
11+
<?import com.dlsc.gemsfx.TagsField?>
1112
<fx:root spacing="10.0" type="VBox"
1213
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
1314
fx:controller="org.jabref.gui.preferences.entry.EntryTab">
@@ -22,21 +23,22 @@
2223

2324
<CheckBox fx:id="resolveStrings" text="%Resolve BibTeX strings"/>
2425
<HBox alignment="CENTER_LEFT" spacing="10.0">
25-
<Label text="%Affected fields"/>
26-
<TextField fx:id="resolveStringsForFields" HBox.hgrow="ALWAYS"
26+
<Label text="%Affected fields" wrapText="true"/>
27+
<TagsField fx:id="resolvableTagsField" HBox.hgrow="ALWAYS"
2728
disable="${!resolveStrings.selected}">
2829
<HBox.margin>
2930
<Insets top="-4.0"/>
3031
</HBox.margin>
31-
</TextField>
32+
</TagsField>
3233
<padding>
3334
<Insets left="20.0"/>
3435
</padding>
3536
</HBox>
3637

3738
<HBox alignment="CENTER_LEFT" spacing="10.0">
38-
<Label text="%Do not wrap when saving"/>
39-
<TextField fx:id="nonWrappableFields" HBox.hgrow="ALWAYS"/>
39+
<Label text="%Do not wrap when saving" wrapText="true"/>
40+
<TagsField fx:id="nonWrappableTagsField" HBox.hgrow="ALWAYS">
41+
</TagsField>
4042
</HBox>
4143

4244
<Label styleClass="sectionHeader" text="%Entry owner"/>

src/main/java/org/jabref/gui/preferences/entry/EntryTab.java

+48-6
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,40 @@
22

33
import java.util.function.UnaryOperator;
44

5+
import javafx.css.PseudoClass;
56
import javafx.fxml.FXML;
7+
import javafx.scene.Node;
68
import javafx.scene.control.Button;
79
import javafx.scene.control.CheckBox;
10+
import javafx.scene.control.ContentDisplay;
11+
import javafx.scene.control.Label;
812
import javafx.scene.control.TextField;
913
import javafx.scene.control.TextFormatter;
14+
import javafx.scene.input.KeyCode;
1015

1116
import org.jabref.gui.actions.ActionFactory;
1217
import org.jabref.gui.actions.StandardActions;
1318
import org.jabref.gui.help.HelpAction;
19+
import org.jabref.gui.icon.IconTheme;
1420
import org.jabref.gui.preferences.AbstractPreferenceTabView;
1521
import org.jabref.gui.preferences.PreferencesTab;
22+
import org.jabref.gui.util.ViewModelListCellFactory;
1623
import org.jabref.logic.help.HelpFile;
1724
import org.jabref.logic.l10n.Localization;
25+
import org.jabref.model.entry.field.Field;
1826

1927
import com.airhacks.afterburner.views.ViewLoader;
28+
import com.dlsc.gemsfx.TagsField;
2029

2130
public class EntryTab extends AbstractPreferenceTabView<EntryTabViewModel> implements PreferencesTab {
22-
23-
31+
private static final PseudoClass FOCUSED = PseudoClass.getPseudoClass("focused");
2432

2533
@FXML private TextField keywordSeparator;
2634

2735
@FXML private CheckBox resolveStrings;
28-
@FXML private TextField resolveStringsForFields;
29-
@FXML private TextField nonWrappableFields;
36+
37+
@FXML private TagsField<Field> resolvableTagsField;
38+
@FXML private TagsField<Field> nonWrappableTagsField;
3039

3140
@FXML private CheckBox markOwner;
3241
@FXML private TextField markOwnerName;
@@ -59,8 +68,11 @@ public void initialize() {
5968
keywordSeparator.setTextFormatter(formatter);
6069

6170
resolveStrings.selectedProperty().bindBidirectional(viewModel.resolveStringsProperty());
62-
resolveStringsForFields.textProperty().bindBidirectional(viewModel.resolveStringsForFieldsProperty());
63-
nonWrappableFields.textProperty().bindBidirectional(viewModel.nonWrappableFieldsProperty());
71+
72+
setupTagsField(resolvableTagsField);
73+
setupTagsField(nonWrappableTagsField);
74+
resolvableTagsField.tagsProperty().bindBidirectional(viewModel.resolvableTagsFieldProperty());
75+
nonWrappableTagsField.tagsProperty().bindBidirectional(viewModel.nonWrappableTagsFieldProperty());
6476

6577
markOwner.selectedProperty().bindBidirectional(viewModel.markOwnerProperty());
6678
markOwnerName.textProperty().bindBidirectional(viewModel.markOwnerNameProperty());
@@ -75,6 +87,36 @@ public void initialize() {
7587
actionFactory.configureIconButton(StandardActions.HELP, new HelpAction(HelpFile.OWNER, dialogService, preferences.getExternalApplicationsPreferences()), markOwnerHelp);
7688
}
7789

90+
private void setupTagsField(TagsField<Field> tagsField) {
91+
tagsField.setCellFactory(new ViewModelListCellFactory<Field>().withText(Field::getDisplayName));
92+
tagsField.setTagViewFactory(field -> createTag(tagsField, field));
93+
94+
tagsField.setSuggestionProvider(request -> viewModel.getSuggestions(request.getUserText()));
95+
tagsField.setConverter(viewModel.getFieldStringConverter());
96+
97+
tagsField.setShowSearchIcon(false);
98+
tagsField.setOnMouseClicked(event -> tagsField.getEditor().requestFocus());
99+
tagsField.getEditor().getStyleClass().clear();
100+
tagsField.getEditor().getStyleClass().add("tags-field-editor");
101+
tagsField.getEditor().focusedProperty().addListener((_, _, newValue) -> tagsField.pseudoClassStateChanged(FOCUSED, newValue));
102+
103+
tagsField.getEditor().setOnKeyReleased(event -> {
104+
if (event.getCode() == KeyCode.ENTER) {
105+
tagsField.commit();
106+
event.consume();
107+
}
108+
});
109+
}
110+
111+
private Node createTag(TagsField<Field> tagsField, Field field) {
112+
Label tagLabel = new Label();
113+
tagLabel.setText(field.getDisplayName());
114+
tagLabel.setGraphic(IconTheme.JabRefIcons.REMOVE_TAGS.getGraphicNode());
115+
tagLabel.getGraphic().setOnMouseClicked(event -> tagsField.removeTags(field));
116+
tagLabel.setContentDisplay(ContentDisplay.RIGHT);
117+
return tagLabel;
118+
}
119+
78120
@Override
79121
public String getTabName() {
80122
return Localization.lang("Entry");

src/main/java/org/jabref/gui/preferences/entry/EntryTabViewModel.java

+46-11
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
package org.jabref.gui.preferences.entry;
22

3+
import java.util.List;
4+
import java.util.stream.Collectors;
5+
36
import javafx.beans.property.BooleanProperty;
7+
import javafx.beans.property.ListProperty;
48
import javafx.beans.property.SimpleBooleanProperty;
9+
import javafx.beans.property.SimpleListProperty;
510
import javafx.beans.property.SimpleStringProperty;
611
import javafx.beans.property.StringProperty;
12+
import javafx.collections.FXCollections;
13+
import javafx.util.StringConverter;
714

815
import org.jabref.gui.preferences.PreferenceTabViewModel;
916
import org.jabref.logic.bibtex.FieldPreferences;
1017
import org.jabref.logic.preferences.CliPreferences;
1118
import org.jabref.logic.preferences.OwnerPreferences;
1219
import org.jabref.logic.preferences.TimestampPreferences;
1320
import org.jabref.model.entry.BibEntryPreferences;
21+
import org.jabref.model.entry.field.Field;
1422
import org.jabref.model.entry.field.FieldFactory;
1523

1624
public class EntryTabViewModel implements PreferenceTabViewModel {
1725

1826
private final StringProperty keywordSeparatorProperty = new SimpleStringProperty("");
1927

2028
private final BooleanProperty resolveStringsProperty = new SimpleBooleanProperty();
21-
private final StringProperty resolveStringsForFieldsProperty = new SimpleStringProperty("");
22-
private final StringProperty nonWrappableFieldsProperty = new SimpleStringProperty("");
29+
30+
private final ListProperty<Field> resolvableTagsFieldProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
31+
private final ListProperty<Field> nonWrappableTagsFieldProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
2332

2433
private final BooleanProperty markOwnerProperty = new SimpleBooleanProperty();
2534
private final StringProperty markOwnerNameProperty = new SimpleStringProperty("");
@@ -44,8 +53,8 @@ public void setValues() {
4453
keywordSeparatorProperty.setValue(bibEntryPreferences.getKeywordSeparator().toString());
4554

4655
resolveStringsProperty.setValue(fieldPreferences.shouldResolveStrings());
47-
resolveStringsForFieldsProperty.setValue(FieldFactory.serializeFieldsList(fieldPreferences.getResolvableFields()));
48-
nonWrappableFieldsProperty.setValue(FieldFactory.serializeFieldsList(fieldPreferences.getNonWrappableFields()));
56+
resolvableTagsFieldProperty.setValue(FXCollections.observableArrayList(fieldPreferences.getResolvableFields()));
57+
nonWrappableTagsFieldProperty.setValue(FXCollections.observableArrayList(fieldPreferences.getNonWrappableFields()));
4958

5059
markOwnerProperty.setValue(ownerPreferences.isUseOwner());
5160
markOwnerNameProperty.setValue(ownerPreferences.getDefaultOwner());
@@ -60,8 +69,8 @@ public void storeSettings() {
6069
bibEntryPreferences.keywordSeparatorProperty().setValue(keywordSeparatorProperty.getValue().charAt(0));
6170

6271
fieldPreferences.setResolveStrings(resolveStringsProperty.getValue());
63-
fieldPreferences.setResolvableFields(FieldFactory.parseFieldList(resolveStringsForFieldsProperty.getValue().trim()));
64-
fieldPreferences.setNonWrappableFields(FieldFactory.parseFieldList(nonWrappableFieldsProperty.getValue().trim()));
72+
fieldPreferences.setResolvableFields(resolvableTagsFieldProperty.getValue());
73+
fieldPreferences.setNonWrappableFields(resolvableTagsFieldProperty.getValue());
6574

6675
ownerPreferences.setUseOwner(markOwnerProperty.getValue());
6776
ownerPreferences.setDefaultOwner(markOwnerNameProperty.getValue());
@@ -79,16 +88,15 @@ public BooleanProperty resolveStringsProperty() {
7988
return resolveStringsProperty;
8089
}
8190

82-
public StringProperty resolveStringsForFieldsProperty() {
83-
return resolveStringsForFieldsProperty;
91+
public ListProperty<Field> resolvableTagsFieldProperty() {
92+
return resolvableTagsFieldProperty;
8493
}
8594

86-
public StringProperty nonWrappableFieldsProperty() {
87-
return nonWrappableFieldsProperty;
95+
public ListProperty<Field> nonWrappableTagsFieldProperty() {
96+
return nonWrappableTagsFieldProperty;
8897
}
8998

9099
// Entry owner
91-
92100
public BooleanProperty markOwnerProperty() {
93101
return this.markOwnerProperty;
94102
}
@@ -110,4 +118,31 @@ public BooleanProperty addCreationDateProperty() {
110118
public BooleanProperty addModificationDateProperty() {
111119
return addModificationDateProperty;
112120
}
121+
122+
public StringConverter<Field> getFieldStringConverter() {
123+
return new StringConverter<>() {
124+
@Override
125+
public String toString(Field field) {
126+
return field.getDisplayName();
127+
}
128+
129+
@Override
130+
public Field fromString(String string) {
131+
return FieldFactory.parseField(string);
132+
}
133+
};
134+
}
135+
136+
public List<Field> getSuggestions(String request) {
137+
List<Field> suggestions = FieldFactory.getAllFieldsWithOutInternal().stream()
138+
.filter(field -> field.getDisplayName().toLowerCase().contains(request.toLowerCase()))
139+
.collect(Collectors.toList());
140+
141+
Field requestedField = FieldFactory.parseField(request.trim());
142+
if (!suggestions.contains(requestedField)) {
143+
suggestions.addFirst(requestedField);
144+
}
145+
146+
return suggestions;
147+
}
113148
}

0 commit comments

Comments
 (0)