import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Frame;
import java.awt.Window;
import java.io.BufferedReader;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
+import javax.swing.JButton;
+import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import static java.nio.charset.StandardCharsets.UTF_8;
var newWindows = currentlyOpenWindows.stream().filter(window -> !windows.containsValue(window)).toList();
newWindows.forEach(newWindow -> {
synchronized (outputWriters) {
- outputWriters.forEach(writeLine -> writeLine.accept(createEvent("window-opened", getWindowObject(newWindow))));
+ outputWriters.forEach(writeLine -> writeLine.accept(createEvent("window-opened", getComponentObject(newWindow))));
}
windows.put(newWindow.getName(), newWindow);
});
if (words.getFirst().equalsIgnoreCase("info") && (words.size() == 3) && words.get(1).equalsIgnoreCase("window")) {
var windowName = words.get(2);
stream(Window.getWindows()).filter(window -> window.getName().equals(windowName))
- .forEach(window -> writeLine.accept(createMessage(getWindowObject(window).put("info", "window"))));
+ .forEach(window -> writeLine.accept(createMessage(getComponentObject(window).put("info", "window"))));
}
}
} finally {
}
}
- private ObjectNode getWindowObject(Window window) {
- var windowNode = objectMapper.createObjectNode();
- windowNode.put("id", window.getName());
- windowNode.put("is-frame", window instanceof Frame);
- return windowNode;
+ private ObjectNode getComponentObject(Component component) {
+ var componentNode = objectMapper.createObjectNode();
+ componentNode.put("id", componentIds.computeIfAbsent(component, c -> idCounter.incrementAndGet()));
+ componentNode.put("type", component.getClass().getName());
+ switch (component) {
+ case Frame frame -> componentNode.put("title", frame.getTitle());
+ case JButton button -> componentNode.put("text", button.getText());
+ case JLabel label -> componentNode.put("text", label.getText());
+ case Container container -> {
+ var childrenNode = componentNode.putArray("children");
+ synchronized (component.getTreeLock()) {
+ stream(container.getComponents())
+ .filter(Component::isVisible)
+ .map(this::getComponentObject)
+ .forEach(childrenNode::add);
+ }
+ }
+ default -> {
+ }
+ }
+ return componentNode;
}
private String createEvent(String name, ObjectNode parameters) {
private final AtomicBoolean closed = new AtomicBoolean(false);
private final Set<Consumer<String>> outputWriters = new HashSet<>();
private final Map<String, Window> windows = new ConcurrentHashMap<>();
+ private final AtomicInteger idCounter = new AtomicInteger();
+ private final WeakHashMap<Component, Integer> componentIds = new WeakHashMap<>();
}
package de.qsheltier.msta;
import com.fasterxml.jackson.databind.ObjectMapper;
+import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Window;
import java.io.BufferedReader;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import static com.spotify.hamcrest.jackson.JsonMatchers.isJsonStringMatching;
-import static com.spotify.hamcrest.jackson.JsonMatchers.jsonBoolean;
-import static com.spotify.hamcrest.jackson.JsonMatchers.jsonMissing;
+import static com.spotify.hamcrest.jackson.JsonMatchers.jsonArray;
+import static com.spotify.hamcrest.jackson.JsonMatchers.jsonInt;
import static com.spotify.hamcrest.jackson.JsonMatchers.jsonObject;
import static com.spotify.hamcrest.jackson.JsonMatchers.jsonText;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.anything;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Timeout.ThreadMode.SEPARATE_THREAD;
@Test
@Timeout(value = 5, unit = TimeUnit.SECONDS, threadMode = SEPARATE_THREAD)
- public void windowInfoContainsButtonInfo() throws Throwable {
+ public void windowInfoContainsInfoAboutAllComponents() throws Throwable {
connectToServer(verifyConnectedEvent((reader, ready, writer) -> {
var window = new Window(null);
- window.setVisible(true);
+ SwingUtilities.invokeAndWait(() -> {
+ var mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(new JLabel("Label"), BorderLayout.NORTH);
+ mainPanel.add(new JButton("Button"), BorderLayout.SOUTH);
+ window.add(mainPanel);
+ window.pack();
+ window.setVisible(true);
+ });
try {
var reply = objectMapper.readTree(reader.get());
- assertThat(reply, jsonObject().where("event", jsonText("window-opened")).where("id", not(jsonMissing())));
- var windowName = reply.get("id").asText();
- writer.accept("info window " + windowName);
- reply = objectMapper.readTree(reader.get());
- assertThat(reply, jsonObject()
- .where("info", jsonText("window"))
- .where("id", jsonText(windowName))
+ System.out.println(reply);
+ assertThat(reply, jsonObject().where("event", jsonText("window-opened")).where("id", jsonInt(anything()))
+ .where("children", jsonArray(contains(jsonObject().where("type", jsonText("javax.swing.JPanel"))
+ .where("children", jsonArray(containsInAnyOrder(
+ jsonObject().where("type", jsonText("javax.swing.JLabel")),
+ jsonObject().where("type", jsonText("javax.swing.JButton"))))))))
);
} finally {
window.setVisible(false);