mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
fae64a82c0
45 changed files with 1087 additions and 445 deletions
|
@ -1188,13 +1188,11 @@ void CollapseStructure::orderLoopBodies(void)
|
||||||
bool CollapseStructure::updateLoopBody(void)
|
bool CollapseStructure::updateLoopBody(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (finaltrace) { // If we've already performed trace on DAG with no likely goto edges
|
||||||
|
return false; // don't repeat the trace
|
||||||
|
}
|
||||||
FlowBlock *loopbottom = (FlowBlock *)0;
|
FlowBlock *loopbottom = (FlowBlock *)0;
|
||||||
FlowBlock *looptop = (FlowBlock *)0;
|
FlowBlock *looptop = (FlowBlock *)0;
|
||||||
if (finaltrace) { // If we've already performed the final trace
|
|
||||||
if (likelyiter == likelygoto.end())
|
|
||||||
return false; // We have nothing more to give
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
while (loopbodyiter != loopbody.end()) { // Last innermost loop
|
while (loopbodyiter != loopbody.end()) { // Last innermost loop
|
||||||
loopbottom = (*loopbodyiter).getCurrentBounds(&looptop,&graph);
|
loopbottom = (*loopbodyiter).getCurrentBounds(&looptop,&graph);
|
||||||
if (loopbottom != (FlowBlock *)0) {
|
if (loopbottom != (FlowBlock *)0) {
|
||||||
|
@ -1206,8 +1204,10 @@ bool CollapseStructure::updateLoopBody(void)
|
||||||
likelylistfull = false; // Need to generate likely list for new loopbody (or no loopbody)
|
likelylistfull = false; // Need to generate likely list for new loopbody (or no loopbody)
|
||||||
loopbottom = (FlowBlock *)0;
|
loopbottom = (FlowBlock *)0;
|
||||||
}
|
}
|
||||||
if (likelylistfull) return true;
|
if (likelylistfull && likelyiter != likelygoto.end())
|
||||||
// If we reach here, need to generate likely gotos for a new inner loop
|
return true;
|
||||||
|
|
||||||
|
// If we reach here, need to generate likely gotos for a new inner loop or DAG
|
||||||
likelygoto.clear(); // Clear out any old likely gotos from last inner loop
|
likelygoto.clear(); // Clear out any old likely gotos from last inner loop
|
||||||
TraceDAG tracer(likelygoto);
|
TraceDAG tracer(likelygoto);
|
||||||
if (loopbottom != (FlowBlock *)0) {
|
if (loopbottom != (FlowBlock *)0) {
|
||||||
|
@ -1216,7 +1216,6 @@ bool CollapseStructure::updateLoopBody(void)
|
||||||
(*loopbodyiter).setExitMarks(&graph); // Set the bounds of the TraceDAG
|
(*loopbodyiter).setExitMarks(&graph); // Set the bounds of the TraceDAG
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
finaltrace = true;
|
|
||||||
for(uint4 i=0;i<graph.getSize();++i) {
|
for(uint4 i=0;i<graph.getSize();++i) {
|
||||||
FlowBlock *bl = graph.getBlock(i);
|
FlowBlock *bl = graph.getBlock(i);
|
||||||
if (bl->sizeIn() == 0)
|
if (bl->sizeIn() == 0)
|
||||||
|
@ -1225,11 +1224,15 @@ bool CollapseStructure::updateLoopBody(void)
|
||||||
}
|
}
|
||||||
tracer.initialize();
|
tracer.initialize();
|
||||||
tracer.pushBranches();
|
tracer.pushBranches();
|
||||||
|
likelylistfull = true; // Mark likelygoto generation complete for current loop or DAG
|
||||||
if (loopbottom != (FlowBlock *)0) {
|
if (loopbottom != (FlowBlock *)0) {
|
||||||
(*loopbodyiter).emitLikelyEdges(likelygoto,&graph);
|
(*loopbodyiter).emitLikelyEdges(likelygoto,&graph);
|
||||||
(*loopbodyiter).clearExitMarks(&graph);
|
(*loopbodyiter).clearExitMarks(&graph);
|
||||||
}
|
}
|
||||||
likelylistfull = true;
|
else if (likelygoto.empty()) {
|
||||||
|
finaltrace = true; // No loops left and trace didn't find gotos
|
||||||
|
return false;
|
||||||
|
}
|
||||||
likelyiter = likelygoto.begin();
|
likelyiter = likelygoto.begin();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -333,10 +333,10 @@ color.fg.listing.bytes = orange
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
Properties defined by the theming system do not follow this pattern. To reference a
|
Properties defined by the theming system do not follow this pattern. To reference a
|
||||||
property that does not have a standard prefix, an ID can be prefixed with <COD>[color]
|
property that does not have a standard prefix, an ID can be prefixed with <CODE>[color]
|
||||||
</CODE>, <CODE>[font]</CODE>, or <CODE>[icon]</CODE> as appropriate to allow the theme
|
</CODE>, <CODE>[font]</CODE>, or <CODE>[icon]</CODE> as appropriate to allow the theme
|
||||||
property parser to recognize the values as IDs to other properties. For example, to refer to a
|
property parser to recognize the values as IDs to other properties. For example, to refer to a
|
||||||
system property named<CODE>system.color.bg.view</CODE>,
|
system property named <CODE>system.color.bg.view</CODE>,
|
||||||
you would use the following definition:
|
you would use the following definition:
|
||||||
<P>
|
<P>
|
||||||
<BLOCKUOTE>
|
<BLOCKUOTE>
|
||||||
|
@ -454,7 +454,7 @@ color.fg.listing.bytes = orange
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<PRE>
|
<PRE>
|
||||||
<CODE>
|
<CODE>
|
||||||
<I>iconName</I>[size(width,height)][disabled]{iconOverlayName[size(width,height)[disabled][move(x,y)]}{...}
|
<I>iconName</I>[size(width,height)][disabled]{overlayIconName[size(width,height)[disabled][move(x,y)]}{...}
|
||||||
|
|
||||||
</CODE>
|
</CODE>
|
||||||
</PRE>
|
</PRE>
|
||||||
|
@ -522,7 +522,7 @@ color.fg.listing.bytes = orange
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>
|
<P>
|
||||||
A list of palette colors has been defined in <CODE>gui.palette.theme.properties.</CODE>.
|
A list of palette colors has been defined in <CODE>gui.palette.theme.properties</CODE>.
|
||||||
These palette colors values are meant to be used by developers to reduce the total number
|
These palette colors values are meant to be used by developers to reduce the total number
|
||||||
of colors used in the application. These color ids and values are viewable in the
|
of colors used in the application. These color ids and values are viewable in the
|
||||||
<A href="ThemingUserDocs.html#Edit_Theme">Theme Editor Dialog</A>.
|
<A href="ThemingUserDocs.html#Edit_Theme">Theme Editor Dialog</A>.
|
||||||
|
|
|
@ -38,8 +38,8 @@
|
||||||
<CODE>ColorValue</CODE>, <CODE>FontValue</CODE>, and
|
<CODE>ColorValue</CODE>, <CODE>FontValue</CODE>, and
|
||||||
<CODE>IconValue</CODE>. Resource values are stored in these <CODE>ThemeValue</CODE> sub-classes
|
<CODE>IconValue</CODE>. Resource values are stored in these <CODE>ThemeValue</CODE> sub-classes
|
||||||
because the value can be
|
because the value can be
|
||||||
either a concrete value or be a reference to some other resource of the same type. So, for
|
either a concrete value or a reference to some other resource of the same type. So, for
|
||||||
example, "color.bg.foo" could map directly to an actual color or its value could be reference
|
example, "color.bg.foo" could map directly to an actual color or its value could be a reference
|
||||||
to some other indirect color like "color.bg.bar". In any <CODE>ThemeValue</CODE> object, either
|
to some other indirect color like "color.bg.bar". In any <CODE>ThemeValue</CODE> object, either
|
||||||
the referenced ID or the direct value must be null. To get the ultimate concrete value, there
|
the referenced ID or the direct value must be null. To get the ultimate concrete value, there
|
||||||
is a convenience method called <CODE>get()</CODE> on <CODE>ThemeValue</CODE>s that takes a
|
is a convenience method called <CODE>get()</CODE> on <CODE>ThemeValue</CODE>s that takes a
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<HTML>
|
<HTML>
|
||||||
<HEAD>
|
<HEAD>
|
||||||
<TITLE>General Overivew</TITLE>
|
<TITLE>Theming Overivew</TITLE>
|
||||||
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||||
</HEAD>
|
</HEAD>
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
themes to choose from and by simply switching the theme, the system will then update the Look
|
themes to choose from and by simply switching the theme, the system will then update the Look
|
||||||
and Feel along with the colors, fonts, and icons, all with one action. The set of themes to
|
and Feel along with the colors, fonts, and icons, all with one action. The set of themes to
|
||||||
choose from is a mix of built-in themes and saved custom themes. There is one built-in theme
|
choose from is a mix of built-in themes and saved custom themes. There is one built-in theme
|
||||||
for each supported Look and Feel. The chosen theme will use the UI values defied by the Look
|
for each supported Look and Feel. The chosen theme will use the UI values defined by the Look
|
||||||
and Feel, as well as all the values for the defined property IDs. Users are able to
|
and Feel, as well as all the values for the defined property IDs. Users are able to
|
||||||
create custom themes to change any color, font, or icon defined by the application, along with
|
create custom themes to change any color, font, or icon defined by the application, along with
|
||||||
UI values supplied by the associated Look and Feel.</P>
|
UI values supplied by the associated Look and Feel.</P>
|
||||||
|
|
|
@ -233,9 +233,9 @@
|
||||||
<BlOCKQUOTE>
|
<BlOCKQUOTE>
|
||||||
|
|
||||||
<P>Theme Property Names (also referred to as IDs or keys) that are defined by the application
|
<P>Theme Property Names (also referred to as IDs or keys) that are defined by the application
|
||||||
use a common format to help make sorting and viewing properties more intuitive as to their use. See
|
use a common format to help make sorting and viewing properties more intuitive as to their use.
|
||||||
the <A href="ThemingDeveloperDocs.html#Resource_Ids">Developer Documentation</A> for more details on the property ID
|
See the <A href="ThemingDeveloperDocs.html#Resource_Ids">Developer Documentation</A> for more
|
||||||
format and naming conventions.</P>
|
details on the property ID format and naming conventions.</P>
|
||||||
|
|
||||||
</BlOCKQUOTE>
|
</BlOCKQUOTE>
|
||||||
<H2>Theme Files</H2>
|
<H2>Theme Files</H2>
|
||||||
|
@ -243,10 +243,10 @@
|
||||||
|
|
||||||
<P>Theme Files are used to store saved custom themes. They are simple text files and are
|
<P>Theme Files are used to store saved custom themes. They are simple text files and are
|
||||||
stored in the user's home application directory under
|
stored in the user's home application directory under
|
||||||
<code><home>/.ghidra/.ghidra-<version>/themes</code>. The first three properties are always the
|
<code><home>/.ghidra/.ghidra-<version>/themes</code>. The first three properties
|
||||||
theme name, the Look and Feel name, and whether the theme uses standard defaults or dark
|
are always the theme name, the Look and Feel name, and whether the theme uses standard
|
||||||
defaults. Finally, there is a list of overridden property "name = value" lines. The format
|
defaults or dark defaults. Finally, there is a list of overridden property "name = value"
|
||||||
is:</P>
|
lines. The format is:</P>
|
||||||
<CODE>
|
<CODE>
|
||||||
<PRE>
|
<PRE>
|
||||||
name = [theme name]
|
name = [theme name]
|
||||||
|
@ -270,18 +270,18 @@
|
||||||
|
|
||||||
color.bg = Black
|
color.bg = Black
|
||||||
color.bg.foo = #012345
|
color.bg.foo = #012345
|
||||||
[color]Panel.background = Red
|
|
||||||
font.button = dialog-PLAIN-14
|
font.button = dialog-PLAIN-14
|
||||||
icon.refresh = images/reload3.png
|
icon.refresh = images/reload3.png
|
||||||
color.bg.bar = color.bg.foo
|
color.bg.bar = color.bg.foo
|
||||||
color.bg.xxx = [color]Panel.background
|
[laf.color]Panel.background = silver
|
||||||
|
[laf.color]TextArea.background = [laf.color]Panel.background
|
||||||
</PRE>
|
</PRE>
|
||||||
|
|
||||||
|
|
||||||
<P>Each property line is expected to begin with either "color.", "font.", or "icon." Since
|
<P>Each property line is expected to begin with either "color.", "font.", or "icon." Since
|
||||||
java defined properties don't start with these prefixes, they will have "[color]", "[font]",
|
java defined properties don't start with these prefixes, they will have "[laf.color]",
|
||||||
or "[icon]" prepended to their property name. These brackets are only used to aid in
|
"[laf.font]", or "[laf.icon]" prepended to their property name. These brackets are only used
|
||||||
parsing this file. When the properties are used in Ghidra, the bracketed prefixes are
|
to aid in parsing this file. When the properties are used in Ghidra, the bracketed prefixes are
|
||||||
removed.</P>
|
removed.</P>
|
||||||
|
|
||||||
<P>Also, note that the values of these properties can reference other property names. If the
|
<P>Also, note that the values of these properties can reference other property names. If the
|
||||||
|
|
|
@ -24,7 +24,7 @@ import ghidra.util.task.Task;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A version of {@link DialogComponentProvider} for clients to extend when they intend for their
|
* A version of {@link DialogComponentProvider} for clients to extend when they intend for their
|
||||||
* dialog to be reused. Typically, dialogs are used once and then no longer referenced.
|
* dialog to be reused. Typically, dialogs are used once and then no longer referenced.
|
||||||
* Alternatively, some clients create a dialog and use it for the lifetime of their code. This
|
* Alternatively, some clients create a dialog and use it for the lifetime of their code. This
|
||||||
* is typical of non-modal plugins.
|
* is typical of non-modal plugins.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -32,7 +32,7 @@ import ghidra.util.task.Task;
|
||||||
* with the dialog, such as in your plugin's {@code dispose()} method.
|
* with the dialog, such as in your plugin's {@code dispose()} method.
|
||||||
* <p>
|
* <p>
|
||||||
* The primary benefit of using this dialog is that any updates to the current theme will update
|
* The primary benefit of using this dialog is that any updates to the current theme will update
|
||||||
* this dialog, even when the dialog is not visible. For dialogs that extend
|
* this dialog, even when the dialog is not visible. For dialogs that extend
|
||||||
* {@link DialogComponentProvider} directly, they only receive theme updates if they are visible.
|
* {@link DialogComponentProvider} directly, they only receive theme updates if they are visible.
|
||||||
*
|
*
|
||||||
* @see DialogComponentProvider
|
* @see DialogComponentProvider
|
||||||
|
@ -62,12 +62,7 @@ public class ReusableDialogComponentProvider extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void themeChanged(ThemeEvent ev) {
|
private void themeChanged(ThemeEvent ev) {
|
||||||
if (!ev.isLookAndFeelChanged()) {
|
// if we are visible, then we don't need to update as the system updates all visible components
|
||||||
return; // we only care if the Look and Feel changes
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we are visible, then we don't need to update as the system updates all
|
|
||||||
// visible components
|
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,7 @@ public class ComponentThemeInspectorAction extends DockingAction {
|
||||||
|
|
||||||
Color bg = component.getBackground();
|
Color bg = component.getBackground();
|
||||||
Color fg = component.getForeground();
|
Color fg = component.getForeground();
|
||||||
|
Font font = component.getFont();
|
||||||
String id;
|
String id;
|
||||||
String clazz = component.getClass().getSimpleName();
|
String clazz = component.getClass().getSimpleName();
|
||||||
if (clazz.isEmpty()) {
|
if (clazz.isEmpty()) {
|
||||||
|
@ -175,6 +176,10 @@ public class ComponentThemeInspectorAction extends DockingAction {
|
||||||
.append(spacer)
|
.append(spacer)
|
||||||
.append("fg: ")
|
.append("fg: ")
|
||||||
.append(fgText)
|
.append(fgText)
|
||||||
|
.append(tabs)
|
||||||
|
.append(spacer)
|
||||||
|
.append("font: ")
|
||||||
|
.append(font)
|
||||||
.append('\n');
|
.append('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,18 @@ public class ThemeEditorDialog extends DialogComponentProvider {
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetSelectedLookAndFeel() {
|
||||||
|
Swing.runLater(() -> {
|
||||||
|
try {
|
||||||
|
combo.removeItemListener(comboListener);
|
||||||
|
combo.setSelectedItem(themeManager.getActiveTheme().getLookAndFeelType());
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
combo.addItemListener(comboListener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void themeComboChanged(ItemEvent e) {
|
private void themeComboChanged(ItemEvent e) {
|
||||||
|
|
||||||
if (e.getStateChange() != ItemEvent.SELECTED) {
|
if (e.getStateChange() != ItemEvent.SELECTED) {
|
||||||
|
@ -181,24 +193,43 @@ public class ThemeEditorDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
LafType lafType = (LafType) e.getItem();
|
LafType lafType = (LafType) e.getItem();
|
||||||
Swing.runLater(() -> {
|
if (!themeManager.hasThemeValueChanges()) {
|
||||||
|
setLookAndFeel(lafType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
themeManager.setLookAndFeel(lafType, lafType.usesDarkDefaults());
|
//@formatter:off
|
||||||
if (lafType == LafType.GTK) {
|
int result = OptionDialog.showOptionDialog(null, "Discard Changes?",
|
||||||
setStatusText(
|
"Changing the Look and Feel type will cause you to lose your changes.\n" +
|
||||||
"Warning - Themes using the GTK LookAndFeel do not support changing java " +
|
"If you would like to keep your changes, cancel this dialog and then save the theme\n" +
|
||||||
"component colors, fonts or icons.",
|
"Would you like to continue?",
|
||||||
MessageType.ERROR);
|
"Lose Changes");
|
||||||
}
|
//@formatter:on
|
||||||
else {
|
if (result == OptionDialog.CANCEL_OPTION) {
|
||||||
setStatusText("");
|
resetSelectedLookAndFeel();
|
||||||
}
|
return;
|
||||||
colorTree.rebuild();
|
}
|
||||||
colorTable.reloadAll();
|
|
||||||
paletteTable.reloadAll();
|
setLookAndFeel(lafType);
|
||||||
fontTable.reloadAll();
|
}
|
||||||
iconTable.reloadAll();
|
|
||||||
});
|
private void setLookAndFeel(LafType lafType) {
|
||||||
|
|
||||||
|
themeManager.setLookAndFeel(lafType, lafType.usesDarkDefaults());
|
||||||
|
if (lafType == LafType.GTK) {
|
||||||
|
setStatusText(
|
||||||
|
"Warning - Themes using the GTK LookAndFeel do not support changing java " +
|
||||||
|
"component colors, fonts or icons.",
|
||||||
|
MessageType.WARNING);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setStatusText("");
|
||||||
|
}
|
||||||
|
colorTree.rebuild();
|
||||||
|
colorTable.reloadAll();
|
||||||
|
paletteTable.reloadAll();
|
||||||
|
fontTable.reloadAll();
|
||||||
|
iconTable.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateButtons() {
|
private void updateButtons() {
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
color.bg = [color]system.color.bg.view
|
color.bg = [color]system.color.bg.view
|
||||||
color.fg = [color]system.color.fg.view
|
color.fg = [color]system.color.fg.view
|
||||||
|
|
||||||
// On some LaFs the tables and trees use the bg color we define. Make that consistent for all LaFs.
|
|
||||||
[color]Viewport.background = color.bg
|
|
||||||
|
|
||||||
color.fg.error = color.palette.red
|
color.fg.error = color.palette.red
|
||||||
color.fg.disabled = color.palette.lightgray
|
color.fg.disabled = color.palette.lightgray
|
||||||
color.bg.uneditable = [color]system.color.bg.control
|
color.bg.uneditable = [color]system.color.bg.control
|
||||||
|
@ -40,6 +37,27 @@ font.standard = [font]system.font.control
|
||||||
font.monospaced = monospaced-PLAIN-12
|
font.monospaced = monospaced-PLAIN-12
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Java LaF Fixups
|
||||||
|
//
|
||||||
|
// Prefer buttons that change on hover
|
||||||
|
[laf.boolean]Button.rollover = true
|
||||||
|
[laf.boolean]Toolbar.isRollover = true
|
||||||
|
|
||||||
|
// Java 1.6 UI consumes MousePressed event when dismissing popup menu
|
||||||
|
// which prevents application components from getting this event.
|
||||||
|
[laf.boolean]PopupMenu.consumeEventOnClose = false
|
||||||
|
|
||||||
|
// On some LaFs the tables and trees use the bg color we define. Make that consistent for all LaFs.
|
||||||
|
[laf.color]Viewport.background = color.bg
|
||||||
|
|
||||||
|
// Fix up the default fonts that Java 1.5.0 changed to Courier
|
||||||
|
[laf.font]TextArea.font = font.monospaced
|
||||||
|
[laf.font]PasswordField.font = font.monospaced
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Icons files
|
// Icons files
|
||||||
icon.flag = flag.png
|
icon.flag = flag.png
|
||||||
icon.lock = kgpg.png
|
icon.lock = kgpg.png
|
||||||
|
@ -108,3 +126,15 @@ color.cursor.unfocused = color.palette.darkgray
|
||||||
icon.make.selection = stack.png
|
icon.make.selection = stack.png
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Flat Dark]
|
||||||
|
|
||||||
|
[laf.boolean]ToolBar.focusableButtons = true
|
||||||
|
|
||||||
|
[Flat Light]
|
||||||
|
|
||||||
|
[laf.boolean]ToolBar.focusableButtons = true
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,18 @@ public abstract class AbstractThemeReader {
|
||||||
reportDuplicateKey(oldValue, lineNumber);
|
reportDuplicateKey(oldValue, lineNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 'external' look and feel property used by the UIManager
|
||||||
|
else if (BooleanPropertyValue.isBooleanKey(key)) {
|
||||||
|
JavaPropertyValue oldValue =
|
||||||
|
valueMap.addProperty(parseBooleanProperty(key, value, lineNumber));
|
||||||
|
reportDuplicateKey(oldValue, lineNumber);
|
||||||
|
}
|
||||||
|
else if (StringPropertyValue.isStringKey(key)) {
|
||||||
|
JavaPropertyValue oldValue =
|
||||||
|
valueMap.addProperty(parseStringProperty(key, value, lineNumber));
|
||||||
|
reportDuplicateKey(oldValue, lineNumber);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
error(lineNumber, "Can't process property: " + key + " = " + value);
|
error(lineNumber, "Can't process property: " + key + " = " + value);
|
||||||
}
|
}
|
||||||
|
@ -143,6 +155,22 @@ public abstract class AbstractThemeReader {
|
||||||
return parsedValue;
|
return parsedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BooleanPropertyValue parseBooleanProperty(String key, String value, int lineNumber) {
|
||||||
|
BooleanPropertyValue parsedValue = BooleanPropertyValue.parse(key, value);
|
||||||
|
if (parsedValue == null) {
|
||||||
|
error(lineNumber, "Could not parse boolean property value: " + value);
|
||||||
|
}
|
||||||
|
return parsedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StringPropertyValue parseStringProperty(String key, String value, int lineNumber) {
|
||||||
|
StringPropertyValue parsedValue = StringPropertyValue.parse(key, value);
|
||||||
|
if (parsedValue == null) {
|
||||||
|
error(lineNumber, "Could not parse String property value: " + value);
|
||||||
|
}
|
||||||
|
return parsedValue;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Section> readSections(LineNumberReader reader) throws IOException {
|
private List<Section> readSections(LineNumberReader reader) throws IOException {
|
||||||
|
|
||||||
List<Section> sections = new ArrayList<>();
|
List<Section> sections = new ArrayList<>();
|
||||||
|
@ -208,7 +236,7 @@ public abstract class AbstractThemeReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents all the value found in a section of the theme properties file. Sections are
|
* Represents all the value found in a section of the theme properties file. Sections are
|
||||||
* defined by a line containing just "[section name]"
|
* defined by a line containing just "[section name]"
|
||||||
*/
|
*/
|
||||||
protected class Section {
|
protected class Section {
|
||||||
|
@ -287,7 +315,7 @@ public abstract class AbstractThemeReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a raw line from the file to this section. The line will be parsed into a a
|
* Adds a raw line from the file to this section. The line will be parsed into a a
|
||||||
* key-value pair.
|
* key-value pair.
|
||||||
* @param line the line to be added/parsed
|
* @param line the line to be added/parsed
|
||||||
* @param lineNumber the line number in the file for this line
|
* @param lineNumber the line number in the file for this line
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restoreThemeValues() {
|
public void restoreThemeValues() {
|
||||||
applicationDefaults = getApplicationDefaults();
|
applicationDefaults = loadApplicationDefaults();
|
||||||
buildCurrentValues();
|
buildCurrentValues();
|
||||||
lookAndFeelManager.resetAll(javaDefaults);
|
lookAndFeelManager.resetAll(javaDefaults);
|
||||||
notifyThemeChanged(new AllValuesChangedThemeEvent(false));
|
notifyThemeChanged(new AllValuesChangedThemeEvent(false));
|
||||||
|
@ -288,6 +288,11 @@ public class ApplicationThemeManager extends ThemeManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasThemeValueChanges() {
|
||||||
|
return !changedValuesMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerFont(Component component, String fontId) {
|
public void registerFont(Component component, String fontId) {
|
||||||
lookAndFeelManager.registerFont(component, fontId);
|
lookAndFeelManager.registerFont(component, fontId);
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Java property value for keys that use boolean values.
|
||||||
|
*/
|
||||||
|
public class BooleanPropertyValue extends JavaPropertyValue {
|
||||||
|
|
||||||
|
private static final String EXTERNAL_LAF_ID_PREFIX = "[laf.boolean]";
|
||||||
|
|
||||||
|
public BooleanPropertyValue(String id, boolean value) {
|
||||||
|
this(id, null, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanPropertyValue(String id, String refId, Boolean value) {
|
||||||
|
super(id, refId, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBooleanKey(String key) {
|
||||||
|
return key.toLowerCase().startsWith(EXTERNAL_LAF_ID_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BooleanPropertyValue parse(String key, String value) {
|
||||||
|
String id = fromExternalId(key);
|
||||||
|
|
||||||
|
if (isBooleanKey(value)) {
|
||||||
|
String refId = fromExternalId(value);
|
||||||
|
return new BooleanPropertyValue(key, refId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean b = Boolean.parseBoolean(value);
|
||||||
|
return new BooleanPropertyValue(id, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String fromExternalId(String externalId) {
|
||||||
|
if (!externalId.toLowerCase().startsWith(EXTERNAL_LAF_ID_PREFIX)) {
|
||||||
|
return externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We return the raw property name (e.g., TextArea.background), not the normalized name
|
||||||
|
// (e.g., laf.color.TextArea.background), since the system currently does not provide the
|
||||||
|
// end-user a way to change these values from the UI.
|
||||||
|
return externalId.substring(EXTERNAL_LAF_ID_PREFIX.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object getUnresolvedReferenceValue(String primaryId, String unresolvedId) {
|
||||||
|
Msg.warn(this,
|
||||||
|
"Could not resolve indirect property for \"" + unresolvedId +
|
||||||
|
"\" for primary id \"" + primaryId + "\", using last resort default");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String toExternalId(String internalId) {
|
||||||
|
return EXTERNAL_LAF_ID_PREFIX + internalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSerializedValue() {
|
||||||
|
return Boolean.toString((Boolean) value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@ package generic.theme;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.WebColors;
|
import ghidra.util.WebColors;
|
||||||
import utilities.util.reflection.ReflectionUtilities;
|
import utilities.util.reflection.ReflectionUtilities;
|
||||||
|
@ -28,6 +30,10 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||||
* and if the class's refId is non-null, then the color value will be null.
|
* and if the class's refId is non-null, then the color value will be null.
|
||||||
*/
|
*/
|
||||||
public class ColorValue extends ThemeValue<Color> {
|
public class ColorValue extends ThemeValue<Color> {
|
||||||
|
|
||||||
|
public static final String LAF_ID_PREFIX = "laf.color.";
|
||||||
|
public static final String EXTERNAL_LAF_ID_PREFIX = "[laf.color]";
|
||||||
|
|
||||||
private static final String COLOR_ID_PREFIX = "color.";
|
private static final String COLOR_ID_PREFIX = "color.";
|
||||||
private static final String EXTERNAL_PREFIX = "[color]";
|
private static final String EXTERNAL_PREFIX = "[color]";
|
||||||
|
|
||||||
|
@ -65,13 +71,14 @@ public class ColorValue extends ThemeValue<Color> {
|
||||||
return !id.startsWith(COLOR_ID_PREFIX);
|
return !id.startsWith(COLOR_ID_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given key string is a valid external key for a color value
|
* Returns true if the given key string is a valid external key for a color value
|
||||||
* @param key the key string to test
|
* @param key the key string to test
|
||||||
* @return true if the given key string is a valid external key for a color value
|
* @return true if the given key string is a valid external key for a color value
|
||||||
*/
|
*/
|
||||||
public static boolean isColorKey(String key) {
|
public static boolean isColorKey(String key) {
|
||||||
return key.startsWith(COLOR_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX);
|
return StringUtils.startsWithAny(key, COLOR_ID_PREFIX, EXTERNAL_PREFIX,
|
||||||
|
EXTERNAL_LAF_ID_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,6 +122,12 @@ public class ColorValue extends ThemeValue<Color> {
|
||||||
if (internalId.startsWith(COLOR_ID_PREFIX)) {
|
if (internalId.startsWith(COLOR_ID_PREFIX)) {
|
||||||
return internalId;
|
return internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (internalId.startsWith(LAF_ID_PREFIX)) {
|
||||||
|
String baseId = internalId.substring(LAF_ID_PREFIX.length());
|
||||||
|
return EXTERNAL_LAF_ID_PREFIX + baseId;
|
||||||
|
}
|
||||||
|
|
||||||
return EXTERNAL_PREFIX + internalId;
|
return EXTERNAL_PREFIX + internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +135,9 @@ public class ColorValue extends ThemeValue<Color> {
|
||||||
if (externalId.startsWith(EXTERNAL_PREFIX)) {
|
if (externalId.startsWith(EXTERNAL_PREFIX)) {
|
||||||
return externalId.substring(EXTERNAL_PREFIX.length());
|
return externalId.substring(EXTERNAL_PREFIX.length());
|
||||||
}
|
}
|
||||||
|
if (externalId.startsWith(EXTERNAL_LAF_ID_PREFIX)) {
|
||||||
|
return LAF_ID_PREFIX + externalId.substring(EXTERNAL_LAF_ID_PREFIX.length());
|
||||||
|
}
|
||||||
return externalId;
|
return externalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ package generic.theme;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,9 +29,14 @@ import ghidra.util.Msg;
|
||||||
* and if the class's refId is non-null, then the font value will be null.
|
* and if the class's refId is non-null, then the font value will be null.
|
||||||
*/
|
*/
|
||||||
public class FontValue extends ThemeValue<Font> {
|
public class FontValue extends ThemeValue<Font> {
|
||||||
|
|
||||||
|
public static final String LAF_ID_PREFIX = "laf.font.";
|
||||||
|
public static final String EXTERNAL_LAF_ID_PREFIX = "[laf.font]";
|
||||||
|
|
||||||
static final String FONT_ID_PREFIX = "font.";
|
static final String FONT_ID_PREFIX = "font.";
|
||||||
public static final Font LAST_RESORT_DEFAULT = new Font("monospaced", Font.PLAIN, 12);
|
|
||||||
private static final String EXTERNAL_PREFIX = "[font]";
|
private static final String EXTERNAL_PREFIX = "[font]";
|
||||||
|
|
||||||
|
public static final Font LAST_RESORT_DEFAULT = new Font("monospaced", Font.PLAIN, 12);
|
||||||
private FontModifier modifier;
|
private FontModifier modifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,13 +104,14 @@ public class FontValue extends ThemeValue<Font> {
|
||||||
return String.format("%s-%s-%s", font.getName(), getStyleString(font), font.getSize());
|
return String.format("%s-%s-%s", font.getName(), getStyleString(font), font.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given key string is a valid external key for a font value
|
* Returns true if the given key string is a valid external key for a font value
|
||||||
* @param key the key string to test
|
* @param key the key string to test
|
||||||
* @return true if the given key string is a valid external key for a font value
|
* @return true if the given key string is a valid external key for a font value
|
||||||
*/
|
*/
|
||||||
public static boolean isFontKey(String key) {
|
public static boolean isFontKey(String key) {
|
||||||
return key.startsWith(FONT_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX);
|
return StringUtils.startsWithAny(key, FONT_ID_PREFIX, EXTERNAL_PREFIX,
|
||||||
|
EXTERNAL_LAF_ID_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,7 +120,7 @@ public class FontValue extends ThemeValue<Font> {
|
||||||
* @param key the key to associate the parsed value with
|
* @param key the key to associate the parsed value with
|
||||||
* @param value the font value to parse
|
* @param value the font value to parse
|
||||||
* @return a FontValue with the given key and the parsed value
|
* @return a FontValue with the given key and the parsed value
|
||||||
* @throws ParseException if there is an exception parsing
|
* @throws ParseException if there is an exception parsing
|
||||||
*/
|
*/
|
||||||
public static FontValue parse(String key, String value) throws ParseException {
|
public static FontValue parse(String key, String value) throws ParseException {
|
||||||
String id = fromExternalId(key);
|
String id = fromExternalId(key);
|
||||||
|
@ -164,6 +172,12 @@ public class FontValue extends ThemeValue<Font> {
|
||||||
if (internalId.startsWith(FONT_ID_PREFIX)) {
|
if (internalId.startsWith(FONT_ID_PREFIX)) {
|
||||||
return internalId;
|
return internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (internalId.startsWith(LAF_ID_PREFIX)) {
|
||||||
|
String baseId = internalId.substring(LAF_ID_PREFIX.length());
|
||||||
|
return EXTERNAL_LAF_ID_PREFIX + baseId;
|
||||||
|
}
|
||||||
|
|
||||||
return EXTERNAL_PREFIX + internalId;
|
return EXTERNAL_PREFIX + internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +185,9 @@ public class FontValue extends ThemeValue<Font> {
|
||||||
if (externalId.startsWith(EXTERNAL_PREFIX)) {
|
if (externalId.startsWith(EXTERNAL_PREFIX)) {
|
||||||
return externalId.substring(EXTERNAL_PREFIX.length());
|
return externalId.substring(EXTERNAL_PREFIX.length());
|
||||||
}
|
}
|
||||||
|
if (externalId.startsWith(EXTERNAL_LAF_ID_PREFIX)) {
|
||||||
|
return LAF_ID_PREFIX + externalId.substring(EXTERNAL_LAF_ID_PREFIX.length());
|
||||||
|
}
|
||||||
return externalId;
|
return externalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,9 +215,7 @@ public class FontValue extends ThemeValue<Font> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FontValue getRefFontValue(String id, String value) throws ParseException {
|
private static FontValue getRefFontValue(String id, String value) throws ParseException {
|
||||||
if (value.startsWith(EXTERNAL_PREFIX)) {
|
value = fromExternalId(value);
|
||||||
value = value.substring(EXTERNAL_PREFIX.length());
|
|
||||||
}
|
|
||||||
int modIndex = value.indexOf("[");
|
int modIndex = value.indexOf("[");
|
||||||
if (modIndex < 0) {
|
if (modIndex < 0) {
|
||||||
return new FontValue(id, fromExternalId(value));
|
return new FontValue(id, fromExternalId(value));
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class GThemeValueMap {
|
||||||
protected Map<String, ColorValue> colorMap = new HashMap<>();
|
protected Map<String, ColorValue> colorMap = new HashMap<>();
|
||||||
protected Map<String, FontValue> fontMap = new HashMap<>();
|
protected Map<String, FontValue> fontMap = new HashMap<>();
|
||||||
protected Map<String, IconValue> iconMap = new HashMap<>();
|
protected Map<String, IconValue> iconMap = new HashMap<>();
|
||||||
|
protected Map<String, JavaPropertyValue> propertyMap = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new empty map.
|
* Constructs a new empty map.
|
||||||
|
@ -88,6 +89,19 @@ public class GThemeValueMap {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given property value to this map. If a property value already exists in the map with
|
||||||
|
* the same id, it will be replaced.
|
||||||
|
* @param value the {@link JavaPropertyValue} to store in the map.
|
||||||
|
* @return the previous value for the icon key or null if no previous value existed.
|
||||||
|
*/
|
||||||
|
public JavaPropertyValue addProperty(JavaPropertyValue value) {
|
||||||
|
if (value != null) {
|
||||||
|
return propertyMap.put(value.getId(), value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current {@link ColorValue} for the given id or null if none exists.
|
* Returns the current {@link ColorValue} for the given id or null if none exists.
|
||||||
* @param id the id to look up a color for
|
* @param id the id to look up a color for
|
||||||
|
@ -116,7 +130,16 @@ public class GThemeValueMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all the values from the given map into this map, replacing values with the
|
* Returns the current {@link JavaPropertyValue} for the given id or null if none exists.
|
||||||
|
* @param id the id to look up a icon for
|
||||||
|
* @return the current {@link JavaPropertyValue} for the given id or null if none exists.
|
||||||
|
*/
|
||||||
|
public JavaPropertyValue getProperty(String id) {
|
||||||
|
return propertyMap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all the values from the given map into this map, replacing values with the
|
||||||
* same ids.
|
* same ids.
|
||||||
* @param valueMap the map whose values are to be loaded into this map
|
* @param valueMap the map whose values are to be loaded into this map
|
||||||
*/
|
*/
|
||||||
|
@ -127,6 +150,7 @@ public class GThemeValueMap {
|
||||||
valueMap.colorMap.values().forEach(v -> addColor(v));
|
valueMap.colorMap.values().forEach(v -> addColor(v));
|
||||||
valueMap.fontMap.values().forEach(v -> addFont(v));
|
valueMap.fontMap.values().forEach(v -> addFont(v));
|
||||||
valueMap.iconMap.values().forEach(v -> addIcon(v));
|
valueMap.iconMap.values().forEach(v -> addIcon(v));
|
||||||
|
valueMap.propertyMap.values().forEach(v -> addProperty(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,6 +177,14 @@ public class GThemeValueMap {
|
||||||
return new ArrayList<>(iconMap.values());
|
return new ArrayList<>(iconMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all the {@link JavaPropertyValue}s stored in this map.
|
||||||
|
* @return a list of all the {@link JavaPropertyValue}s stored in this map.
|
||||||
|
*/
|
||||||
|
public List<JavaPropertyValue> getProperties() {
|
||||||
|
return new ArrayList<>(propertyMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a {@link ColorValue} exists in this map for the given id.
|
* Returns true if a {@link ColorValue} exists in this map for the given id.
|
||||||
* @param id the id to check
|
* @param id the id to check
|
||||||
|
@ -181,11 +213,20 @@ public class GThemeValueMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total number of color, font, and icon values stored in this map
|
* Returns true if an {@link JavaPropertyValue} exists in this map for the given id.
|
||||||
* @return the total number of color, font, and icon values stored in this map
|
* @param id the id to check
|
||||||
|
* @return true if an {@link JavaPropertyValue} exists in this map for the given id
|
||||||
|
*/
|
||||||
|
public boolean containsProperty(String id) {
|
||||||
|
return propertyMap.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total number of color, font, icon and property values stored in this map
|
||||||
|
* @return the total number of color, font, icon and property values stored in this map
|
||||||
*/
|
*/
|
||||||
public Object size() {
|
public Object size() {
|
||||||
return colorMap.size() + fontMap.size() + iconMap.size();
|
return colorMap.size() + fontMap.size() + iconMap.size() + propertyMap.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -195,14 +236,16 @@ public class GThemeValueMap {
|
||||||
colorMap.clear();
|
colorMap.clear();
|
||||||
fontMap.clear();
|
fontMap.clear();
|
||||||
iconMap.clear();
|
iconMap.clear();
|
||||||
|
propertyMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there are not color, font, or icon values in this map
|
* Returns true if there are not color, font, icon or property values in this map
|
||||||
* @return true if there are not color, font, or icon values in this map
|
* @return true if there are not color, font, icon or property values in this map
|
||||||
*/
|
*/
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return colorMap.isEmpty() && fontMap.isEmpty() && iconMap.isEmpty();
|
return colorMap.isEmpty() && fontMap.isEmpty() && iconMap.isEmpty() &&
|
||||||
|
propertyMap.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,10 +272,18 @@ public class GThemeValueMap {
|
||||||
iconMap.remove(id);
|
iconMap.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes any {@link JavaPropertyValue} with the given id from this map.
|
||||||
|
* @param id the id to remove
|
||||||
|
*/
|
||||||
|
public void removeProperty(String id) {
|
||||||
|
propertyMap.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new {@link GThemeValueMap} that is only populated by values that don't exist
|
* Returns a new {@link GThemeValueMap} that is only populated by values that don't exist
|
||||||
* in the give map.
|
* in the give map.
|
||||||
* @param base the set of values (usually the default set) to compare against to determine
|
* @param base the set of values (usually the default set) to compare against to determine
|
||||||
* what values are changed.
|
* what values are changed.
|
||||||
* @return a new {@link GThemeValueMap} that is only populated by values that don't exist
|
* @return a new {@link GThemeValueMap} that is only populated by values that don't exist
|
||||||
* in the give map
|
* in the give map
|
||||||
|
@ -254,13 +305,18 @@ public class GThemeValueMap {
|
||||||
map.addIcon(icon);
|
map.addIcon(icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (JavaPropertyValue property : propertyMap.values()) {
|
||||||
|
if (!property.equals(base.getProperty(property.getId()))) {
|
||||||
|
map.addProperty(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the set of icon (.png, .gif) files that are used by IconValues that came from files
|
* Gets the set of icon (.png, .gif) files that are used by IconValues that came from files
|
||||||
* versus resources in the classpath. These are the icon files that need to be included
|
* versus resources in the classpath. These are the icon files that need to be included when
|
||||||
* when exporting this set of values to a zip file.
|
* exporting this set of values to a zip file.
|
||||||
* @return the set of icon (.png, .gif) files that are used by IconValues that came from files
|
* @return the set of icon (.png, .gif) files that are used by IconValues that came from files
|
||||||
* versus resources in the classpath
|
* versus resources in the classpath
|
||||||
*/
|
*/
|
||||||
|
@ -268,18 +324,24 @@ public class GThemeValueMap {
|
||||||
Set<File> files = new HashSet<>();
|
Set<File> files = new HashSet<>();
|
||||||
for (IconValue iconValue : iconMap.values()) {
|
for (IconValue iconValue : iconMap.values()) {
|
||||||
Icon icon = iconValue.getRawValue();
|
Icon icon = iconValue.getRawValue();
|
||||||
if (icon instanceof UrlImageIcon urlIcon) {
|
if (!(icon instanceof UrlImageIcon urlIcon)) {
|
||||||
String originalPath = urlIcon.getOriginalPath();
|
continue;
|
||||||
if (originalPath.startsWith(ResourceManager.EXTERNAL_ICON_PREFIX)) {
|
}
|
||||||
URL url = urlIcon.getUrl();
|
|
||||||
String filePath = url.getFile();
|
String originalPath = urlIcon.getOriginalPath();
|
||||||
if (filePath != null) {
|
if (!originalPath.startsWith(ResourceManager.EXTERNAL_ICON_PREFIX)) {
|
||||||
File iconFile = new File(filePath);
|
continue;
|
||||||
if (iconFile.exists()) {
|
}
|
||||||
files.add(iconFile);
|
|
||||||
}
|
URL url = urlIcon.getUrl();
|
||||||
}
|
String filePath = url.getFile();
|
||||||
}
|
if (filePath == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
File iconFile = new File(filePath);
|
||||||
|
if (iconFile.exists()) {
|
||||||
|
files.add(iconFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
|
@ -287,7 +349,7 @@ public class GThemeValueMap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(colorMap, fontMap, iconMap);
|
return Objects.hash(colorMap, fontMap, iconMap, propertyMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -302,8 +364,10 @@ public class GThemeValueMap {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
GThemeValueMap other = (GThemeValueMap) obj;
|
GThemeValueMap other = (GThemeValueMap) obj;
|
||||||
return Objects.equals(colorMap, other.colorMap) && Objects.equals(fontMap, other.fontMap) &&
|
return Objects.equals(colorMap, other.colorMap) &&
|
||||||
Objects.equals(iconMap, other.iconMap);
|
Objects.equals(fontMap, other.fontMap) &&
|
||||||
|
Objects.equals(iconMap, other.iconMap) &&
|
||||||
|
Objects.equals(propertyMap, other.propertyMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkForUnresolvedReferences() {
|
public void checkForUnresolvedReferences() {
|
||||||
|
@ -317,6 +381,9 @@ public class GThemeValueMap {
|
||||||
for (IconValue iconValue : iconMap.values()) {
|
for (IconValue iconValue : iconMap.values()) {
|
||||||
iconValue.get(this);
|
iconValue.get(this);
|
||||||
}
|
}
|
||||||
|
for (JavaPropertyValue propertyValue : propertyMap.values()) {
|
||||||
|
propertyValue.get(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -344,10 +411,18 @@ public class GThemeValueMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the resolved color, following indirections as need to get the color ultimately
|
* Returns the set of all Java property ids in this map
|
||||||
|
* @return the set of all Java property ids in this map
|
||||||
|
*/
|
||||||
|
public Set<String> getPropertyIds() {
|
||||||
|
return propertyMap.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resolved color, following indirections as needed to get the color ultimately
|
||||||
* assigned to the given id.
|
* assigned to the given id.
|
||||||
* @param id the id for which to get a color
|
* @param id the id for which to get a color
|
||||||
* @return the resolved color, following indirections as need to get the color ultimately
|
* @return the resolved color, following indirections as needed to get the color ultimately
|
||||||
* assigned to the given id.
|
* assigned to the given id.
|
||||||
*/
|
*/
|
||||||
public Color getResolvedColor(String id) {
|
public Color getResolvedColor(String id) {
|
||||||
|
@ -359,10 +434,10 @@ public class GThemeValueMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the resolved font, following indirections as need to get the font ultimately
|
* Returns the resolved font, following indirections as needed to get the font ultimately
|
||||||
* assigned to the given id.
|
* assigned to the given id.
|
||||||
* @param id the id for which to get a font
|
* @param id the id for which to get a font
|
||||||
* @return the resolved font, following indirections as need to get the font ultimately
|
* @return the resolved font, following indirections as needed to get the font ultimately
|
||||||
* assigned to the given id
|
* assigned to the given id
|
||||||
*/
|
*/
|
||||||
public Font getResolvedFont(String id) {
|
public Font getResolvedFont(String id) {
|
||||||
|
@ -374,10 +449,10 @@ public class GThemeValueMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the resolved icon, following indirections as need to get the icon ultimately
|
* Returns the resolved icon, following indirections as needed to get the icon ultimately
|
||||||
* assigned to the given id.
|
* assigned to the given id.
|
||||||
* @param id the id for which to get an icon
|
* @param id the id for which to get an icon
|
||||||
* @return the resolved icon, following indirections as need to get the icon ultimately
|
* @return the resolved icon, following indirections as needed to get the icon ultimately
|
||||||
* assigned to the given id
|
* assigned to the given id
|
||||||
*/
|
*/
|
||||||
public Icon getResolvedIcon(String id) {
|
public Icon getResolvedIcon(String id) {
|
||||||
|
@ -388,4 +463,18 @@ public class GThemeValueMap {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resolved property, following indirections as needed to get the property
|
||||||
|
* ultimately assigned to the given id.
|
||||||
|
* @param id the id for which to get an property
|
||||||
|
* @return the resolved property, following indirections as needed to get the property
|
||||||
|
* ultimately assigned to the given id
|
||||||
|
*/
|
||||||
|
public Object getResolvedProperty(String id) {
|
||||||
|
JavaPropertyValue propertyValue = propertyMap.get(id);
|
||||||
|
if (propertyValue != null) {
|
||||||
|
return propertyValue.get(this);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ import java.text.ParseException;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
import resources.icons.EmptyIcon;
|
import resources.icons.EmptyIcon;
|
||||||
|
@ -33,14 +35,14 @@ import resources.icons.UrlImageIcon;
|
||||||
public class IconValue extends ThemeValue<Icon> {
|
public class IconValue extends ThemeValue<Icon> {
|
||||||
private static final String EMPTY_ICON_STRING = "EMPTY_ICON";
|
private static final String EMPTY_ICON_STRING = "EMPTY_ICON";
|
||||||
|
|
||||||
|
public static final String LAF_ID_PREFIX = "laf.icon.";
|
||||||
|
public static final String EXTERNAL_LAF_ID_PREFIX = "[laf.icon]";
|
||||||
|
|
||||||
static final String ICON_ID_PREFIX = "icon.";
|
static final String ICON_ID_PREFIX = "icon.";
|
||||||
|
|
||||||
public static final Icon LAST_RESORT_DEFAULT = ResourceManager.getDefaultIcon();
|
|
||||||
|
|
||||||
private static final String EXTERNAL_PREFIX = "[icon]";
|
private static final String EXTERNAL_PREFIX = "[icon]";
|
||||||
|
|
||||||
|
public static final Icon LAST_RESORT_DEFAULT = ResourceManager.getDefaultIcon();
|
||||||
private static final int STANDARD_EMPTY_ICON_SIZE = 16;
|
private static final int STANDARD_EMPTY_ICON_SIZE = 16;
|
||||||
|
|
||||||
private IconModifier modifier;
|
private IconModifier modifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -94,13 +96,14 @@ public class IconValue extends ThemeValue<Icon> {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given key string is a valid external key for an icon value
|
* Returns true if the given key string is a valid external key for an icon value
|
||||||
* @param key the key string to test
|
* @param key the key string to test
|
||||||
* @return true if the given key string is a valid external key for an icon value
|
* @return true if the given key string is a valid external key for an icon value
|
||||||
*/
|
*/
|
||||||
public static boolean isIconKey(String key) {
|
public static boolean isIconKey(String key) {
|
||||||
return key.startsWith(ICON_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX);
|
return StringUtils.startsWithAny(key, ICON_ID_PREFIX, EXTERNAL_PREFIX,
|
||||||
|
EXTERNAL_LAF_ID_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,9 +175,7 @@ public class IconValue extends ThemeValue<Icon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IconValue parseRefIcon(String id, String value) throws ParseException {
|
private static IconValue parseRefIcon(String id, String value) throws ParseException {
|
||||||
if (value.startsWith(EXTERNAL_PREFIX)) {
|
value = fromExternalId(value);
|
||||||
value = value.substring(EXTERNAL_PREFIX.length());
|
|
||||||
}
|
|
||||||
int modifierIndex = getModifierIndex(value);
|
int modifierIndex = getModifierIndex(value);
|
||||||
if (modifierIndex < 0) {
|
if (modifierIndex < 0) {
|
||||||
return new IconValue(id, value);
|
return new IconValue(id, value);
|
||||||
|
@ -213,6 +214,12 @@ public class IconValue extends ThemeValue<Icon> {
|
||||||
if (internalId.startsWith(ICON_ID_PREFIX)) {
|
if (internalId.startsWith(ICON_ID_PREFIX)) {
|
||||||
return internalId;
|
return internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (internalId.startsWith(LAF_ID_PREFIX)) {
|
||||||
|
String baseId = internalId.substring(LAF_ID_PREFIX.length());
|
||||||
|
return EXTERNAL_LAF_ID_PREFIX + baseId;
|
||||||
|
}
|
||||||
|
|
||||||
return EXTERNAL_PREFIX + internalId;
|
return EXTERNAL_PREFIX + internalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +227,9 @@ public class IconValue extends ThemeValue<Icon> {
|
||||||
if (externalId.startsWith(EXTERNAL_PREFIX)) {
|
if (externalId.startsWith(EXTERNAL_PREFIX)) {
|
||||||
return externalId.substring(EXTERNAL_PREFIX.length());
|
return externalId.substring(EXTERNAL_PREFIX.length());
|
||||||
}
|
}
|
||||||
|
if (externalId.startsWith(EXTERNAL_LAF_ID_PREFIX)) {
|
||||||
|
return LAF_ID_PREFIX + externalId.substring(EXTERNAL_LAF_ID_PREFIX.length());
|
||||||
|
}
|
||||||
return externalId;
|
return externalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class that represents a Java UIManager property. This value is used to allow for
|
||||||
|
* overriding Java UI values using the theme properties files.
|
||||||
|
*/
|
||||||
|
public abstract class JavaPropertyValue extends ThemeValue<Object> {
|
||||||
|
|
||||||
|
public JavaPropertyValue(String id, String refId, Object value) {
|
||||||
|
super(id, refId, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExternal() {
|
||||||
|
// Java properties are always used to define 'external' UIManager values
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSerializationString() {
|
||||||
|
String outputId = toExternalId(id);
|
||||||
|
return outputId + " = " + getSerializedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String toExternalId(String internalId);
|
||||||
|
|
||||||
|
protected abstract String getSerializedValue();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ThemeValue<Object> getReferredValue(GThemeValueMap values, String refId) {
|
||||||
|
return values.getProperty(refId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void installValue(ThemeManager themeManager) {
|
||||||
|
// We do not currently support changing these values from the UI or API. Assuming that,
|
||||||
|
// then this method is probably not needed for properties
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Java property value for keys that use String values.
|
||||||
|
*/
|
||||||
|
public class StringPropertyValue extends JavaPropertyValue {
|
||||||
|
|
||||||
|
private static final String EXTERNAL_LAF_ID_PREFIX = "[laf.string]";
|
||||||
|
|
||||||
|
public StringPropertyValue(String id, String value) {
|
||||||
|
this(id, null, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringPropertyValue(String id, String refId, String value) {
|
||||||
|
super(id, refId, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStringKey(String key) {
|
||||||
|
return key.toLowerCase().startsWith(EXTERNAL_LAF_ID_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringPropertyValue parse(String key, String value) {
|
||||||
|
String id = fromExternalId(key);
|
||||||
|
|
||||||
|
if (isStringKey(value)) {
|
||||||
|
String refId = fromExternalId(value);
|
||||||
|
return new StringPropertyValue(id, refId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StringPropertyValue(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String fromExternalId(String externalId) {
|
||||||
|
if (!externalId.toLowerCase().startsWith(EXTERNAL_LAF_ID_PREFIX)) {
|
||||||
|
return externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We return the raw property name (e.g., TextArea.background), not the normalized name
|
||||||
|
// (e.g., laf.color.TextArea.background), since the system currently does not provide the
|
||||||
|
// end-user a way to change these values from the UI.
|
||||||
|
return externalId.substring(EXTERNAL_LAF_ID_PREFIX.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object getUnresolvedReferenceValue(String primaryId, String unresolvedId) {
|
||||||
|
Msg.warn(this,
|
||||||
|
"Could not resolve indirect property for \"" + unresolvedId +
|
||||||
|
"\" for primary id \"" + primaryId + "\", using last resort default");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String toExternalId(String internalId) {
|
||||||
|
return EXTERNAL_LAF_ID_PREFIX + internalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSerializedValue() {
|
||||||
|
return String.valueOf(value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -211,7 +211,7 @@ public class StubThemeManager extends ThemeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ApplicationThemeDefaults getApplicationDefaults() {
|
protected ApplicationThemeDefaults loadApplicationDefaults() {
|
||||||
return new ApplicationThemeDefaults() {
|
return new ApplicationThemeDefaults() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,7 +22,7 @@ import generic.theme.laf.UiDefaultsMapper;
|
||||||
* and Feel (LaF) is being used.
|
* and Feel (LaF) is being used.
|
||||||
* <P>
|
* <P>
|
||||||
* Various LaFs have different names for common concepts and even define additional concepts not
|
* Various LaFs have different names for common concepts and even define additional concepts not
|
||||||
* listed here. The values in this class are those the application used use regardless of the LaF
|
* listed here. The values in this class are those the application uses use regardless of the LaF
|
||||||
* being used. When we load a specific LaF, a {@link UiDefaultsMapper} specific to that LaF is used
|
* being used. When we load a specific LaF, a {@link UiDefaultsMapper} specific to that LaF is used
|
||||||
* to map its common LaF ids to these standard system ids. The {@link GThemeDefaults} uses these
|
* to map its common LaF ids to these standard system ids. The {@link GThemeDefaults} uses these
|
||||||
* system ids to define colors that can be used throughout the application without using these ids
|
* system ids to define colors that can be used throughout the application without using these ids
|
||||||
|
|
|
@ -70,6 +70,7 @@ public abstract class ThemeManager {
|
||||||
protected LafType activeLafType = activeTheme.getLookAndFeelType();
|
protected LafType activeLafType = activeTheme.getLookAndFeelType();
|
||||||
protected boolean useDarkDefaults = activeTheme.useDarkDefaults();
|
protected boolean useDarkDefaults = activeTheme.useDarkDefaults();
|
||||||
|
|
||||||
|
// this use our normalized ids (e.g., 'laf.')
|
||||||
protected GThemeValueMap javaDefaults = new GThemeValueMap();
|
protected GThemeValueMap javaDefaults = new GThemeValueMap();
|
||||||
protected GThemeValueMap currentValues = new GThemeValueMap();
|
protected GThemeValueMap currentValues = new GThemeValueMap();
|
||||||
|
|
||||||
|
@ -89,10 +90,11 @@ public abstract class ThemeManager {
|
||||||
// default behavior is only install to INSTANCE if first time
|
// default behavior is only install to INSTANCE if first time
|
||||||
INSTANCE = this;
|
INSTANCE = this;
|
||||||
}
|
}
|
||||||
applicationDefaults = getApplicationDefaults();
|
|
||||||
|
applicationDefaults = loadApplicationDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ApplicationThemeDefaults getApplicationDefaults() {
|
protected ApplicationThemeDefaults loadApplicationDefaults() {
|
||||||
return new PropertyFileThemeDefaults();
|
return new PropertyFileThemeDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,9 +102,35 @@ public abstract class ThemeManager {
|
||||||
Gui.setThemeManager(this);
|
Gui.setThemeManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called to create the internal set of theme value used by the application. To
|
||||||
|
* do this, we use a layered approach to install values, with the last values added overwriting
|
||||||
|
* any pre-existing values with the same key. The values are added in the following order:
|
||||||
|
* <pre>
|
||||||
|
* java defaults -> light values -> dark values -> look and feel values -> property file values -> theme values
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* At the point this method is called, this is the state of these various values:
|
||||||
|
* <ul>
|
||||||
|
* <li>The 'javaValues' are normalized in the form of 'laf.font.TextArea'
|
||||||
|
* </li>
|
||||||
|
* <li>The 'applicationDefaults' contains values loaded from the {@code theme.properties}
|
||||||
|
* files:
|
||||||
|
* <pre>
|
||||||
|
* font.listing.base
|
||||||
|
* font.monospaced
|
||||||
|
* [color]Viewport.background = color.bg
|
||||||
|
* [laf.font]TextArea.font = font.monospaced
|
||||||
|
* [laf.boolean]Button.rollover = true
|
||||||
|
* </pre>
|
||||||
|
* </li>
|
||||||
|
* <li>The 'activeTheme' values are those loaded by the current theme, which has any changes
|
||||||
|
* made to the default values
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
protected void buildCurrentValues() {
|
protected void buildCurrentValues() {
|
||||||
GThemeValueMap map = new GThemeValueMap();
|
GThemeValueMap map = new GThemeValueMap();
|
||||||
|
|
||||||
map.load(javaDefaults);
|
map.load(javaDefaults);
|
||||||
map.load(applicationDefaults.getLightValues());
|
map.load(applicationDefaults.getLightValues());
|
||||||
if (useDarkDefaults) {
|
if (useDarkDefaults) {
|
||||||
|
@ -500,6 +528,16 @@ public abstract class ThemeManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if any theme values have changed. This does not take into account the current
|
||||||
|
* Look and Feel. Use {@link #hasThemeChanges()} to also account for changes to the Look and
|
||||||
|
* Feel.
|
||||||
|
* @return true if any theme values have changed
|
||||||
|
*/
|
||||||
|
public boolean hasThemeValueChanges() {
|
||||||
|
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
|
||||||
* @param id the id to check for an existing color.
|
* @param id the id to check for an existing color.
|
||||||
|
|
|
@ -28,6 +28,7 @@ import ghidra.util.Msg;
|
||||||
* @param <T> the base type this ThemeValue works on (i.e., Colors, Fonts, Icons)
|
* @param <T> the base type this ThemeValue works on (i.e., Colors, Fonts, Icons)
|
||||||
*/
|
*/
|
||||||
public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
|
public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
|
||||||
|
|
||||||
protected final String id;
|
protected final String id;
|
||||||
protected final T value;
|
protected final T value;
|
||||||
protected final String referenceId;
|
protected final String referenceId;
|
||||||
|
@ -36,13 +37,19 @@ public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
|
||||||
if (id.equals(referenceId)) {
|
if (id.equals(referenceId)) {
|
||||||
throw new IllegalArgumentException("Can't create a themeValue that referencs itself");
|
throw new IllegalArgumentException("Can't create a themeValue that referencs itself");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id.startsWith("[")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Theme values must be constructed with normalized, non-external ids");
|
||||||
|
}
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.referenceId = referenceId;
|
this.referenceId = referenceId;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if this value is one that is one that is defined outside of the application, such as a
|
* True if this value is one that is one that is defined outside of the application, such as a
|
||||||
* Java Look and Feel key.
|
* Java Look and Feel key.
|
||||||
* @return true if external
|
* @return true if external
|
||||||
*/
|
*/
|
||||||
|
@ -84,7 +91,7 @@ public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
|
||||||
* reference chains, an error stack trace will be generated and the default T value will
|
* reference chains, an error stack trace will be generated and the default T value will
|
||||||
* be returned. In rare situations where it is acceptable for the value to not be resolvable,
|
* be returned. In rare situations where it is acceptable for the value to not be resolvable,
|
||||||
* use the {@link #hasResolvableValue(GThemeValueMap)} method first.
|
* use the {@link #hasResolvableValue(GThemeValueMap)} method first.
|
||||||
* @param values the {@link GThemeValueMap} used to resolve references if this
|
* @param values the {@link GThemeValueMap} used to resolve references if this
|
||||||
* instance doesn't have an actual value.
|
* instance doesn't have an actual value.
|
||||||
* @return the T value for this instance, following references as needed.
|
* @return the T value for this instance, following references as needed.
|
||||||
*/
|
*/
|
||||||
|
@ -116,7 +123,7 @@ public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
|
||||||
* Returns true if the ThemeValue can resolve to the concrete T value (color, font, or icon)
|
* Returns true if the ThemeValue can resolve to the concrete T value (color, font, or icon)
|
||||||
* from the given set of theme values.
|
* from the given set of theme values.
|
||||||
* @param values the set of values to use to try and follow reference chains to ultimately
|
* @param values the set of values to use to try and follow reference chains to ultimately
|
||||||
* resolve the ThemeValue to a an actual T value
|
* resolve the ThemeValue to a an actual T value
|
||||||
* @return true if the ThemeValue can resolve to the concrete T value (color, font, or icon)
|
* @return true if the ThemeValue can resolve to the concrete T value (color, font, or icon)
|
||||||
* from the given set of theme values.
|
* from the given set of theme values.
|
||||||
*/
|
*/
|
||||||
|
@ -197,7 +204,7 @@ public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
|
||||||
/**
|
/**
|
||||||
* Returns the T to be used if the indirect reference couldn't be resolved.
|
* Returns the T to be used if the indirect reference couldn't be resolved.
|
||||||
* @param primaryId the id we are trying to get a value for
|
* @param primaryId the id we are trying to get a value for
|
||||||
* @param unresolvedId the reference id that couldn't be resolved
|
* @param unresolvedId the reference id that couldn't be resolved
|
||||||
* @return the default value to be used if the indirect reference couldn't be resolved.
|
* @return the default value to be used if the indirect reference couldn't be resolved.
|
||||||
*/
|
*/
|
||||||
protected abstract T getUnresolvedReferenceValue(String primaryId, String unresolvedId);
|
protected abstract T getUnresolvedReferenceValue(String primaryId, String unresolvedId);
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class CustomNimbusLookAndFeel extends NimbusLookAndFeel {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void installJavaDefaultsIntoThemeManager(UiDefaultsMapper uiDefaultsMapper) {
|
protected void installJavaDefaultsIntoThemeManager(UiDefaultsMapper uiDefaultsMapper) {
|
||||||
GThemeValueMap javaDefaults = uiDefaultsMapper.getJavaDefaults();
|
GThemeValueMap javaDefaults = uiDefaultsMapper.getNormalizedJavaDefaults();
|
||||||
themeManager.setJavaDefaults(javaDefaults);
|
themeManager.setJavaDefaults(javaDefaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,13 @@ public class FlatDarkUiDefaultsMapper extends FlatUiDefaultsMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void assignSystemColorValues() {
|
protected void pickRepresentativeValueForColorGroups() {
|
||||||
super.assignSystemColorValues();
|
super.pickRepresentativeValueForColorGroups();
|
||||||
|
|
||||||
// We don't think the FlatDark LaF's view background (Trees, Tables, Lists) is dark
|
// We don't think the FlatDark LaF's view background (Trees, Tables, Lists) is dark
|
||||||
// enough, so we are overriding the view group background and foreground colors
|
// enough, so we are overriding the view group background and foreground colors
|
||||||
assignSystemColorDirect(BG_VIEW_ID, new Color(0x1c1d1e));
|
setGroupColor(BG_VIEW_ID, new Color(0x1c1d1e));
|
||||||
assignSystemColorDirect(FG_VIEW_ID, WebColors.LIGHT_GRAY);
|
setGroupColor(FG_VIEW_ID, WebColors.LIGHT_GRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package generic.theme.laf;
|
package generic.theme.laf;
|
||||||
|
|
||||||
import javax.swing.UIDefaults;
|
import javax.swing.UIDefaults;
|
||||||
import javax.swing.UIManager;
|
|
||||||
|
|
||||||
import generic.theme.ApplicationThemeManager;
|
import generic.theme.ApplicationThemeManager;
|
||||||
import generic.theme.LafType;
|
import generic.theme.LafType;
|
||||||
|
@ -28,16 +27,7 @@ public class FlatLookAndFeelManager extends LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fixupLookAndFeelIssues() {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
super.fixupLookAndFeelIssues();
|
|
||||||
|
|
||||||
// We have historically managed button focus-ability ourselves. Allow this by default so
|
|
||||||
// features continue to work as expected, such as right-clicking on ToolButtons.
|
|
||||||
UIManager.put("ToolBar.focusableButtons", Boolean.TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
|
||||||
if (getLookAndFeelType() == LafType.FLAT_DARK) {
|
if (getLookAndFeelType() == LafType.FLAT_DARK) {
|
||||||
return new FlatDarkUiDefaultsMapper(defaults);
|
return new FlatDarkUiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,42 +24,42 @@ public class FlatUiDefaultsMapper extends UiDefaultsMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void registerIgnoredLafIds() {
|
protected void registerIgnoredJavaIds() {
|
||||||
super.registerIgnoredLafIds();
|
super.registerIgnoredJavaIds();
|
||||||
ignoredLafIds.add("Actions.Blue");
|
ignoredJavaIds.add("Actions.Blue");
|
||||||
ignoredLafIds.add("Actions.Green");
|
ignoredJavaIds.add("Actions.Green");
|
||||||
ignoredLafIds.add("Actions.Grey");
|
ignoredJavaIds.add("Actions.Grey");
|
||||||
ignoredLafIds.add("Actions.Greyinline");
|
ignoredJavaIds.add("Actions.Greyinline");
|
||||||
ignoredLafIds.add("Actions.Red");
|
ignoredJavaIds.add("Actions.Red");
|
||||||
ignoredLafIds.add("Actions.Yellow");
|
ignoredJavaIds.add("Actions.Yellow");
|
||||||
|
|
||||||
ignoredLafIds.add("Objects.BlackText");
|
ignoredJavaIds.add("Objects.BlackText");
|
||||||
ignoredLafIds.add("Objects.Blue");
|
ignoredJavaIds.add("Objects.Blue");
|
||||||
ignoredLafIds.add("Objects.Green");
|
ignoredJavaIds.add("Objects.Green");
|
||||||
ignoredLafIds.add("Objects.GreenAndroid");
|
ignoredJavaIds.add("Objects.GreenAndroid");
|
||||||
ignoredLafIds.add("Objects.Grey");
|
ignoredJavaIds.add("Objects.Grey");
|
||||||
ignoredLafIds.add("Objects.Pink");
|
ignoredJavaIds.add("Objects.Pink");
|
||||||
ignoredLafIds.add("Objects.Purple");
|
ignoredJavaIds.add("Objects.Purple");
|
||||||
ignoredLafIds.add("Objects.Red");
|
ignoredJavaIds.add("Objects.Red");
|
||||||
ignoredLafIds.add("Objects.RedStatus");
|
ignoredJavaIds.add("Objects.RedStatus");
|
||||||
ignoredLafIds.add("Objects.Yellow");
|
ignoredJavaIds.add("Objects.Yellow");
|
||||||
ignoredLafIds.add("Objects.YellowDark");
|
ignoredJavaIds.add("Objects.YellowDark");
|
||||||
|
|
||||||
ignoredLafIds.add("h0.font");
|
ignoredJavaIds.add("h0.font");
|
||||||
ignoredLafIds.add("h00.font");
|
ignoredJavaIds.add("h00.font");
|
||||||
ignoredLafIds.add("h1.font");
|
ignoredJavaIds.add("h1.font");
|
||||||
ignoredLafIds.add("h1.regular.font");
|
ignoredJavaIds.add("h1.regular.font");
|
||||||
ignoredLafIds.add("h2.font");
|
ignoredJavaIds.add("h2.font");
|
||||||
ignoredLafIds.add("h2.regular.font");
|
ignoredJavaIds.add("h2.regular.font");
|
||||||
ignoredLafIds.add("h3.font");
|
ignoredJavaIds.add("h3.font");
|
||||||
ignoredLafIds.add("h3.regular.font");
|
ignoredJavaIds.add("h3.regular.font");
|
||||||
ignoredLafIds.add("h4.font");
|
ignoredJavaIds.add("h4.font");
|
||||||
ignoredLafIds.add("large.font");
|
ignoredJavaIds.add("large.font");
|
||||||
ignoredLafIds.add("light.font");
|
ignoredJavaIds.add("light.font");
|
||||||
ignoredLafIds.add("medium.font");
|
ignoredJavaIds.add("medium.font");
|
||||||
ignoredLafIds.add("mini.font");
|
ignoredJavaIds.add("mini.font");
|
||||||
ignoredLafIds.add("monospaced.font");
|
ignoredJavaIds.add("monospaced.font");
|
||||||
ignoredLafIds.add("small.font");
|
ignoredJavaIds.add("small.font");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class GtkLookAndFeelManager extends LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
return new UiDefaultsMapper(defaults);
|
return new UiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,6 @@ public abstract class LookAndFeelManager {
|
||||||
doInstallLookAndFeel();
|
doInstallLookAndFeel();
|
||||||
processJavaDefaults();
|
processJavaDefaults();
|
||||||
fixupLookAndFeelIssues();
|
fixupLookAndFeelIssues();
|
||||||
installGlobalProperties();
|
|
||||||
installCustomLookAndFeelActions();
|
installCustomLookAndFeelActions();
|
||||||
updateComponentUis();
|
updateComponentUis();
|
||||||
}
|
}
|
||||||
|
@ -157,22 +156,26 @@ public abstract class LookAndFeelManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when one or more fonts have changed.
|
* Called when one or more fonts have changed.
|
||||||
* @param changedJavaFontIds the set of Java Font ids that are affected by this change
|
* <p>
|
||||||
|
* This will update the Java {@link UIManager} and trigger a reload of the UIs.
|
||||||
|
*
|
||||||
|
* @param changedFontIds the set of Java Font ids that are affected by this change; these are
|
||||||
|
* the normalized ids
|
||||||
*/
|
*/
|
||||||
public void fontsChanged(Set<String> changedJavaFontIds) {
|
public void fontsChanged(Set<String> changedFontIds) {
|
||||||
UIDefaults defaults = UIManager.getDefaults();
|
UIDefaults defaults = UIManager.getDefaults();
|
||||||
for (String changedFontId : changedJavaFontIds) {
|
for (String changedFontId : changedFontIds) {
|
||||||
// even though all these derive from the new font, they might be different
|
// even though all these derive from the new font, they might be different
|
||||||
// because of FontModifiers.
|
// because of FontModifiers.
|
||||||
Font font = Gui.getFont(changedFontId);
|
Font font = Gui.getFont(changedFontId);
|
||||||
String lafFontId = normalizedIdToLafIdMap.get(changedFontId);
|
String javaFontId = normalizedIdToLafIdMap.get(changedFontId);
|
||||||
if (lafFontId != null) {
|
if (javaFontId != null) {
|
||||||
// lafFontId is null for group ids
|
// lafFontId is null for group ids
|
||||||
defaults.put(lafFontId, new FontUIResource(font));
|
defaults.put(javaFontId, new FontUIResource(font));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changedJavaFontIds.isEmpty()) {
|
if (!changedFontIds.isEmpty()) {
|
||||||
updateComponentUis();
|
updateComponentUis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,10 +234,23 @@ public abstract class LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass may override this method to do specific LookAndFeel fix ups
|
* Subclass may override this method to do specific LookAndFeel fixes.
|
||||||
|
* <p>
|
||||||
|
* This will get called after default values are loaded. This means that any values installed
|
||||||
|
* by this method will overwrite any values registered by the theme.
|
||||||
|
* <p>
|
||||||
|
* Standard properties, such as strings and booleans, can be set inside of the theme
|
||||||
|
* properties files. For more complicated UIManager properties, look and feel classes will
|
||||||
|
* need to override this method and install those directly.
|
||||||
|
* <p>
|
||||||
|
* Any property installed here will not fully be part of the theme system, but rather will be
|
||||||
|
* directly installed into the Java Look and Feel. Thus, properties installed here will be
|
||||||
|
* hard-coded overrides for the system. If we decided that a hard-coded value should be put
|
||||||
|
* into the theme system, then we will need to add support for that property type so that it
|
||||||
|
* can be used when loading the theme files.
|
||||||
*/
|
*/
|
||||||
protected void fixupLookAndFeelIssues() {
|
protected void fixupLookAndFeelIssues() {
|
||||||
// no generic fix-ups at this time.
|
installGlobalFontSizeOverride();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,15 +260,14 @@ public abstract class LookAndFeelManager {
|
||||||
*/
|
*/
|
||||||
protected void processJavaDefaults() {
|
protected void processJavaDefaults() {
|
||||||
UIDefaults defaults = UIManager.getDefaults();
|
UIDefaults defaults = UIManager.getDefaults();
|
||||||
UiDefaultsMapper uiDefaultsMapper = getUiDefaultsMapper(defaults);
|
UiDefaultsMapper uiDefaultsMapper = createUiDefaultsMapper(defaults);
|
||||||
|
GThemeValueMap javaDefaults = uiDefaultsMapper.getNormalizedJavaDefaults();
|
||||||
GThemeValueMap javaDefaults = uiDefaultsMapper.getJavaDefaults();
|
|
||||||
themeManager.setJavaDefaults(javaDefaults);
|
themeManager.setJavaDefaults(javaDefaults);
|
||||||
uiDefaultsMapper.installValuesIntoUIDefaults(themeManager.getCurrentValues());
|
uiDefaultsMapper.installValuesIntoUIDefaults(themeManager.getCurrentValues());
|
||||||
normalizedIdToLafIdMap = uiDefaultsMapper.getNormalizedIdToLafIdMap();
|
normalizedIdToLafIdMap = uiDefaultsMapper.getNormalizedIdToLafIdMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults);
|
protected abstract UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults);
|
||||||
|
|
||||||
protected String findLookAndFeelClassName(String lookAndFeelName) {
|
protected String findLookAndFeelClassName(String lookAndFeelName) {
|
||||||
LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels();
|
LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels();
|
||||||
|
@ -277,38 +292,20 @@ public abstract class LookAndFeelManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setKeyBinding(String existingKsText, String newKsText, String[] prefixValues) {
|
protected void setKeyBinding(String existingKsText, String newKsText,
|
||||||
|
String[] prefixValues) {
|
||||||
|
|
||||||
KeyStroke existingKs = KeyStroke.getKeyStroke(existingKsText);
|
KeyStroke existingKs = KeyStroke.getKeyStroke(existingKsText);
|
||||||
KeyStroke newKs = KeyStroke.getKeyStroke(newKsText);
|
KeyStroke newKs = KeyStroke.getKeyStroke(newKsText);
|
||||||
|
UIDefaults uiDefaults = UIManager.getDefaults();
|
||||||
for (String properyPrefix : prefixValues) {
|
for (String properyPrefix : prefixValues) {
|
||||||
|
Object object = uiDefaults.get(properyPrefix + ".focusInputMap");
|
||||||
UIDefaults defaults = UIManager.getDefaults();
|
|
||||||
Object object = defaults.get(properyPrefix + ".focusInputMap");
|
|
||||||
InputMap inputMap = (InputMap) object;
|
InputMap inputMap = (InputMap) object;
|
||||||
Object action = inputMap.get(existingKs);
|
Object action = inputMap.get(existingKs);
|
||||||
inputMap.put(newKs, action);
|
inputMap.put(newKs, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installGlobalLookAndFeelAttributes() {
|
|
||||||
// Fix up the default fonts that Java 1.5.0 changed to Courier, which looked terrible.
|
|
||||||
Font f = new Font("Monospaced", Font.PLAIN, 12);
|
|
||||||
UIManager.put("PasswordField.font", f);
|
|
||||||
UIManager.put("TextArea.font", f);
|
|
||||||
|
|
||||||
// We like buttons that change on hover, so force that to happen (see Tracker SCR 3966)
|
|
||||||
UIManager.put("Button.rollover", Boolean.TRUE);
|
|
||||||
UIManager.put("ToolBar.isRollover", Boolean.TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void installPopupMenuSettingsOverride() {
|
|
||||||
// Java 1.6 UI consumes MousePressed event when dismissing popup menu
|
|
||||||
// which prevents application components from getting this event.
|
|
||||||
UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void installGlobalFontSizeOverride() {
|
private void installGlobalFontSizeOverride() {
|
||||||
|
|
||||||
// only set a global size if the property is set
|
// only set a global size if the property is set
|
||||||
|
@ -375,12 +372,6 @@ public abstract class LookAndFeelManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installGlobalProperties() {
|
|
||||||
installGlobalLookAndFeelAttributes();
|
|
||||||
installGlobalFontSizeOverride();
|
|
||||||
installPopupMenuSettingsOverride();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the given UIDefaults for ids whose value matches the given class
|
* Searches the given UIDefaults for ids whose value matches the given class
|
||||||
* @param defaults the UIDefaults to search
|
* @param defaults the UIDefaults to search
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class MacLookAndFeelManager extends LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
return new MacUiDefaultsMapper(defaults);
|
return new MacUiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class MetalLookAndFeelManager extends LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
return new UiDefaultsMapper(defaults);
|
return new UiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,15 @@ public class MotifLookAndFeelManager extends LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
return new MotifUiDefaultsMapper(defaults);
|
return new MotifUiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fixupLookAndFeelIssues() {
|
protected void fixupLookAndFeelIssues() {
|
||||||
|
|
||||||
|
super.fixupLookAndFeelIssues();
|
||||||
|
|
||||||
//
|
//
|
||||||
// The Motif LaF does not bind copy/paste/cut to Control-C/V/X by default. Rather, they
|
// The Motif LaF does not bind copy/paste/cut to Control-C/V/X by default. Rather, they
|
||||||
// only use the COPY/PASTE/CUT keys. The other LaFs bind both shortcuts.
|
// only use the COPY/PASTE/CUT keys. The other LaFs bind both shortcuts.
|
||||||
|
|
|
@ -24,9 +24,9 @@ public class MotifUiDefaultsMapper extends UiDefaultsMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void registerIgnoredLafIds() {
|
protected void registerIgnoredJavaIds() {
|
||||||
super.registerIgnoredLafIds();
|
super.registerIgnoredJavaIds();
|
||||||
ignoredLafIds.add("controlLightShadow");
|
ignoredJavaIds.add("controlLightShadow");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,14 +103,14 @@ public class NimbusLookAndFeelManager extends LookAndFeelManager {
|
||||||
// fix scroll bar grabber disappearing. See
|
// fix scroll bar grabber disappearing. See
|
||||||
// https://bugs.openjdk.java.net/browse/JDK-8134828. This fix looks like it should not cause
|
// https://bugs.openjdk.java.net/browse/JDK-8134828. This fix looks like it should not cause
|
||||||
// harm even if the bug is fixed on the jdk side.
|
// harm even if the bug is fixed on the jdk side.
|
||||||
UIDefaults defaults = UIManager.getDefaults();
|
UIDefaults uiDefaults = UIManager.getDefaults();
|
||||||
defaults.put("ScrollBar.minimumThumbSize", new Dimension(30, 30));
|
uiDefaults.put("ScrollBar.minimumThumbSize", new Dimension(30, 30));
|
||||||
|
|
||||||
// (see NimbusDefaults for key values that can be changed here)
|
// (see NimbusDefaults for key values that can be changed here)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
return new NimbusUiDefaultsMapper(defaults);
|
return new NimbusUiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,45 +28,45 @@ public class NimbusUiDefaultsMapper extends UiDefaultsMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void registerIgnoredLafIds() {
|
protected void registerIgnoredJavaIds() {
|
||||||
super.registerIgnoredLafIds();
|
super.registerIgnoredJavaIds();
|
||||||
ignoredLafIds.add("background");
|
ignoredJavaIds.add("background");
|
||||||
|
|
||||||
ignoredLafIds.add("controlLHighlight");
|
ignoredJavaIds.add("controlLHighlight");
|
||||||
|
|
||||||
ignoredLafIds.add("nimbusAlertYellow");
|
ignoredJavaIds.add("nimbusAlertYellow");
|
||||||
ignoredLafIds.add("nimbusBase");
|
ignoredJavaIds.add("nimbusBase");
|
||||||
ignoredLafIds.add("nimbusBlueGrey");
|
ignoredJavaIds.add("nimbusBlueGrey");
|
||||||
ignoredLafIds.add("nimbusDisabledText");
|
ignoredJavaIds.add("nimbusDisabledText");
|
||||||
ignoredLafIds.add("nimbusFocus");
|
ignoredJavaIds.add("nimbusFocus");
|
||||||
ignoredLafIds.add("nimbusGreen");
|
ignoredJavaIds.add("nimbusGreen");
|
||||||
ignoredLafIds.add("nimbusInfoBlue");
|
ignoredJavaIds.add("nimbusInfoBlue");
|
||||||
ignoredLafIds.add("nimbusOrange");
|
ignoredJavaIds.add("nimbusOrange");
|
||||||
ignoredLafIds.add("nimbusRed");
|
ignoredJavaIds.add("nimbusRed");
|
||||||
ignoredLafIds.add("nimbusSelectedText");
|
ignoredJavaIds.add("nimbusSelectedText");
|
||||||
ignoredLafIds.add("nimbusSelection");
|
ignoredJavaIds.add("nimbusSelection");
|
||||||
ignoredLafIds.add("nimbusSelectionBackground");
|
ignoredJavaIds.add("nimbusSelectionBackground");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void assignSystemColorValues() {
|
protected void pickRepresentativeValueForColorGroups() {
|
||||||
|
|
||||||
// different from base class
|
// different from base class
|
||||||
assignSystemColorFromLafId(BG_CONTROL_ID, "Button.background");
|
setGroupColorUsingJavaRepresentative(BG_CONTROL_ID, "Button.background");
|
||||||
assignSystemColorFromLafId(FG_CONTROL_ID, "Button.foreground");
|
setGroupColorUsingJavaRepresentative(FG_CONTROL_ID, "Button.foreground");
|
||||||
assignSystemColorFromLafId(BG_BORDER_ID, "nimbusBorder");
|
setGroupColorUsingJavaRepresentative(BG_BORDER_ID, "nimbusBorder");
|
||||||
assignSystemColorFromLafId(BG_VIEW_ID, "nimbusLightBackground");
|
setGroupColorUsingJavaRepresentative(BG_VIEW_ID, "nimbusLightBackground");
|
||||||
assignSystemColorFromLafId(FG_VIEW_ID, "controlText");
|
setGroupColorUsingJavaRepresentative(FG_VIEW_ID, "controlText");
|
||||||
|
|
||||||
// the following are the same as the base class (we can't just call super because
|
// the following are the same as the base class (we can't just call super because
|
||||||
// it will report errors for missing lafIds such as "window"
|
// it will report errors for missing lafIds such as "window"
|
||||||
|
|
||||||
assignSystemColorFromLafId(BG_VIEW_SELECTED_ID, "textHighlight");
|
setGroupColorUsingJavaRepresentative(BG_VIEW_SELECTED_ID, "textHighlight");
|
||||||
assignSystemColorFromLafId(FG_VIEW_SELECTED_ID, "textHighlightText");
|
setGroupColorUsingJavaRepresentative(FG_VIEW_SELECTED_ID, "textHighlightText");
|
||||||
assignSystemColorFromLafId(FG_DISABLED_ID, "textInactiveText");
|
setGroupColorUsingJavaRepresentative(FG_DISABLED_ID, "textInactiveText");
|
||||||
assignSystemColorFromLafId(BG_TOOLTIP_ID, "info");
|
setGroupColorUsingJavaRepresentative(BG_TOOLTIP_ID, "info");
|
||||||
assignSystemColorFromLafId(FG_TOOLTIP_ID, "infoText");
|
setGroupColorUsingJavaRepresentative(FG_TOOLTIP_ID, "infoText");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,8 +83,8 @@ public class NimbusUiDefaultsMapper extends UiDefaultsMapper {
|
||||||
super.installGColorsIntoUIDefaults();
|
super.installGColorsIntoUIDefaults();
|
||||||
|
|
||||||
// The Nimbus selected text field color is not honored if the value is a ColorUIResource.
|
// The Nimbus selected text field color is not honored if the value is a ColorUIResource.
|
||||||
// We install GColorUIResources by default. Thus, our setting for this particular
|
// We install GColorUIResources by default. Thus, our setting for this particular
|
||||||
// attribute was being ignored. We set it here to be a GColor, which causes Nimbus
|
// attribute was being ignored. We set it here to be a GColor, which causes Nimbus
|
||||||
// to honor the value. We may need to add more entries here as they are discovered.
|
// to honor the value. We may need to add more entries here as they are discovered.
|
||||||
|
|
||||||
defaults.put("TextField.selectionForeground",
|
defaults.put("TextField.selectionForeground",
|
||||||
|
|
|
@ -71,9 +71,13 @@ import ghidra.util.Msg;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class UiDefaultsMapper {
|
public class UiDefaultsMapper {
|
||||||
public static final String LAF_COLOR_ID_PREFIX = "laf.color.";
|
|
||||||
public static final String LAF_FONT_ID_PREFIX = "laf.font.";
|
public static final String LAF_COLOR_ID_PREFIX = ColorValue.LAF_ID_PREFIX;
|
||||||
public static final String LAF_ICON_ID_PREFIX = "laf.icon.";
|
public static final String LAF_FONT_ID_PREFIX = FontValue.LAF_ID_PREFIX;
|
||||||
|
public static final String LAF_ICON_ID_PREFIX = IconValue.LAF_ID_PREFIX;
|
||||||
|
|
||||||
|
/** A prefix for UIManager properties that are not colors, fonts or icons (e.g., boolean) */
|
||||||
|
public static final String LAF_PROPERTY_PREFIX = "laf.property.";
|
||||||
private static final String LAF_COLOR_PALETTE_PREFIX = "laf.palette.color.";
|
private static final String LAF_COLOR_PALETTE_PREFIX = "laf.palette.color.";
|
||||||
private static final String LAF_FONT_PALETTE_PREFIX = "laf.palette.font.";
|
private static final String LAF_FONT_PALETTE_PREFIX = "laf.palette.font.";
|
||||||
|
|
||||||
|
@ -86,22 +90,25 @@ public class UiDefaultsMapper {
|
||||||
|
|
||||||
protected UIDefaults defaults;
|
protected UIDefaults defaults;
|
||||||
private GThemeValueMap extractedValues;
|
private GThemeValueMap extractedValues;
|
||||||
|
|
||||||
|
/** 'normalized' values have keys that start with 'laf.' */
|
||||||
private GThemeValueMap normalizedValues = new GThemeValueMap();
|
private GThemeValueMap normalizedValues = new GThemeValueMap();
|
||||||
|
|
||||||
private Map<String, String> lafIdToNormalizedIdMap = new HashMap<>();
|
/** Maps Look and Feel keys to standardized keys that start with 'laf.' */
|
||||||
protected Set<String> ignoredLafIds = new HashSet<>();
|
private Map<String, String> javaIdToNormalizedId = new HashMap<>();
|
||||||
|
protected Set<String> ignoredJavaIds = new HashSet<>();
|
||||||
|
|
||||||
private Map<String, ColorMatcher> componentToColorMatcherMap = new HashMap<>();
|
private Map<String, ColorGrouper> componentToColorGrouper = new HashMap<>();
|
||||||
private Map<String, FontMatcher> componentToFontMatcherMap = new HashMap<>();
|
private Map<String, FontGrouper> componentToFontGrouper = new HashMap<>();
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
protected ColorMatcher viewColorMatcher = new ColorMatcher(BG_VIEW_ID,
|
protected ColorGrouper viewColorGrouper = new ColorGrouper(BG_VIEW_ID,
|
||||||
FG_VIEW_ID,
|
FG_VIEW_ID,
|
||||||
BG_VIEW_SELECTED_ID,
|
BG_VIEW_SELECTED_ID,
|
||||||
FG_VIEW_SELECTED_ID);
|
FG_VIEW_SELECTED_ID);
|
||||||
protected ColorMatcher tooltipColorMatcher = new ColorMatcher(BG_TOOLTIP_ID,
|
protected ColorGrouper tooltipColorGrouper = new ColorGrouper(BG_TOOLTIP_ID,
|
||||||
FG_TOOLTIP_ID);
|
FG_TOOLTIP_ID);
|
||||||
protected ColorMatcher defaultColorMatcher = new ColorMatcher(BG_CONTROL_ID,
|
protected ColorGrouper defaultColorMatcher = new ColorGrouper(BG_CONTROL_ID,
|
||||||
FG_CONTROL_ID,
|
FG_CONTROL_ID,
|
||||||
BG_VIEW_ID,
|
BG_VIEW_ID,
|
||||||
FG_VIEW_ID,
|
FG_VIEW_ID,
|
||||||
|
@ -111,9 +118,9 @@ public class UiDefaultsMapper {
|
||||||
BG_TOOLTIP_ID,
|
BG_TOOLTIP_ID,
|
||||||
BG_BORDER_ID);
|
BG_BORDER_ID);
|
||||||
|
|
||||||
protected FontMatcher menuFontMatcher = new FontMatcher(FONT_MENU_ID);
|
protected FontGrouper menuFontGrouper = new FontGrouper(FONT_MENU_ID);
|
||||||
protected FontMatcher viewFontMatcher = new FontMatcher(FONT_VIEW_ID);
|
protected FontGrouper viewFontGrouper = new FontGrouper(FONT_VIEW_ID);
|
||||||
protected FontMatcher defaultFontMatcher = new FontMatcher(FONT_CONTROL_ID,
|
protected FontGrouper defaultFontMatcher = new FontGrouper(FONT_CONTROL_ID,
|
||||||
FONT_VIEW_ID,
|
FONT_VIEW_ID,
|
||||||
FONT_MENU_ID);
|
FONT_MENU_ID);
|
||||||
|
|
||||||
|
@ -128,13 +135,13 @@ public class UiDefaultsMapper {
|
||||||
this.defaults = defaults;
|
this.defaults = defaults;
|
||||||
this.extractedValues = extractColorFontAndIconValuesFromDefaults();
|
this.extractedValues = extractColorFontAndIconValuesFromDefaults();
|
||||||
|
|
||||||
assignSystemColorValues();
|
pickRepresentativeValueForColorGroups();
|
||||||
assignSystemFontValues();
|
pickRepresentativeValueForFontGroups();
|
||||||
|
|
||||||
registerIgnoredLafIds();
|
registerIgnoredJavaIds();
|
||||||
|
|
||||||
assignColorMatchersToComponentIds();
|
buildComponentToColorGrouperMap();
|
||||||
assignFontMatchersToComponentIds();
|
buildComponentToFontGrouperMap();
|
||||||
|
|
||||||
assignNormalizedColorValues();
|
assignNormalizedColorValues();
|
||||||
assignNormalizedFontValues();
|
assignNormalizedFontValues();
|
||||||
|
@ -142,12 +149,15 @@ public class UiDefaultsMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the normalized id to value map that will be installed into the
|
* Returns the normalized id to value map that will be installed into the theme manager to be
|
||||||
* ApplicationThemeManager to be the user changeable values for affecting the Java
|
* the user changeable values for affecting the Java LookAndFeel colors, fonts, and icons.
|
||||||
* LookAndFeel colors, fonts, and icons
|
* <p>
|
||||||
|
* The keys in the returned map have been normalized and all start with 'laf.'
|
||||||
|
*
|
||||||
|
*
|
||||||
* @return a map of changeable values that affect java LookAndFeel values
|
* @return a map of changeable values that affect java LookAndFeel values
|
||||||
*/
|
*/
|
||||||
public GThemeValueMap getJavaDefaults() {
|
public GThemeValueMap getNormalizedJavaDefaults() {
|
||||||
return normalizedValues;
|
return normalizedValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,22 +171,25 @@ public class UiDefaultsMapper {
|
||||||
//
|
//
|
||||||
// In the UI Defaults, colors use indirect values and fonts and icons use direct values.
|
// In the UI Defaults, colors use indirect values and fonts and icons use direct values.
|
||||||
// Here we install our GColors for the indirect colors. Then we set any font and icon
|
// Here we install our GColors for the indirect colors. Then we set any font and icon
|
||||||
// values that are different than the defaults.
|
// values that are different than the defaults. Finally, we apply any overridden Java
|
||||||
|
// properties.
|
||||||
//
|
//
|
||||||
installGColorsIntoUIDefaults();
|
installGColorsIntoUIDefaults();
|
||||||
installOverriddenFontsIntoUIDefaults(currentValues);
|
installOverriddenFontsIntoUIDefaults(currentValues);
|
||||||
installOverriddenIconsIntoUIDefaults(currentValues);
|
installOverriddenIconsIntoUIDefaults(currentValues);
|
||||||
|
installOverriddenPropertiesIntoUIDefaults(currentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a mapping of normalized LaF Ids so that when fonts and icons get changed using the
|
* Returns a mapping of normalized LaF Ids so that when fonts and icons get changed using the
|
||||||
* normalized ids that are presented to the user, we know which LaF ids need to be updated in
|
* normalized ids that are presented to the user, we know which LaF ids need to be updated in
|
||||||
* the UiDefaults so that the LookAndFeel will pick up and use the changes.
|
* the UiDefaults so that the LookAndFeel will pick up and use the changes.
|
||||||
|
*
|
||||||
* @return a mapping of normalized LaF ids to original LaF ids.
|
* @return a mapping of normalized LaF ids to original LaF ids.
|
||||||
*/
|
*/
|
||||||
public Map<String, String> getNormalizedIdToLafIdMap() {
|
public Map<String, String> getNormalizedIdToLafIdMap() {
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
for (Entry<String, String> entry : lafIdToNormalizedIdMap.entrySet()) {
|
for (Entry<String, String> entry : javaIdToNormalizedId.entrySet()) {
|
||||||
String lafId = entry.getKey();
|
String lafId = entry.getKey();
|
||||||
String standardId = entry.getValue();
|
String standardId = entry.getValue();
|
||||||
map.put(standardId, lafId);
|
map.put(standardId, lafId);
|
||||||
|
@ -191,41 +204,41 @@ public class UiDefaultsMapper {
|
||||||
* used to seed the values for the system color and fonts. Subclasses should
|
* used to seed the values for the system color and fonts. Subclasses should
|
||||||
* override this method to add additional ids so they won't show up in the theme values.
|
* override this method to add additional ids so they won't show up in the theme values.
|
||||||
*/
|
*/
|
||||||
protected void registerIgnoredLafIds() {
|
protected void registerIgnoredJavaIds() {
|
||||||
|
|
||||||
ignoredLafIds.add("desktop");
|
ignoredJavaIds.add("desktop");
|
||||||
ignoredLafIds.add("activeCaption");
|
ignoredJavaIds.add("activeCaption");
|
||||||
ignoredLafIds.add("activeCaptionText");
|
ignoredJavaIds.add("activeCaptionText");
|
||||||
ignoredLafIds.add("activeCaptionBorder");
|
ignoredJavaIds.add("activeCaptionBorder");
|
||||||
ignoredLafIds.add("inactiveCaption");
|
ignoredJavaIds.add("inactiveCaption");
|
||||||
ignoredLafIds.add("inactiveCaptionText");
|
ignoredJavaIds.add("inactiveCaptionText");
|
||||||
ignoredLafIds.add("inactiveCaptionBorder");
|
ignoredJavaIds.add("inactiveCaptionBorder");
|
||||||
ignoredLafIds.add("window");
|
ignoredJavaIds.add("window");
|
||||||
ignoredLafIds.add("windowBorder");
|
ignoredJavaIds.add("windowBorder");
|
||||||
ignoredLafIds.add("windowText");
|
ignoredJavaIds.add("windowText");
|
||||||
ignoredLafIds.add("menu");
|
ignoredJavaIds.add("menu");
|
||||||
ignoredLafIds.add("menuText");
|
ignoredJavaIds.add("menuText");
|
||||||
ignoredLafIds.add("text");
|
ignoredJavaIds.add("text");
|
||||||
ignoredLafIds.add("textText");
|
ignoredJavaIds.add("textText");
|
||||||
ignoredLafIds.add("textHighlight");
|
ignoredJavaIds.add("textHighlight");
|
||||||
ignoredLafIds.add("textHighightText");
|
ignoredJavaIds.add("textHighightText");
|
||||||
ignoredLafIds.add("textInactiveText");
|
ignoredJavaIds.add("textInactiveText");
|
||||||
ignoredLafIds.add("control");
|
ignoredJavaIds.add("control");
|
||||||
ignoredLafIds.add("controlText");
|
ignoredJavaIds.add("controlText");
|
||||||
ignoredLafIds.add("controlHighlight");
|
ignoredJavaIds.add("controlHighlight");
|
||||||
ignoredLafIds.add("controlLtHighlight");
|
ignoredJavaIds.add("controlLtHighlight");
|
||||||
ignoredLafIds.add("controlShadow");
|
ignoredJavaIds.add("controlShadow");
|
||||||
ignoredLafIds.add("controlDkShadow");
|
ignoredJavaIds.add("controlDkShadow");
|
||||||
ignoredLafIds.add("info");
|
ignoredJavaIds.add("info");
|
||||||
ignoredLafIds.add("infoText");
|
ignoredJavaIds.add("infoText");
|
||||||
ignoredLafIds.add("scrollbar");
|
ignoredJavaIds.add("scrollbar");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the values to assign to all the system color ids based on the best representative
|
* Defines the values to assign to all the system color ids based on the best representative
|
||||||
* value defined in the {@link BasicLookAndFeel}
|
* value defined in the {@link BasicLookAndFeel}
|
||||||
*/
|
*/
|
||||||
protected void assignSystemColorValues() {
|
protected void pickRepresentativeValueForColorGroups() {
|
||||||
// Originally, these values were assigned to the corresponding concepts as defined
|
// Originally, these values were assigned to the corresponding concepts as defined
|
||||||
// in the BasicLookAndFeel such as "control", "text", etc. Unfortunately, those
|
// in the BasicLookAndFeel such as "control", "text", etc. Unfortunately, those
|
||||||
// conventions are rarely used by specific look and feels. It was discovered that using a
|
// conventions are rarely used by specific look and feels. It was discovered that using a
|
||||||
|
@ -235,114 +248,118 @@ public class UiDefaultsMapper {
|
||||||
// subclassed where the values can be overridden. See the NimbusUiDefaultsMapper as an
|
// subclassed where the values can be overridden. See the NimbusUiDefaultsMapper as an
|
||||||
// example.
|
// example.
|
||||||
|
|
||||||
assignSystemColorFromLafId(BG_CONTROL_ID, "Button.background");
|
setGroupColorUsingJavaRepresentative(BG_CONTROL_ID, "Button.background");
|
||||||
assignSystemColorFromLafId(FG_CONTROL_ID, "Button.foreground");
|
setGroupColorUsingJavaRepresentative(FG_CONTROL_ID, "Button.foreground");
|
||||||
assignSystemColorFromLafId(BG_BORDER_ID, "InternalFrame.borderColor");
|
setGroupColorUsingJavaRepresentative(BG_BORDER_ID, "InternalFrame.borderColor");
|
||||||
|
|
||||||
assignSystemColorFromLafId(BG_VIEW_ID, "TextArea.background");
|
setGroupColorUsingJavaRepresentative(BG_VIEW_ID, "TextArea.background");
|
||||||
assignSystemColorFromLafId(FG_VIEW_ID, "TextArea.foreground");
|
setGroupColorUsingJavaRepresentative(FG_VIEW_ID, "TextArea.foreground");
|
||||||
assignSystemColorFromLafId(BG_VIEW_SELECTED_ID, "TextArea.selectionBackground");
|
setGroupColorUsingJavaRepresentative(BG_VIEW_SELECTED_ID, "TextArea.selectionBackground");
|
||||||
assignSystemColorFromLafId(FG_VIEW_SELECTED_ID, "TextArea.selectionForeground");
|
setGroupColorUsingJavaRepresentative(FG_VIEW_SELECTED_ID, "TextArea.selectionForeground");
|
||||||
|
|
||||||
assignSystemColorFromLafId(FG_DISABLED_ID, "Label.disabledForeground");
|
setGroupColorUsingJavaRepresentative(FG_DISABLED_ID, "Label.disabledForeground");
|
||||||
|
|
||||||
assignSystemColorFromLafId(BG_TOOLTIP_ID, "ToolTip.background");
|
setGroupColorUsingJavaRepresentative(BG_TOOLTIP_ID, "ToolTip.background");
|
||||||
assignSystemColorFromLafId(FG_TOOLTIP_ID, "ToolTip.foreground");
|
setGroupColorUsingJavaRepresentative(FG_TOOLTIP_ID, "ToolTip.foreground");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the system color id to a color value from the UiDefaults map.
|
* Assigns the system color id to a color value from the UiDefaults map.
|
||||||
* @param systemColorId the system color id to get a value for
|
* @param group the system color id to get a value for
|
||||||
* @param lafId the LaF key to use to retrieve a color from the UiDefaults
|
* @param javaId the LaF key to use to retrieve a color from the UiDefaults
|
||||||
*/
|
*/
|
||||||
protected void assignSystemColorFromLafId(String systemColorId, String lafId) {
|
protected void setGroupColorUsingJavaRepresentative(String group, String javaId) {
|
||||||
Color lafColor = defaults.getColor(lafId);
|
Color javaColor = defaults.getColor(javaId);
|
||||||
if (lafColor == null) {
|
if (javaColor == null) {
|
||||||
Msg.debug(this, "Missing value for system color: \"" + systemColorId +
|
Msg.debug(this, "Missing value for system color: \"" + group +
|
||||||
"\". No value for laf id: \"" + lafId + "\".");
|
"\". No value for java id: \"" + javaId + "\".");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
normalizedValues.addColor(new ColorValue(systemColorId, lafColor));
|
normalizedValues.addColor(new ColorValue(group, javaColor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the system color id to a directly specified color and does not use the LaF to populate
|
* This allows clients to hard-code a chosen color for a group
|
||||||
* the system color.
|
*
|
||||||
* @param systemColorId the system color id to assign the given color
|
* @param group the system color id to assign the given color
|
||||||
* @param color the color to be assigned to the system color id
|
* @param color the color to be assigned to the system color id
|
||||||
*/
|
*/
|
||||||
protected void assignSystemColorDirect(String systemColorId, Color color) {
|
protected void setGroupColor(String group, Color color) {
|
||||||
normalizedValues.addColor(new ColorValue(systemColorId, color));
|
normalizedValues.addColor(new ColorValue(group, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the system font id a directly specified font and does not use the LaF to populate
|
* This allows clients to hard-code a chosen font for a group
|
||||||
* the system font.
|
*
|
||||||
* @param systemFontId the system font id to assign the given font
|
* @param group the system font id to assign the given font
|
||||||
* @param font the font to be assigned to the system font id
|
* @param font the font to be assigned to the system font id
|
||||||
*/
|
*/
|
||||||
protected void assignSystemFontDirect(String systemFontId, Font font) {
|
protected void setGroupFont(String group, Font font) {
|
||||||
normalizedValues.addFont(new FontValue(systemFontId, font));
|
normalizedValues.addFont(new FontValue(group, font));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setComponentFont(String componentName, Font font) {
|
||||||
|
normalizedValues.addFont(new FontValue(componentName, font));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the values to use for the system fonts.
|
* Defines the font values to use for each group based upon a chosen Java representative.
|
||||||
*/
|
*/
|
||||||
protected void assignSystemFontValues() {
|
protected void pickRepresentativeValueForFontGroups() {
|
||||||
assignSystemFontFromLafId(FONT_CONTROL_ID, "Button.font");
|
setGroupFontUsingRepresentative(FONT_CONTROL_ID, "Button.font");
|
||||||
assignSystemFontFromLafId(FONT_VIEW_ID, "Table.font");
|
setGroupFontUsingRepresentative(FONT_VIEW_ID, "Table.font");
|
||||||
assignSystemFontFromLafId(FONT_MENU_ID, "Menu.font");
|
setGroupFontUsingRepresentative(FONT_MENU_ID, "Menu.font");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignSystemFontFromLafId(String systemFontId, String lafId) {
|
private void setGroupFontUsingRepresentative(String fontGroup, String javaId) {
|
||||||
|
|
||||||
Font lafFont = extractedValues.getResolvedFont(lafId);
|
Font representativeFont = extractedValues.getResolvedFont(javaId);
|
||||||
if (lafFont == null) {
|
if (representativeFont == null) {
|
||||||
Msg.debug(this, "Missing value for system font: \"" + systemFontId +
|
Msg.debug(this, "Missing value for system font: \"" + fontGroup +
|
||||||
"\". No value for laf id: \"" + lafId + "\".");
|
"\". No value for java id: \"" + javaId + "\".");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
normalizedValues.addFont(new FontValue(systemFontId, fromUiResource(lafFont)));
|
normalizedValues.addFont(new FontValue(fontGroup, fromUiResource(representativeFont)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the appropriate font matcher to each component in the related component group
|
* Sets the font grouper for each component group
|
||||||
*/
|
*/
|
||||||
protected void assignFontMatchersToComponentIds() {
|
protected void buildComponentToFontGrouperMap() {
|
||||||
defineComponentFontMatcher(MENU_COMPONENTS, menuFontMatcher);
|
mapComponentsToFontGrouper(menuFontGrouper, MENU_COMPONENTS);
|
||||||
defineComponentFontMatcher(VIEW_COMPONENTS, viewFontMatcher);
|
mapComponentsToFontGrouper(viewFontGrouper, VIEW_COMPONENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the appropriate color matcher to each component in the related component group
|
* Sets the color grouper for each component group
|
||||||
*/
|
*/
|
||||||
protected void assignColorMatchersToComponentIds() {
|
protected void buildComponentToColorGrouperMap() {
|
||||||
defineComponentColorMatcher(VIEW_COMPONENTS, viewColorMatcher);
|
mapComponentsToColorGrouper(viewColorGrouper, VIEW_COMPONENTS);
|
||||||
defineComponentColorMatcher(TOOLTIP_COMPONENTS, tooltipColorMatcher);
|
mapComponentsToColorGrouper(tooltipColorGrouper, TOOLTIP_COMPONENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns every component name in the component group to the given ColorValueMatcher
|
* Assigns every component name in the component group to the given ColorValueMatcher
|
||||||
* @param componentGroups a list of component names
|
* @param grouper the ColorMatcher that will provide the precedence of system ids to
|
||||||
* @param matcher the ColorMatcher that will provide the precedence of system ids to
|
|
||||||
* search when replacing LaF component specific values
|
* search when replacing LaF component specific values
|
||||||
|
* @param componentGroup a list of component names
|
||||||
*/
|
*/
|
||||||
private void defineComponentColorMatcher(String[] componentGroups, ColorMatcher matcher) {
|
private void mapComponentsToColorGrouper(ColorGrouper grouper, String... componentGroup) {
|
||||||
for (String componentGroup : componentGroups) {
|
for (String name : componentGroup) {
|
||||||
componentToColorMatcherMap.put(componentGroup, matcher);
|
componentToColorGrouper.put(name, grouper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns every component name in a component group to the given FontValueMapper
|
* Assigns every component name in a component group to the given FontValueMapper
|
||||||
* @param componentGroups a list of component names
|
* @param grouper the FontValueMatcher that will provide the precedence of system font ids to
|
||||||
* @param matcher the FontValueMatcher that will provide the precedence of ststem font ids to
|
|
||||||
* search when replacing LaF component specific fonts with a system Font
|
* search when replacing LaF component specific fonts with a system Font
|
||||||
|
* @param componentGroup a list of component names
|
||||||
*/
|
*/
|
||||||
private void defineComponentFontMatcher(String[] componentGroups, FontMatcher matcher) {
|
private void mapComponentsToFontGrouper(FontGrouper grouper, String... componentGroup) {
|
||||||
for (String componentGroup : componentGroups) {
|
for (String name : componentGroup) {
|
||||||
componentToFontMatcherMap.put(componentGroup, matcher);
|
componentToFontGrouper.put(name, grouper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,12 +373,12 @@ public class UiDefaultsMapper {
|
||||||
for (String lafId : list) {
|
for (String lafId : list) {
|
||||||
// we don't want to create java defaults for laf system ids since changing them would
|
// we don't want to create java defaults for laf system ids since changing them would
|
||||||
// have no effect
|
// have no effect
|
||||||
if (ignoredLafIds.contains(lafId)) {
|
if (ignoredJavaIds.contains(lafId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String createdId = LAF_FONT_ID_PREFIX + lafId;
|
String createdId = LAF_FONT_ID_PREFIX + lafId;
|
||||||
lafIdToNormalizedIdMap.put(lafId, createdId);
|
javaIdToNormalizedId.put(lafId, createdId);
|
||||||
|
|
||||||
Font lafFont = extractedValues.getResolvedFont(lafId);
|
Font lafFont = extractedValues.getResolvedFont(lafId);
|
||||||
FontValue fontValue = getFontValue(createdId, lafId, lafFont);
|
FontValue fontValue = getFontValue(createdId, lafId, lafFont);
|
||||||
|
@ -380,7 +397,7 @@ public class UiDefaultsMapper {
|
||||||
Icon icon = extractedValues.getResolvedIcon(lafId);
|
Icon icon = extractedValues.getResolvedIcon(lafId);
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
normalizedValues.addIcon(new IconValue(createdId, icon));
|
normalizedValues.addIcon(new IconValue(createdId, icon));
|
||||||
lafIdToNormalizedIdMap.put(lafId, createdId);
|
javaIdToNormalizedId.put(lafId, createdId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -393,11 +410,11 @@ public class UiDefaultsMapper {
|
||||||
List<String> list = new ArrayList<>(extractedValues.getColorIds());
|
List<String> list = new ArrayList<>(extractedValues.getColorIds());
|
||||||
Collections.sort(list);
|
Collections.sort(list);
|
||||||
for (String lafId : list) {
|
for (String lafId : list) {
|
||||||
if (ignoredLafIds.contains(lafId)) {
|
if (ignoredJavaIds.contains(lafId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String createdId = LAF_COLOR_ID_PREFIX + lafId;
|
String createdId = LAF_COLOR_ID_PREFIX + lafId;
|
||||||
lafIdToNormalizedIdMap.put(lafId, createdId);
|
javaIdToNormalizedId.put(lafId, createdId);
|
||||||
|
|
||||||
Color lafColor = extractedValues.getResolvedColor(lafId);
|
Color lafColor = extractedValues.getResolvedColor(lafId);
|
||||||
ColorValue colorValue = getColorValue(createdId, lafId, lafColor);
|
ColorValue colorValue = getColorValue(createdId, lafId, lafColor);
|
||||||
|
@ -486,16 +503,16 @@ public class UiDefaultsMapper {
|
||||||
*/
|
*/
|
||||||
private String findSystemColorId(String lafId, Color lafColor) {
|
private String findSystemColorId(String lafId, Color lafColor) {
|
||||||
String componentName = getComponentName(lafId);
|
String componentName = getComponentName(lafId);
|
||||||
ColorMatcher colorMatcher = componentToColorMatcherMap.get(componentName);
|
ColorGrouper colorMatcher = componentToColorGrouper.get(componentName);
|
||||||
// check in widget specific group first
|
// check in widget specific group first
|
||||||
if (colorMatcher != null) {
|
if (colorMatcher != null) {
|
||||||
String systemId = colorMatcher.getSystemId(lafColor);
|
String systemId = colorMatcher.getGroupId(lafColor);
|
||||||
if (systemId != null) {
|
if (systemId != null) {
|
||||||
return systemId;
|
return systemId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not found in widget specific group, check general component groups
|
// not found in widget specific group, check general component groups
|
||||||
return defaultColorMatcher.getSystemId(lafColor);
|
return defaultColorMatcher.getGroupId(lafColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -508,16 +525,16 @@ public class UiDefaultsMapper {
|
||||||
*/
|
*/
|
||||||
private String findSystemFontId(String lafId, Font lafFont) {
|
private String findSystemFontId(String lafId, Font lafFont) {
|
||||||
String componentName = getComponentName(lafId);
|
String componentName = getComponentName(lafId);
|
||||||
FontMatcher fontMatcher = componentToFontMatcherMap.get(componentName);
|
FontGrouper fontMatcher = componentToFontGrouper.get(componentName);
|
||||||
// check in widget specific group first
|
// check in widget specific group first
|
||||||
if (fontMatcher != null) {
|
if (fontMatcher != null) {
|
||||||
String systemId = fontMatcher.getSystemId(lafFont);
|
String systemId = fontMatcher.getGroupId(lafFont);
|
||||||
if (systemId != null) {
|
if (systemId != null) {
|
||||||
return systemId;
|
return systemId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not found in widget specific group, check general component groups
|
// not found in widget specific group, check general component groups
|
||||||
return defaultFontMatcher.getSystemId(lafFont);
|
return defaultFontMatcher.getGroupId(lafFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -541,7 +558,7 @@ public class UiDefaultsMapper {
|
||||||
Map<String, GColorUIResource> cachedColors = new HashMap<>();
|
Map<String, GColorUIResource> cachedColors = new HashMap<>();
|
||||||
|
|
||||||
for (String lafId : extractedValues.getColorIds()) {
|
for (String lafId : extractedValues.getColorIds()) {
|
||||||
String standardColorId = lafIdToNormalizedIdMap.get(lafId);
|
String standardColorId = javaIdToNormalizedId.get(lafId);
|
||||||
if (standardColorId != null) {
|
if (standardColorId != null) {
|
||||||
GColorUIResource sharedGColor = getSharedGColor(cachedColors, standardColorId);
|
GColorUIResource sharedGColor = getSharedGColor(cachedColors, standardColorId);
|
||||||
defaults.put(lafId, sharedGColor);
|
defaults.put(lafId, sharedGColor);
|
||||||
|
@ -556,7 +573,7 @@ public class UiDefaultsMapper {
|
||||||
private void installOverriddenIconsIntoUIDefaults(GThemeValueMap currentValues) {
|
private void installOverriddenIconsIntoUIDefaults(GThemeValueMap currentValues) {
|
||||||
for (String lafId : extractedValues.getIconIds()) {
|
for (String lafId : extractedValues.getIconIds()) {
|
||||||
Icon currentIcon = extractedValues.getResolvedIcon(lafId);
|
Icon currentIcon = extractedValues.getResolvedIcon(lafId);
|
||||||
String standardId = lafIdToNormalizedIdMap.get(lafId);
|
String standardId = javaIdToNormalizedId.get(lafId);
|
||||||
Icon overriddenIcon = currentValues.getResolvedIcon(standardId);
|
Icon overriddenIcon = currentValues.getResolvedIcon(standardId);
|
||||||
if (overriddenIcon != null && currentIcon != overriddenIcon) {
|
if (overriddenIcon != null && currentIcon != overriddenIcon) {
|
||||||
defaults.put(lafId, overriddenIcon);
|
defaults.put(lafId, overriddenIcon);
|
||||||
|
@ -572,7 +589,7 @@ public class UiDefaultsMapper {
|
||||||
private void installOverriddenFontsIntoUIDefaults(GThemeValueMap currentValues) {
|
private void installOverriddenFontsIntoUIDefaults(GThemeValueMap currentValues) {
|
||||||
for (String lafId : extractedValues.getFontIds()) {
|
for (String lafId : extractedValues.getFontIds()) {
|
||||||
Font currentFont = extractedValues.getResolvedFont(lafId);
|
Font currentFont = extractedValues.getResolvedFont(lafId);
|
||||||
String standardId = lafIdToNormalizedIdMap.get(lafId);
|
String standardId = javaIdToNormalizedId.get(lafId);
|
||||||
Font overriddenFont = currentValues.getResolvedFont(standardId);
|
Font overriddenFont = currentValues.getResolvedFont(standardId);
|
||||||
if (overriddenFont != null && overriddenFont != currentFont) {
|
if (overriddenFont != null && overriddenFont != currentFont) {
|
||||||
defaults.put(lafId, new FontUIResource(overriddenFont));
|
defaults.put(lafId, new FontUIResource(overriddenFont));
|
||||||
|
@ -580,6 +597,18 @@ public class UiDefaultsMapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all non- (color/font/icon) UIManager properties. These properties are UIManager
|
||||||
|
* properties that the user has overridden in the {@code theme.properties} files. These
|
||||||
|
* properties may use any type of value that is not a color/font/icon.
|
||||||
|
* @param currentValues the theme values that potentially override a laf font value
|
||||||
|
*/
|
||||||
|
private void installOverriddenPropertiesIntoUIDefaults(GThemeValueMap currentValues) {
|
||||||
|
for (JavaPropertyValue property : currentValues.getProperties()) {
|
||||||
|
defaults.put(property.getId(), property.get(currentValues));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When putting {@link GColorUIResource} values into the UiDefaults, we need to make sure
|
* When putting {@link GColorUIResource} values into the UiDefaults, we need to make sure
|
||||||
* we use the same instance for the same color. Some LookAndFeels do "==" checks on colors
|
* we use the same instance for the same color. Some LookAndFeels do "==" checks on colors
|
||||||
|
@ -598,7 +627,7 @@ public class UiDefaultsMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void overrideColor(String lafId, String sytemId) {
|
protected void overrideColor(String lafId, String sytemId) {
|
||||||
String normalizedId = lafIdToNormalizedIdMap.get(lafId);
|
String normalizedId = javaIdToNormalizedId.get(lafId);
|
||||||
if (normalizedId == null) {
|
if (normalizedId == null) {
|
||||||
Msg.debug(this, "Missing value for laf id: \"" + lafId);
|
Msg.debug(this, "Missing value for laf id: \"" + lafId);
|
||||||
return;
|
return;
|
||||||
|
@ -644,54 +673,59 @@ public class UiDefaultsMapper {
|
||||||
* @return a list of all ids that have the given value type
|
* @return a list of all ids that have the given value type
|
||||||
*/
|
*/
|
||||||
private List<String> getLookAndFeelIdsForType(Class<?> clazz) {
|
private List<String> getLookAndFeelIdsForType(Class<?> clazz) {
|
||||||
List<String> colorKeys = new ArrayList<>();
|
List<String> ids = new ArrayList<>();
|
||||||
List<Object> keyList = IteratorUtils.toList(defaults.keys().asIterator());
|
List<Object> keyList = IteratorUtils.toList(defaults.keys().asIterator());
|
||||||
for (Object key : keyList) {
|
for (Object key : keyList) {
|
||||||
if (key instanceof String) {
|
if (key instanceof String) {
|
||||||
Object value = defaults.get(key);
|
Object value = defaults.get(key);
|
||||||
if (clazz.isInstance(value)) {
|
if (clazz.isInstance(value)) {
|
||||||
colorKeys.add((String) key);
|
ids.add((String) key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return colorKeys;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to match values (Colors or Fonts) into appropriate system ids. System ids are searched
|
* Used to match values (Colors or Fonts) into appropriate system groups. System group are
|
||||||
* in the order the system ids are given in the constructor.
|
* searched in the order the groups are given in the constructor.
|
||||||
|
* <p>
|
||||||
|
* Groups allow us to use the same group id for many components that by default have the same
|
||||||
|
* value (Color or Font). This grouper allows us to specify the precedence to use when
|
||||||
|
* searching for the best group.
|
||||||
|
*
|
||||||
* @param <T> The theme value type (Color or Font)
|
* @param <T> The theme value type (Color or Font)
|
||||||
*/
|
*/
|
||||||
private abstract class ValueMatcher<T> {
|
private abstract class ValueGrouper<T> {
|
||||||
private Map<T, String> map = new HashMap<>();
|
private Map<T, String> idsByFont = new HashMap<>();
|
||||||
private List<String> systemIdList;
|
private List<String> groupIds;
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
|
|
||||||
ValueMatcher(String... systemIds) {
|
ValueGrouper(String... ids) {
|
||||||
systemIdList = new ArrayList<>(Arrays.asList(systemIds));
|
groupIds = new ArrayList<>(Arrays.asList(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
// process in reverse order so that earlier items in the list can overwrite later
|
// process in reverse order so that earlier items in the list can overwrite later
|
||||||
// items if they have the same font
|
// items if they have the same value
|
||||||
for (int i = systemIdList.size() - 1; i >= 0; i--) {
|
for (int i = groupIds.size() - 1; i >= 0; i--) {
|
||||||
String systemId = systemIdList.get(i);
|
String groupId = groupIds.get(i);
|
||||||
T value = getValueFromJavaDefaults(systemId);
|
T value = getValueFromJavaDefaults(groupId);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
map.put(value, systemId);
|
idsByFont.put(value, groupId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract T getValueFromJavaDefaults(String systemId);
|
protected abstract T getValueFromJavaDefaults(String systemId);
|
||||||
|
|
||||||
String getSystemId(T value) {
|
String getGroupId(T value) {
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
return map.get(value);
|
return idsByFont.get(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -700,9 +734,9 @@ public class UiDefaultsMapper {
|
||||||
* id that matches a given color. The order that color system ids are added is important and is
|
* id that matches a given color. The order that color system ids are added is important and is
|
||||||
* the precedence order if more than one system color id has the same color.
|
* the precedence order if more than one system color id has the same color.
|
||||||
*/
|
*/
|
||||||
private class ColorMatcher extends ValueMatcher<Color> {
|
private class ColorGrouper extends ValueGrouper<Color> {
|
||||||
|
|
||||||
ColorMatcher(String... systemIds) {
|
ColorGrouper(String... systemIds) {
|
||||||
super(systemIds);
|
super(systemIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,8 +752,8 @@ public class UiDefaultsMapper {
|
||||||
* that matches a given font. The order that system font ids are added is important and is
|
* that matches a given font. The order that system font ids are added is important and is
|
||||||
* the precedence order if more than one system id has the same font.
|
* the precedence order if more than one system id has the same font.
|
||||||
*/
|
*/
|
||||||
private class FontMatcher extends ValueMatcher<Font> {
|
private class FontGrouper extends ValueGrouper<Font> {
|
||||||
FontMatcher(String... systemIds) {
|
FontGrouper(String... systemIds) {
|
||||||
super(systemIds);
|
super(systemIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class WindowsClassicLookAndFeelManager extends LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
return new UiDefaultsMapper(defaults);
|
return new UiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class WindowsLookAndFeelManager extends LookAndFeelManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
protected UiDefaultsMapper createUiDefaultsMapper(UIDefaults defaults) {
|
||||||
return new UiDefaultsMapper(defaults);
|
return new UiDefaultsMapper(defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -352,7 +352,7 @@ public class ApplicationThemeManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ApplicationThemeDefaults getApplicationDefaults() {
|
protected ApplicationThemeDefaults loadApplicationDefaults() {
|
||||||
return new ApplicationThemeDefaults() {
|
return new ApplicationThemeDefaults() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.awt.Color;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ghidra.util.WebColors;
|
import ghidra.util.*;
|
||||||
|
|
||||||
public class ColorValueTest {
|
public class ColorValueTest {
|
||||||
|
|
||||||
|
@ -30,6 +30,10 @@ public class ColorValueTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
||||||
|
// disable warning messages when some test values cannot be found
|
||||||
|
Msg.setErrorLogger(new SpyErrorLogger());
|
||||||
|
|
||||||
values = new GThemeValueMap();
|
values = new GThemeValueMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,4 +154,34 @@ public class ColorValueTest {
|
||||||
assertEquals("color.parent", value.getReferenceId());
|
assertEquals("color.parent", value.getReferenceId());
|
||||||
assertNull(value.getRawValue());
|
assertNull(value.getRawValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJavaColorValueRoundTrip() {
|
||||||
|
|
||||||
|
ColorValue value = ColorValue.parse("[laf.color]TextArea.background", "red");
|
||||||
|
values.addColor(value);
|
||||||
|
|
||||||
|
assertEquals("laf.color.TextArea.background", value.getId());
|
||||||
|
assertEquals(Color.RED, value.get(values));
|
||||||
|
|
||||||
|
assertEquals("[laf.color]TextArea.background = #ff0000 // Red",
|
||||||
|
value.getSerializationString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInheritsFrom_JavaValues() {
|
||||||
|
|
||||||
|
ColorValue parent = ColorValue.parse("[laf.color]TextArea.background", "red");
|
||||||
|
values.addColor(parent);
|
||||||
|
ColorValue value =
|
||||||
|
ColorValue.parse("[laf.color]Button.background", "[laf.color]TextArea.background");
|
||||||
|
values.addColor(value);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Note: ColorValue.parse() works on external ids or normalized ids.
|
||||||
|
//
|
||||||
|
// ColorValue() constructor and inheritsFrom() only work on normalized ids
|
||||||
|
//
|
||||||
|
assertTrue(value.inheritsFrom("laf.color.TextArea.background", values));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,19 @@ import java.text.ParseException;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.SpyErrorLogger;
|
||||||
|
|
||||||
public class FontValueTest {
|
public class FontValueTest {
|
||||||
private static Font FONT = new Font("Dialog", Font.PLAIN, 12);
|
private static Font FONT = new Font("Dialog", Font.PLAIN, 12);
|
||||||
private GThemeValueMap values;
|
private GThemeValueMap values;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
||||||
|
// disable warning messages when some test values cannot be found
|
||||||
|
Msg.setErrorLogger(new SpyErrorLogger());
|
||||||
|
|
||||||
values = new GThemeValueMap();
|
values = new GThemeValueMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,4 +147,33 @@ public class FontValueTest {
|
||||||
assertFalse(grandParent.inheritsFrom("font.test", values));
|
assertFalse(grandParent.inheritsFrom("font.test", values));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJavaFontValueRoundTrip() throws Exception {
|
||||||
|
|
||||||
|
FontValue value = FontValue.parse("[laf.font]Button.font", "monospaced-PLAIN-12");
|
||||||
|
values.addFont(value);
|
||||||
|
|
||||||
|
assertEquals("laf.font.Button.font", value.getId());
|
||||||
|
assertEquals(new Font("monospaced", Font.PLAIN, 12), value.get(values));
|
||||||
|
|
||||||
|
assertEquals("[laf.font]Button.font = monospaced-PLAIN-12",
|
||||||
|
value.getSerializationString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInheritsFrom_JavaValues() throws Exception {
|
||||||
|
|
||||||
|
FontValue parent = FontValue.parse("[laf.font]Button.font", "monospaced-PLAIN-12");
|
||||||
|
values.addFont(parent);
|
||||||
|
FontValue value =
|
||||||
|
FontValue.parse("[laf.font]ToggleButton.font", "[laf.font]Button.font");
|
||||||
|
values.addFont(value);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Note: ColorValue.parse() works on external ids or normalized ids.
|
||||||
|
//
|
||||||
|
// ColorValue() constructor and inheritsFrom() only work on normalized ids
|
||||||
|
//
|
||||||
|
assertTrue(value.inheritsFrom("laf.font.Button.font", values));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,8 @@ public class GThemeTest extends AbstractGenericTest {
|
||||||
theme.setColor("foo.bar", Color.GREEN);
|
theme.setColor("foo.bar", Color.GREEN);
|
||||||
theme.setColorRef("foo.bar.xyz", "foo.bar");
|
theme.setColorRef("foo.bar.xyz", "foo.bar");
|
||||||
|
|
||||||
|
theme.setColor("laf.color.TextArea.background", Color.GREEN);
|
||||||
|
|
||||||
theme.setFont("font.a.1", COURIER);
|
theme.setFont("font.a.1", COURIER);
|
||||||
theme.setFont("font.a.2", DIALOG);
|
theme.setFont("font.a.2", DIALOG);
|
||||||
theme.setFontRef("font.a.3", "font.a.1");
|
theme.setFontRef("font.a.3", "font.a.1");
|
||||||
|
@ -110,6 +112,7 @@ public class GThemeTest extends AbstractGenericTest {
|
||||||
assertEquals(Color.RED, theme.getColor("color.a.4").get(theme));
|
assertEquals(Color.RED, theme.getColor("color.a.4").get(theme));
|
||||||
assertEquals(Color.GREEN, theme.getColor("foo.bar").get(theme));
|
assertEquals(Color.GREEN, theme.getColor("foo.bar").get(theme));
|
||||||
assertEquals(Color.GREEN, theme.getColor("foo.bar.xyz").get(theme));
|
assertEquals(Color.GREEN, theme.getColor("foo.bar.xyz").get(theme));
|
||||||
|
assertEquals(Color.GREEN, theme.getColor("laf.color.TextArea.background").get(theme));
|
||||||
|
|
||||||
assertEquals(COURIER, theme.getFont("font.a.1").get(theme));
|
assertEquals(COURIER, theme.getFont("font.a.1").get(theme));
|
||||||
assertEquals(DIALOG, theme.getFont("font.a.2").get(theme));
|
assertEquals(DIALOG, theme.getFont("font.a.2").get(theme));
|
||||||
|
|
|
@ -24,6 +24,8 @@ import javax.swing.Icon;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.SpyErrorLogger;
|
||||||
import resources.MultiIcon;
|
import resources.MultiIcon;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
import resources.icons.EmptyIcon;
|
import resources.icons.EmptyIcon;
|
||||||
|
@ -35,6 +37,10 @@ public class IconValueTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
||||||
|
// disable warning messages when some test values cannot be found
|
||||||
|
Msg.setErrorLogger(new SpyErrorLogger());
|
||||||
|
|
||||||
values = new GThemeValueMap();
|
values = new GThemeValueMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,4 +231,37 @@ public class IconValueTest {
|
||||||
assertEquals("icon.test = EMPTY_ICON[size(22,13)]", value.getSerializationString());
|
assertEquals("icon.test = EMPTY_ICON[size(22,13)]", value.getSerializationString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJavaIconValueRoundTrip() throws Exception {
|
||||||
|
|
||||||
|
IconValue value =
|
||||||
|
IconValue.parse("[laf.icon]FileChooser.homeFolderIcon", "images/go-home.png");
|
||||||
|
values.addIcon(value);
|
||||||
|
|
||||||
|
assertEquals("laf.icon.FileChooser.homeFolderIcon", value.getId());
|
||||||
|
assertEquals(ResourceManager.loadIcon("images/go-home.png"), value.get(values));
|
||||||
|
|
||||||
|
assertEquals("[laf.icon]FileChooser.homeFolderIcon = images/go-home.png",
|
||||||
|
value.getSerializationString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInheritsFrom_JavaValues() throws Exception {
|
||||||
|
|
||||||
|
IconValue parent =
|
||||||
|
IconValue.parse("[laf.icon]FileChooser.homeFolderIcon", "images/go-home.png");
|
||||||
|
values.addIcon(parent);
|
||||||
|
|
||||||
|
IconValue value =
|
||||||
|
IconValue.parse("[laf.icon]FileView.computerIcon",
|
||||||
|
"[laf.icon]FileChooser.homeFolderIcon");
|
||||||
|
values.addIcon(value);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Note: IconValue.parse() works on external ids or normalized ids.
|
||||||
|
//
|
||||||
|
// IconValue() constructor and inheritsFrom() only work on normalized ids
|
||||||
|
//
|
||||||
|
assertTrue(value.inheritsFrom("laf.icon.FileChooser.homeFolderIcon", values));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDefaults() throws IOException {
|
public void testDefaults() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" color.b.1 = white", // WHITE
|
" color.b.1 = white", // WHITE
|
||||||
" color.b.2 = #ff0000", // RED
|
" color.b.2 = #ff0000", // RED
|
||||||
" color.b.3 = 0x008000", // GREEN
|
" color.b.3 = 0x008000", // GREEN
|
||||||
|
@ -53,12 +53,18 @@ public class ThemePropertyFileReaderTest {
|
||||||
" icon.a.12 = icon.a.10[size(17,21)]",
|
" icon.a.12 = icon.a.10[size(17,21)]",
|
||||||
" icon.a.13 = core.png[size(17,21)]",
|
" icon.a.13 = core.png[size(17,21)]",
|
||||||
" icon.a.14 = icon.a.10{core.png[size(4,4)][move(8, 8)]}",
|
" icon.a.14 = icon.a.10{core.png[size(4,4)][move(8, 8)]}",
|
||||||
|
" [laf.font]PasswordField.font = font.a.8",
|
||||||
|
" [laf.font]TextArea.font = dialog-PLAIN-14",
|
||||||
|
" [laf.color]TextArea.background = color.b.1",
|
||||||
|
" [laf.string]Fake.title = This is my title",
|
||||||
|
" [laf.string]OtherFake.title = [laf.string]Fake.title",
|
||||||
|
" [laf.boolean]PopupMenu.consumeEventOnClose = false",
|
||||||
"")));
|
"")));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
Color halfAlphaRed = new Color(0x80ff0000, true);
|
Color halfAlphaRed = new Color(0x80ff0000, true);
|
||||||
GThemeValueMap values = reader.getDefaultValues();
|
GThemeValueMap values = reader.getDefaultValues();
|
||||||
assertEquals(15, values.size());
|
assertEquals(21, values.size());
|
||||||
|
|
||||||
assertEquals(WHITE, getColor(values, "color.b.1"));
|
assertEquals(WHITE, getColor(values, "color.b.1"));
|
||||||
assertEquals(RED, getColor(values, "color.b.2"));
|
assertEquals(RED, getColor(values, "color.b.2"));
|
||||||
|
@ -85,21 +91,27 @@ public class ThemePropertyFileReaderTest {
|
||||||
icon = getIcon(values, "icon.a.14");
|
icon = getIcon(values, "icon.a.14");
|
||||||
assertTrue(icon instanceof MultiIcon);
|
assertTrue(icon instanceof MultiIcon);
|
||||||
|
|
||||||
|
Font f = new Font("dialog", Font.PLAIN, 14);
|
||||||
|
assertEquals(f, getFont(values, "laf.font.PasswordField.font")); // direct font
|
||||||
|
assertEquals(f, getFont(values, "laf.font.TextArea.font")); // font reference
|
||||||
|
assertEquals("This is my title", getLafString(values, "Fake.title"));
|
||||||
|
assertEquals("This is my title", getLafString(values, "OtherFake.title"));
|
||||||
|
assertEquals(false, getLafBoolean(values, "PopupMenu.consumeEventOnClose"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDarkDefaults() throws IOException {
|
public void testDarkDefaults() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" color.b.1 = red",
|
" color.b.1 = red",
|
||||||
" color.b.2 = red",
|
" color.b.2 = red",
|
||||||
" color.b.3 = red",
|
" color.b.3 = red",
|
||||||
" color.b.4 = red",
|
" color.b.4 = red",
|
||||||
" color.b.5 = red",
|
" color.b.5 = red",
|
||||||
" color.b.6 = red",
|
" color.b.6 = red",
|
||||||
" color.b.7 = red",
|
" color.b.7 = red",
|
||||||
"[Dark Defaults]",
|
"[Dark Defaults]",
|
||||||
" color.b.1 = white", // WHITE
|
" color.b.1 = white", // WHITE
|
||||||
" color.b.2 = #ff0000", // RED
|
" color.b.2 = #ff0000", // RED
|
||||||
" color.b.3 = 0x008000", // GREEN
|
" color.b.3 = 0x008000", // GREEN
|
||||||
|
@ -126,11 +138,11 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testBothDefaultsAndDarkDefaultsInSameFile() throws IOException {
|
public void testBothDefaultsAndDarkDefaultsInSameFile() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" color.b.1 = white", // WHITE
|
" color.b.1 = white", // WHITE
|
||||||
" color.b.2 = #ff0000", // RED
|
" color.b.2 = #ff0000", // RED
|
||||||
"[Dark Defaults]",
|
"[Dark Defaults]",
|
||||||
" color.b.1 = black", // BLACK
|
" color.b.1 = black", // BLACK
|
||||||
" color.b.2 = #0000ff", // BLUE
|
" color.b.2 = #0000ff", // BLUE
|
||||||
"")));
|
"")));
|
||||||
|
@ -151,14 +163,14 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testLookAndFeelValues() throws IOException {
|
public void testLookAndFeelValues() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" color.b.1 = white",
|
" color.b.1 = white",
|
||||||
"[Dark Defaults]",
|
"[Dark Defaults]",
|
||||||
" color.b.1 = black",
|
" color.b.1 = black",
|
||||||
"[Metal]",
|
"[Metal]",
|
||||||
" color.b.1 = red",
|
" color.b.1 = red",
|
||||||
"[Nimbus]",
|
"[Nimbus]",
|
||||||
" color.b.1 = green",
|
" color.b.1 = green",
|
||||||
"")));
|
"")));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
@ -188,8 +200,8 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testParseColorError() throws IOException {
|
public void testParseColorError() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" color.b.1 = white", // WHITE
|
" color.b.1 = white", // WHITE
|
||||||
" color.b.2 = sdfsdf", // RED
|
" color.b.2 = sdfsdf", // RED
|
||||||
"")));
|
"")));
|
||||||
|
@ -204,11 +216,11 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testParseFontError() throws IOException {
|
public void testParseFontError() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" font.b.1 = Dialog-PLAIN-14",
|
" font.b.1 = Dialog-PLAIN-14",
|
||||||
" font.b.2 = Dialog-PLANE-13",
|
" font.b.2 = Dialog-PLANE-13",
|
||||||
" font.b.3 = Dialog-BOLD-ITALIC",
|
" font.b.3 = Dialog-BOLD-ITALIC",
|
||||||
"")));
|
"")));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
List<String> errors = reader.getErrors();
|
List<String> errors = reader.getErrors();
|
||||||
|
@ -219,10 +231,10 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testParseFontModiferError() throws IOException {
|
public void testParseFontModiferError() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" font.b.1 = Dialog-PLAIN-14",
|
" font.b.1 = Dialog-PLAIN-14",
|
||||||
" font.b.2 = (font.b.1[)",
|
" font.b.2 = (font.b.1[)",
|
||||||
"")));
|
"")));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
List<String> errors = reader.getErrors();
|
List<String> errors = reader.getErrors();
|
||||||
|
@ -233,10 +245,10 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIconNoRightHandValueError() throws IOException {
|
public void testIconNoRightHandValueError() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" icon.b.1 = core.png",
|
" icon.b.1 = core.png",
|
||||||
" icon.b.2 = ",
|
" icon.b.2 = ",
|
||||||
"")));
|
"")));
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
List<String> errors = reader.getErrors();
|
List<String> errors = reader.getErrors();
|
||||||
|
@ -247,8 +259,8 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testColorIdDefinedInNonDefaultsSectionOnly() throws IOException {
|
public void testColorIdDefinedInNonDefaultsSectionOnly() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" color.foo = red",
|
" color.foo = red",
|
||||||
"[Dark Defaults]",
|
"[Dark Defaults]",
|
||||||
" color.bar = blue",
|
" color.bar = blue",
|
||||||
|
@ -264,7 +276,7 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testFontIdDefinedInNonDefaultsSectionOnly() throws IOException {
|
public void testFontIdDefinedInNonDefaultsSectionOnly() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
"[Dark Defaults]",
|
"[Dark Defaults]",
|
||||||
" font.bar = dialog-PLAIN-14",
|
" font.bar = dialog-PLAIN-14",
|
||||||
|
@ -280,7 +292,7 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIconIdDefinedInNonDefaultsSectionOnly() throws IOException {
|
public void testIconIdDefinedInNonDefaultsSectionOnly() throws IOException {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
"[Dark Defaults]",
|
"[Dark Defaults]",
|
||||||
" icon.bar = core.png",
|
" icon.bar = core.png",
|
||||||
|
@ -296,8 +308,8 @@ public class ThemePropertyFileReaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultSectionMustBeFirst() throws Exception {
|
public void testDefaultSectionMustBeFirst() throws Exception {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
ThemePropertyFileReader reader = new SilentThemePropertyFileReader("test", new StringReader(String.join("\n",
|
||||||
"[Dark Defaults]",
|
"[Dark Defaults]",
|
||||||
" color.foo = red",
|
" color.foo = red",
|
||||||
"[Defaults]",
|
"[Defaults]",
|
||||||
" color.bar = blue",
|
" color.bar = blue",
|
||||||
|
@ -326,6 +338,16 @@ public class ThemePropertyFileReaderTest {
|
||||||
return icon.get(values);
|
return icon.get(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getLafString(GThemeValueMap values, String id) {
|
||||||
|
StringPropertyValue value = (StringPropertyValue) values.getProperty(id);
|
||||||
|
return (String) value.get(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getLafBoolean(GThemeValueMap values, String id) {
|
||||||
|
BooleanPropertyValue value = (BooleanPropertyValue) values.getProperty(id);
|
||||||
|
return (Boolean) value.get(values);
|
||||||
|
}
|
||||||
|
|
||||||
private class SilentThemePropertyFileReader extends ThemePropertyFileReader {
|
private class SilentThemePropertyFileReader extends ThemePropertyFileReader {
|
||||||
|
|
||||||
protected SilentThemePropertyFileReader(String source, Reader reader) throws IOException {
|
protected SilentThemePropertyFileReader(String source, Reader reader) throws IOException {
|
||||||
|
|
|
@ -28,6 +28,8 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import generic.theme.*;
|
import generic.theme.*;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.SpyErrorLogger;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class UIDefaultsMapperTest {
|
public class UIDefaultsMapperTest {
|
||||||
|
@ -40,6 +42,10 @@ public class UIDefaultsMapperTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
||||||
|
// disable warning messages when some default UI values cannot be found
|
||||||
|
Msg.setErrorLogger(new SpyErrorLogger());
|
||||||
|
|
||||||
defaults = createDefaults();
|
defaults = createDefaults();
|
||||||
defaults.put("control", Color.RED);
|
defaults.put("control", Color.RED);
|
||||||
defaults.put("Button.background", Color.RED);
|
defaults.put("Button.background", Color.RED);
|
||||||
|
@ -51,7 +57,7 @@ public class UIDefaultsMapperTest {
|
||||||
@Test
|
@Test
|
||||||
public void testGetJavaDefaults() {
|
public void testGetJavaDefaults() {
|
||||||
mapper = new UiDefaultsMapper(defaults);
|
mapper = new UiDefaultsMapper(defaults);
|
||||||
GThemeValueMap javaDefaults = mapper.getJavaDefaults();
|
GThemeValueMap javaDefaults = mapper.getNormalizedJavaDefaults();
|
||||||
|
|
||||||
assertEquals(Color.RED, javaDefaults.getResolvedColor("system.color.bg.control"));
|
assertEquals(Color.RED, javaDefaults.getResolvedColor("system.color.bg.control"));
|
||||||
assertEquals(Color.RED, javaDefaults.getResolvedColor("laf.color.Button.background"));
|
assertEquals(Color.RED, javaDefaults.getResolvedColor("laf.color.Button.background"));
|
||||||
|
@ -71,7 +77,7 @@ public class UIDefaultsMapperTest {
|
||||||
defaults.put("RadioButton.background", Color.BLUE); // Blue not defined in a color group
|
defaults.put("RadioButton.background", Color.BLUE); // Blue not defined in a color group
|
||||||
mapper = new UiDefaultsMapper(defaults);
|
mapper = new UiDefaultsMapper(defaults);
|
||||||
|
|
||||||
GThemeValueMap javaDefaults = mapper.getJavaDefaults();
|
GThemeValueMap javaDefaults = mapper.getNormalizedJavaDefaults();
|
||||||
|
|
||||||
// expecting two palette groups to be created
|
// expecting two palette groups to be created
|
||||||
String greenPalette = findPaletteColor(javaDefaults, Color.GREEN);
|
String greenPalette = findPaletteColor(javaDefaults, Color.GREEN);
|
||||||
|
@ -90,7 +96,7 @@ public class UIDefaultsMapperTest {
|
||||||
defaults.put("ToggleButton.font", SMALL_FONT); // Green not defined in a color group
|
defaults.put("ToggleButton.font", SMALL_FONT); // Green not defined in a color group
|
||||||
mapper = new UiDefaultsMapper(defaults);
|
mapper = new UiDefaultsMapper(defaults);
|
||||||
|
|
||||||
GThemeValueMap javaDefaults = mapper.getJavaDefaults();
|
GThemeValueMap javaDefaults = mapper.getNormalizedJavaDefaults();
|
||||||
|
|
||||||
assertDirectFont(javaDefaults, "laf.palette.font.01", SMALL_FONT);
|
assertDirectFont(javaDefaults, "laf.palette.font.01", SMALL_FONT);
|
||||||
assertIndirectFont(javaDefaults, "laf.font.ToggleButton.font", "laf.palette.font.01");
|
assertIndirectFont(javaDefaults, "laf.font.ToggleButton.font", "laf.palette.font.01");
|
||||||
|
|
|
@ -210,7 +210,7 @@
|
||||||
<target name="___chkstk_ms"/>
|
<target name="___chkstk_ms"/>
|
||||||
<pcode>
|
<pcode>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
RSP = RSP + 0;
|
RSP = RSP + 8;
|
||||||
]]></body>
|
]]></body>
|
||||||
</pcode>
|
</pcode>
|
||||||
</callfixup>
|
</callfixup>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue