1
0
mirror of https://github.com/SKCraft/Launcher.git synced 2024-11-27 12:46:22 +01:00

Update launcher settings dialog with new runtime selection dropdown

This commit is contained in:
Henry Le Grys 2021-06-19 23:04:56 +01:00
parent 2ff147fc10
commit e12eec29b5
7 changed files with 202 additions and 14 deletions

View File

@ -62,6 +62,8 @@ public class Configuration {
* Backwards compatibility for old configs with jvmPaths
*/
public void setJvmPath(String jvmPath) {
if (jvmPath != null) {
this.javaRuntime = JavaRuntimeFinder.getRuntimeFromPath(jvmPath);
}
}
}

View File

@ -8,6 +8,9 @@ package com.skcraft.launcher.dialog;
import com.skcraft.launcher.Configuration;
import com.skcraft.launcher.Launcher;
import com.skcraft.launcher.dialog.component.BetterComboBox;
import com.skcraft.launcher.launch.JavaRuntime;
import com.skcraft.launcher.launch.JavaRuntimeFinder;
import com.skcraft.launcher.persistence.Persistence;
import com.skcraft.launcher.swing.*;
import com.skcraft.launcher.util.SharedLocale;
@ -29,7 +32,7 @@ public class ConfigurationDialog extends JDialog {
private final JPanel tabContainer = new JPanel(new BorderLayout());
private final JTabbedPane tabbedPane = new JTabbedPane();
private final FormPanel javaSettingsPanel = new FormPanel();
private final JTextField jvmPathText = new JTextField();
private final JComboBox<JavaRuntime> jvmRuntime = new BetterComboBox<>();
private final JTextField jvmArgsText = new JTextField();
private final JSpinner minMemorySpinner = new JSpinner();
private final JSpinner maxMemorySpinner = new JSpinner();
@ -70,7 +73,10 @@ public class ConfigurationDialog extends JDialog {
setResizable(false);
setLocationRelativeTo(owner);
mapper.map(jvmPathText, "jvmPath");
JavaRuntime[] javaRuntimes = JavaRuntimeFinder.getAvailableRuntimes().toArray(new JavaRuntime[0]);
jvmRuntime.setModel(new DefaultComboBoxModel<>(javaRuntimes));
jvmRuntime.setSelectedItem(config.getJavaRuntime());
mapper.map(jvmArgsText, "jvmArgs");
mapper.map(minMemorySpinner, "minMemory");
mapper.map(maxMemorySpinner, "maxMemory");
@ -88,7 +94,7 @@ public class ConfigurationDialog extends JDialog {
}
private void initComponents() {
javaSettingsPanel.addRow(new JLabel(SharedLocale.tr("options.jvmPath")), jvmPathText);
javaSettingsPanel.addRow(new JLabel(SharedLocale.tr("options.jvmPath")), jvmRuntime);
javaSettingsPanel.addRow(new JLabel(SharedLocale.tr("options.jvmArguments")), jvmArgsText);
javaSettingsPanel.addRow(Box.createVerticalStrut(15));
javaSettingsPanel.addRow(new JLabel(SharedLocale.tr("options.64BitJavaWarning")));
@ -157,6 +163,8 @@ public class ConfigurationDialog extends JDialog {
*/
public void save() {
mapper.copyFromSwing();
config.setJavaRuntime((JavaRuntime) jvmRuntime.getSelectedItem());
Persistence.commitAndForget(config);
dispose();
}

View File

@ -0,0 +1,28 @@
package com.skcraft.launcher.dialog.component;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import java.awt.*;
public class BetterComboBox<E> extends JComboBox<E> {
public BetterComboBox() {
setUI(new BetterComboBoxUI());
}
private static class BetterComboBoxUI extends BasicComboBoxUI {
@Override
protected ComboPopup createPopup() {
BasicComboPopup popup = new BasicComboPopup(comboBox) {
@Override
protected Rectangle computePopupBounds(int px, int py, int pw, int ph) {
return super.computePopupBounds(px, py, Math.max(comboBox.getPreferredSize().width, pw), ph);
}
};
popup.getAccessibleContext().setAccessibleParent(comboBox);
return popup;
}
}
}

View File

@ -12,6 +12,10 @@ public class JavaRuntime implements Comparable<JavaRuntime> {
private boolean isMinecraftBundled = false;
public int getMajorVersion() {
if (version == null) {
return 0; //
}
String[] parts = version.split("\\.");
if (parts.length < 2) {
@ -39,6 +43,12 @@ public class JavaRuntime implements Comparable<JavaRuntime> {
return 1;
}
if (version == null) {
return 1;
} else if (o.version == null) {
return -1;
}
String[] a = version.split("[\\._]");
String[] b = o.version.split("[\\._]");
int min = Math.min(a.length, b.length);

View File

@ -48,6 +48,22 @@ public final class JavaRuntimeFinder {
Collections.sort(entries);
} else if (env.getPlatform() == Platform.LINUX) {
launcherDir = new File(System.getenv("HOME"), ".minecraft");
String javaHome = System.getenv("JAVA_HOME");
if (javaHome != null) {
entries.add(getRuntimeFromPath(javaHome));
}
File[] runtimesList = new File("/usr/lib/jvm").listFiles();
if (runtimesList != null) {
Arrays.stream(runtimesList).map(file -> {
try {
return file.getCanonicalFile();
} catch (IOException exception) {
return file;
}
}).distinct().forEach(file -> entries.add(getRuntimeFromPath(file.getAbsolutePath())));
}
} else {
return Collections.emptyList();
}
@ -57,7 +73,12 @@ public final class JavaRuntimeFinder {
}
File runtimes = new File(launcherDir, "runtime");
for (File potential : Objects.requireNonNull(runtimes.listFiles())) {
File[] runtimeList = runtimes.listFiles();
if (runtimeList == null) {
return entries;
}
for (File potential : runtimeList) {
if (potential.getName().startsWith("jre-x")) {
boolean is64Bit = potential.getName().equals("jre-x64");
@ -108,6 +129,12 @@ public final class JavaRuntimeFinder {
public static JavaRuntime getRuntimeFromPath(String path) {
File target = new File(path);
{
File jre = new File(target, "jre/release");
if (jre.isFile()) {
target = jre.getParentFile();
}
}
return new JavaRuntime(target, readVersionFromRelease(target), guessIf64Bit(target));
}
@ -150,7 +177,8 @@ public final class JavaRuntimeFinder {
Map<String, String> releaseDetails = EnvironmentParser.parse(releaseFile);
return releaseDetails.get("JAVA_VERSION");
} catch (IOException ignored) {
} catch (IOException e) {
throw new RuntimeException("Failed to read release file", e);
}
}

View File

@ -1,27 +1,139 @@
package com.skcraft.launcher.util;
import com.google.common.base.Splitter;
import com.google.common.io.CharSource;
import com.google.common.io.Files;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* Parses dotenv-style files.
*/
@RequiredArgsConstructor
public class EnvironmentParser {
private final BufferedReader reader;
private char read() throws IOException {
int c = reader.read();
if (c == -1) {
throw new EOFException("End of stream reached unexpectedly!");
}
return (char) c;
}
public Map<String, String> parse() throws IOException {
HashMap<String, String> result = new HashMap<>();
while (reader.ready()) {
KeyValue entry = parseLine();
result.put(entry.getKey(), entry.getValue());
}
return result;
}
public KeyValue parseLine() throws IOException {
String key = parseKey();
String value = parseValue();
try {
reader.mark(1);
char newline = read();
if (newline == '\r') {
reader.mark(1);
if (read() != '\n') {
throw new IOException("Expected CRLF but only got CR");
}
reader.reset();
} else if (newline != '\n') {
reader.reset();
}
} catch (EOFException ignored) {
}
return new KeyValue(key, value);
}
private String parseKey() throws IOException {
StringBuilder buffer = new StringBuilder();
// Very lenient key parsing.
while (true) {
char c = read();
switch (c) {
case '=':
case '\r':
case '\n':
return buffer.toString();
default:
buffer.append(c);
}
}
}
private String parseValue() throws IOException {
StringBuffer buffer = new StringBuffer();
while (true) {
char c = read();
switch (c) {
case '\r':
case '\n':
return buffer.toString();
case '"':
buffer.append(parseQuotedPhrase());
break;
case '\\':
char next = read();
buffer.append(next);
break;
default:
buffer.append(c);
}
}
}
private String parseQuotedPhrase() throws IOException {
StringBuilder buffer = new StringBuilder();
while (true) {
char c = read();
switch (c) {
case '"':
return buffer.toString();
case '\\':
char next = read();
buffer.append(next);
break;
default:
buffer.append(c);
}
}
}
public static Map<String, String> parse(File target) throws IOException {
CharSource charSource = Files.asCharSource(target, StandardCharsets.UTF_8);
Map<String, String> values = Splitter.onPattern("\r?\n").withKeyValueSeparator('=')
.split(charSource.read());
// Remove quotes
// TODO do this better. it works fine for the release file, though
values.replaceAll((key, value) -> value.substring(1, value.length() - 1));
EnvironmentParser parser = new EnvironmentParser(charSource.openBufferedStream());
return parser.parse();
}
return values;
@Data
private static class KeyValue {
private final String key;
private final String value;
}
}

View File

@ -25,7 +25,7 @@ button.ok=OK
options.title = Options
options.useProxyCheck = Use following proxy in Minecraft
options.jvmPath=JVM path\:
options.jvmPath=Java Runtime\:
options.jvmArguments=JVM arguments\:
options.64BitJavaWarning=<html>Make sure to have <strong>64-bit Java installed</strong> if you are planning to set the memory limits higher.
options.minMemory=Minimum memory (MB)\: