Package and qualify standalone macOS designer with bundled runtime
This commit is contained in:
+20
-8
@@ -8,7 +8,7 @@ import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/** Development standalone entry: launch settings file and initial FXML path. */
|
||||
/** Standalone document windows and lifecycle, shared by development and packaged launch. */
|
||||
public final class DesignerApplication extends Application {
|
||||
private HostLaunch launch;
|
||||
private StandaloneHost host;
|
||||
@@ -17,12 +17,24 @@ public final class DesignerApplication extends Application {
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
var args = getParameters().getRaw();
|
||||
if (args.size() != 2)
|
||||
throw new IllegalArgumentException("Arguments: local-launch.properties View.fxml");
|
||||
var options = StandaloneOptions.parse(getParameters().getRaw());
|
||||
Path file = options.document();
|
||||
if (file == null) {
|
||||
var chooser = new javafx.stage.FileChooser();
|
||||
chooser.setTitle("Open FXML View");
|
||||
chooser
|
||||
.getExtensionFilters()
|
||||
.add(new javafx.stage.FileChooser.ExtensionFilter("FXML Views", "*.fxml"));
|
||||
var selected = chooser.showOpenDialog(stage);
|
||||
if (selected == null) {
|
||||
javafx.application.Platform.exit();
|
||||
return;
|
||||
}
|
||||
file = selected.toPath();
|
||||
}
|
||||
try {
|
||||
launch = HostLaunch.load(Path.of(args.get(0)));
|
||||
open(stage, Path.of(args.get(1)));
|
||||
launch = options.load();
|
||||
open(stage, file);
|
||||
} catch (Exception setup) {
|
||||
if (host != null) host.close();
|
||||
host =
|
||||
@@ -32,7 +44,7 @@ public final class DesignerApplication extends Application {
|
||||
diagnostic -> System.err.println(diagnostic.message()));
|
||||
var source =
|
||||
new de.neitzel.fxdesigner.kit.SourceOnlyPane(
|
||||
host.services(), Path.of(args.get(1)), String.valueOf(setup.getMessage()));
|
||||
host.services(), file, String.valueOf(setup.getMessage()));
|
||||
stage.setTitle("Neitzel FX Designer — source");
|
||||
stage.setScene(new Scene(source, 1000, 700));
|
||||
stage.setOnCloseRequest(
|
||||
@@ -119,7 +131,7 @@ public final class DesignerApplication extends Application {
|
||||
},
|
||||
d -> System.err.println(d.message()));
|
||||
var pane = new DesignerPane(host.services(), launch, file);
|
||||
stage.setTitle("Neitzel FX Designer — " + file.getFileName());
|
||||
stage.setTitle("Neitzel FX Designer — " + file.getFileName() + " [" + launch.context() + "]");
|
||||
stage.setScene(new Scene(pane, 1300, 850));
|
||||
windows++;
|
||||
editors.put(identity, stage);
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
package de.neitzel.fxdesigner.standalone;
|
||||
|
||||
/** Plain launcher supports the development classpath packaging of JavaFX. */
|
||||
/** Plain entry point shared by the packaged launcher and development runs. */
|
||||
public final class Launcher {
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 1 && args[0].equals("--help")) {
|
||||
System.out.println(StandaloneOptions.USAGE);
|
||||
return;
|
||||
}
|
||||
if (args.length == 1 && args[0].equals("--version")) {
|
||||
System.out.println(
|
||||
"Neitzel FX Designer 0.1.0-SNAPSHOT; Java "
|
||||
+ System.getProperty("java.version")
|
||||
+ "; runtime "
|
||||
+ System.getProperty("java.home"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
StandaloneOptions.parse(java.util.List.of(args));
|
||||
} catch (IllegalArgumentException error) {
|
||||
System.err.println(error.getMessage() + "\n" + StandaloneOptions.USAGE);
|
||||
System.exit(2);
|
||||
return;
|
||||
}
|
||||
javafx.application.Application.launch(DesignerApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package de.neitzel.fxdesigner.standalone;
|
||||
|
||||
import de.neitzel.fxdesigner.config.*;
|
||||
import de.neitzel.fxdesigner.workflow.HostLaunch;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
/** Standalone launch inputs; application runtimes remain explicitly configured. */
|
||||
public record StandaloneOptions(
|
||||
Path legacy, Path configuration, Path settings, String context, Path maven, Path document) {
|
||||
public static final String USAGE =
|
||||
"Neitzel FX Designer\n"
|
||||
+ " --configuration project/neitzel-fx-designer.json --settings runtimes.json\n"
|
||||
+ " [--context name] [--maven /path/to/mvnw] [View.fxml]\n"
|
||||
+ " --launch host.properties [View.fxml]\n"
|
||||
+ " --help | --version\n"
|
||||
+ "Without View.fxml, select a document in the file chooser. Multiple contexts require"
|
||||
+ " --context.";
|
||||
|
||||
public static StandaloneOptions parse(List<String> args) {
|
||||
if (args.size() == 2 && !args.get(0).startsWith("--"))
|
||||
return new StandaloneOptions(
|
||||
Path.of(args.get(0)), null, null, null, null, Path.of(args.get(1)));
|
||||
var values = new HashMap<String, String>();
|
||||
Path document = null;
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
String arg = args.get(i);
|
||||
if (arg.startsWith("--")) {
|
||||
if (!Set.of("--launch", "--configuration", "--settings", "--context", "--maven")
|
||||
.contains(arg)
|
||||
|| i + 1 == args.size()
|
||||
|| args.get(i + 1).startsWith("--")
|
||||
|| values.containsKey(arg))
|
||||
throw new IllegalArgumentException("Unknown, duplicate or incomplete option: " + arg);
|
||||
values.put(arg, args.get(++i));
|
||||
} else {
|
||||
if (document != null)
|
||||
throw new IllegalArgumentException("Specify only one initial FXML document");
|
||||
document = Path.of(arg);
|
||||
}
|
||||
}
|
||||
if (values.containsKey("--launch")) {
|
||||
if (values.size() != 1)
|
||||
throw new IllegalArgumentException("--launch cannot be combined with project options");
|
||||
} else if (!values.containsKey("--configuration") || !values.containsKey("--settings"))
|
||||
throw new IllegalArgumentException("Supply --configuration and --settings, or --launch");
|
||||
return new StandaloneOptions(
|
||||
path(values, "--launch"),
|
||||
path(values, "--configuration"),
|
||||
path(values, "--settings"),
|
||||
values.get("--context"),
|
||||
path(values, "--maven"),
|
||||
document);
|
||||
}
|
||||
|
||||
private static Path path(Map<String, String> values, String key) {
|
||||
return values.containsKey(key) ? Path.of(values.get(key)).toAbsolutePath().normalize() : null;
|
||||
}
|
||||
|
||||
public HostLaunch load() throws Exception {
|
||||
if (legacy != null) return HostLaunch.load(legacy);
|
||||
var contexts = ConfigurationFiles.load(configuration).contexts();
|
||||
String selected = context;
|
||||
if (selected == null && contexts.size() == 1) selected = contexts.keySet().iterator().next();
|
||||
if (selected == null || !contexts.containsKey(selected))
|
||||
throw new IllegalArgumentException(
|
||||
"Select --context from: " + String.join(", ", contexts.keySet()));
|
||||
Path app =
|
||||
Path.of(StandaloneOptions.class.getProtectionDomain().getCodeSource().getLocation().toURI())
|
||||
.getParent();
|
||||
Path directory = app.resolve("tools");
|
||||
List<Path> tools;
|
||||
try (var entries = Files.list(directory)) {
|
||||
tools = entries.filter(p -> p.toString().endsWith(".jar")).sorted().toList();
|
||||
}
|
||||
if (tools.size() != 3)
|
||||
throw new IllegalArgumentException("Bundled target tools missing: " + directory);
|
||||
return new HostLaunch(configuration, selected, maven, tools, LocalSettings.load(settings));
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package de.neitzel.fxdesigner.standalone;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class StandaloneOptionsTest {
|
||||
@Test
|
||||
void supportsProjectArgumentsAndOptionalDocument() {
|
||||
var options =
|
||||
StandaloneOptions.parse(
|
||||
List.of("--configuration", "project/config.json", "--settings", "local.json"));
|
||||
assertNull(options.document());
|
||||
assertTrue(options.configuration().isAbsolute());
|
||||
assertEquals(
|
||||
"sample",
|
||||
StandaloneOptions.parse(List.of("--launch", "host.properties", "sample"))
|
||||
.document()
|
||||
.toString());
|
||||
assertNotNull(StandaloneOptions.parse(List.of("host.properties", "View.fxml")).legacy());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAmbiguousAndIncompleteArguments() {
|
||||
for (var args :
|
||||
List.of(
|
||||
List.<String>of(),
|
||||
List.of("--bad"),
|
||||
List.of("--launch"),
|
||||
List.of("--launch", "a", "--context", "b"),
|
||||
List.of("--launch", "a", "--launch", "b"),
|
||||
List.of("--configuration", "a"),
|
||||
List.of("--launch", "a", "one", "two")))
|
||||
assertThrows(IllegalArgumentException.class, () -> StandaloneOptions.parse(args));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user