Skip to content

Commit a19675b

Browse files
committed
Add darklaf look and feel
It is an evolution of Darcula look and feel which theming support.
1 parent f197ee4 commit a19675b

14 files changed

Lines changed: 244 additions & 76 deletions

File tree

build.gradle.kts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -449,18 +449,6 @@ allprojects {
449449

450450
repositories {
451451
jcenter()
452-
ivy {
453-
url = uri("https://github.com/bulenkov/Darcula/raw/")
454-
content {
455-
includeModule("com.github.bulenkov.darcula", "darcula")
456-
}
457-
patternLayout {
458-
artifact("[revision]/build/[module].[ext]")
459-
}
460-
metadataSources {
461-
artifact() // == don't try downloading .pom file from the repository
462-
}
463-
}
464452
}
465453

466454
tasks {

checksum.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
<trusted-key id='c9fbaa83a8753994' group='com.fasterxml.jackson.core' />
99
<trusted-key id='4c00043bec5cb7cb' group='com.fifesoft' />
1010
<trusted-key id='af10873874630863' group='com.flipkart.zjsonpatch' />
11+
<trusted-key id='379ce192d401ab61' group='com.formdev' />
1112
<trusted-key id='105cb91cac2aee0e' group='com.github.autostyle' />
1213
<trusted-key id='3c0a8f4744f37328' group='com.github.ben-manes.caffeine' />
1314
<trusted-key id='8ea48d105232855d' group='com.github.jknack' />
1415
<trusted-key id='461a804f2609fd89' group='com.github.shyiko.klob' />
1516
<trusted-key id='1756b920eecf0e90' group='com.github.spotbugs' />
1617
<trusted-key id='78fcd238c26ea995' group='com.github.tomakehurst' />
1718
<trusted-key id='105cb91cac2aee0e' group='com.github.vlsi.gradle' />
19+
<trusted-key id='254e9c64c264c176' group='com.github.weisj' />
1820
<trusted-key id='59a252fb1199d873' group='com.google.code.findbugs' />
1921
<trusted-key id='7a01b0f236e5430f' group='com.google.code.gson' />
2022
<trusted-key id='912d2c0eccda55c0' group='com.google.errorprone' />
@@ -29,6 +31,7 @@
2931
<trusted-key id='e57428da9e879e7d' group='com.helger' />
3032
<trusted-key id='3684155e9365c30e' group='com.jayway.jsonpath' />
3133
<trusted-key id='a50569c7ca7fa1f0' group='com.jcraft' />
34+
<trusted-key id='0a36eef644cff773' group='com.metsci.ext.com.kitfox.svg' />
3235
<trusted-key id='db45d3a62a183ce2' group='com.miglayout' />
3336
<trusted-key id='aa49c633b4734832' group='com.pinterest' />
3437
<trusted-key id='aa49c633b4734832' group='com.pinterest.ktlint' />
@@ -59,6 +62,8 @@
5962
<trusted-key id='528dc75aa68f0923' group='jcharts' />
6063
<trusted-key id='85911f425ec61b51' group='junit' />
6164
<trusted-key id='efe8086f9e93774e' group='junit' />
65+
<trusted-key id='15c71c0a4e0b8edd' group='net.java.dev.jna' />
66+
<trusted-key id='75bf031b7c94e183' group='net.java.dev.jna' />
6267
<trusted-key id='f6bc09712c8df6ec' group='net.minidev' />
6368
<trusted-key id='0da8a5ec02d11ead' group='net.sf.jopt-simple' />
6469
<trusted-key id='d4012dda1f1f0f82' group='net.sf.jtidy' />
@@ -135,6 +140,7 @@
135140
<trusted-key id='cfca4a29d26468de' group='org.sonarsource.scanner.gradle' />
136141
<trusted-key id='72fefd1572eb75e1' group='org.spockframework' />
137142
<trusted-key id='9a2c7a98e457c53d' group='org.springframework' />
143+
<trusted-key id='e4b53844e02b191b' group='org.swinglabs' />
138144
<trusted-key id='a2115ae15f6b8b72' group='org.xmlunit' />
139145
<trusted-key id='9ff25980f5ba7e4f' group='xalan' />
140146
<trusted-key id='858fc4c4f43856a3' group='xerces' />

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ commons-math3.version=3.6.1
6666
commons-net.version=3.6
6767
commons-pool2.version=2.8.0
6868
commons-text.version=1.8
69-
darcula.version=e208efb96f70e4be9dc362fbb46f6e181ef501dd
69+
darklaf-core.version=1.4.1.0
7070
dec.version=0.1.2
7171
dnsjava.version=2.1.9
7272
equalsverifier.version=3.1.12

settings.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,10 @@ apply(plugin = "com.github.vlsi.checksum-dependency")
145145
// This enables to try local Autostyle
146146
property("localAutostyle")?.ifBlank { "../autostyle" }?.let {
147147
println("Importing project '$it'")
148-
includeBuild("../autostyle")
148+
includeBuild(it)
149+
}
150+
151+
property("localDarklaf")?.ifBlank { "../darklaf" }?.let {
152+
println("Importing project '$it'")
153+
includeBuild(it)
149154
}

src/bom/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ dependencies {
4848
// dependency on it during compilation
4949
runtimev("org.apache.tika:tika-parsers", "tika")
5050
runtimev("org.ow2.asm:asm")
51-
runtimev("com.github.bulenkov.darcula:darcula")
51+
apiv("com.github.weisj:darklaf-core")
5252

5353
// activemq-all should not be used as it provides secondary slf4j binding
5454
runtimev("org.apache.activemq:activemq-broker", "activemq")

src/core/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ dependencies {
2424
api(project(":src:jorphan"))
2525
testCompile(project(":src:jorphan", "testClasses"))
2626

27+
implementation("com.github.weisj:darklaf-core")
2728
api("bsf:bsf") {
2829
because("protected BSFManager BSFTestElement#getManager()")
2930
}

src/core/src/main/java/org/apache/jmeter/JMeter.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
import javax.script.ScriptEngineManager;
5454
import javax.script.ScriptException;
5555
import javax.swing.JTree;
56-
import javax.swing.UIManager;
5756
import javax.swing.tree.TreePath;
5857

5958
import org.apache.commons.cli.avalon.CLArgsParser;
@@ -372,16 +371,16 @@ private void startGui(String testFile) {
372371
System.out.println("Check : https://jmeter.apache.org/usermanual/best-practices.html");//NOSONAR
373372
System.out.println("================================================================================");//NOSONAR
374373

375-
SplashScreen splash = new SplashScreen();
376-
splash.showScreen();
377-
String jMeterLaf = LookAndFeelCommand.getJMeterLaf();
374+
String jMeterLaf = LookAndFeelCommand.getPreferredLafCommand();
378375
try {
379376
log.info("Setting LAF to: {}", jMeterLaf);
380-
UIManager.setLookAndFeel(jMeterLaf);
381-
UIManager.put("Button.defaultButtonFollowsFocus", false);
382-
} catch (Exception ex) {
377+
LookAndFeelCommand.activateLookAndFeel(jMeterLaf);
378+
} catch (IllegalArgumentException ex) {
383379
log.warn("Could not set LAF to: {}", jMeterLaf, ex);
384380
}
381+
// SplashWindow is created after LaF activation. Otherwise it would cause splash flicker
382+
SplashScreen splash = new SplashScreen();
383+
splash.showScreen();
385384
splash.setProgress(10);
386385
JMeterUtils.applyHiDPIOnFonts();
387386
PluginManager.install(this, true);

src/core/src/main/java/org/apache/jmeter/gui/action/LookAndFeelCommand.java

Lines changed: 127 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@
1818
package org.apache.jmeter.gui.action;
1919

2020
import 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;
2227
import java.util.List;
2328
import java.util.Locale;
29+
import java.util.Map;
2430
import java.util.Set;
2531
import java.util.prefs.Preferences;
26-
import java.util.stream.Collectors;
2732

2833
import javax.swing.JOptionPane;
2934
import javax.swing.UIManager;
@@ -35,6 +40,13 @@
3540
import org.slf4j.Logger;
3641
import 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

Comments
 (0)