mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Refresh detached Channel-tab swing components on theme toggle
The Channel tab swaps one of three right-pane components into its JSplitPane depending on the active decoder type: SignalPowerView for AM, the NoiseSquelchPanel JFXPanel for NBFM, the SymbolPanel JFXPanel for feedback decoders. Only one is attached at any moment - the other two are detached references on the ChannelSpectrumPanel. SwingUtilities.updateComponentTreeUI(Window) during a theme toggle walks only the currently-realized component trees, so the detached swappables miss the refresh and carry stale colours from the LAF that was active when they were last attached. Swapping back in then shows e.g. an AM SignalPowerView in dark colours after a light-mode toggle. Add ThemeManager.registerSwing(Component) tracking, walk those refs on every toggle, and register the three swappables when constructed.
This commit is contained in:
@@ -102,6 +102,11 @@ public class ChannelSpectrumPanel extends JPanel implements Listener<ProcessingC
|
||||
mPlaylistManager = playlistManager;
|
||||
mNoiseSquelchView = new NoiseSquelchView(mPlaylistManager);
|
||||
mSignalPowerView = new SignalPowerView(mPlaylistManager);
|
||||
|
||||
//Register the three swappable right-pane components with the theme manager. Only one is
|
||||
//attached to the split pane at a time, so the LAF-toggle walk of Window.getWindows() can
|
||||
//miss the detached ones - they get refreshed explicitly via registerSwing.
|
||||
ThemeManager.getInstance().registerSwing(mSignalPowerView);
|
||||
setLayout(new MigLayout("insets 0", "[grow,fill]", "[grow,fill]"));
|
||||
|
||||
JPanel fftPanel = new JPanel();
|
||||
@@ -197,6 +202,8 @@ public class ChannelSpectrumPanel extends JPanel implements Listener<ProcessingC
|
||||
|
||||
mNoiseSquelchPanel = new JFXPanel();
|
||||
mSymbolPanel = new JFXPanel();
|
||||
ThemeManager.getInstance().registerSwing(mNoiseSquelchPanel);
|
||||
ThemeManager.getInstance().registerSwing(mSymbolPanel);
|
||||
|
||||
//Spin noise squelch panel construction off onto the JavafX UI thread.
|
||||
Platform.runLater(() -> {
|
||||
|
||||
@@ -61,6 +61,7 @@ public class ThemeManager
|
||||
private static final ThemeManager INSTANCE = new ThemeManager();
|
||||
|
||||
private final Set<WeakReference<Scene>> mScenes = new LinkedHashSet<>();
|
||||
private final Set<WeakReference<java.awt.Component>> mSwingRoots = new LinkedHashSet<>();
|
||||
private final String mDarkStylesheetUrl;
|
||||
private volatile UserPreferences mUserPreferences;
|
||||
private volatile boolean mDarkMode;
|
||||
@@ -140,6 +141,36 @@ public class ThemeManager
|
||||
applyToScene(scene, mDarkMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a Swing component that may be temporarily detached from any Window's component tree
|
||||
* (e.g. swappable right-pane components in the Channel tab). Plain
|
||||
* {@link SwingUtilities#updateComponentTreeUI(java.awt.Component)} walks of
|
||||
* {@link Window#getWindows()} miss such components and they end up carrying stale colours from
|
||||
* the LAF that was active when they were last attached. Registered components get
|
||||
* {@code updateComponentTreeUI} called on them whenever the theme is applied.
|
||||
*/
|
||||
public void registerSwing(java.awt.Component component)
|
||||
{
|
||||
if(component == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized(mSwingRoots)
|
||||
{
|
||||
Iterator<WeakReference<java.awt.Component>> it = mSwingRoots.iterator();
|
||||
while(it.hasNext())
|
||||
{
|
||||
java.awt.Component existing = it.next().get();
|
||||
if(existing == null || existing == component)
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
mSwingRoots.add(new WeakReference<>(component));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives notification when any preference changes. Re-reads the dark-mode setting and
|
||||
* propagates if it differs from the last known value.
|
||||
@@ -309,12 +340,31 @@ public class ThemeManager
|
||||
//near-white rather than FlatLaf's #bbbbbb so text reads sharply on the dark panels.
|
||||
applyExplicitOverrides(darkMode);
|
||||
|
||||
//Re-rendering any already-realized Swing windows must happen on the EDT.
|
||||
//Re-rendering any already-realized Swing windows must happen on the EDT. Also walk any
|
||||
//Swing components explicitly registered via registerSwing(...) - they may be detached
|
||||
//from any Window's tree at toggle time (e.g. swappable channel-tab right components).
|
||||
Runnable updateRealized = () -> {
|
||||
for(Window window: Window.getWindows())
|
||||
{
|
||||
SwingUtilities.updateComponentTreeUI(window);
|
||||
}
|
||||
|
||||
synchronized(mSwingRoots)
|
||||
{
|
||||
Iterator<WeakReference<java.awt.Component>> it = mSwingRoots.iterator();
|
||||
while(it.hasNext())
|
||||
{
|
||||
java.awt.Component c = it.next().get();
|
||||
if(c == null)
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
SwingUtilities.updateComponentTreeUI(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(EventQueue.isDispatchThread())
|
||||
|
||||
Reference in New Issue
Block a user