Skip to content

Commit

Permalink
Add CSS Customisation (#6725)
Browse files Browse the repository at this point in the history
* feat/#1 Add CSS file type, add button in preferences to import custom CSS file, started on import functionality

* feat/#1 Change so that the log messages uses format specifiers instead of string concatenation

* feat/#1 Add RadioButton for toggling custom theme

* feat/#1 Add preference for setting path to custom CSS theme

* feat/#1 Load custom CSS if toggled

* feat/#1 Add missing language keys

* feat/#1 Remove check if current theme is applied again, check is remove since we don't need it

* feat/#1 Save path to custom CSS file in program preferences

* Add functionality to let the user import custom CSS file #5790

* Add CSS file type, add button in preferences to import a custom CSS file, started on import functionality

* Change so that the log uses format specifiers instead of string concatenation

* Add RadioButton for toggling custom theme

* Add preference for setting the path to custom CSS theme

* Load custom CSS if toggled

* Add missing language keys

* Remove check if the current theme is applied again, the check is removed since we don't need it

* Save path to the custom CSS file in program preferences

* fix/#5 Add checks so that the theme change notification is only shown once, disable custom theme radio button i no custom theme has been imported

* Remove added stuff from merge conflict

* Add export current theme #5790

* Add method for saving theme to file

* Add modal for selection witch theme to export as CSS

* Add missing language lines

* Add information about import/export of themes, #5790

* Fix CodaCy and checkstyle issues, #5790

* Add fixes from code review, #5790

* Remove unused import #5790

* Move the import/export buttons to the Appearance tab #5790

* Fixed merge errors

* Fixed easy remarks

* Introduced AppereancePreferences and changed some visual elements

* Refactored ExportThemeDialog

* Fixed merge error

* Removed export theme logic and added validation

* CHANGELOG.md

* Removed obsolete viewmodel class

* Refactored io.File to nio.Path, use of JabRefPreferences and removed vmOption

* Refactored ThemeLoader object class to enum with static util methods

* Fixed overlooked merge error

* Refactored static methods to object methods

* Checkstyle

Co-authored-by: Nils Streijffert <nils.streijffert@gmail.com>
Co-authored-by: Christoph <siedlerkiller@gmail.com>
  • Loading branch information
3 people authored Aug 31, 2020
1 parent dca0f80 commit 43c8ba2
Show file tree
Hide file tree
Showing 19 changed files with 383 additions and 193 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
### Added

- We added a query parser and mapping layer to enable conversion of queries formulated in simplified lucene syntax by the user into api queries. [#6799](https://github.com/JabRef/jabref/pull/6799)
- We added some basic functionality to customise the look of JabRef by importing a css theme file. [#5790](https://github.com/JabRef/jabref/issues/5790)

### Changed

Expand Down
10 changes: 1 addition & 9 deletions src/main/java/org/jabref/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.jabref.gui.util.DefaultFileUpdateMonitor;
import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.gui.util.TaskExecutor;
import org.jabref.gui.util.ThemeLoader;
import org.jabref.logic.exporter.ExporterFactory;
import org.jabref.logic.importer.ImportFormatReader;
import org.jabref.logic.journals.JournalAbbreviationRepository;
Expand Down Expand Up @@ -80,7 +79,6 @@ public class Globals {
private static KeyBindingRepository keyBindingRepository;

private static DefaultFileUpdateMonitor fileUpdateMonitor;
private static ThemeLoader themeLoader;
private static TelemetryClient telemetryClient;

private Globals() {
Expand All @@ -95,12 +93,10 @@ public static synchronized KeyBindingRepository getKeyPrefs() {
}

// Background tasks
public static void startBackgroundTasks() throws JabRefException {
public static void startBackgroundTasks() {
Globals.fileUpdateMonitor = new DefaultFileUpdateMonitor();
JabRefExecutorService.INSTANCE.executeInterruptableTask(Globals.fileUpdateMonitor, "FileUpdateMonitor");

themeLoader = new ThemeLoader(fileUpdateMonitor, prefs);

if (Globals.prefs.shouldCollectTelemetry() && !GraphicsEnvironment.isHeadless()) {
startTelemetryClient();
}
Expand Down Expand Up @@ -146,8 +142,4 @@ public static void stopBackgroundTasks() {
public static Optional<TelemetryClient> getTelemetryClient() {
return Optional.ofNullable(telemetryClient);
}

public static ThemeLoader getThemeLoader() {
return themeLoader;
}
}
3 changes: 2 additions & 1 deletion src/main/java/org/jabref/JabRefGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public JabRefGUI(Stage mainStage, List<ParserResult> databases, boolean isBlank)
this.bibDatabases = databases;
this.isBlank = isBlank;
this.correctedWindowPos = false;

mainFrame = new JabRefFrame(mainStage);

openWindow(mainStage);
Expand Down Expand Up @@ -86,7 +87,7 @@ private void openWindow(Stage mainStage) {
root.getChildren().add(JabRefGUI.mainFrame);

Scene scene = new Scene(root, 800, 800);
Globals.getThemeLoader().installCss(scene, Globals.prefs);
Globals.prefs.getTheme().installCss(scene);
mainStage.setTitle(JabRefFrame.FRAME_TITLE);
mainStage.getIcons().addAll(IconTheme.getLogoSetFX());
mainStage.setScene(scene);
Expand Down
27 changes: 12 additions & 15 deletions src/main/java/org/jabref/gui/JabRefDialogService.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import org.jabref.gui.util.BackgroundTask;
import org.jabref.gui.util.DirectoryDialogConfiguration;
import org.jabref.gui.util.FileDialogConfiguration;
import org.jabref.gui.util.ThemeLoader;
import org.jabref.gui.util.ZipFileChooser;
import org.jabref.logic.l10n.Localization;
import org.jabref.preferences.JabRefPreferences;
Expand Down Expand Up @@ -69,21 +68,19 @@ public class JabRefDialogService implements DialogService {
private static final Duration TOAST_MESSAGE_DISPLAY_TIME = Duration.millis(3000);
private static final Logger LOGGER = LoggerFactory.getLogger(JabRefDialogService.class);
private static JabRefPreferences preferences;
private static ThemeLoader themeLoader;

private final Window mainWindow;
private final JFXSnackbar statusLine;

public JabRefDialogService(Window mainWindow, Pane mainPane, JabRefPreferences preferences, ThemeLoader themeLoader) {
public JabRefDialogService(Window mainWindow, Pane mainPane, JabRefPreferences preferences) {
this.mainWindow = mainWindow;
this.statusLine = new JFXSnackbar(mainPane);
JabRefDialogService.preferences = preferences;
JabRefDialogService.themeLoader = themeLoader;
}

private static FXDialog createDialog(AlertType type, String title, String content) {
FXDialog alert = new FXDialog(type, title, true);
themeLoader.installCss(alert.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(alert.getDialogPane().getScene());
alert.setHeaderText(null);
alert.setContentText(content);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
Expand Down Expand Up @@ -116,7 +113,7 @@ protected Node createDetailsButton() {

// Reset the dialog graphic using the default style
alert.getDialogPane().setGraphic(graphic);
themeLoader.installCss(alert.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(alert.getDialogPane().getScene());
alert.setHeaderText(null);
alert.setContentText(content);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
Expand All @@ -139,7 +136,7 @@ public <T> Optional<T> showChoiceDialogAndWait(String title, String content, Str
choiceDialog.setHeaderText(title);
choiceDialog.setTitle(title);
choiceDialog.setContentText(content);
themeLoader.installCss(choiceDialog.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(choiceDialog.getDialogPane().getScene());
return choiceDialog.showAndWait();
}

Expand All @@ -148,7 +145,7 @@ public Optional<String> showInputDialogAndWait(String title, String content) {
TextInputDialog inputDialog = new TextInputDialog();
inputDialog.setHeaderText(title);
inputDialog.setContentText(content);
themeLoader.installCss(inputDialog.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(inputDialog.getDialogPane().getScene());
return inputDialog.showAndWait();
}

Expand All @@ -157,7 +154,7 @@ public Optional<String> showInputDialogWithDefaultAndWait(String title, String c
TextInputDialog inputDialog = new TextInputDialog(defaultValue);
inputDialog.setHeaderText(title);
inputDialog.setContentText(content);
themeLoader.installCss(inputDialog.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(inputDialog.getDialogPane().getScene());
return inputDialog.showAndWait();
}

Expand All @@ -184,7 +181,7 @@ public void showErrorDialogAndWait(String message, Throwable exception) {
ExceptionDialog exceptionDialog = new ExceptionDialog(exception);
exceptionDialog.getDialogPane().setMaxWidth(mainWindow.getWidth() / 2);
exceptionDialog.setHeaderText(message);
themeLoader.installCss(exceptionDialog.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(exceptionDialog.getDialogPane().getScene());
exceptionDialog.showAndWait();
}

Expand All @@ -193,7 +190,7 @@ public void showErrorDialogAndWait(String title, String content, Throwable excep
ExceptionDialog exceptionDialog = new ExceptionDialog(exception);
exceptionDialog.setHeaderText(title);
exceptionDialog.setContentText(content);
themeLoader.installCss(exceptionDialog.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(exceptionDialog.getDialogPane().getScene());
exceptionDialog.showAndWait();
}

Expand Down Expand Up @@ -262,7 +259,7 @@ public Optional<ButtonType> showCustomDialogAndWait(String title, DialogPane con
alert.getButtonTypes().setAll(buttonTypes);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.setResizable(true);
themeLoader.installCss(alert.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(alert.getDialogPane().getScene());
return alert.showAndWait();
}

Expand All @@ -287,7 +284,7 @@ public <V> void showProgressDialog(String title, String content, Task<V> task) {
task.cancel();
progressDialog.close();
});
themeLoader.installCss(progressDialog.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(progressDialog.getDialogPane().getScene());
progressDialog.show();
}

Expand All @@ -310,7 +307,7 @@ public <V> Optional<ButtonType> showBackgroundProgressDialogAndWait(String title
alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.CANCEL);
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.setResizable(true);
themeLoader.installCss(alert.getDialogPane().getScene(), preferences);
preferences.getTheme().installCss(alert.getDialogPane().getScene());

stateManager.getAnyTaskRunning().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
Expand All @@ -319,7 +316,7 @@ public <V> Optional<ButtonType> showBackgroundProgressDialogAndWait(String title
}
});

Dialog<ButtonType> dialog = () -> alert.showAndWait();
Dialog<ButtonType> dialog = alert::showAndWait;

return showCustomDialogAndWait(dialog);
}
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@
import org.jabref.gui.undo.UndoRedoAction;
import org.jabref.gui.util.BackgroundTask;
import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.gui.util.ThemeLoader;
import org.jabref.logic.autosaveandbackup.AutosaveManager;
import org.jabref.logic.autosaveandbackup.BackupManager;
import org.jabref.logic.citationstyle.CitationStyleOutputFormat;
Expand Down Expand Up @@ -162,7 +161,6 @@ public class JabRefFrame extends BorderPane {

private final SplitPane splitPane = new SplitPane();
private final JabRefPreferences prefs = Globals.prefs;
private final ThemeLoader themeLoader = Globals.getThemeLoader();
private final GlobalSearchBar globalSearchBar = new GlobalSearchBar(this, Globals.stateManager, prefs);

private final FileHistoryMenu fileHistory;
Expand All @@ -180,7 +178,7 @@ public class JabRefFrame extends BorderPane {

public JabRefFrame(Stage mainStage) {
this.mainStage = mainStage;
this.dialogService = new JabRefDialogService(mainStage, this, prefs, themeLoader);
this.dialogService = new JabRefDialogService(mainStage, this, prefs);
this.stateManager = Globals.stateManager;
this.pushToApplicationsManager = new PushToApplicationsManager(dialogService, stateManager, prefs);
this.undoManager = Globals.undoManager;
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/org/jabref/gui/preferences/AppearanceTab.fxml
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<?import org.jabref.gui.icon.JabRefIconView?>

<fx:root prefWidth="650.0" spacing="10.0" type="VBox" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.jabref.gui.preferences.AppearanceTabView">
<fx:define>
Expand All @@ -28,4 +34,18 @@
<Label styleClass="sectionHeader" text="%Visual theme"/>
<RadioButton fx:id="themeLight" text="%Light theme" toggleGroup="$theme"/>
<RadioButton fx:id="themeDark" text="%Dark theme" toggleGroup="$theme"/>
<HBox alignment="CENTER_LEFT" spacing="4.0">
<RadioButton fx:id="customTheme" text="%Custom theme" toggleGroup="$theme"/>
<TextField fx:id="customThemePath" prefWidth="350.0" disable="${!customTheme.selected}"/>
<Button onAction="#importTheme" disable="${!customTheme.selected}"
styleClass="icon-button,narrow"
prefHeight="20.0" prefWidth="20.0">
<graphic>
<JabRefIconView glyph="OPEN"/>
</graphic>
<tooltip>
<Tooltip text="%Browse"/>
</tooltip>
</Button>
</HBox>
</fx:root>
15 changes: 14 additions & 1 deletion src/main/java/org/jabref/gui/preferences/AppearanceTabView.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import javafx.scene.control.CheckBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Spinner;
import javafx.scene.control.TextField;

import org.jabref.gui.util.IconValidationDecorator;
import org.jabref.logic.l10n.Localization;
Expand All @@ -20,6 +21,8 @@ public class AppearanceTabView extends AbstractPreferenceTabView<AppearanceTabVi
@FXML public Spinner<Integer> fontSize;
@FXML public RadioButton themeLight;
@FXML public RadioButton themeDark;
@FXML public RadioButton customTheme;
@FXML public TextField customThemePath;

private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer();

Expand Down Expand Up @@ -49,8 +52,18 @@ public void initialize() {

themeLight.selectedProperty().bindBidirectional(viewModel.themeLightProperty());
themeDark.selectedProperty().bindBidirectional(viewModel.themeDarkProperty());
customTheme.selectedProperty().bindBidirectional(viewModel.customThemeProperty());
customThemePath.textProperty().bindBidirectional(viewModel.customPathToThemeProperty());

validationVisualizer.setDecoration(new IconValidationDecorator());
Platform.runLater(() -> validationVisualizer.initVisualization(viewModel.fontSizeValidationStatus(), fontSize));
Platform.runLater(() -> {
validationVisualizer.initVisualization(viewModel.fontSizeValidationStatus(), fontSize);
validationVisualizer.initVisualization(viewModel.customPathToThemeValidationStatus(), customThemePath);
});
}

@FXML
void importTheme() {
viewModel.importCSSFile();
}
}
Loading

0 comments on commit 43c8ba2

Please sign in to comment.