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

Live reloading when switching themes #7336

Merged
merged 55 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
87a8c32
live reloading when switching themes, refs #7335
docrjp Jan 12, 2021
0e3310f
preview fully live reloads now, refs #7335
docrjp Jan 12, 2021
3d442d5
remove restart warnings for theme, rfs #7335
docrjp Jan 12, 2021
be101ba
fix import checkstyle violations
docrjp Jan 12, 2021
6293332
add custom static factory to ThemePreference
docrjp Jan 12, 2021
04a202d
live reload font override preference changes
docrjp Jan 17, 2021
752095a
rename Theme to ThemeManager
docrjp Jan 17, 2021
27445da
rename empty theme to light and remove StyleSheetEmpty
docrjp Jan 17, 2021
ed8feb2
remove redundant restart messages from resource bundle
docrjp Jan 17, 2021
fcff1d5
Merge remote-tracking branch 'upstream/master' into fix-7335
calixtus Feb 26, 2021
4902c79
Moved construction of ThemeManager to Globals and added some small fixes
calixtus Feb 28, 2021
7d6d510
Fixed some tests
calixtus Feb 28, 2021
ac437d5
Merge remote-tracking branch 'upstream/master' into fix-7335
calixtus Mar 5, 2021
13a9f2e
Merge remote-tracking branch 'upstream/master' into fix-7335
calixtus Mar 10, 2021
09cd062
Fixed ThemeTest
calixtus Mar 10, 2021
0593492
Removed Light.css
calixtus Mar 10, 2021
9c1e9d0
Merge remote-tracking branch 'upstream/master' into fix-7335
calixtus Mar 11, 2021
8e8ceb7
Injecting ThemeManager
calixtus Mar 11, 2021
c04ed80
Removed restart message
calixtus Mar 11, 2021
a4c0917
Minor tweaks and checkstyle
calixtus Mar 13, 2021
ebddcaa
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Apr 26, 2021
557f0de
Changed constant names to more meaningful ones
calixtus Apr 26, 2021
9cdab98
Removed workaround for fixed bug with external jrt stylesheets and re…
calixtus Apr 26, 2021
699aaca
Fixed concurrency issue
calixtus Apr 26, 2021
8a7e119
Fixed ThemeTest
calixtus Apr 27, 2021
f295619
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus May 7, 2021
a89b255
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus May 9, 2021
74b5559
Restored DataUrl
calixtus May 10, 2021
2d2e506
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Jun 1, 2021
477dbdc
Removed currentAppearancePreferences, refactored ThemeManager and add…
calixtus Jun 2, 2021
c9c9595
Removed setter in PreviewViewer
calixtus Jun 2, 2021
767830e
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Jun 4, 2021
f7b6e82
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Aug 18, 2021
471659e
Fixed merge errors
calixtus Aug 18, 2021
9c833f4
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Sep 2, 2021
c1216eb
Fixed merge errors
calixtus Sep 2, 2021
a4d782a
Fixed merge errors
calixtus Sep 2, 2021
d9ca623
Fixed IndexOutOfBoundsException
calixtus Sep 2, 2021
27352cc
Fixed IndexOutOfBoundsException
calixtus Sep 2, 2021
5d261c1
WIP tests
calixtus Sep 10, 2021
a40d317
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Sep 10, 2021
35af350
Fixed merge error
calixtus Sep 10, 2021
02cee7c
Checkstyle
calixtus Sep 10, 2021
cdf354a
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Dec 14, 2021
4f1fa8f
Fixed merge conflicts and annoying race condition
calixtus Dec 14, 2021
1053f9c
Merge remote-tracking branch 'upstream/main' into fix-7335
calixtus Dec 30, 2021
f8ca9dd
Fixed merge errors
calixtus Dec 30, 2021
85787e3
Fixed tests
calixtus Dec 31, 2021
8574d53
Avoided Optional as field, implemented TDiez suggestion
calixtus Dec 31, 2021
ae0e432
Checkstyle and CHANGELOG.md
calixtus Dec 31, 2021
749f023
Fix issue about font sizing, removed restart warnings
calixtus Jan 1, 2022
12c9839
Fixed tests
calixtus Jan 1, 2022
0253a3a
checkstyle
calixtus Jan 1, 2022
ad7a8a8
l10n
calixtus Jan 1, 2022
72775e9
Modified comments
calixtus Jan 3, 2022
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
Expand Up @@ -39,7 +39,6 @@ public class AppearanceTabViewModel implements PreferenceTabViewModel {

private final DialogService dialogService;
private final PreferencesService preferences;
private final AppearancePreferences initialAppearancePreferences;

private final Validator fontSizeValidator;
private final Validator customPathToThemeValidator;
Expand All @@ -49,7 +48,6 @@ public class AppearanceTabViewModel implements PreferenceTabViewModel {
public AppearanceTabViewModel(DialogService dialogService, PreferencesService preferences) {
this.dialogService = dialogService;
this.preferences = preferences;
this.initialAppearancePreferences = preferences.getAppearancePreferences();

fontSizeValidator = new FunctionBasedValidator<>(
fontSizeProperty,
Expand All @@ -76,10 +74,11 @@ public AppearanceTabViewModel(DialogService dialogService, PreferencesService pr

@Override
public void setValues() {
fontOverrideProperty.setValue(initialAppearancePreferences.shouldOverrideDefaultFontSize());
fontSizeProperty.setValue(String.valueOf(initialAppearancePreferences.getMainFontSize()));
AppearancePreferences appearancePreferences = preferences.getAppearancePreferences();
fontOverrideProperty.setValue(appearancePreferences.shouldOverrideDefaultFontSize());
fontSizeProperty.setValue(String.valueOf(appearancePreferences.getMainFontSize()));

ThemePreference currentTheme = initialAppearancePreferences.getThemePreference();
ThemePreference currentTheme = appearancePreferences.getThemePreference();
if (currentTheme.getType() == Theme.Type.LIGHT) {
themeLightProperty.setValue(true);
themeDarkProperty.setValue(false);
Expand All @@ -98,24 +97,20 @@ public void setValues() {

@Override
public void storeSettings() {
if (initialAppearancePreferences.shouldOverrideDefaultFontSize() != fontOverrideProperty.getValue()) {

AppearancePreferences currentPreferences = preferences.getAppearancePreferences();
if (currentPreferences.shouldOverrideDefaultFontSize() != fontOverrideProperty.getValue()) {
restartWarnings.add(Localization.lang("Override font settings"));
}

int newFontSize = Integer.parseInt(fontSizeProperty.getValue());
if (initialAppearancePreferences.getMainFontSize() != newFontSize) {
restartWarnings.add(Localization.lang("Override font size"));
}

ThemePreference newTheme = initialAppearancePreferences.getThemePreference();
if (themeLightProperty.getValue() && initialAppearancePreferences.getThemePreference().getType() != Theme.Type.LIGHT) {
ThemePreference newTheme = currentPreferences.getThemePreference();
if (themeLightProperty.getValue()) {
newTheme = ThemePreference.light();
} else if (themeDarkProperty.getValue() && initialAppearancePreferences.getThemePreference().getType() != Theme.Type.DARK) {
} else if (themeDarkProperty.getValue()) {
newTheme = ThemePreference.dark();
} else if (themeCustomProperty.getValue() &&
(!initialAppearancePreferences.getThemePreference().getName()
.equalsIgnoreCase(customPathToThemeProperty.getValue())
|| initialAppearancePreferences.getThemePreference().getType() != Theme.Type.CUSTOM)) {
} else if (themeCustomProperty.getValue()) {
newTheme = ThemePreference.custom(customPathToThemeProperty.getValue());
}

Expand Down
105 changes: 39 additions & 66 deletions src/main/java/org/jabref/gui/theme/ThemeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
Expand All @@ -16,7 +17,6 @@
import org.jabref.gui.util.Theme;
import org.jabref.model.util.FileUpdateMonitor;
import org.jabref.preferences.AppearancePreferences;
import org.jabref.preferences.PreferencesService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -38,51 +38,20 @@ public class ThemeImpl implements Theme {

private static final Logger LOGGER = LoggerFactory.getLogger(ThemeImpl.class);

private final PreferencesService preferencesService;

private final FileUpdateMonitor fileUpdateMonitor;

private final Consumer<Runnable> updateRunner;

private final StyleSheet baseStyleSheet;

private final AtomicReference<ThemeState> state = new AtomicReference<>();
private final AtomicReference<AppearancePreferences> appearancePreferences = new AtomicReference<>();

private final Set<Scene> scenes = Collections.newSetFromMap(new WeakHashMap<>());
private final Set<WebEngine> webEngines = Collections.newSetFromMap(new WeakHashMap<>());

private static final class ThemeState {

private final ThemePreference themePreference;

private final StyleSheet additionalStylesheet;

public ThemeState(ThemePreference themePreference) {
this.themePreference = themePreference;
this.additionalStylesheet = switch (themePreference.getType()) {
case LIGHT -> StyleSheetEmpty.EMPTY;
case DARK -> StyleSheet.create("Dark.css");
case CUSTOM -> StyleSheet.create(themePreference.getName());
};
}
}

public ThemeImpl(ThemePreference themePreference, PreferencesService preferencesService, FileUpdateMonitor fileUpdateMonitor, Consumer<Runnable> updateRunner) {
if (themePreference == null) {
throw new IllegalArgumentException("Theme preference required");
}
if (preferencesService == null) {
throw new IllegalArgumentException("Preference service required");
}
if (fileUpdateMonitor == null) {
throw new IllegalArgumentException("File update monitor required");
}
if (updateRunner == null) {
throw new IllegalArgumentException("Update runner required");
}
this.preferencesService = preferencesService;
this.fileUpdateMonitor = fileUpdateMonitor;
this.updateRunner = updateRunner;
public ThemeImpl(AppearancePreferences initialAppearance, FileUpdateMonitor fileUpdateMonitor, Consumer<Runnable> updateRunner) {
this.fileUpdateMonitor = Objects.requireNonNull(fileUpdateMonitor);
this.updateRunner = Objects.requireNonNull(updateRunner);

this.baseStyleSheet = StyleSheet.create(BASE_CSS);

Expand All @@ -98,34 +67,34 @@ public ThemeImpl(ThemePreference themePreference, PreferencesService preferences
}
}

baseCssLiveUpdate();
updateThemePreference(themePreference);
updateAppearancePreferences(Objects.requireNonNull(initialAppearance));
}

private StyleSheet additionalStylesheet() {
return appearancePreferences.get().getThemePreference().getAdditionalStylesheet();
}

@Override
public void updateThemePreference(ThemePreference themePreference) {
public void updateAppearancePreferences(AppearancePreferences newPreferences) {

if (themePreference == null) {
if (newPreferences == null) {
throw new IllegalArgumentException("Theme preference required");
}

ThemeState oldState = this.state.get();
if (oldState != null) {

if (oldState.themePreference.equals(themePreference)) {
LOGGER.info("Not updating theme preference because it hasn't changed");
return;
}
AppearancePreferences oldPreferences = this.appearancePreferences.get();
if (oldPreferences != null) {
if (!newPreferences.equals(oldPreferences)) {
LOGGER.info("Not updating appearance preferences because it hasn't changed");

Path oldPath = oldState.additionalStylesheet.getWatchPath();
if (oldPath != null) {
fileUpdateMonitor.removeListener(oldPath, this::additionalCssLiveUpdate);
LOGGER.info("No longer watch css {} for live updates", oldPath);
Path oldPath = oldPreferences.getThemePreference().getAdditionalStylesheet().getWatchPath();
if (oldPath != null) {
fileUpdateMonitor.removeListener(oldPath, this::additionalCssLiveUpdate);
LOGGER.info("No longer watch css {} for live updates", oldPath);
}
}
}
ThemeState newState = new ThemeState(themePreference);
Path newPath = newState.additionalStylesheet.getWatchPath();
this.state.set(newState);
Path newPath = newPreferences.getThemePreference().getAdditionalStylesheet().getWatchPath();
this.appearancePreferences.set(newPreferences);

if (newPath != null) {
try {
Expand All @@ -139,28 +108,24 @@ public void updateThemePreference(ThemePreference themePreference) {
additionalCssLiveUpdate();

LOGGER.info("Theme set to {} with base css {} and additional css {}",
themePreference, baseStyleSheet, state.get().additionalStylesheet);
newPreferences.getThemePreference(), baseStyleSheet, additionalStylesheet());
}

@Override
public void installCss(Scene scene) {
AppearancePreferences appearancePreferences = preferencesService.getAppearancePreferences();
updateRunner.accept(() -> {
if (this.scenes.add(scene)) {
updateBaseCss(scene);
updateAdditionalCss(scene);
}
if (appearancePreferences.shouldOverrideDefaultFontSize()) {
scene.getRoot().setStyle("-fx-font-size: " + appearancePreferences.getMainFontSize() + "pt;");
}
});
}

@Override
public void installCss(WebEngine webEngine) {
updateRunner.accept(() -> {
if (this.webEngines.add(webEngine)) {
webEngine.setUserStyleSheetLocation(state.get().additionalStylesheet.getWebEngineStylesheet());
webEngine.setUserStyleSheetLocation(additionalStylesheet().getWebEngineStylesheet());
}
});
}
Expand All @@ -172,9 +137,9 @@ private void baseCssLiveUpdate() {
}

private void additionalCssLiveUpdate() {
StyleSheet styleSheet = state.get().additionalStylesheet;
StyleSheet styleSheet = additionalStylesheet();
styleSheet.reload();
String newStyleSheetLocation = state.get().additionalStylesheet.getWebEngineStylesheet();
String newStyleSheetLocation = styleSheet.getWebEngineStylesheet();

LOGGER.debug("Updating additional CSS for {} scenes and {} web engines", scenes.size(), webEngines.size());
updateRunner.accept(() -> {
Expand All @@ -199,21 +164,29 @@ private void updateBaseCss(Scene scene) {
}

private void updateAdditionalCss(Scene scene) {
AppearancePreferences appearance = this.appearancePreferences.get();
List<String> stylesheets = scene.getStylesheets();
if (stylesheets.size() == 2) {
stylesheets.remove(1);
}
stylesheets.add(1, state.get().additionalStylesheet.getSceneStylesheet().toExternalForm());
stylesheets.add(1,
appearance.getThemePreference().getAdditionalStylesheet().getSceneStylesheet().toExternalForm());

if (appearance.shouldOverrideDefaultFontSize()) {
scene.getRoot().setStyle("-fx-font-size: " + appearance.getMainFontSize() + "pt;");
} else {
scene.getRoot().setStyle("");
}
}

@Override
public ThemePreference getPreference() {
return state.get().themePreference;
public AppearancePreferences getCurrentAppearancePreferences() {
return appearancePreferences.get();
}

@Override
@Deprecated(forRemoval = true) // TODO ThemeTest needs updating, and should be based on installCss(WebEngine) instead
public Optional<String> getAdditionalStylesheet() {
return Optional.of(state.get().additionalStylesheet.getWebEngineStylesheet());
return Optional.of(additionalStylesheet().getWebEngineStylesheet());
}
}
11 changes: 11 additions & 0 deletions src/main/java/org/jabref/gui/theme/ThemePreference.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class ThemePreference {

private final String name;

private final StyleSheet additionalStylesheet;

public ThemePreference(String name) {
this.name = name != null ? name : "";
if (StringUtil.isBlank(this.name) || Theme.BASE_CSS.equalsIgnoreCase(this.name)) {
Expand All @@ -22,6 +24,11 @@ public ThemePreference(String name) {
} else {
this.type = Theme.Type.CUSTOM;
}
this.additionalStylesheet = switch (type) {
case LIGHT -> StyleSheetEmpty.EMPTY;
case DARK -> StyleSheet.create("Dark.css");
case CUSTOM -> StyleSheet.create(name);
};
}

public static ThemePreference light() {
Expand Down Expand Up @@ -72,6 +79,10 @@ public int hashCode() {
return Objects.hash(type, name);
}

public StyleSheet getAdditionalStylesheet() {
return additionalStylesheet;
}

@Override
public String toString() {
return "ThemePreference{" +
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/jabref/gui/util/Theme.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;

import org.jabref.gui.theme.ThemePreference;
import org.jabref.preferences.AppearancePreferences;

public interface Theme {

Expand All @@ -31,9 +31,9 @@ enum Type {
*/
void installCss(WebEngine webEngine);

void updateThemePreference(ThemePreference themePreference);
void updateAppearancePreferences(AppearancePreferences appearancePreferences);

ThemePreference getPreference();
AppearancePreferences getCurrentAppearancePreferences();

/**
* This method allows callers to obtain the theme's additional stylesheet.
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/org/jabref/preferences/AppearancePreferences.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jabref.preferences;

import java.util.Objects;

import org.jabref.gui.theme.ThemePreference;

public class AppearancePreferences {
Expand All @@ -24,4 +26,23 @@ public int getMainFontSize() {
public ThemePreference getThemePreference() {
return themePreference;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AppearancePreferences that = (AppearancePreferences) o;
return shouldOverrideDefaultFontSize == that.shouldOverrideDefaultFontSize &&
docrjp marked this conversation as resolved.
Show resolved Hide resolved
mainFontSize == that.mainFontSize &&
themePreference.equals(that.themePreference);
}

@Override
public int hashCode() {
return Objects.hash(shouldOverrideDefaultFontSize, mainFontSize, themePreference);
}
}
16 changes: 10 additions & 6 deletions src/main/java/org/jabref/preferences/JabRefPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -1985,25 +1985,29 @@ public void storeMainTableNameFormatPreferences(MainTableNameFormatPreferences p
// AppearancePreferences
//*************************************************************************************************************

private AppearancePreferences createAppearancePreferences() {
return new AppearancePreferences(
getBoolean(OVERRIDE_DEFAULT_FONT_SIZE),
getInt(MAIN_FONT_SIZE),
new ThemePreference(get(FX_THEME)));
}

@Override
public Theme getTheme() {
if (globalTheme == null) {
globalTheme = new ThemeImpl(new ThemePreference(get(FX_THEME)), this, getFileUpdateMonitor(), DefaultTaskExecutor::runInJavaFXThread);
globalTheme = new ThemeImpl(createAppearancePreferences(), getFileUpdateMonitor(), DefaultTaskExecutor::runInJavaFXThread);
}
return globalTheme;
}

@Override
public void updateTheme() {
getTheme().updateThemePreference(new ThemePreference(get(FX_THEME)));
getTheme().updateAppearancePreferences(createAppearancePreferences());
}

@Override
public AppearancePreferences getAppearancePreferences() {
return new AppearancePreferences(
getBoolean(OVERRIDE_DEFAULT_FONT_SIZE),
getInt(MAIN_FONT_SIZE),
globalTheme.getPreference());
return getTheme().getCurrentAppearancePreferences();
}

@Override
Expand Down