mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GHelpBuilder fix to allow theme usage in headless
This commit is contained in:
parent
3586062eb4
commit
65542e9937
10 changed files with 332 additions and 258 deletions
|
@ -41,6 +41,7 @@ public class ThemeUtils {
|
||||||
* Asks the user if they want to save the current theme changes. If they answer yes, it
|
* Asks the user if they want to save the current theme changes. If they answer yes, it
|
||||||
* will handle several use cases such as whether it gets saved to a new file or
|
* will handle several use cases such as whether it gets saved to a new file or
|
||||||
* overwrites an existing file.
|
* overwrites an existing file.
|
||||||
|
* @param themeManager the theme manager
|
||||||
* @return true if the operation was not cancelled
|
* @return true if the operation was not cancelled
|
||||||
*/
|
*/
|
||||||
public static boolean askToSaveThemeChanges(ThemeManager themeManager) {
|
public static boolean askToSaveThemeChanges(ThemeManager themeManager) {
|
||||||
|
@ -61,6 +62,7 @@ public class ThemeUtils {
|
||||||
/**
|
/**
|
||||||
* Saves all current theme changes. Handles several use cases such as requesting a new theme
|
* Saves all current theme changes. Handles several use cases such as requesting a new theme
|
||||||
* name and asking to overwrite an existing file.
|
* name and asking to overwrite an existing file.
|
||||||
|
* @param themeManager the theme manager
|
||||||
* @return true if the operation was not cancelled
|
* @return true if the operation was not cancelled
|
||||||
*/
|
*/
|
||||||
public static boolean saveThemeChanges(ThemeManager themeManager) {
|
public static boolean saveThemeChanges(ThemeManager themeManager) {
|
||||||
|
@ -78,10 +80,11 @@ public class ThemeUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the theme to the default, handling the case where the current theme has changes.
|
* Resets the theme to the default, handling the case where the current theme has changes.
|
||||||
|
* @param themeManager the theme manager
|
||||||
*/
|
*/
|
||||||
public static void resetThemeToDefault(ThemeManager themeManager) {
|
public static void resetThemeToDefault(ThemeManager themeManager) {
|
||||||
if (askToSaveThemeChanges(themeManager)) {
|
if (askToSaveThemeChanges(themeManager)) {
|
||||||
themeManager.setTheme(themeManager.getDefaultTheme());
|
themeManager.setTheme(ThemeManager.getDefaultTheme());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,8 +141,7 @@ public class ThemeUtils {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean hasExternalIcons = !themeManager.getActiveTheme().getExternalIconFiles().isEmpty();
|
boolean hasExternalIcons = !themeManager.getActiveTheme().getExternalIconFiles().isEmpty();
|
||||||
String message =
|
String message = "Export as zip file? (You are not using any external icons so the zip\n" +
|
||||||
"Export as zip file? (You are not using any external icons so the zip\n" +
|
|
||||||
"file would only contain a single theme file.)";
|
"file would only contain a single theme file.)";
|
||||||
if (hasExternalIcons) {
|
if (hasExternalIcons) {
|
||||||
message =
|
message =
|
||||||
|
@ -159,6 +161,7 @@ public class ThemeUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompts for and deletes a selected theme.
|
* Prompts for and deletes a selected theme.
|
||||||
|
* @param themeManager the theme manager
|
||||||
*/
|
*/
|
||||||
public static void deleteTheme(ThemeManager themeManager) {
|
public static void deleteTheme(ThemeManager themeManager) {
|
||||||
List<GTheme> savedThemes = new ArrayList<>(
|
List<GTheme> savedThemes = new ArrayList<>(
|
||||||
|
@ -239,7 +242,7 @@ public class ThemeUtils {
|
||||||
|
|
||||||
private static File getSaveFile(String themeName) {
|
private static File getSaveFile(String themeName) {
|
||||||
File dir = Application.getUserSettingsDirectory();
|
File dir = Application.getUserSettingsDirectory();
|
||||||
File themeDir = new File(dir, ThemeFileLoader.THEME_DIR);
|
File themeDir = new File(dir, ThemeManager.THEME_DIR);
|
||||||
if (!themeDir.exists()) {
|
if (!themeDir.exists()) {
|
||||||
themeDir.mkdir();
|
themeDir.mkdir();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,16 @@
|
||||||
package generic.theme;
|
package generic.theme;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.plaf.ComponentUI;
|
|
||||||
|
|
||||||
import com.formdev.flatlaf.FlatDarkLaf;
|
import com.formdev.flatlaf.FlatDarkLaf;
|
||||||
import com.formdev.flatlaf.FlatLightLaf;
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
|
|
||||||
import generic.theme.laf.LookAndFeelManager;
|
import generic.theme.laf.LookAndFeelManager;
|
||||||
|
import ghidra.framework.Application;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
|
|
||||||
|
@ -35,15 +35,9 @@ import ghidra.util.classfinder.ClassSearcher;
|
||||||
* {@link ApplicationThemeManager#initialize()}
|
* {@link ApplicationThemeManager#initialize()}
|
||||||
*/
|
*/
|
||||||
public class ApplicationThemeManager extends ThemeManager {
|
public class ApplicationThemeManager extends ThemeManager {
|
||||||
private GTheme activeTheme = getDefaultTheme();
|
|
||||||
private Set<GTheme> allThemes = null;
|
private Set<GTheme> allThemes = null;
|
||||||
|
|
||||||
private GThemeValueMap applicationDefaults = new GThemeValueMap();
|
|
||||||
private GThemeValueMap applicationDarkDefaults = new GThemeValueMap();
|
|
||||||
private GThemeValueMap javaDefaults = new GThemeValueMap();
|
|
||||||
private GThemeValueMap systemValues = new GThemeValueMap();
|
|
||||||
|
|
||||||
protected ThemeFileLoader themeFileLoader = new ThemeFileLoader();
|
|
||||||
protected ThemePreferences themePreferences = new ThemePreferences();
|
protected ThemePreferences themePreferences = new ThemePreferences();
|
||||||
|
|
||||||
private Map<String, GColorUIResource> gColorMap = new HashMap<>();
|
private Map<String, GColorUIResource> gColorMap = new HashMap<>();
|
||||||
|
@ -58,7 +52,8 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
*/
|
*/
|
||||||
public static void initialize() {
|
public static void initialize() {
|
||||||
if (INSTANCE instanceof ApplicationThemeManager) {
|
if (INSTANCE instanceof ApplicationThemeManager) {
|
||||||
Msg.error(ThemeManager.class, "Attempted to initialize theming more than once!");
|
Msg.error(ApplicationThemeManager.class,
|
||||||
|
"Attempted to initialize theming more than once!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,13 +69,13 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
|
|
||||||
protected void doInitialize() {
|
protected void doInitialize() {
|
||||||
installFlatLookAndFeels();
|
installFlatLookAndFeels();
|
||||||
loadThemeDefaults();
|
loadDefaultThemeValues();
|
||||||
setTheme(themePreferences.load());
|
setTheme(themePreferences.load());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reloadApplicationDefaults() {
|
public void reloadApplicationDefaults() {
|
||||||
loadThemeDefaults();
|
loadDefaultThemeValues();
|
||||||
buildCurrentValues();
|
buildCurrentValues();
|
||||||
lookAndFeelManager.resetAll(javaDefaults);
|
lookAndFeelManager.resetAll(javaDefaults);
|
||||||
notifyThemeChanged(new AllValuesChangedThemeEvent(false));
|
notifyThemeChanged(new AllValuesChangedThemeEvent(false));
|
||||||
|
@ -183,16 +178,6 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public GTheme getActiveTheme() {
|
|
||||||
return activeTheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LafType getLookAndFeelType() {
|
|
||||||
return activeTheme.getLookAndFeelType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GTheme getTheme(String themeName) {
|
public GTheme getTheme(String themeName) {
|
||||||
Optional<GTheme> first =
|
Optional<GTheme> first =
|
||||||
|
@ -200,19 +185,6 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
return first.orElse(null);
|
return first.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public GThemeValueMap getThemeValues() {
|
|
||||||
GThemeValueMap map = new GThemeValueMap();
|
|
||||||
map.load(javaDefaults);
|
|
||||||
map.load(systemValues);
|
|
||||||
map.load(applicationDefaults);
|
|
||||||
if (activeTheme.useDarkDefaults()) {
|
|
||||||
map.load(applicationDarkDefaults);
|
|
||||||
}
|
|
||||||
map.load(activeTheme);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFont(FontValue newValue) {
|
public void setFont(FontValue newValue) {
|
||||||
FontValue currentValue = currentValues.getFont(newValue.getId());
|
FontValue currentValue = currentValues.getFont(newValue.getId());
|
||||||
|
@ -286,41 +258,6 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
return gIcon;
|
return gIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public GThemeValueMap getJavaDefaults() {
|
|
||||||
GThemeValueMap map = new GThemeValueMap();
|
|
||||||
map.load(javaDefaults);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GThemeValueMap getApplicationDarkDefaults() {
|
|
||||||
GThemeValueMap map = new GThemeValueMap(applicationDefaults);
|
|
||||||
map.load(applicationDarkDefaults);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GThemeValueMap getApplicationLightDefaults() {
|
|
||||||
GThemeValueMap map = new GThemeValueMap(applicationDefaults);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link GThemeValueMap} containing all default values for the current theme. It
|
|
||||||
* is a combination of application defined defaults and java {@link LookAndFeel} defaults.
|
|
||||||
* @return the current set of defaults.
|
|
||||||
*/
|
|
||||||
public GThemeValueMap getDefaults() {
|
|
||||||
GThemeValueMap currentDefaults = new GThemeValueMap(javaDefaults);
|
|
||||||
currentDefaults.load(systemValues);
|
|
||||||
currentDefaults.load(applicationDefaults);
|
|
||||||
if (activeTheme.useDarkDefaults()) {
|
|
||||||
currentDefaults.load(applicationDarkDefaults);
|
|
||||||
}
|
|
||||||
return currentDefaults;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets specially defined system UI values. These values are created by the application as a
|
* Sets specially defined system UI values. These values are created by the application as a
|
||||||
* convenience for mapping generic concepts to values that differ by Look and Feel. This allows
|
* convenience for mapping generic concepts to values that differ by Look and Feel. This allows
|
||||||
|
@ -347,16 +284,6 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
GIcon.refreshAll(currentValues);
|
GIcon.refreshAll(currentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUsingAquaUI(ComponentUI UI) {
|
|
||||||
return activeTheme.getLookAndFeelType() == LafType.MAC;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUsingNimbusUI() {
|
|
||||||
return activeTheme.getLookAndFeelType() == LafType.NIMBUS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasThemeChanges() {
|
public boolean hasThemeChanges() {
|
||||||
return !changedValuesMap.isEmpty();
|
return !changedValuesMap.isEmpty();
|
||||||
|
@ -367,32 +294,14 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
lookAndFeelManager.registerFont(component, fontId);
|
lookAndFeelManager.registerFont(component, fontId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDarkTheme() {
|
|
||||||
return activeTheme.useDarkDefaults();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void installFlatLookAndFeels() {
|
private void installFlatLookAndFeels() {
|
||||||
UIManager.installLookAndFeel(LafType.FLAT_LIGHT.getName(), FlatLightLaf.class.getName());
|
UIManager.installLookAndFeel(LafType.FLAT_LIGHT.getName(), FlatLightLaf.class.getName());
|
||||||
UIManager.installLookAndFeel(LafType.FLAT_DARK.getName(), FlatDarkLaf.class.getName());
|
UIManager.installLookAndFeel(LafType.FLAT_DARK.getName(), FlatDarkLaf.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadThemeDefaults() {
|
@Override
|
||||||
themeFileLoader.loadThemeDefaultFiles();
|
protected void buildCurrentValues() {
|
||||||
applicationDefaults = themeFileLoader.getDefaults();
|
super.buildCurrentValues();
|
||||||
applicationDarkDefaults = themeFileLoader.getDarkDefaults();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildCurrentValues() {
|
|
||||||
GThemeValueMap map = new GThemeValueMap();
|
|
||||||
|
|
||||||
map.load(javaDefaults);
|
|
||||||
map.load(systemValues);
|
|
||||||
map.load(applicationDefaults);
|
|
||||||
if (activeTheme.useDarkDefaults()) {
|
|
||||||
map.load(applicationDarkDefaults);
|
|
||||||
}
|
|
||||||
map.load(activeTheme);
|
|
||||||
currentValues = map;
|
|
||||||
changedValuesMap.clear();
|
changedValuesMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,11 +309,42 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
if (allThemes == null) {
|
if (allThemes == null) {
|
||||||
Set<GTheme> set = new HashSet<>();
|
Set<GTheme> set = new HashSet<>();
|
||||||
set.addAll(findDiscoverableThemes());
|
set.addAll(findDiscoverableThemes());
|
||||||
set.addAll(themeFileLoader.loadThemeFiles());
|
set.addAll(loadThemeFiles());
|
||||||
allThemes = set;
|
allThemes = set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Collection<GTheme> loadThemeFiles() {
|
||||||
|
List<File> fileList = new ArrayList<>();
|
||||||
|
FileFilter themeFileFilter = file -> file.getName().endsWith("." + GTheme.FILE_EXTENSION);
|
||||||
|
|
||||||
|
File dir = Application.getUserSettingsDirectory();
|
||||||
|
File themeDir = new File(dir, THEME_DIR);
|
||||||
|
File[] files = themeDir.listFiles(themeFileFilter);
|
||||||
|
if (files != null) {
|
||||||
|
fileList.addAll(Arrays.asList(files));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GTheme> list = new ArrayList<>();
|
||||||
|
for (File file : fileList) {
|
||||||
|
GTheme theme = loadTheme(file);
|
||||||
|
if (theme != null) {
|
||||||
|
list.add(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GTheme loadTheme(File file) {
|
||||||
|
try {
|
||||||
|
return new ThemeReader(file).readTheme();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Msg.error(Gui.class, "Could not load theme from file: " + file.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private Collection<DiscoverableGTheme> findDiscoverableThemes() {
|
private Collection<DiscoverableGTheme> findDiscoverableThemes() {
|
||||||
return ClassSearcher.getInstances(DiscoverableGTheme.class);
|
return ClassSearcher.getInstances(DiscoverableGTheme.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,13 @@ import javax.swing.LookAndFeel;
|
||||||
* The basic idea is that all the colors, fonts, and icons used in an application should be
|
* The basic idea is that all the colors, fonts, and icons used in an application should be
|
||||||
* accessed indirectly via an "id" string. Then the actual color, font, or icon can be changed
|
* accessed indirectly via an "id" string. Then the actual color, font, or icon can be changed
|
||||||
* without changing the source code. The default mapping of the id strings to a value is defined
|
* without changing the source code. The default mapping of the id strings to a value is defined
|
||||||
* in <name>.theme.properties files which are dynamically discovered by searching the module's
|
* in {name}.theme.properties files which are dynamically discovered by searching the module's
|
||||||
* data directory. Also, these files can optionally define a dark default value for an id which
|
* data directory. Also, these files can optionally define a dark default value for an id which
|
||||||
* would replace the standard default value in the event that the current theme specifies that it
|
* would replace the standard default value in the event that the current theme specifies that it
|
||||||
* is a dark theme. Themes are used to specify the application's {@link LookAndFeel}, whether or
|
* is a dark theme. Themes are used to specify the application's {@link LookAndFeel}, whether or
|
||||||
* not it is dark, and any customized values for colors, fonts, or icons. There are several
|
* not it is dark, and any customized values for colors, fonts, or icons. There are several
|
||||||
* "built-in" themes, one for each supported {@link LookAndFeel}, but additional themes can
|
* "built-in" themes, one for each supported {@link LookAndFeel}, but additional themes can
|
||||||
* be defined and stored in the users application home directory as a <name>.theme file.
|
* be defined and stored in the users application home directory as a {name}.theme file.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Gui {
|
public class Gui {
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package generic.theme;
|
||||||
|
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a strange implementation of {@link ThemeManager} that is meant to be used in a headless
|
||||||
|
* environment, but also needs theme properties to have been loaded. This is needed by any
|
||||||
|
* application that needs to do theme property validation.
|
||||||
|
*/
|
||||||
|
public class HeadlessThemeManager extends ThemeManager {
|
||||||
|
|
||||||
|
public static void initialize() {
|
||||||
|
if (INSTANCE instanceof HeadlessThemeManager) {
|
||||||
|
Msg.error(HeadlessThemeManager.class,
|
||||||
|
"Attempted to initialize theming more than once!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeadlessThemeManager themeManager = new HeadlessThemeManager();
|
||||||
|
themeManager.doInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HeadlessThemeManager() {
|
||||||
|
INSTANCE = this;
|
||||||
|
installInGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doInitialize() {
|
||||||
|
loadDefaultThemeValues();
|
||||||
|
|
||||||
|
buildCurrentValues();
|
||||||
|
GColor.refreshAll(currentValues);
|
||||||
|
GIcon.refreshAll(currentValues);
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ public class StubThemeManager extends ThemeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// palette colors are used statically throughout the application, so having them have values
|
// palette colors are used statically throughout the application, so having them have values
|
||||||
// in the stub will allow unit tests to run withouth initializing theming
|
// in the stub will allow unit tests to run without initializing theming
|
||||||
protected void installPaletteColors() {
|
protected void installPaletteColors() {
|
||||||
addPalette("nocolor", BLACK);
|
addPalette("nocolor", BLACK);
|
||||||
addPalette("black", BLACK);
|
addPalette("black", BLACK);
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package generic.theme;
|
package generic.theme;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
|
@ -26,17 +26,20 @@ import ghidra.util.Msg;
|
||||||
* Loads all the system theme.property files that contain all the default color, font, and
|
* Loads all the system theme.property files that contain all the default color, font, and
|
||||||
* icon values.
|
* icon values.
|
||||||
*/
|
*/
|
||||||
public class ThemeFileLoader {
|
public class ThemeDefaultsProvider {
|
||||||
public static final String THEME_DIR = "themes";
|
|
||||||
|
|
||||||
private GThemeValueMap defaults = new GThemeValueMap();
|
private GThemeValueMap defaults = new GThemeValueMap();
|
||||||
private GThemeValueMap darkDefaults = new GThemeValueMap();
|
private GThemeValueMap darkDefaults = new GThemeValueMap();
|
||||||
|
|
||||||
|
ThemeDefaultsProvider() {
|
||||||
|
loadThemeDefaultFiles();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for all the theme.property files and loads them into either the standard
|
* Searches for all the theme.property files and loads them into either the standard
|
||||||
* defaults (light) map or the dark defaults map.
|
* defaults (light) map or the dark defaults map.
|
||||||
*/
|
*/
|
||||||
public void loadThemeDefaultFiles() {
|
private void loadThemeDefaultFiles() {
|
||||||
defaults.clear();
|
defaults.clear();
|
||||||
darkDefaults.clear();
|
darkDefaults.clear();
|
||||||
|
|
||||||
|
@ -56,28 +59,6 @@ public class ThemeFileLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<GTheme> loadThemeFiles() {
|
|
||||||
List<File> fileList = new ArrayList<>();
|
|
||||||
FileFilter themeFileFilter = file -> file.getName().endsWith("." + GTheme.FILE_EXTENSION);
|
|
||||||
|
|
||||||
File dir = Application.getUserSettingsDirectory();
|
|
||||||
File themeDir = new File(dir, THEME_DIR);
|
|
||||||
File[] files = themeDir.listFiles(themeFileFilter);
|
|
||||||
if (files != null) {
|
|
||||||
fileList.addAll(Arrays.asList(files));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GTheme> list = new ArrayList<>();
|
|
||||||
for (File file : fileList) {
|
|
||||||
GTheme theme = loadTheme(file);
|
|
||||||
if (theme != null) {
|
|
||||||
list.add(theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the standard defaults {@link GThemeValueMap}
|
* Returns the standard defaults {@link GThemeValueMap}
|
||||||
* @return the standard defaults {@link GThemeValueMap}
|
* @return the standard defaults {@link GThemeValueMap}
|
||||||
|
@ -93,14 +74,4 @@ public class ThemeFileLoader {
|
||||||
public GThemeValueMap getDarkDefaults() {
|
public GThemeValueMap getDarkDefaults() {
|
||||||
return darkDefaults;
|
return darkDefaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GTheme loadTheme(File file) {
|
|
||||||
try {
|
|
||||||
return new ThemeReader(file).readTheme();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
Msg.error(Gui.class, "Could not load theme from file: " + file.getAbsolutePath(), e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -55,13 +55,23 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public abstract class ThemeManager {
|
public abstract class ThemeManager {
|
||||||
|
|
||||||
|
public static final String THEME_DIR = "themes";
|
||||||
|
|
||||||
static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12);
|
static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12);
|
||||||
static final Color DEFAULT_COLOR = Color.CYAN;
|
static final Color DEFAULT_COLOR = Color.CYAN;
|
||||||
|
|
||||||
protected static ThemeManager INSTANCE;
|
protected static ThemeManager INSTANCE;
|
||||||
|
|
||||||
|
protected GTheme activeTheme = getDefaultTheme();
|
||||||
|
|
||||||
|
protected GThemeValueMap javaDefaults = new GThemeValueMap();
|
||||||
|
protected GThemeValueMap systemValues = new GThemeValueMap();
|
||||||
protected GThemeValueMap currentValues = new GThemeValueMap();
|
protected GThemeValueMap currentValues = new GThemeValueMap();
|
||||||
|
|
||||||
|
protected GThemeValueMap applicationDefaults = new GThemeValueMap();
|
||||||
|
protected GThemeValueMap applicationDarkDefaults = new GThemeValueMap();
|
||||||
|
|
||||||
// these notifications are only when the user is manipulating theme values, so rare and at
|
// these notifications are only when the user is manipulating theme values, so rare and at
|
||||||
// user speed, so using copy on read
|
// user speed, so using copy on read
|
||||||
private WeakSet<ThemeListener> themeListeners =
|
private WeakSet<ThemeListener> themeListeners =
|
||||||
|
@ -82,37 +92,66 @@ public abstract class ThemeManager {
|
||||||
Gui.setThemeManager(this);
|
Gui.setThemeManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void loadDefaultThemeValues() {
|
||||||
|
ThemeDefaultsProvider provider = new ThemeDefaultsProvider();
|
||||||
|
applicationDefaults = provider.getDefaults();
|
||||||
|
applicationDarkDefaults = provider.getDarkDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void buildCurrentValues() {
|
||||||
|
GThemeValueMap map = new GThemeValueMap();
|
||||||
|
|
||||||
|
map.load(javaDefaults);
|
||||||
|
map.load(systemValues);
|
||||||
|
map.load(applicationDefaults);
|
||||||
|
if (activeTheme.useDarkDefaults()) {
|
||||||
|
map.load(applicationDarkDefaults);
|
||||||
|
}
|
||||||
|
map.load(activeTheme);
|
||||||
|
currentValues = map;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads the defaults from all the discoverable theme.property files.
|
* Reloads the defaults from all the discoverable theme.property files.
|
||||||
*/
|
*/
|
||||||
public abstract void reloadApplicationDefaults();
|
public void reloadApplicationDefaults() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores all the current application back to the values as specified by the active theme.
|
* Restores all the current application back to the values as specified by the active theme.
|
||||||
* In other words, reverts any changes to the active theme that haven't been saved.
|
* In other words, reverts any changes to the active theme that haven't been saved.
|
||||||
*/
|
*/
|
||||||
public abstract void restoreThemeValues();
|
public void restoreThemeValues() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the current color value for the given color id to the value established by the
|
* Restores the current color value for the given color id to the value established by the
|
||||||
* current theme.
|
* current theme.
|
||||||
* @param id the color id to restore back to the original theme value
|
* @param id the color id to restore back to the original theme value
|
||||||
*/
|
*/
|
||||||
public abstract void restoreColor(String id);
|
public void restoreColor(String id) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the current font value for the given font id to the value established by the
|
* Restores the current font value for the given font id to the value established by the
|
||||||
* current theme.
|
* current theme.
|
||||||
* @param id the font id to restore back to the original theme value
|
* @param id the font id to restore back to the original theme value
|
||||||
*/
|
*/
|
||||||
public abstract void restoreFont(String id);
|
public void restoreFont(String id) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the current icon value for the given icon id to the value established by the
|
* Restores the current icon value for the given icon id to the value established by the
|
||||||
* current theme.
|
* current theme.
|
||||||
* @param id the icon id to restore back to the original theme value
|
* @param id the icon id to restore back to the original theme value
|
||||||
*/
|
*/
|
||||||
public abstract void restoreIcon(String id);
|
public void restoreIcon(String id) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the color associated with the given id has been changed from the current
|
* Returns true if the color associated with the given id has been changed from the current
|
||||||
|
@ -121,7 +160,9 @@ public abstract class ThemeManager {
|
||||||
* @return true if the color associated with the given id has been changed from the current
|
* @return true if the color associated with the given id has been changed from the current
|
||||||
* theme value for that id.
|
* theme value for that id.
|
||||||
*/
|
*/
|
||||||
public abstract boolean isChangedColor(String id);
|
public boolean isChangedColor(String id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the font associated with the given id has been changed from the current
|
* Returns true if the font associated with the given id has been changed from the current
|
||||||
|
@ -130,7 +171,9 @@ public abstract class ThemeManager {
|
||||||
* @return true if the font associated with the given id has been changed from the current
|
* @return true if the font associated with the given id has been changed from the current
|
||||||
* theme value for that id.
|
* theme value for that id.
|
||||||
*/
|
*/
|
||||||
public abstract boolean isChangedFont(String id);
|
public boolean isChangedFont(String id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the Icon associated with the given id has been changed from the current
|
* Returns true if the Icon associated with the given id has been changed from the current
|
||||||
|
@ -139,57 +182,75 @@ public abstract class ThemeManager {
|
||||||
* @return true if the Icon associated with the given id has been changed from the current
|
* @return true if the Icon associated with the given id has been changed from the current
|
||||||
* theme value for that id.
|
* theme value for that id.
|
||||||
*/
|
*/
|
||||||
public abstract boolean isChangedIcon(String id);
|
public boolean isChangedIcon(String id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the application's active theme to the given theme.
|
* Sets the application's active theme to the given theme.
|
||||||
* @param theme the theme to make active
|
* @param theme the theme to make active
|
||||||
*/
|
*/
|
||||||
public abstract void setTheme(GTheme theme);
|
public void setTheme(GTheme theme) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given theme to set of all themes.
|
* Adds the given theme to set of all themes.
|
||||||
* @param newTheme the theme to add
|
* @param newTheme the theme to add
|
||||||
*/
|
*/
|
||||||
public abstract void addTheme(GTheme newTheme);
|
public void addTheme(GTheme newTheme) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the theme from the set of all themes. Also, if the theme has an associated
|
* Removes the theme from the set of all themes. Also, if the theme has an associated
|
||||||
* file, the file will be deleted.
|
* file, the file will be deleted.
|
||||||
* @param theme the theme to delete
|
* @param theme the theme to delete
|
||||||
*/
|
*/
|
||||||
public abstract void deleteTheme(GTheme theme);
|
public void deleteTheme(GTheme theme) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set of all known themes.
|
* Returns a set of all known themes.
|
||||||
* @return a set of all known themes.
|
* @return a set of all known themes.
|
||||||
*/
|
*/
|
||||||
public abstract Set<GTheme> getAllThemes();
|
public Set<GTheme> getAllThemes() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set of all known themes that are supported on the current platform.
|
* Returns a set of all known themes that are supported on the current platform.
|
||||||
* @return a set of all known themes that are supported on the current platform.
|
* @return a set of all known themes that are supported on the current platform.
|
||||||
*/
|
*/
|
||||||
public abstract Set<GTheme> getSupportedThemes();
|
public Set<GTheme> getSupportedThemes() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the active theme.
|
* Returns the active theme.
|
||||||
* @return the active theme.
|
* @return the active theme.
|
||||||
*/
|
*/
|
||||||
public abstract GTheme getActiveTheme();
|
public GTheme getActiveTheme() {
|
||||||
|
return activeTheme;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link LafType} for the currently active {@link LookAndFeel}
|
* Returns the {@link LafType} for the currently active {@link LookAndFeel}
|
||||||
* @return the {@link LafType} for the currently active {@link LookAndFeel}
|
* @return the {@link LafType} for the currently active {@link LookAndFeel}
|
||||||
*/
|
*/
|
||||||
public abstract LafType getLookAndFeelType();
|
public LafType getLookAndFeelType() {
|
||||||
|
return activeTheme.getLookAndFeelType();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the known theme that has the given name.
|
* Returns the known theme that has the given name.
|
||||||
* @param themeName the name of the theme to retrieve
|
* @param themeName the name of the theme to retrieve
|
||||||
* @return the known theme that has the given name
|
* @return the known theme that has the given name
|
||||||
*/
|
*/
|
||||||
public abstract GTheme getTheme(String themeName);
|
public GTheme getTheme(String themeName) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link GThemeValueMap} of all current theme values including unsaved changes to the
|
* Returns a {@link GThemeValueMap} of all current theme values including unsaved changes to the
|
||||||
|
@ -206,7 +267,17 @@ public abstract class ThemeManager {
|
||||||
* @return the theme values as defined by the current theme, ignoring any unsaved changes that
|
* @return the theme values as defined by the current theme, ignoring any unsaved changes that
|
||||||
* are currently applied to the application
|
* are currently applied to the application
|
||||||
*/
|
*/
|
||||||
public abstract GThemeValueMap getThemeValues();
|
public GThemeValueMap getThemeValues() {
|
||||||
|
GThemeValueMap map = new GThemeValueMap();
|
||||||
|
map.load(javaDefaults);
|
||||||
|
map.load(systemValues);
|
||||||
|
map.load(applicationDefaults);
|
||||||
|
if (activeTheme.useDarkDefaults()) {
|
||||||
|
map.load(applicationDarkDefaults);
|
||||||
|
}
|
||||||
|
map.load(activeTheme);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link GThemeValueMap} contains all values that differ from the default
|
* Returns a {@link GThemeValueMap} contains all values that differ from the default
|
||||||
|
@ -277,7 +348,9 @@ public abstract class ThemeManager {
|
||||||
* Updates the current value for the font id in the newValue
|
* Updates the current value for the font id in the newValue
|
||||||
* @param newValue the new {@link FontValue} to install in the current values.
|
* @param newValue the new {@link FontValue} to install in the current values.
|
||||||
*/
|
*/
|
||||||
public abstract void setFont(FontValue newValue);
|
public void setFont(FontValue newValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the current color for the given id.
|
* Updates the current color for the given id.
|
||||||
|
@ -303,7 +376,9 @@ public abstract class ThemeManager {
|
||||||
* Updates the current value for the color id in the newValue
|
* Updates the current value for the color id in the newValue
|
||||||
* @param newValue the new {@link ColorValue} to install in the current values.
|
* @param newValue the new {@link ColorValue} to install in the current values.
|
||||||
*/
|
*/
|
||||||
public abstract void setColor(ColorValue newValue);
|
public void setColor(ColorValue newValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the current {@link Icon} for the given id.
|
* Updates the current {@link Icon} for the given id.
|
||||||
|
@ -318,7 +393,9 @@ public abstract class ThemeManager {
|
||||||
* Updates the current value for the {@link Icon} id in the newValue
|
* Updates the current value for the {@link Icon} id in the newValue
|
||||||
* @param newValue the new {@link IconValue} to install in the current values.
|
* @param newValue the new {@link IconValue} to install in the current values.
|
||||||
*/
|
*/
|
||||||
public abstract void setIcon(IconValue newValue);
|
public void setIcon(IconValue newValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets a UIResource version of the GColor for the given id. Using this method ensures that
|
* gets a UIResource version of the GColor for the given id. Using this method ensures that
|
||||||
|
@ -327,7 +404,9 @@ public abstract class ThemeManager {
|
||||||
* @param id the id to get a GColorUIResource for
|
* @param id the id to get a GColorUIResource for
|
||||||
* @return a GColorUIResource for the given id
|
* @return a GColorUIResource for the given id
|
||||||
*/
|
*/
|
||||||
public abstract GColorUIResource getGColorUiResource(String id);
|
public GColorUIResource getGColorUiResource(String id) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets a UIResource version of the GIcon for the given id. Using this method ensures that
|
* gets a UIResource version of the GIcon for the given id. Using this method ensures that
|
||||||
|
@ -336,7 +415,9 @@ public abstract class ThemeManager {
|
||||||
* @param id the id to get a {@link GIconUIResource} for
|
* @param id the id to get a {@link GIconUIResource} for
|
||||||
* @return a GIconUIResource for the given id
|
* @return a GIconUIResource for the given id
|
||||||
*/
|
*/
|
||||||
public abstract GIconUIResource getGIconUiResource(String id);
|
public GIconUIResource getGIconUiResource(String id) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link GThemeValueMap} containing all the default theme values defined by the
|
* Returns the {@link GThemeValueMap} containing all the default theme values defined by the
|
||||||
|
@ -344,7 +425,11 @@ public abstract class ThemeManager {
|
||||||
* @return the {@link GThemeValueMap} containing all the default theme values defined by the
|
* @return the {@link GThemeValueMap} containing all the default theme values defined by the
|
||||||
* current {@link LookAndFeel}
|
* current {@link LookAndFeel}
|
||||||
*/
|
*/
|
||||||
public abstract GThemeValueMap getJavaDefaults();
|
public GThemeValueMap getJavaDefaults() {
|
||||||
|
GThemeValueMap map = new GThemeValueMap();
|
||||||
|
map.load(javaDefaults);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link GThemeValueMap} containing all the dark default values defined
|
* Returns the {@link GThemeValueMap} containing all the dark default values defined
|
||||||
|
@ -353,7 +438,11 @@ public abstract class ThemeManager {
|
||||||
* @return the {@link GThemeValueMap} containing all the dark values defined in
|
* @return the {@link GThemeValueMap} containing all the dark values defined in
|
||||||
* theme.properties files
|
* theme.properties files
|
||||||
*/
|
*/
|
||||||
public abstract GThemeValueMap getApplicationDarkDefaults();
|
public GThemeValueMap getApplicationDarkDefaults() {
|
||||||
|
GThemeValueMap map = new GThemeValueMap(applicationDefaults);
|
||||||
|
map.load(applicationDarkDefaults);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link GThemeValueMap} containing all the standard default values defined
|
* Returns the {@link GThemeValueMap} containing all the standard default values defined
|
||||||
|
@ -361,27 +450,42 @@ public abstract class ThemeManager {
|
||||||
* @return the {@link GThemeValueMap} containing all the standard values defined in
|
* @return the {@link GThemeValueMap} containing all the standard values defined in
|
||||||
* theme.properties files
|
* theme.properties files
|
||||||
*/
|
*/
|
||||||
public abstract GThemeValueMap getApplicationLightDefaults();
|
public GThemeValueMap getApplicationLightDefaults() {
|
||||||
|
GThemeValueMap map = new GThemeValueMap(applicationDefaults);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link GThemeValueMap} containing all default values for the current theme. It
|
* Returns a {@link GThemeValueMap} containing all default values for the current theme. It
|
||||||
* is a combination of application defined defaults and java {@link LookAndFeel} defaults.
|
* is a combination of application defined defaults and java {@link LookAndFeel} defaults.
|
||||||
* @return the current set of defaults.
|
* @return the current set of defaults.
|
||||||
*/
|
*/
|
||||||
public abstract GThemeValueMap getDefaults();
|
public GThemeValueMap getDefaults() {
|
||||||
|
GThemeValueMap currentDefaults = new GThemeValueMap(javaDefaults);
|
||||||
|
currentDefaults.load(systemValues);
|
||||||
|
currentDefaults.load(applicationDefaults);
|
||||||
|
if (activeTheme.useDarkDefaults()) {
|
||||||
|
currentDefaults.load(applicationDarkDefaults);
|
||||||
|
}
|
||||||
|
return currentDefaults;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given UI object is using the Aqua Look and Feel.
|
* Returns true if the given UI object is using the Aqua Look and Feel.
|
||||||
* @param UI the UI to examine.
|
* @param UI the UI to examine.
|
||||||
* @return true if the UI is using Aqua
|
* @return true if the UI is using Aqua
|
||||||
*/
|
*/
|
||||||
public abstract boolean isUsingAquaUI(ComponentUI UI);
|
public boolean isUsingAquaUI(ComponentUI UI) {
|
||||||
|
return activeTheme.getLookAndFeelType() == LafType.MAC;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if 'Nimbus' is the current Look and Feel
|
* Returns true if 'Nimbus' is the current Look and Feel
|
||||||
* @return true if 'Nimbus' is the current Look and Feel
|
* @return true if 'Nimbus' is the current Look and Feel
|
||||||
*/
|
*/
|
||||||
public abstract boolean isUsingNimbusUI();
|
public boolean isUsingNimbusUI() {
|
||||||
|
return activeTheme.getLookAndFeelType() == LafType.NIMBUS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a {@link ThemeListener} to be notified of theme changes.
|
* Adds a {@link ThemeListener} to be notified of theme changes.
|
||||||
|
@ -400,29 +504,13 @@ public abstract class ThemeManager {
|
||||||
themeListeners.remove(listener);
|
themeListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the default theme for the current platform.
|
|
||||||
* @return the default theme for the current platform.
|
|
||||||
*/
|
|
||||||
public static GTheme getDefaultTheme() {
|
|
||||||
OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem();
|
|
||||||
switch (OS) {
|
|
||||||
case MAC_OS_X:
|
|
||||||
return new MacTheme();
|
|
||||||
case WINDOWS:
|
|
||||||
return new WindowsTheme();
|
|
||||||
case LINUX:
|
|
||||||
case UNSUPPORTED:
|
|
||||||
default:
|
|
||||||
return new NimbusTheme();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there are any unsaved changes to the current theme.
|
* Returns true if there are any unsaved changes to the current theme.
|
||||||
* @return true if there are any unsaved changes to the current theme.
|
* @return true if there are any unsaved changes to the current theme.
|
||||||
*/
|
*/
|
||||||
public abstract boolean hasThemeChanges();
|
public boolean hasThemeChanges() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if an color for the given Id has been defined
|
* Returns true if an color for the given Id has been defined
|
||||||
|
@ -457,13 +545,35 @@ public abstract class ThemeManager {
|
||||||
* @param component the component to set/update the font
|
* @param component the component to set/update the font
|
||||||
* @param fontId the id of the font to register with the given component
|
* @param fontId the id of the font to register with the given component
|
||||||
*/
|
*/
|
||||||
public abstract void registerFont(Component component, String fontId);
|
public void registerFont(Component component, String fontId) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the current theme use dark default values.
|
* Returns true if the current theme use dark default values.
|
||||||
* @return true if the current theme use dark default values.
|
* @return true if the current theme use dark default values.
|
||||||
*/
|
*/
|
||||||
public abstract boolean isDarkTheme();
|
public boolean isDarkTheme() {
|
||||||
|
return activeTheme.useDarkDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default theme for the current platform.
|
||||||
|
* @return the default theme for the current platform.
|
||||||
|
*/
|
||||||
|
public static GTheme getDefaultTheme() {
|
||||||
|
OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem();
|
||||||
|
switch (OS) {
|
||||||
|
case MAC_OS_X:
|
||||||
|
return new MacTheme();
|
||||||
|
case WINDOWS:
|
||||||
|
return new WindowsTheme();
|
||||||
|
case LINUX:
|
||||||
|
case UNSUPPORTED:
|
||||||
|
default:
|
||||||
|
return new NimbusTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void notifyThemeChanged(ThemeEvent event) {
|
protected void notifyThemeChanged(ThemeEvent event) {
|
||||||
for (ThemeListener listener : themeListeners) {
|
for (ThemeListener listener : themeListeners) {
|
||||||
|
@ -474,10 +584,10 @@ public abstract class ThemeManager {
|
||||||
protected void error(String message) {
|
protected void error(String message) {
|
||||||
Throwable t = ReflectionUtilities.createThrowableWithStackOlderThan();
|
Throwable t = ReflectionUtilities.createThrowableWithStackOlderThan();
|
||||||
StackTraceElement[] trace = t.getStackTrace();
|
StackTraceElement[] trace = t.getStackTrace();
|
||||||
StackTraceElement[] filtered =
|
StackTraceElement[] filtered = ReflectionUtilities.filterStackTrace(trace, "java.",
|
||||||
ReflectionUtilities.filterStackTrace(trace, "java.", "theme.Gui", "theme.ThemeManager",
|
"theme.Gui", "theme.ThemeManager", "theme.GColor");
|
||||||
"theme.GColor");
|
|
||||||
t.setStackTrace(filtered);
|
t.setStackTrace(filtered);
|
||||||
Msg.error(this, message, t);
|
Msg.error(this, message, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,7 @@ public abstract class LookAndFeelManager {
|
||||||
installJavaDefaults();
|
installJavaDefaults();
|
||||||
fixupLookAndFeelIssues();
|
fixupLookAndFeelIssues();
|
||||||
installGlobalProperties();
|
installGlobalProperties();
|
||||||
|
installCustomLookAndFeelActions();
|
||||||
updateComponentUis();
|
updateComponentUis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,7 +460,6 @@ public abstract class LookAndFeelManager {
|
||||||
private void installGlobalProperties() {
|
private void installGlobalProperties() {
|
||||||
installGlobalLookAndFeelAttributes();
|
installGlobalLookAndFeelAttributes();
|
||||||
installGlobalFontSizeOverride();
|
installGlobalFontSizeOverride();
|
||||||
installCustomLookAndFeelActions();
|
|
||||||
installPopupMenuSettingsOverride();
|
installPopupMenuSettingsOverride();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ import generic.theme.builtin.*;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
import resources.icons.UrlImageIcon;
|
import resources.icons.UrlImageIcon;
|
||||||
|
|
||||||
public class ThemeManagerTest {
|
public class ApplicationThemeManagerTest {
|
||||||
|
|
||||||
private Font FONT = new Font("Dialog", Font.PLAIN, 13);
|
private Font FONT = new Font("Dialog", Font.PLAIN, 13);
|
||||||
private Font SMALL_FONT = new Font("Dialog", Font.PLAIN, 4);
|
private Font SMALL_FONT = new Font("Dialog", Font.PLAIN, 4);
|
||||||
|
@ -51,6 +51,8 @@ public class ThemeManagerTest {
|
||||||
private GTheme MAC_THEME = new MacTheme();
|
private GTheme MAC_THEME = new MacTheme();
|
||||||
private ThemeManager themeManager;
|
private ThemeManager themeManager;
|
||||||
|
|
||||||
|
private boolean errorsExpected;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
|
||||||
|
@ -69,7 +71,6 @@ public class ThemeManagerTest {
|
||||||
darkDefaultValues.addColor(new ColorValue("color.test.bg", BLACK));
|
darkDefaultValues.addColor(new ColorValue("color.test.bg", BLACK));
|
||||||
darkDefaultValues.addColor(new ColorValue("color.test.fg", BLUE));
|
darkDefaultValues.addColor(new ColorValue("color.test.fg", BLUE));
|
||||||
themeManager = new DummyApplicationThemeManager();
|
themeManager = new DummyApplicationThemeManager();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -264,16 +265,19 @@ public class ThemeManagerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetColorWithUnresolvedId() {
|
public void testGetColorWithUnresolvedId() {
|
||||||
|
errorsExpected = true;
|
||||||
assertEquals(CYAN, themeManager.getColor("color.badid"));
|
assertEquals(CYAN, themeManager.getColor("color.badid"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetIconWithUnresolvedId() {
|
public void testGetIconWithUnresolvedId() {
|
||||||
|
errorsExpected = true;
|
||||||
assertEquals(ResourceManager.getDefaultIcon(), themeManager.getIcon("icon.badid"));
|
assertEquals(ResourceManager.getDefaultIcon(), themeManager.getIcon("icon.badid"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetFontWithUnresolvedId() {
|
public void testGetFontWithUnresolvedId() {
|
||||||
|
errorsExpected = true;
|
||||||
assertEquals(ThemeManager.DEFAULT_FONT, themeManager.getFont("font.badid"));
|
assertEquals(ThemeManager.DEFAULT_FONT, themeManager.getFont("font.badid"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +341,7 @@ public class ThemeManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplicationThemeManager that doesn't read in theme.properties files or preferences
|
// ApplicationThemeManager that doesn't read in theme.properties files or preferences
|
||||||
class DummyApplicationThemeManager extends ApplicationThemeManager {
|
private class DummyApplicationThemeManager extends ApplicationThemeManager {
|
||||||
DummyApplicationThemeManager() {
|
DummyApplicationThemeManager() {
|
||||||
themePreferences = new ThemePreferences() {
|
themePreferences = new ThemePreferences() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -350,28 +354,25 @@ public class ThemeManagerTest {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
themeFileLoader = new ThemeFileLoader() {
|
doInitialize();
|
||||||
@Override
|
|
||||||
public void loadThemeDefaultFiles() {
|
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<GTheme> loadThemeFiles() {
|
protected void loadDefaultThemeValues() {
|
||||||
|
this.applicationDefaults = defaultValues;
|
||||||
|
this.applicationDarkDefaults = darkDefaultValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Collection<GTheme> loadThemeFiles() {
|
||||||
return new HashSet<>(themes);
|
return new HashSet<>(themes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GThemeValueMap getDefaults() {
|
protected void error(String message) {
|
||||||
return defaultValues;
|
if (!errorsExpected) {
|
||||||
|
super.error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public GThemeValueMap getDarkDefaults() {
|
|
||||||
return darkDefaultValues;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
doInitialize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import generic.theme.ApplicationThemeManager;
|
import generic.theme.HeadlessThemeManager;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.ApplicationConfiguration;
|
import ghidra.framework.ApplicationConfiguration;
|
||||||
import help.validator.*;
|
import help.validator.*;
|
||||||
|
@ -69,12 +69,11 @@ public class GHelpBuilder {
|
||||||
ApplicationConfiguration config = new ApplicationConfiguration() {
|
ApplicationConfiguration config = new ApplicationConfiguration() {
|
||||||
@Override
|
@Override
|
||||||
protected void initializeApplication() {
|
protected void initializeApplication() {
|
||||||
ApplicationThemeManager.initialize();
|
//
|
||||||
}
|
// We must be headless, as we are utility class. But, we also need theme properties
|
||||||
|
// to be loaded and correct for the help system to function properly.
|
||||||
@Override
|
//
|
||||||
public boolean isHeadless() {
|
HeadlessThemeManager.initialize();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Application.initializeApplication(new HelpApplicationLayout("Help Builder", "0.1"), config);
|
Application.initializeApplication(new HelpApplicationLayout("Help Builder", "0.1"), config);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue