Skip to content

Commit 91fb7c5

Browse files
committed
OptionsLookAndFeel: improve L&F refresh logic
Now it looks for all Swing components affiliated with all visible UIs. Then it refreshes them all using SwingUtilities.updateComponentTreeUI (the same way it did before). But non-Component objects of active UIs are now ignored, rather than doing unsafe casts. As a consequence, L&F refresh should be more robust and more thorough.
1 parent 0047d46 commit 91fb7c5

File tree

1 file changed

+52
-7
lines changed

1 file changed

+52
-7
lines changed

src/main/java/org/scijava/ui/swing/options/OptionsLookAndFeel.java

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,20 @@
3030

3131
package org.scijava.ui.swing.options;
3232

33+
import java.awt.Component;
3334
import java.awt.EventQueue;
35+
import java.awt.Window;
3436
import java.util.ArrayList;
37+
import java.util.HashSet;
38+
import java.util.Set;
3539

3640
import javax.swing.SwingUtilities;
3741
import javax.swing.UIManager;
3842
import javax.swing.UIManager.LookAndFeelInfo;
3943
import javax.swing.UnsupportedLookAndFeelException;
4044

45+
import org.scijava.display.Display;
46+
import org.scijava.display.DisplayService;
4147
import org.scijava.log.LogService;
4248
import org.scijava.menu.MenuConstants;
4349
import org.scijava.module.MutableModuleItem;
@@ -47,7 +53,8 @@
4753
import org.scijava.plugin.Plugin;
4854
import org.scijava.ui.UIService;
4955
import org.scijava.ui.UserInterface;
50-
import org.scijava.ui.swing.SwingApplicationFrame;
56+
import org.scijava.ui.viewer.DisplayViewer;
57+
import org.scijava.widget.UIComponent;
5158

5259
/**
5360
* Runs the Edit::Options::Look and Feel dialog.
@@ -70,6 +77,9 @@ public class OptionsLookAndFeel extends OptionsPlugin {
7077
@Parameter
7178
private UIService uiService;
7279

80+
@Parameter
81+
private DisplayService displayService;
82+
7383
@Parameter
7484
private LogService log;
7585

@@ -148,12 +158,47 @@ protected void initLookAndFeel() {
148158

149159
/** Tells all known Swing components to change to the new Look & Feel. */
150160
private void refreshSwingComponents() {
151-
// FIXME: Get all windows from UIService rather than just app.
152-
final UserInterface ui = uiService.getDefaultUI();
153-
final SwingApplicationFrame swingAppFrame =
154-
(SwingApplicationFrame) ui.getApplicationFrame();
155-
SwingUtilities.updateComponentTreeUI(swingAppFrame);
156-
swingAppFrame.pack();
161+
// TODO: Change this hacky logic to call a clean UIService API
162+
// for window retrieval. But does not exist as of this writing.
163+
164+
final Set<Component> components = new HashSet<>();
165+
166+
// add Swing UI components from visible UIs
167+
for (final UserInterface ui : uiService.getVisibleUIs()) {
168+
findComponents(components, ui.getApplicationFrame());
169+
findComponents(components, ui.getConsolePane());
170+
}
171+
172+
// add Swing UI components from visible displays
173+
for (final Display<?> d : displayService.getDisplays()) {
174+
final DisplayViewer<?> viewer = uiService.getDisplayViewer(d);
175+
if (viewer == null) continue;
176+
findComponents(components, viewer.getWindow());
177+
}
178+
179+
// refresh all discovered components
180+
for (final Component c : components) {
181+
SwingUtilities.updateComponentTreeUI(c);
182+
if (c instanceof Window) ((Window) c).pack();
183+
}
184+
}
185+
186+
/**
187+
* Extracts Swing components from the given object, adding them to
188+
* the specified set.
189+
*/
190+
private void findComponents(final Set<Component> set, final Object o) {
191+
if (o == null) return;
192+
if (o instanceof UIComponent) {
193+
final UIComponent<?> c = (UIComponent<?>) o;
194+
findComponents(set, c.getComponent());
195+
}
196+
if (o instanceof Window) set.add((Window) o);
197+
else if (o instanceof Component) {
198+
final Component c = (Component) o;
199+
final Window w = SwingUtilities.getWindowAncestor(c);
200+
set.add(w == null ? c : w);
201+
}
157202
}
158203

159204
// -- Deprecated methods --

0 commit comments

Comments
 (0)