1818package org .apache .jmeter .gui .action ;
1919
2020import java .awt .event .ActionEvent ;
21- import java .util .Arrays ;
21+ import java .lang .reflect .InvocationTargetException ;
22+ import java .util .ArrayList ;
23+ import java .util .Collection ;
24+ import java .util .Collections ;
25+ import java .util .Comparator ;
26+ import java .util .LinkedHashMap ;
2227import java .util .List ;
2328import java .util .Locale ;
29+ import java .util .Map ;
2430import java .util .Set ;
2531import java .util .prefs .Preferences ;
26- import java .util .stream .Collectors ;
2732
2833import javax .swing .JOptionPane ;
2934import javax .swing .UIManager ;
3540import org .slf4j .Logger ;
3641import org .slf4j .LoggerFactory ;
3742
43+ import com .github .weisj .darklaf .LafManager ;
44+ import com .github .weisj .darklaf .theme .DarculaTheme ;
45+ import com .github .weisj .darklaf .theme .IntelliJTheme ;
46+ import com .github .weisj .darklaf .theme .SolarizedDarkTheme ;
47+ import com .github .weisj .darklaf .theme .SolarizedLightTheme ;
48+ import com .github .weisj .darklaf .theme .Theme ;
49+
3850/**
3951 * Implements the Look and Feel menu item.
4052 */
@@ -44,31 +56,72 @@ public class LookAndFeelCommand extends AbstractAction {
4456
4557 private static final String JMETER_LAF = "jmeter.laf" ; // $NON-NLS-1$
4658
47- private static final Set <String > commands ;
59+ private static final Map <String , MenuItem > items = new LinkedHashMap <>() ;
4860
4961 private static final Preferences PREFS = Preferences .userNodeForPackage (LookAndFeelCommand .class );
5062 // Note: Windows user preferences are stored relative to: HKEY_CURRENT_USER\Software\JavaSoft\Prefs
5163
5264 /** Prefix for the user preference key */
53- private static final String USER_PREFS_KEY = "laf.class" ; //$NON-NLS-1$
65+ private static final String USER_PREFS_KEY = "laf.command" ; //$NON-NLS-1$
66+
67+ public static class MenuItem {
68+ final String title ;
69+ final String command ;
70+ final String lafClassName ;
71+ final Class <? extends Theme > lafTheme ;
72+
73+ private MenuItem (String title , String command , String lafClassName , Class <? extends Theme > lafTheme ) {
74+ this .title = title ;
75+ this .command = command ;
76+ this .lafClassName = lafClassName ;
77+ this .lafTheme = lafTheme ;
78+ }
79+
80+ public String getTitle () {
81+ return title ;
82+ }
83+
84+ public String getCommand () {
85+ return command ;
86+ }
87+
88+ private static MenuItem of (String title , String lafClass ) {
89+ return new MenuItem (title ,ActionNames .LAF_PREFIX + lafClass , lafClass , null );
90+ }
91+
92+ private static MenuItem ofDarklafTheme (Class <? extends Theme > lafTheme ) {
93+ return new MenuItem ("Darklaf - " + lafTheme .getSimpleName ().replace ("Theme" , "" ),
94+ JMeterMenuBar .DARKLAF_LAF_CLASS + ":" + lafTheme .getName (),
95+ JMeterMenuBar .DARKLAF_LAF_CLASS ,
96+ lafTheme );
97+ }
98+ }
5499
55100 static {
56- log .info ("Installing Darcula LAF" );
57- UIManager .installLookAndFeel (JMeterMenuBar .DARCULA_LAF , JMeterMenuBar .DARCULA_LAF_CLASS );
58- UIManager .LookAndFeelInfo [] allLAFs = JMeterMenuBar .getAllLAFs ();
59- commands = Arrays .stream (allLAFs )
60- .map (lf -> ActionNames .LAF_PREFIX + lf .getClassName ())
61- .collect (Collectors .toSet ());
62- if (log .isInfoEnabled ()) {
63- final String jMeterLaf = getJMeterLaf ();
64- List <String > names = Arrays .stream (allLAFs )
65- .filter (laf -> laf .getClassName ().equals (JMeterMenuBar .DARCULA_LAF_CLASS ))
66- .map (UIManager .LookAndFeelInfo ::getName )
67- .collect (Collectors .toList ());
68- log .info ("Using look and feel: {} {}" , jMeterLaf , names );
101+ System .setProperty ("darklaf.decorations" , "false" );
102+ UIManager .installLookAndFeel (JMeterMenuBar .DARKLAF_LAF , JMeterMenuBar .DARKLAF_LAF_CLASS );
103+
104+ List <MenuItem > items = new ArrayList <>();
105+ for (UIManager .LookAndFeelInfo laf : JMeterMenuBar .getAllLAFs ()) {
106+ if (!laf .getClassName ().equals (JMeterMenuBar .DARKLAF_LAF_CLASS )) {
107+ items .add (MenuItem .of (laf .getName (), laf .getClassName ()));
108+ continue ;
109+ }
110+ items .add (MenuItem .ofDarklafTheme (DarculaTheme .class ));
111+ items .add (MenuItem .ofDarklafTheme (IntelliJTheme .class ));
112+ items .add (MenuItem .ofDarklafTheme (SolarizedDarkTheme .class ));
113+ items .add (MenuItem .ofDarklafTheme (SolarizedLightTheme .class ));
114+ }
115+ items .sort (Comparator .comparing (MenuItem ::getTitle ));
116+ for (MenuItem item : items ) {
117+ LookAndFeelCommand .items .put (item .command , item );
69118 }
70119 }
71120
121+ public static Collection <MenuItem > getMenuItems () {
122+ return Collections .unmodifiableCollection (items .values ());
123+ }
124+
72125 /**
73126 * Get LookAndFeel classname from the following properties:
74127 * <ul>
@@ -79,7 +132,10 @@ public class LookAndFeelCommand extends AbstractAction {
79132 * <li>UIManager.getCrossPlatformLookAndFeelClassName()</li>
80133 * </ul>
81134 * @return LAF classname
135+ * @deprecated see #getPreferredLafCommand
136+ * @see #getPreferredLafCommand
82137 */
138+ @ Deprecated
83139 public static String getJMeterLaf (){
84140 String laf = PREFS .get (USER_PREFS_KEY , null );
85141 if (laf != null ) {
@@ -105,6 +161,25 @@ public static String getJMeterLaf(){
105161 return UIManager .getCrossPlatformLookAndFeelClassName ();
106162 }
107163
164+ /**
165+ * Returns a command that would activate the preferred LaF.
166+ * @return command that would activate the preferred LaF
167+ */
168+ public static String getPreferredLafCommand () {
169+ String laf = PREFS .get (USER_PREFS_KEY , null );
170+ if (laf != null ) {
171+ return laf ;
172+ }
173+
174+ String jMeterLaf = getJMeterLaf ();
175+ if (jMeterLaf .equals (JMeterMenuBar .DARCULA_LAF_CLASS )) {
176+ // Convert old Darcula to new Darklaf-Darcula LaF
177+ return MenuItem .ofDarklafTheme (DarculaTheme .class ).command ;
178+ }
179+
180+ return MenuItem .of ("default" , jMeterLaf ).command ; // $NON-NLS-1$
181+ }
182+
108183 // Check if LAF is a built-in one
109184 private static String checkLafName (String laf ){
110185 if (JMeterMenuBar .SYSTEM_LAF .equalsIgnoreCase (laf )){
@@ -120,31 +195,56 @@ public LookAndFeelCommand() {
120195 // NOOP
121196 }
122197
198+ public static boolean isDark (String command ) {
199+ MenuItem item = items .get (command );
200+ if (item == null ) {
201+ return false ;
202+ }
203+ return item .lafTheme == DarculaTheme .class || item .lafTheme == SolarizedDarkTheme .class ;
204+ }
205+
206+ public static void activateLookAndFeel (String command ) {
207+ MenuItem item = items .get (command );
208+ String className = item .lafClassName ;
209+ try {
210+ if (item .lafTheme != null ) {
211+ LafManager .installTheme (item .lafTheme .getConstructor ().newInstance ());
212+ } else {
213+ UIManager .setLookAndFeel (className );
214+ UIManager .put ("Button.defaultButtonFollowsFocus" , false );
215+ }
216+ PREFS .put (USER_PREFS_KEY , item .command );
217+ } catch (UnsupportedLookAndFeelException
218+ | InstantiationException
219+ | ClassNotFoundException
220+ | NoSuchMethodException
221+ | IllegalAccessException e ) {
222+ throw new IllegalArgumentException ("Look and Feel unavailable:" + e .toString (), e );
223+ } catch (InvocationTargetException e ) {
224+ Throwable c = e .getCause ();
225+ throw new IllegalArgumentException ("Look and Feel unavailable:" + c .toString (), c );
226+ }
227+ }
228+
123229 @ Override
124230 public void doAction (ActionEvent ev ) {
125231 try {
126- String className = ev .getActionCommand ().substring (ActionNames .LAF_PREFIX .length ()).replace ('/' , '.' );
127- UIManager .setLookAndFeel (className );
128- UIManager .put ("Button.defaultButtonFollowsFocus" , false );
232+ activateLookAndFeel (ev .getActionCommand ());
129233 JMeterUtils .refreshUI ();
130- PREFS .put (USER_PREFS_KEY , className );
131234 int chosenOption = JOptionPane .showConfirmDialog (GuiPackage .getInstance ().getMainFrame (), JMeterUtils
132235 .getResString ("laf_quit_after_change" ), // $NON-NLS-1$
133236 JMeterUtils .getResString ("exit" ), // $NON-NLS-1$
134237 JOptionPane .YES_NO_OPTION , JOptionPane .QUESTION_MESSAGE );
135238 if (chosenOption == JOptionPane .YES_OPTION ) {
136239 ActionRouter .getInstance ().doActionNow (new ActionEvent (ev .getSource (), ev .getID (), ActionNames .RESTART ));
137240 }
138- } catch (UnsupportedLookAndFeelException
139- | InstantiationException
140- | ClassNotFoundException
141- | IllegalAccessException e ) {
142- JMeterUtils .reportErrorToUser ("Look and Feel unavailable:" + e .toString ());
241+ } catch (IllegalArgumentException e ) {
242+ JMeterUtils .reportErrorToUser (e .getMessage (), e );
143243 }
144244 }
145245
146246 @ Override
147247 public Set <String > getActionNames () {
148- return commands ;
248+ return Collections . unmodifiableSet ( items . keySet ()) ;
149249 }
150250}
0 commit comments