diff --git a/CHANGELOG.md b/CHANGELOG.md index 8800794bdf4..939d375f7c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,10 +39,10 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed a problem where the "editor" information has been duplicated during saving a .bib-Database. [#5359](https://github.com/JabRef/jabref/issues/5359) - We re-introduced the feature to switch between different preview styles. [#5221](https://github.com/JabRef/jabref/issues/5221) - We fixed various issues (including [#5263](https://github.com/JabRef/jabref/issues/5263)) related to copying entries to the clipboard +- We fixed some display errors in the preferences dialog and replaced some of the controls [#5033](https://github.com/JabRef/jabref/pull/5033) [#5047](https://github.com/JabRef/jabref/pull/5047) [#5062](https://github.com/JabRef/jabref/pull/5062) [#5141](https://github.com/JabRef/jabref/pull/5141) [#5185](https://github.com/JabRef/jabref/pull/5185) [#5265](https://github.com/JabRef/jabref/pull/5265) [#5315](https://github.com/JabRef/jabref/pull/5315) [#5360](https://github.com/JabRef/jabref/pull/5360) - We fixed an exception which occurred when trying to import entries without an open library. [#5447](https://github.com/JabRef/jabref/issues/5447) - ### Removed diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 35f32a1c71c..42042f8d668 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -1059,7 +1059,3 @@ We want to have a look that matches our icons in the tool-bar */ .dialog-pane { -fx-background-color: -fx-control-inner-background; } - -.preference-sidepane { - -fx-background-color: -jr-sidepane-background; -} diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java index 3246ff21267..b6f7c913d66 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java @@ -40,6 +40,26 @@ private void init() { return null; }); + // Keep this for later conversion of the library-properties +/* void storeSettings() { + DataBaseKeyPattern newKeyPattern = new DatabaseBibtexKeyPattern(preferences.getKeyPattern()); + + bibtexKeyPatternTableView.patternListProperty.forEach(item -> { + String patternString = item.getPattern(); + if (!item.getEntryType().getName().equals("default")) { + if (!patternString.trim().isEmpty()) { + newKeyPattern.addBibtexKeyPattern(item.getEntryType(), patternString); + } + } + }); + + if (!defaultItem.getPattern().trim().isEmpty()) { + // we do not trim the value at the assignment to enable users to have spaces at the beginning and + // at the end of the pattern + newKeyPattern.setDefaultValue(defaultItemProperty.getPattern()); + } + } */ + } } diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java index 34c1fd863b6..7a5123476bb 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java @@ -19,7 +19,6 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; import org.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern; -import org.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.types.EntryType; @@ -118,12 +117,6 @@ private void buildGUI() { gridPane.add(btnDefaultAll1, 2, rowIndex); } - protected GlobalBibtexKeyPattern getKeyPatternAsGlobalBibtexKeyPattern() { - GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern(Globals.prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); - fillPatternUsingPanelData(res); - return res; - } - public DatabaseBibtexKeyPattern getKeyPatternAsDatabaseBibtexKeyPattern() { DatabaseBibtexKeyPattern res = new DatabaseBibtexKeyPattern(Globals.prefs.getKeyPattern()); fillPatternUsingPanelData(res); diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTable.fxml b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTable.fxml new file mode 100644 index 00000000000..a905a82060b --- /dev/null +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTable.fxml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableItemModel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableItemModel.java new file mode 100644 index 00000000000..7431346de46 --- /dev/null +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableItemModel.java @@ -0,0 +1,39 @@ +package org.jabref.gui.bibtexkeypattern; + +import java.util.Objects; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import org.jabref.model.entry.types.EntryType; + +public class BibtexKeyPatternTableItemModel { + private final ObjectProperty entryType = new SimpleObjectProperty<>(); + private final StringProperty pattern = new SimpleStringProperty(""); + + public BibtexKeyPatternTableItemModel(EntryType entryType, String pattern) { + Objects.requireNonNull(entryType); + Objects.requireNonNull(pattern); + this.entryType.setValue(entryType); + this.pattern.setValue(pattern); + } + + public EntryType getEntryType() { return entryType.getValue(); } + + public ObjectProperty entryType() { return entryType; } + + public void setPattern(String pattern) { + this.pattern.setValue(pattern); + } + + public String getPattern() { + return pattern.getValue(); + } + + public StringProperty pattern() { return pattern; } + + @Override + public String toString() { return "[" + entryType.getValue().getName() + "," + pattern.getValue() + "]"; } +} diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableView.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableView.java new file mode 100644 index 00000000000..124e8b8c48c --- /dev/null +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableView.java @@ -0,0 +1,123 @@ +package org.jabref.gui.bibtexkeypattern; + +import java.util.Collection; + +import javafx.beans.property.ListProperty; +import javafx.beans.property.ObjectProperty; +import javafx.fxml.FXML; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.TextFieldTableCell; +import javafx.scene.input.KeyEvent; + +import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.util.ValueTableCellFactory; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; +import org.jabref.model.entry.BibEntryType; +import org.jabref.model.entry.types.EntryType; +import org.jabref.preferences.JabRefPreferences; + +import com.airhacks.afterburner.views.ViewLoader; + +public class BibtexKeyPatternTableView extends TableView { + + @FXML public TableColumn entryTypeColumn; + @FXML public TableColumn patternColumn; + @FXML public TableColumn actionsColumn; + + private BibtexKeyPatternTableViewModel viewModel; + + private long lastKeyPressTime; + private String tableSearchTerm; + + public BibtexKeyPatternTableView(JabRefPreferences preferences, Collection entryTypeList, AbstractBibtexKeyPattern keyPattern) { + super(); + + viewModel = new BibtexKeyPatternTableViewModel(preferences, entryTypeList, keyPattern); + + ViewLoader.view(this) + .root(this) + .load(); + } + + @FXML + private void initialize() { + this.setEditable(true); + + entryTypeColumn.setSortable(true); + entryTypeColumn.setReorderable(false); + entryTypeColumn.setCellValueFactory(cellData -> cellData.getValue().entryType()); + new ValueTableCellFactory() + .withText(EntryType::getDisplayName) + .install(entryTypeColumn); + this.setOnSort(event -> + viewModel.patternListProperty().sort(BibtexKeyPatternTableViewModel.defaultOnTopComparator)); + + patternColumn.setSortable(true); + patternColumn.setReorderable(false); + patternColumn.setCellValueFactory(cellData -> cellData.getValue().pattern()); + patternColumn.setCellFactory(TextFieldTableCell.forTableColumn()); + patternColumn.setEditable(true); + patternColumn.setOnEditCommit( + (TableColumn.CellEditEvent event) -> + event.getRowValue().setPattern(event.getNewValue())); + + actionsColumn.setSortable(false); + actionsColumn.setReorderable(false); + actionsColumn.setCellValueFactory(cellData -> cellData.getValue().entryType()); + new ValueTableCellFactory() + .withGraphic(entryType -> IconTheme.JabRefIcons.REFRESH.getGraphicNode()) + .withTooltip(entryType -> + String.format(Localization.lang("Reset %s to default value"), entryType.getDisplayName())) + .withOnMouseClickedEvent(item -> evt -> + viewModel.setItemToDefaultPattern(this.getFocusModel().getFocusedItem())) + .install(actionsColumn); + + this.setRowFactory(item -> new HighlightTableRow()); + this.setOnKeyTyped(this::jumpToSearchKey); + this.itemsProperty().bindBidirectional(viewModel.patternListProperty()); + } + + public void setValues() { viewModel.setValues(); } + + public void resetAll() { viewModel.resetAll(); } + + public ListProperty patternListProperty() { return viewModel.patternListProperty(); } + + public ObjectProperty defaultKeyPatternProperty() { return viewModel.defaultKeyPatternProperty(); } + + private void jumpToSearchKey(KeyEvent keypressed) { + if (keypressed.getCharacter() == null) { + return; + } + + if (System.currentTimeMillis() - lastKeyPressTime < 1000) { + tableSearchTerm += keypressed.getCharacter().toLowerCase(); + } else { + tableSearchTerm = keypressed.getCharacter().toLowerCase(); + } + + lastKeyPressTime = System.currentTimeMillis(); + + this.getItems().stream().filter(item -> item.getEntryType().getName().toLowerCase().startsWith(tableSearchTerm)) + .findFirst().ifPresent(this::scrollTo); + } + + private static class HighlightTableRow extends TableRow { + @Override + public void updateItem(BibtexKeyPatternTableItemModel item, boolean empty) { + super.updateItem(item, empty); + if (item == null || item.getEntryType() == null) { + setStyle(""); + } else if (isSelected()) { + setStyle("-fx-background-color: -fx-selection-bar"); + } else if (item.getEntryType().getName().equals(BibtexKeyPatternTableViewModel.ENTRY_TYPE_DEFAULT_NAME)) { + setStyle("-fx-background-color: -fx-default-button"); + } else { + setStyle(""); + } + } + } +} diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableViewModel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableViewModel.java new file mode 100644 index 00000000000..971347b4b3f --- /dev/null +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternTableViewModel.java @@ -0,0 +1,94 @@ +package org.jabref.gui.bibtexkeypattern; + +import java.util.Collection; +import java.util.Comparator; + +import javafx.beans.property.ListProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; + +import org.jabref.logic.l10n.Localization; +import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; +import org.jabref.model.entry.BibEntryType; +import org.jabref.model.entry.types.EntryType; +import org.jabref.preferences.JabRefPreferences; + +public class BibtexKeyPatternTableViewModel { + + public static final String ENTRY_TYPE_DEFAULT_NAME = "default"; + + public static Comparator defaultOnTopComparator = (o1, o2) -> { + String itemOneName = o1.getEntryType().getName(); + String itemTwoName = o2.getEntryType().getName(); + + if (itemOneName.equals(itemTwoName)) { + return 0; + } else if (itemOneName.equals(ENTRY_TYPE_DEFAULT_NAME)) { + return -1; + } else if (itemTwoName.equals(ENTRY_TYPE_DEFAULT_NAME)) { + return 1; + } + + return 0; + }; + + private final ListProperty patternListProperty = new SimpleListProperty<>(); + private final ObjectProperty defaultItemProperty = new SimpleObjectProperty<>(); + private final AbstractBibtexKeyPattern initialKeyPattern; + private final Collection bibEntryTypeList; + private final JabRefPreferences preferences; + + public BibtexKeyPatternTableViewModel(JabRefPreferences preferences, Collection entryTypeList, AbstractBibtexKeyPattern initialKeyPattern) { + this.preferences = preferences; + this.bibEntryTypeList = entryTypeList; + this.initialKeyPattern = initialKeyPattern; + } + + public void setValues() { + String defaultPattern; + if ((initialKeyPattern.getDefaultValue() == null) || initialKeyPattern.getDefaultValue().isEmpty()) { + defaultPattern = ""; + } else { + defaultPattern = initialKeyPattern.getDefaultValue().get(0); + } + + defaultItemProperty.setValue(new BibtexKeyPatternTableItemModel(new DefaultEntryType(), defaultPattern)); + patternListProperty.setValue(FXCollections.observableArrayList()); + patternListProperty.add(defaultItemProperty.getValue()); + + bibEntryTypeList.stream() + .map(BibEntryType::getType) + .forEach(entryType -> { + String pattern; + if (initialKeyPattern.isDefaultValue(entryType)) { + pattern = ""; + } else { + pattern = initialKeyPattern.getPatterns().get(entryType).get(0); + } + patternListProperty.add(new BibtexKeyPatternTableItemModel(entryType, pattern)); + }); + } + + public void setItemToDefaultPattern(BibtexKeyPatternTableItemModel item) { + item.setPattern((String) preferences.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); + } + + public void resetAll() { + patternListProperty.forEach(item -> item.setPattern("")); + defaultItemProperty.getValue().setPattern((String) preferences.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); + } + + public ListProperty patternListProperty() { return patternListProperty; } + + public ObjectProperty defaultKeyPatternProperty() { return defaultItemProperty; } + + public static class DefaultEntryType implements EntryType { + @Override + public String getName() { return ENTRY_TYPE_DEFAULT_NAME; } + + @Override + public String getDisplayName() { return Localization.lang("Default pattern"); } + } +} diff --git a/src/main/java/org/jabref/gui/preferences/AppearancePrefsTab.java b/src/main/java/org/jabref/gui/preferences/AppearancePrefsTab.java deleted file mode 100644 index 74f29edbe34..00000000000 --- a/src/main/java/org/jabref/gui/preferences/AppearancePrefsTab.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.jabref.gui.preferences; - -import java.util.ArrayList; -import java.util.List; - -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.CheckBox; -import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; -import javafx.scene.control.TextField; -import javafx.scene.control.ToggleGroup; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; - -import org.jabref.gui.DialogService; -import org.jabref.gui.util.ControlHelper; -import org.jabref.gui.util.ThemeLoader; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.strings.StringUtil; -import org.jabref.preferences.JabRefPreferences; - -class AppearancePrefsTab extends Pane implements PreferencesTab { - - private final JabRefPreferences prefs; - private final TextField fontSize; - private final CheckBox overrideFonts; - private final DialogService dialogService; - private final RadioButton lightTheme; - private final RadioButton darkTheme; - private final GridPane builder = new GridPane(); - - /** - * Customization of appearance parameters. - * - * @param prefs a JabRefPreferences value - */ - public AppearancePrefsTab(DialogService dialogService, JabRefPreferences prefs) { - this.dialogService = dialogService; - this.prefs = prefs; - builder.setVgap(8); - - overrideFonts = new CheckBox(Localization.lang("Override default font settings")); - fontSize = new TextField(); - fontSize.setTextFormatter(ControlHelper.getIntegerTextFormatter()); - Label fontSizeLabel = new Label(Localization.lang("Font size:")); - - ToggleGroup themeGroup = new ToggleGroup(); - lightTheme = new RadioButton("Light theme"); - lightTheme.setToggleGroup(themeGroup); - darkTheme = new RadioButton("Dark theme"); - darkTheme.setToggleGroup(themeGroup); - - String cssFileName = prefs.get(JabRefPreferences.FX_THEME); - if (StringUtil.isBlank(cssFileName) || ThemeLoader.MAIN_CSS.equalsIgnoreCase(cssFileName)) { - lightTheme.setSelected(true); - } else if (ThemeLoader.DARK_CSS.equals(cssFileName)) { - darkTheme.setSelected(true); - } - - // Font configuration - HBox fontBox = new HBox(); - fontBox.setSpacing(10); - fontBox.setAlignment(Pos.CENTER_LEFT); - fontBox.getChildren().setAll(overrideFonts, fontSizeLabel, fontSize); - builder.add(fontBox, 1, 2); - - // Theme configuration - HBox themeBox = new HBox(); - themeBox.setSpacing(10); - themeBox.setAlignment(Pos.CENTER_LEFT); - themeBox.getChildren().setAll(lightTheme, darkTheme); - builder.add(themeBox, 1, 4); - } - - @Override - public Node getBuilder() { - return builder; - } - - @Override - public void setValues() { - overrideFonts.setSelected(prefs.getBoolean(JabRefPreferences.OVERRIDE_DEFAULT_FONT_SIZE)); - fontSize.setText(String.valueOf(prefs.getInt(JabRefPreferences.MAIN_FONT_SIZE))); - } - - @Override - public void storeSettings() { - final boolean oldOverrideDefaultFontSize = prefs.getBoolean(JabRefPreferences.OVERRIDE_DEFAULT_FONT_SIZE); - final int oldFontSize = prefs.getInt(JabRefPreferences.MAIN_FONT_SIZE); - prefs.putBoolean(JabRefPreferences.OVERRIDE_DEFAULT_FONT_SIZE, overrideFonts.isSelected()); - int newFontSize = Integer.parseInt(fontSize.getText()); - prefs.putInt(JabRefPreferences.MAIN_FONT_SIZE, newFontSize); - - boolean isThemeChanged = false; - - if (lightTheme.isSelected() && !prefs.get(JabRefPreferences.FX_THEME).equals(ThemeLoader.MAIN_CSS)) { - prefs.put(JabRefPreferences.FX_THEME, ThemeLoader.MAIN_CSS); - isThemeChanged = true; - } else if (darkTheme.isSelected() && !prefs.get(JabRefPreferences.FX_THEME).equals(ThemeLoader.DARK_CSS)) { - prefs.put(JabRefPreferences.FX_THEME, ThemeLoader.DARK_CSS); - isThemeChanged = true; - } - - boolean isRestartRequired = - (oldOverrideDefaultFontSize != overrideFonts.isSelected()) - || (oldFontSize != newFontSize) - || isThemeChanged; - if (isRestartRequired) { - dialogService.showWarningDialogAndWait(Localization.lang("Settings"), - Localization.lang("Some appearance settings you changed require to restart JabRef to come into effect.")); - } - } - - @Override - public boolean validateSettings() { - return true; - } - - @Override - public String getTabName() { - return Localization.lang("Appearance"); - } - - @Override - public List getRestartWarnings() { return new ArrayList<>(); } -} diff --git a/src/main/java/org/jabref/gui/preferences/AppearanceTab.fxml b/src/main/java/org/jabref/gui/preferences/AppearanceTab.fxml new file mode 100644 index 00000000000..ed2f9605c5e --- /dev/null +++ b/src/main/java/org/jabref/gui/preferences/AppearanceTab.fxml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/preferences/AppearanceTabView.java b/src/main/java/org/jabref/gui/preferences/AppearanceTabView.java new file mode 100644 index 00000000000..54eebaeac8e --- /dev/null +++ b/src/main/java/org/jabref/gui/preferences/AppearanceTabView.java @@ -0,0 +1,50 @@ +package org.jabref.gui.preferences; + +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.RadioButton; +import javafx.scene.control.TextField; + +import org.jabref.gui.util.ControlHelper; +import org.jabref.gui.util.IconValidationDecorator; +import org.jabref.logic.l10n.Localization; +import org.jabref.preferences.JabRefPreferences; + +import com.airhacks.afterburner.views.ViewLoader; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; + +public class AppearanceTabView extends AbstractPreferenceTabView implements PreferencesTab { + + @FXML public CheckBox fontOverride; + @FXML public TextField fontSize; + @FXML public RadioButton themeLight; + @FXML public RadioButton themeDark; + + private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); + + public AppearanceTabView(JabRefPreferences preferences) { + this.preferences = preferences; + + ViewLoader.view(this) + .root(this) + .load(); + } + + @Override + public String getTabName() { return Localization.lang("Appearance"); } + + public void initialize () { + this.viewModel = new AppearanceTabViewModel(dialogService, preferences); + + fontOverride.selectedProperty().bindBidirectional(viewModel.fontOverrideProperty()); + fontSize.setTextFormatter(ControlHelper.getIntegerTextFormatter()); + fontSize.textProperty().bindBidirectional(viewModel.fontSizeProperty()); + + themeLight.selectedProperty().bindBidirectional(viewModel.themeLightProperty()); + themeDark.selectedProperty().bindBidirectional(viewModel.themeDarkProperty()); + + validationVisualizer.setDecoration(new IconValidationDecorator()); + Platform.runLater(() -> validationVisualizer.initVisualization(viewModel.fontSizeValidationStatus(), fontSize)); + } +} diff --git a/src/main/java/org/jabref/gui/preferences/AppearanceTabViewModel.java b/src/main/java/org/jabref/gui/preferences/AppearanceTabViewModel.java new file mode 100644 index 00000000000..63a4abfe78a --- /dev/null +++ b/src/main/java/org/jabref/gui/preferences/AppearanceTabViewModel.java @@ -0,0 +1,117 @@ +package org.jabref.gui.preferences; + +import java.util.ArrayList; +import java.util.List; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import org.jabref.gui.DialogService; +import org.jabref.gui.util.ThemeLoader; +import org.jabref.logic.l10n.Localization; +import org.jabref.preferences.JabRefPreferences; + +import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; +import de.saxsys.mvvmfx.utils.validation.ValidationMessage; +import de.saxsys.mvvmfx.utils.validation.ValidationStatus; + +public class AppearanceTabViewModel implements PreferenceTabViewModel { + + private final BooleanProperty fontOverrideProperty = new SimpleBooleanProperty(); + private final StringProperty fontSizeProperty = new SimpleStringProperty(); + private final BooleanProperty themeLightProperty = new SimpleBooleanProperty(); + private final BooleanProperty themeDarkProperty = new SimpleBooleanProperty(); + + private final DialogService dialogService; + private final JabRefPreferences preferences; + + private FunctionBasedValidator fontSizeValidator; + + private List restartWarnings = new ArrayList<>(); + + public AppearanceTabViewModel(DialogService dialogService, JabRefPreferences preferences) { + this.dialogService = dialogService; + this.preferences = preferences; + + fontSizeValidator = new FunctionBasedValidator<>( + fontSizeProperty, + input -> { + try { + return Integer.parseInt(fontSizeProperty().getValue()) > 8; + } catch (NumberFormatException ex) { + return false; + } + }, + ValidationMessage.error(String.format("%s > %s %n %n %s", + Localization.lang("Appearance"), + Localization.lang("Font settings"), + Localization.lang("You must enter an integer value higher than 8.")))); + } + + @Override + public void setValues() { + fontOverrideProperty.setValue(preferences.getBoolean(JabRefPreferences.OVERRIDE_DEFAULT_FONT_SIZE)); + fontSizeProperty.setValue(String.valueOf(preferences.getInt(JabRefPreferences.MAIN_FONT_SIZE))); + + switch (preferences.get(JabRefPreferences.FX_THEME)) { + case ThemeLoader.DARK_CSS: + themeLightProperty.setValue(false); + themeDarkProperty.setValue(true); + break; + case ThemeLoader.MAIN_CSS: + default: + themeLightProperty.setValue(true); + themeDarkProperty.setValue(false); + } + } + + @Override + public void storeSettings() { + if (preferences.getBoolean(JabRefPreferences.OVERRIDE_DEFAULT_FONT_SIZE) != fontOverrideProperty.getValue()) { + restartWarnings.add(Localization.lang("Override font settings")); + preferences.putBoolean(JabRefPreferences.OVERRIDE_DEFAULT_FONT_SIZE, fontOverrideProperty.getValue()); + } + + int newFontSize = Integer.parseInt(fontSizeProperty.getValue()); + if (preferences.getInt(JabRefPreferences.MAIN_FONT_SIZE) != newFontSize) { + restartWarnings.add(Localization.lang("Override font size")); + preferences.putInt(JabRefPreferences.MAIN_FONT_SIZE, newFontSize); + } + + if (themeLightProperty.getValue() && !preferences.get(JabRefPreferences.FX_THEME).equals(ThemeLoader.MAIN_CSS)) { + restartWarnings.add(Localization.lang("Theme changed:") + " " + ThemeLoader.MAIN_CSS); + preferences.put(JabRefPreferences.FX_THEME, ThemeLoader.MAIN_CSS); + } else if (themeDarkProperty.getValue() && !preferences.get(JabRefPreferences.FX_THEME).equals(ThemeLoader.DARK_CSS)) { + restartWarnings.add(Localization.lang("Theme changed:") + " " + ThemeLoader.DARK_CSS); + preferences.put(JabRefPreferences.FX_THEME, ThemeLoader.DARK_CSS); + } + } + + public ValidationStatus fontSizeValidationStatus() { return fontSizeValidator.getValidationStatus(); } + + @Override + public boolean validateSettings() { + if (fontOverrideProperty.getValue()) { + if (!fontSizeValidator.getValidationStatus().isValid()) { + fontSizeValidator.getValidationStatus().getHighestMessage().ifPresent(message -> + dialogService.showErrorDialogAndWait(message.getMessage())); + return false; + } + } + return true; + } + + @Override + public List getRestartWarnings() { return restartWarnings; } + + public BooleanProperty fontOverrideProperty() { return fontOverrideProperty; } + + public StringProperty fontSizeProperty() { return fontSizeProperty; } + + public BooleanProperty themeLightProperty() { return themeLightProperty; } + + public BooleanProperty themeDarkProperty() { return themeDarkProperty; } + +} diff --git a/src/main/java/org/jabref/gui/preferences/BibtexKeyPatternPrefTab.java b/src/main/java/org/jabref/gui/preferences/BibtexKeyPatternPrefTab.java deleted file mode 100644 index 834e879fffe..00000000000 --- a/src/main/java/org/jabref/gui/preferences/BibtexKeyPatternPrefTab.java +++ /dev/null @@ -1,146 +0,0 @@ -package org.jabref.gui.preferences; - -import java.util.ArrayList; -import java.util.List; - -import javafx.scene.Node; -import javafx.scene.control.CheckBox; -import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; -import javafx.scene.control.TextField; -import javafx.scene.layout.GridPane; - -import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.bibtexkeypattern.BibtexKeyPatternPanel; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern; -import org.jabref.preferences.JabRefPreferences; - -/** - * The Preferences panel for key generation. - */ -class BibtexKeyPatternPrefTab extends BibtexKeyPatternPanel implements PreferencesTab { - - private final JabRefPreferences prefs; - private final GridPane builder = new GridPane(); - private final CheckBox dontOverwrite = new CheckBox(Localization.lang("Do not overwrite existing keys")); - private final CheckBox warnBeforeOverwriting = new CheckBox(Localization.lang("Warn before overwriting existing keys")); - private final CheckBox generateOnSave = new CheckBox(Localization.lang("Generate keys before saving (for entries without a key)")); - - private final RadioButton letterStartA = new RadioButton(Localization.lang("Ensure unique keys using letters (a, b, ...)")); - private final RadioButton letterStartB = new RadioButton(Localization.lang("Ensure unique keys using letters (b, c, ...)")); - private final RadioButton alwaysAddLetter = new RadioButton(Localization.lang("Always add letter (a, b, ...) to generated keys")); - - private final TextField keyPatternRegex = new TextField(); - private final TextField keyPatternReplacement = new TextField(); - - - public BibtexKeyPatternPrefTab(JabRefPreferences prefs, BasePanel panel) { - super(panel); - builder.add(super.getPanel(), 1, 1); - builder.add(new Label(""), 1, 2); - this.prefs = prefs; - appendKeyGeneratorSettings(); - } - - - /** - * Store changes to table preferences. This method is called when the user clicks Ok. - * - */ - @Override - public void storeSettings() { - // Set the default value: - Globals.prefs.put(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN, defaultPat.getText()); - Globals.prefs.putBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY, warnBeforeOverwriting.isSelected()); - Globals.prefs.putBoolean(JabRefPreferences.AVOID_OVERWRITING_KEY, dontOverwrite.isSelected()); - - Globals.prefs.put(JabRefPreferences.KEY_PATTERN_REGEX, keyPatternRegex.getText()); - Globals.prefs.put(JabRefPreferences.KEY_PATTERN_REPLACEMENT, keyPatternReplacement.getText()); - Globals.prefs.putBoolean(JabRefPreferences.GENERATE_KEYS_BEFORE_SAVING, generateOnSave.isSelected()); - - if (alwaysAddLetter.isSelected()) { - Globals.prefs.putBoolean(JabRefPreferences.KEY_GEN_ALWAYS_ADD_LETTER, true); - } else if (letterStartA.isSelected()) { - Globals.prefs.putBoolean(JabRefPreferences.KEY_GEN_FIRST_LETTER_A, true); - Globals.prefs.putBoolean(JabRefPreferences.KEY_GEN_ALWAYS_ADD_LETTER, false); - } - else { - Globals.prefs.putBoolean(JabRefPreferences.KEY_GEN_FIRST_LETTER_A, false); - Globals.prefs.putBoolean(JabRefPreferences.KEY_GEN_ALWAYS_ADD_LETTER, false); - } - - // fetch entries from GUI - GlobalBibtexKeyPattern keypatterns = getKeyPatternAsGlobalBibtexKeyPattern(); - // store new patterns globally - prefs.putKeyPattern(keypatterns); - } - - private void appendKeyGeneratorSettings() { - // Build a panel for checkbox settings: - Label keyGeneratorSettings = new Label(Localization.lang("Key generator settings")); - keyGeneratorSettings.getStyleClass().add("sectionHeader"); - builder.add(keyGeneratorSettings, 1, 10); - builder.add(letterStartA, 2, 11); - builder.add(warnBeforeOverwriting, 1, 12); - builder.add(letterStartB, 2, 12); - builder.add(dontOverwrite, 1, 13); - builder.add(alwaysAddLetter, 2, 13); - builder.add(generateOnSave, 1, 14); - - builder.add((new Label(Localization.lang("Replace (regular expression)") + ':')), 1, 15); - builder.add(new Label(Localization.lang("by") + ':'), 2, 15); - - builder.add(keyPatternRegex, 1, 16); - builder.add(keyPatternReplacement, 2, 16); - - dontOverwrite.setOnAction(e -> - // Warning before overwriting is only relevant if overwriting can happen: - warnBeforeOverwriting.setDisable(dontOverwrite.isSelected())); - } - - @Override - public Node getBuilder() { - return builder; - } - - @Override - public boolean validateSettings() { - return true; - } - - @Override - public void setValues() { - super.setValues(Globals.prefs.getKeyPattern()); - defaultPat.setText(Globals.prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); - dontOverwrite.setSelected(Globals.prefs.getBoolean(JabRefPreferences.AVOID_OVERWRITING_KEY)); - generateOnSave.setSelected(Globals.prefs.getBoolean(JabRefPreferences.GENERATE_KEYS_BEFORE_SAVING)); - warnBeforeOverwriting.setSelected(Globals.prefs.getBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY)); - - boolean prefAlwaysAddLetter = Globals.prefs.getBoolean(JabRefPreferences.KEY_GEN_ALWAYS_ADD_LETTER); - boolean firstLetterA = Globals.prefs.getBoolean(JabRefPreferences.KEY_GEN_FIRST_LETTER_A); - if (prefAlwaysAddLetter) { - this.alwaysAddLetter.setSelected(true); - } else if (firstLetterA) { - this.letterStartA.setSelected(true); - } else { - this.letterStartB.setSelected(true); - } - - // Warning before overwriting is only relevant if overwriting can happen: - warnBeforeOverwriting.setDisable(dontOverwrite.isSelected()); - - keyPatternRegex.setText(Globals.prefs.get(JabRefPreferences.KEY_PATTERN_REGEX)); - keyPatternReplacement.setText(Globals.prefs.get(JabRefPreferences.KEY_PATTERN_REPLACEMENT)); - - } - - @Override - public String getTabName() { - return Localization.lang("BibTeX key generator"); - } - - @Override - public List getRestartWarnings() { return new ArrayList<>(); } -} diff --git a/src/main/java/org/jabref/gui/preferences/BibtexKeyPatternTab.fxml b/src/main/java/org/jabref/gui/preferences/BibtexKeyPatternTab.fxml new file mode 100644 index 00000000000..7e587331443 --- /dev/null +++ b/src/main/java/org/jabref/gui/preferences/BibtexKeyPatternTab.fxml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + +