diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java index 20bfef2bc5..6604b66ddd 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java @@ -22,8 +22,7 @@ import java.util.*; import javax.swing.*; import docking.action.*; -import generic.theme.Gui; -import generic.theme.ThemeManager; +import generic.theme.*; import ghidra.util.*; import ghidra.util.exception.AssertException; import help.HelpDescriptor; @@ -117,6 +116,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext private String registeredFontId; + private ThemeListener themeListener = this::themeChanged; + /** * Creates a new component provider with a default location of {@link WindowPosition#WINDOW}. * @param tool The tool will manage and show this provider @@ -145,6 +146,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext this.contextType = contextType; recordInception(); + + Gui.addThemeListener(themeListener); } /** @@ -171,6 +174,24 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext showProviderAction = new ShowProviderAction(supportsKeyBindings); } + private void themeChanged(ThemeEvent e) { + if (!e.isLookAndFeelChanged()) { + return; // we only care if the Look and Feel changes + } + + if (isVisible()) { + // if we are visible, then we don't need to update as the system updates all + // visible components + return; + } + + // update this providers components ui for the new Look and Feel + JComponent component = getComponent(); + if (component != null) { + SwingUtilities.updateComponentTreeUI(component); + } + } + /** * Returns the component to be displayed * @return the component to be displayed diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java index 8d47d68f05..38fe4f4b06 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java @@ -32,7 +32,7 @@ import docking.event.mouse.GMouseListenerAdapter; import docking.menu.DialogToolbarButton; import docking.util.AnimationUtils; import docking.widgets.label.GDHtmlLabel; -import generic.theme.GColor; +import generic.theme.*; import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.*; import ghidra.util.exception.AssertException; @@ -103,6 +103,7 @@ public class DialogComponentProvider private boolean isTransient = false; private Dimension defaultSize; + private ThemeListener themeListener = this::themeChanged; /** * Constructor for a DialogComponentProvider that will be modal and will include a status line and @@ -177,6 +178,8 @@ public class DialogComponentProvider installEscapeAction(); doInitialize(); + + Gui.addThemeListener(themeListener); } private void installEscapeAction() { @@ -341,6 +344,20 @@ public class DialogComponentProvider } } + private void themeChanged(ThemeEvent ev) { + if (!ev.isLookAndFeelChanged()) { + 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()) { + return; + } + Component component = dialog != null ? dialog : rootPanel; + SwingUtilities.updateComponentTreeUI(component); + } + private void uninstallMouseListener(Component comp) { if (comp instanceof CellRendererPane) { return; @@ -888,6 +905,7 @@ public class DialogComponentProvider } public void dispose() { + Gui.removeThemeListener(themeListener); cancelCurrentTask(); close(); popupManager.dispose(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java index 904735753a..d842a3b25a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java @@ -495,6 +495,13 @@ public class GTable extends JTable { return; // must be initializing } + // don't try to update if we are not in window hierarchy + // as this will cause look and feel issues + Window window = SwingUtilities.windowForComponent(this); + if (window == null) { + return; + } + int linesPerRow = getLinesPerRow(); int preferredHeight = calculatePreferredRowHeight(); int newHeight = linesPerRow * preferredHeight; @@ -694,7 +701,7 @@ public class GTable extends JTable { addColumn(newColumn); } - for (int i = 0; i < columnCount; i++ ) { + for (int i = 0; i < columnCount; i++) { TableCellRenderer headerRenderer = getHeaderRendererOverride(i); if (headerRenderer != null) { tableColumnModel.getColumn(i).setHeaderRenderer(headerRenderer); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java index 19f3339b70..a6a2568fd5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java @@ -28,8 +28,7 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableModel; import docking.widgets.AbstractGCellRenderer; -import generic.theme.GColor; -import generic.theme.Gui; +import generic.theme.*; import ghidra.docking.settings.*; import ghidra.util.*; import ghidra.util.exception.AssertException; @@ -53,6 +52,11 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe private static DecimalFormat decimalFormat; private static Map decimalFormatCache; + private ThemeListener themeListener = e -> { + if (e.isLookAndFeelChanged()) { + updateUI(); + } + }; /** * Constructs a new GTableCellRenderer. @@ -60,11 +64,7 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe public GTableCellRenderer() { // When the Look And Feel changes, renderers are not auto updated because they // are not part of the component tree. So listen for a change to the Look And Feel. - Gui.addThemeListener(e -> { - if (e.isLookAndFeelChanged()) { - updateUI(); - } - }); + Gui.addThemeListener(themeListener); } /** diff --git a/Ghidra/Framework/Gui/src/main/java/generic/theme/ApplicationThemeManager.java b/Ghidra/Framework/Gui/src/main/java/generic/theme/ApplicationThemeManager.java index 8501d5fb20..fe0ef5313b 100644 --- a/Ghidra/Framework/Gui/src/main/java/generic/theme/ApplicationThemeManager.java +++ b/Ghidra/Framework/Gui/src/main/java/generic/theme/ApplicationThemeManager.java @@ -130,12 +130,12 @@ public class ApplicationThemeManager extends ThemeManager { lookAndFeelManager = lafType.getLookAndFeelManager(this); try { lookAndFeelManager.installLookAndFeel(); - themePreferences.save(theme); notifyThemeChanged(new AllValuesChangedThemeEvent(true)); } catch (Exception e) { Msg.error(this, "Error setting LookAndFeel: " + lafType.getName(), e); } + themePreferences.save(theme); } currentValues.checkForUnresolvedReferences(); } @@ -192,12 +192,12 @@ public class ApplicationThemeManager extends ThemeManager { updateChangedValuesMap(currentValue, newValue); currentValues.addFont(newValue); - notifyThemeChanged(new FontChangedThemeEvent(currentValues, newValue)); // update all java LookAndFeel fonts affected by this changed String id = newValue.getId(); Set changedFontIds = findChangedJavaFontIds(id); lookAndFeelManager.fontsChanged(changedFontIds); + notifyThemeChanged(new FontChangedThemeEvent(currentValues, newValue)); } @Override @@ -208,12 +208,8 @@ public class ApplicationThemeManager extends ThemeManager { } updateChangedValuesMap(currentValue, newValue); currentValues.addColor(newValue); + lookAndFeelManager.colorsChanged(); notifyThemeChanged(new ColorChangedThemeEvent(currentValues, newValue)); - - // now update the ui - if (lookAndFeelManager != null) { - lookAndFeelManager.colorsChanged(); - } } @Override @@ -225,7 +221,6 @@ public class ApplicationThemeManager extends ThemeManager { updateChangedValuesMap(currentValue, newValue); currentValues.addIcon(newValue); - notifyThemeChanged(new IconChangedThemeEvent(currentValues, newValue)); // now update the ui // update all java LookAndFeel icons affected by this changed @@ -233,6 +228,7 @@ public class ApplicationThemeManager extends ThemeManager { Set changedIconIds = findChangedJavaIconIds(id); Icon newIcon = newValue.get(currentValues); lookAndFeelManager.iconsChanged(changedIconIds, newIcon); + notifyThemeChanged(new IconChangedThemeEvent(currentValues, newValue)); } /** diff --git a/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemeManager.java b/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemeManager.java index fc1c46ef2b..7da3583276 100644 --- a/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemeManager.java +++ b/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemeManager.java @@ -30,6 +30,7 @@ import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; import resources.ResourceManager; import utilities.util.reflection.ReflectionUtilities; +import utility.function.Callback; /** * This class manages application themes and their values. The ThemeManager is an abstract