Connect minimal hosts to snapshots, target workers and shared Kit editing
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
package qualification;
|
||||
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupActivity;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.oracle.javafx.scenebuilder.kit.fxom.*;
|
||||
import de.neitzel.fxdesigner.kit.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.concurrent.*;
|
||||
import javafx.application.Platform;
|
||||
import javafx.embed.swing.JFXPanel;
|
||||
import javafx.scene.control.Button;
|
||||
|
||||
/** Disposable companion plugin, never included in the delivered designer plugin. */
|
||||
public final class WorkflowProbe implements StartupActivity.DumbAware {
|
||||
static final Path output = Path.of(System.getProperty("designer.check.output"));
|
||||
static DesignerPane active;
|
||||
static final java.util.concurrent.atomic.AtomicBoolean started =
|
||||
new java.util.concurrent.atomic.AtomicBoolean();
|
||||
|
||||
static <T> T edt(Callable<T> action) throws Exception {
|
||||
var f = new CompletableFuture<T>();
|
||||
ApplicationManager.getApplication()
|
||||
.invokeLater(
|
||||
() ->
|
||||
WriteIntentReadAction.run(
|
||||
() -> {
|
||||
try {
|
||||
f.complete(action.call());
|
||||
} catch (Throwable t) {
|
||||
f.completeExceptionally(t);
|
||||
}
|
||||
}),
|
||||
ModalityState.nonModal());
|
||||
return f.get(20, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
static <T> T fx(Callable<T> action) throws Exception {
|
||||
var f = new CompletableFuture<T>();
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
try {
|
||||
f.complete(action.call());
|
||||
} catch (Throwable t) {
|
||||
f.completeExceptionally(t);
|
||||
}
|
||||
});
|
||||
return f.get(20, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
static JFXPanel bridge(java.awt.Component c) {
|
||||
if (c instanceof JFXPanel p) return p;
|
||||
if (c instanceof java.awt.Container parent)
|
||||
for (var child : parent.getComponents()) {
|
||||
var p = bridge(child);
|
||||
if (p != null) return p;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void await(Callable<Boolean> condition) throws Exception {
|
||||
long until = System.nanoTime() + TimeUnit.SECONDS.toNanos(120);
|
||||
while (System.nanoTime() < until) {
|
||||
if (condition.call()) return;
|
||||
Thread.sleep(100);
|
||||
}
|
||||
throw new AssertionError("IDE workflow timed out");
|
||||
}
|
||||
|
||||
static void click(DesignerPane pane, String text) throws Exception {
|
||||
fx(
|
||||
() -> {
|
||||
((Button)
|
||||
pane.lookupAll(".button").stream()
|
||||
.filter(n -> n instanceof Button b && b.getText().equals(text))
|
||||
.findFirst()
|
||||
.orElseThrow())
|
||||
.fire();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public void runActivity(Project project) {
|
||||
if (!started.compareAndSet(false, true)) return;
|
||||
ApplicationManager.getApplication()
|
||||
.executeOnPooledThread(
|
||||
() -> {
|
||||
try {
|
||||
Path path =
|
||||
Path.of(
|
||||
project.getBasePath(),
|
||||
"app/src/main/resources/fixture/components/Person.fxml");
|
||||
VirtualFile file =
|
||||
edt(() -> LocalFileSystem.getInstance().refreshAndFindFileByNioFile(path));
|
||||
FileEditor editor =
|
||||
edt(
|
||||
() -> {
|
||||
var manager = FileEditorManager.getInstance(project);
|
||||
var all = manager.openFile(file, true);
|
||||
manager.setSelectedEditor(file, "neitzel-fx-designer");
|
||||
return java.util.Arrays.stream(all)
|
||||
.filter(e -> e.getName().equals("Neitzel Designer"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
});
|
||||
await(() -> edt(() -> bridge(editor.getComponent()) != null));
|
||||
JFXPanel bridge = edt(() -> bridge(editor.getComponent()));
|
||||
await(
|
||||
() ->
|
||||
fx(
|
||||
() ->
|
||||
bridge.getScene() != null
|
||||
&& bridge.getScene().getRoot() instanceof DesignerPane));
|
||||
DesignerPane pane = fx(() -> (DesignerPane) bridge.getScene().getRoot());
|
||||
active = pane;
|
||||
await(() -> fx(() -> pane.kit().editor().getFxomDocument() != null));
|
||||
click(pane, "Build and Refresh");
|
||||
await(
|
||||
() ->
|
||||
fx(
|
||||
() ->
|
||||
java.util.List.of("card", "second").stream()
|
||||
.allMatch(
|
||||
id -> {
|
||||
var item =
|
||||
new FXOMFxIdIndex(
|
||||
pane.kit().editor().getFxomDocument())
|
||||
.lookup(id);
|
||||
return item instanceof FXOMInstance instance
|
||||
&& instance.getSceneGraphObject()
|
||||
instanceof SnapshotRegion region
|
||||
&& region.image() != null
|
||||
&& region.statusText().equals("Target runtime");
|
||||
})));
|
||||
fx(
|
||||
() -> {
|
||||
var kit = pane.kit().editor();
|
||||
var card =
|
||||
(FXOMInstance) new FXOMFxIdIndex(kit.getFxomDocument()).lookup("card");
|
||||
kit.getSelection().select(card);
|
||||
var property =
|
||||
(FXOMPropertyT)
|
||||
card.getProperties()
|
||||
.get(
|
||||
new com.oracle.javafx.scenebuilder.kit.metadata.util
|
||||
.PropertyName("caption"));
|
||||
String old = property.getValue();
|
||||
kit.getJobManager()
|
||||
.push(
|
||||
new com.oracle.javafx.scenebuilder.kit.editor.job.Job(kit) {
|
||||
public boolean isExecutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "IDE caption check";
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
set("IDE canvas draft");
|
||||
}
|
||||
|
||||
public void undo() {
|
||||
set(old);
|
||||
}
|
||||
|
||||
public void redo() {
|
||||
execute();
|
||||
}
|
||||
|
||||
void set(String text) {
|
||||
var doc = kit.getFxomDocument();
|
||||
doc.beginUpdate();
|
||||
try {
|
||||
property.setValue(text);
|
||||
} finally {
|
||||
doc.endUpdate();
|
||||
}
|
||||
}
|
||||
});
|
||||
return null;
|
||||
});
|
||||
await(
|
||||
() ->
|
||||
edt(
|
||||
() ->
|
||||
FileDocumentManager.getInstance()
|
||||
.getDocument(file)
|
||||
.getText()
|
||||
.contains("IDE canvas draft")));
|
||||
click(pane, "Undo");
|
||||
await(
|
||||
() ->
|
||||
edt(
|
||||
() ->
|
||||
FileDocumentManager.getInstance()
|
||||
.getDocument(file)
|
||||
.getText()
|
||||
.contains("FXML caption")));
|
||||
click(pane, "Redo");
|
||||
await(
|
||||
() ->
|
||||
edt(
|
||||
() ->
|
||||
FileDocumentManager.getInstance()
|
||||
.getDocument(file)
|
||||
.getText()
|
||||
.contains("IDE canvas draft")));
|
||||
click(pane, "Render drafts");
|
||||
await(
|
||||
() ->
|
||||
fx(
|
||||
() ->
|
||||
java.util.List.of("card", "second").stream()
|
||||
.allMatch(
|
||||
id -> {
|
||||
var item =
|
||||
new FXOMFxIdIndex(
|
||||
pane.kit().editor().getFxomDocument())
|
||||
.lookup(id);
|
||||
return item instanceof FXOMInstance instance
|
||||
&& instance.getSceneGraphObject()
|
||||
instanceof SnapshotRegion region
|
||||
&& region.image() != null
|
||||
&& region.statusText().equals("Target runtime");
|
||||
})));
|
||||
fx(
|
||||
() -> {
|
||||
javax.imageio.ImageIO.write(
|
||||
javafx.embed.swing.SwingFXUtils.fromFXImage(
|
||||
pane.snapshot(null, null), null),
|
||||
"png",
|
||||
output.resolve("intellij.png").toFile());
|
||||
return null;
|
||||
});
|
||||
String version = fx(() -> System.getProperty("javafx.runtime.version"));
|
||||
if (!version.startsWith("26"))
|
||||
throw new AssertionError("Wrong host JavaFX: " + version);
|
||||
Files.writeString(
|
||||
output.resolve("SUCCESS.txt"),
|
||||
"PASS registered IntelliJ editor, shared Kit, real Build and Refresh, target"
|
||||
+ " pixels, native document edits, undo/redo, draft render; JavaFX "
|
||||
+ version
|
||||
+ "\n");
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
if (active != null)
|
||||
fx(
|
||||
() -> {
|
||||
Files.writeString(
|
||||
output.resolve("ui-state.txt"),
|
||||
active.lookupAll(".label").stream()
|
||||
.filter(n -> n instanceof javafx.scene.control.Label)
|
||||
.map(
|
||||
n ->
|
||||
String.valueOf(
|
||||
((javafx.scene.control.Label) n).getText()))
|
||||
.toList()
|
||||
.toString());
|
||||
javax.imageio.ImageIO.write(
|
||||
javafx.embed.swing.SwingFXUtils.fromFXImage(
|
||||
active.snapshot(null, null), null),
|
||||
"png",
|
||||
output.resolve("failed.png").toFile());
|
||||
return null;
|
||||
});
|
||||
var w = new java.io.StringWriter();
|
||||
e.printStackTrace(new java.io.PrintWriter(w));
|
||||
Files.writeString(output.resolve("FAILURE.txt"), w.toString());
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user