New oracle DocuRun on Java's JDocuElement. Italic is kept (the model knew only bold), an item keeps its file's size and font size (Swift's 32 x 24 and 8-72 changed Java's files), an item without a colour is Java's light grey. Java's new items, colour lists, font sizes and styles, the drag's smallest sizes and Java's stacking; document commands for the editor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
392 lines
17 KiB
Java
392 lines
17 KiB
Java
// FILIUS' documentation mode measured on its own elements (JDocuElement on a
|
|
// GUIDocumentationPanel, as the sidebar's drag makes them): a new text and a
|
|
// new rectangle (size, colour, font), their menus (font size, style, colour,
|
|
// the colour lists), the font and colour chosen there, the smallest size a
|
|
// drag on an edge leaves (a text is dragged while it has the focus, in its
|
|
// enlarged frame), how an element is painted in the documentation mode and
|
|
// in the others (fill, border, transparency), the order in which the panel
|
|
// stacks texts and rectangles, and a project saved with them and loaded
|
|
// again (SzenarioVerwaltung.speichern, laden). The reference for the
|
|
// editor's documentation mode (packages/doc/test/documentation.test.ts).
|
|
//
|
|
// Usage: java -cp filius.jar:lib/*:classes DocuRun <out.json> <saved.fls>
|
|
|
|
import filius.gui.netzwerksicht.GUIDocuItem;
|
|
import filius.gui.netzwerksicht.GUIDocumentationPanel;
|
|
import filius.gui.netzwerksicht.JDocuColorSelector;
|
|
import filius.gui.netzwerksicht.JDocuElement;
|
|
import filius.rahmenprogramm.SzenarioVerwaltung;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Component;
|
|
import java.awt.Container;
|
|
import java.awt.Font;
|
|
import java.awt.Window;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.FileOutputStream;
|
|
import java.lang.reflect.Method;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JMenu;
|
|
import javax.swing.JMenuItem;
|
|
import javax.swing.JPanel;
|
|
import javax.swing.JPopupMenu;
|
|
import javax.swing.MenuElement;
|
|
import javax.swing.SwingUtilities;
|
|
|
|
public class DocuRun {
|
|
static final Map<String, Object> output = new LinkedHashMap<>();
|
|
static GUIDocumentationPanel panel;
|
|
|
|
static void onEdt(Runnable action) throws Exception {
|
|
SwingUtilities.invokeAndWait(action);
|
|
Thread.sleep(200);
|
|
}
|
|
|
|
static List<Object> color(Color color) {
|
|
List<Object> rgba = new ArrayList<>();
|
|
rgba.add(color.getRed());
|
|
rgba.add(color.getGreen());
|
|
rgba.add(color.getBlue());
|
|
rgba.add(color.getAlpha());
|
|
return rgba;
|
|
}
|
|
|
|
static Map<String, Object> font(Font font) {
|
|
Map<String, Object> shown = new LinkedHashMap<>();
|
|
if (font == null) return null;
|
|
shown.put("name", font.getName());
|
|
shown.put("style", font.getStyle());
|
|
shown.put("size", font.getSize());
|
|
return shown;
|
|
}
|
|
|
|
static Map<String, Object> element(JDocuElement element) {
|
|
Map<String, Object> shown = new LinkedHashMap<>();
|
|
shown.put("bounds", List.of(element.getX(), element.getY(), element.getWidth(), element.getHeight()));
|
|
shown.put("color", color(element.getColor()));
|
|
shown.put("font", font(element.getFont()));
|
|
shown.put("text", element.getText());
|
|
return shown;
|
|
}
|
|
|
|
static Map<String, Object> item(GUIDocuItem item) {
|
|
Map<String, Object> shown = new LinkedHashMap<>();
|
|
shown.put("type", item.getType());
|
|
shown.put("text", item.getText());
|
|
shown.put("bounds", List.of(item.getX(), item.getY(), item.getWidth(), item.getHeight()));
|
|
shown.put("color", color(item.getColor()));
|
|
shown.put("font", font(item.getFont()));
|
|
return shown;
|
|
}
|
|
|
|
static JPopupMenu shownMenu() {
|
|
for (Window window : Window.getWindows()) {
|
|
JPopupMenu found = find(window, JPopupMenu.class);
|
|
if (found != null) return found;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static <T> T find(Component component, Class<T> type) {
|
|
if (type.isInstance(component) && component.isShowing()) return type.cast(component);
|
|
if (component instanceof Container) {
|
|
for (Component child : ((Container) component).getComponents()) {
|
|
T found = find(child, type);
|
|
if (found != null) return found;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** The element's menu (showPopupMenu, private): each entry with its sub-entries or colours. */
|
|
static JPopupMenu openMenu(JDocuElement element) throws Exception {
|
|
Method show = JDocuElement.class.getDeclaredMethod("showPopupMenu", int.class, int.class);
|
|
show.setAccessible(true);
|
|
onEdt(() -> {
|
|
try {
|
|
show.invoke(element, 5, 5);
|
|
} catch (Exception error) {
|
|
throw new RuntimeException(error);
|
|
}
|
|
});
|
|
return shownMenu();
|
|
}
|
|
|
|
static List<Object> menu(JPopupMenu menu) {
|
|
List<Object> entries = new ArrayList<>();
|
|
for (Component component : menu.getComponents()) {
|
|
Map<String, Object> entry = new LinkedHashMap<>();
|
|
if (component instanceof JDocuColorSelector) {
|
|
JDocuColorSelector selector = (JDocuColorSelector) component;
|
|
entry.put("colors", selector.getText());
|
|
List<Object> colors = new ArrayList<>();
|
|
List<Object> chosen = new ArrayList<>();
|
|
JPanel samples = (JPanel) selector.getPopupMenu().getComponent(0);
|
|
for (Component sample : samples.getComponents()) {
|
|
colors.add(color(sample.getBackground()));
|
|
chosen.add(((javax.swing.JComponent) sample).getBorder().getBorderInsets(sample).top == 3);
|
|
}
|
|
entry.put("list", colors);
|
|
entry.put("chosen", chosen);
|
|
entry.put("rows", ((java.awt.GridLayout) samples.getLayout()).getRows());
|
|
} else if (component instanceof JMenu) {
|
|
JMenu sub = (JMenu) component;
|
|
entry.put("menu", sub.getText());
|
|
List<Object> items = new ArrayList<>();
|
|
for (MenuElement each : sub.getSubElements()[0].getSubElements()) {
|
|
JMenuItem item = (JMenuItem) each;
|
|
items.add(item.getText() + (item.isSelected() ? " *" : ""));
|
|
}
|
|
entry.put("items", items);
|
|
} else if (component instanceof JMenuItem) {
|
|
entry.put("item", ((JMenuItem) component).getText());
|
|
} else {
|
|
entry.put("separator", true);
|
|
}
|
|
entries.add(entry);
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
static void choose(JPopupMenu menu, String text) throws Exception {
|
|
for (Component component : menu.getComponents()) {
|
|
if (component instanceof JMenu && !(component instanceof JDocuColorSelector)) {
|
|
for (MenuElement each : ((JMenu) component).getSubElements()[0].getSubElements()) {
|
|
JMenuItem item = (JMenuItem) each;
|
|
if (item.getText().equals(text)) {
|
|
onEdt(item::doClick);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
throw new IllegalStateException("no entry " + text);
|
|
}
|
|
|
|
static void closeMenu(JPopupMenu menu) throws Exception {
|
|
onEdt(() -> menu.setVisible(false));
|
|
}
|
|
|
|
static void pickColor(JPopupMenu menu, Color color) throws Exception {
|
|
for (Component component : menu.getComponents()) {
|
|
if (component instanceof JDocuColorSelector) {
|
|
onEdt(() -> ((JDocuColorSelector) component).triggerMenuResponse(color));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static MouseEvent mouse(Component on, int id, int x, int y) {
|
|
return new MouseEvent(on, id, System.currentTimeMillis(), id == MouseEvent.MOUSE_DRAGGED ? MouseEvent.BUTTON1_DOWN_MASK : 0, x, y, 1, false, MouseEvent.BUTTON1);
|
|
}
|
|
|
|
/** A drag from a point of the element to another, in its coordinates (the edge decides what changes). */
|
|
static void drag(JDocuElement element, int fromX, int fromY, int toX, int toY) throws Exception {
|
|
onEdt(() -> {
|
|
element.dispatchEvent(mouse(element, MouseEvent.MOUSE_MOVED, fromX, fromY));
|
|
element.dispatchEvent(mouse(element, MouseEvent.MOUSE_PRESSED, fromX, fromY));
|
|
element.dispatchEvent(mouse(element, MouseEvent.MOUSE_DRAGGED, toX, toY));
|
|
element.dispatchEvent(mouse(element, MouseEvent.MOUSE_RELEASED, toX, toY));
|
|
});
|
|
}
|
|
|
|
/** The element painted alone: the pixels at the given points, as RGBA. */
|
|
static Map<String, Object> pixels(JDocuElement element, int[][] points) throws Exception {
|
|
Map<String, Object> shown = new LinkedHashMap<>();
|
|
BufferedImage image = new BufferedImage(element.getWidth(), element.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
|
onEdt(() -> {
|
|
java.awt.Graphics2D graphics = image.createGraphics();
|
|
element.paint(graphics);
|
|
graphics.dispose();
|
|
});
|
|
for (int[] point : points) {
|
|
int argb = image.getRGB(point[0], point[1]);
|
|
shown.put(point[0] + "," + point[1], List.of((argb >> 16) & 255, (argb >> 8) & 255, argb & 255, (argb >>> 24) & 255));
|
|
}
|
|
return shown;
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
try {
|
|
run(args);
|
|
} catch (Throwable error) {
|
|
error.printStackTrace();
|
|
System.exit(1);
|
|
}
|
|
System.exit(0);
|
|
}
|
|
|
|
static void run(String[] args) throws Exception {
|
|
JFrame frame = new JFrame();
|
|
List<JDocuElement> made = new ArrayList<>();
|
|
SwingUtilities.invokeAndWait(() -> {
|
|
panel = new GUIDocumentationPanel(800, 600);
|
|
frame.getContentPane().setLayout(null);
|
|
frame.getContentPane().add(panel);
|
|
frame.setSize(820, 640);
|
|
frame.setVisible(true);
|
|
// As the sidebar's drop: made by drag, placed, added to the panel (which gives it the focus).
|
|
JDocuElement text = new JDocuElement(true, true);
|
|
text.setLocation(100, 100);
|
|
JDocuElement rectangle = new JDocuElement(false, true);
|
|
rectangle.setLocation(300, 100);
|
|
made.add(text);
|
|
made.add(rectangle);
|
|
});
|
|
JDocuElement text = made.get(0);
|
|
JDocuElement rectangle = made.get(1);
|
|
Map<String, Object> fresh = new LinkedHashMap<>();
|
|
fresh.put("text", element(text));
|
|
fresh.put("rectangle", element(rectangle));
|
|
output.put("new", fresh);
|
|
|
|
onEdt(() -> panel.add(text));
|
|
Thread.sleep(300);
|
|
Map<String, Object> focused = new LinkedHashMap<>();
|
|
focused.put("text", element(text));
|
|
onEdt(panel::removeElementsFocus);
|
|
focused.put("textUnfocused", element(text));
|
|
output.put("dropped", focused);
|
|
|
|
// The menus.
|
|
JPopupMenu menu = openMenu(text);
|
|
Map<String, Object> menus = new LinkedHashMap<>();
|
|
menus.put("text", menu(menu));
|
|
choose(menu, "Groß");
|
|
closeMenu(menu);
|
|
List<Object> fonts = new ArrayList<>();
|
|
fonts.add(font(text.getFont()));
|
|
menu = openMenu(text);
|
|
menus.put("textAfterLarge", menu(menu));
|
|
choose(menu, "Kursiv");
|
|
closeMenu(menu);
|
|
fonts.add(font(text.getFont()));
|
|
menu = openMenu(text);
|
|
choose(menu, "Fett");
|
|
closeMenu(menu);
|
|
fonts.add(font(text.getFont()));
|
|
menu = openMenu(text);
|
|
choose(menu, "Normal"); // the first "Normal", the size menu's
|
|
closeMenu(menu);
|
|
fonts.add(font(text.getFont()));
|
|
menu = openMenu(text);
|
|
choose(menu, "Sehr Gro\u00df");
|
|
closeMenu(menu);
|
|
fonts.add(font(text.getFont()));
|
|
menu = openMenu(text);
|
|
choose(menu, "Normal");
|
|
closeMenu(menu);
|
|
menu = openMenu(text);
|
|
pickColor(menu, new Color(0.31f, 0.51f, 0.74f));
|
|
closeMenu(menu);
|
|
output.put("fonts", fonts);
|
|
output.put("textColor", color(text.getColor()));
|
|
onEdt(() -> panel.add(rectangle));
|
|
menu = openMenu(rectangle);
|
|
menus.put("rectangle", menu(menu));
|
|
pickColor(menu, new Color(1f, 0.79f, 0.79f));
|
|
closeMenu(menu);
|
|
output.put("rectangleColor", color(rectangle.getColor()));
|
|
output.put("menus", menus);
|
|
|
|
// The smallest sizes a drag leaves: a rectangle by its corner; a text, focused, by its corner, then unfocused.
|
|
Map<String, Object> smallest = new LinkedHashMap<>();
|
|
onEdt(() -> rectangle.setLocalFocus(true));
|
|
drag(rectangle, rectangle.getWidth() - 2, rectangle.getHeight() - 2, 3, 3);
|
|
smallest.put("rectangle", element(rectangle));
|
|
drag(rectangle, 1, 1, 200, 200);
|
|
smallest.put("rectangleByItsTopLeft", element(rectangle));
|
|
onEdt(() -> text.setLocalFocus(true));
|
|
smallest.put("textFocused", element(text));
|
|
drag(text, text.getWidth() - 2, text.getHeight() - 2, 3, 3);
|
|
smallest.put("textFocusedSmallest", element(text));
|
|
onEdt(panel::removeElementsFocus);
|
|
smallest.put("textSmallest", element(text));
|
|
// A drag on an unfocused text does nothing (Java moves and sizes a text only in its enlarged frame).
|
|
drag(text, 10, 10, 60, 60);
|
|
smallest.put("textDraggedUnfocused", element(text));
|
|
output.put("smallest", smallest);
|
|
|
|
// Painted: a rectangle and a text, in the documentation mode (enabled) unfocused and focused, and in the others.
|
|
Map<String, Object> painted = new LinkedHashMap<>();
|
|
JDocuElement plain = new JDocuElement(false);
|
|
JDocuElement words = new JDocuElement(true);
|
|
onEdt(() -> {
|
|
plain.setBounds(400, 300, 100, 50);
|
|
plain.setColor(new Color(1f, 0.79f, 0.79f));
|
|
words.setBounds(400, 400, 100, 50);
|
|
words.setText("Text");
|
|
panel.add(plain);
|
|
panel.add(words);
|
|
});
|
|
int[][] points = { { 50, 25 }, { 1, 25 }, { 2, 25 }, { 0, 25 } };
|
|
painted.put("rectangleEnabled", pixels(plain, points));
|
|
onEdt(() -> plain.setLocalFocus(true));
|
|
painted.put("rectangleFocused", pixels(plain, new int[][] { { 50, 25 }, { 3, 25 }, { 1, 25 } }));
|
|
onEdt(() -> plain.setEnabled(false));
|
|
painted.put("rectangleDisabled", pixels(plain, points));
|
|
painted.put("textEnabled", pixels(words, new int[][] { { 0, 25 }, { 1, 25 }, { 50, 0 }, { 99, 25 } }));
|
|
onEdt(() -> words.setEnabled(false));
|
|
painted.put("textDisabled", pixels(words, new int[][] { { 0, 25 }, { 1, 25 }, { 50, 0 } }));
|
|
output.put("painted", painted);
|
|
|
|
// The stacking: texts first, then rectangles, each in the list's order; the first component is on top.
|
|
List<GUIDocuItem> items = new ArrayList<>();
|
|
JDocuElement[] elements = { new JDocuElement(true), new JDocuElement(false), new JDocuElement(true), new JDocuElement(false) };
|
|
String[] names = { "text 1", "rectangle 1", "text 2", "rectangle 2" };
|
|
onEdt(() -> {
|
|
for (int index = 0; index < elements.length; index++) {
|
|
elements[index].setBounds(50 + 10 * index, 50 + 10 * index, 100, 50);
|
|
elements[index].setText(names[index]);
|
|
elements[index].setName(names[index]);
|
|
items.add(GUIDocuItem.createDocuItem(elements[index]));
|
|
}
|
|
panel.updateViewport(items, true);
|
|
});
|
|
List<String> stacking = new ArrayList<>();
|
|
for (Component component : panel.getComponents()) stacking.add(component.getName());
|
|
output.put("stacking", stacking);
|
|
output.put("topAt", panel.getComponentAt(85, 85).getName());
|
|
|
|
// A project with documentation, saved and loaded again.
|
|
List<GUIDocuItem> saved = new ArrayList<>();
|
|
JDocuElement italic = new JDocuElement(true);
|
|
JDocuElement bold = new JDocuElement(true);
|
|
JDocuElement pink = new JDocuElement(false);
|
|
JDocuElement grey = new JDocuElement(false);
|
|
onEdt(() -> {
|
|
italic.setBounds(40, 40, 160, 60);
|
|
italic.setText("Kursiv und mittel\nzweite Zeile");
|
|
italic.setFont(italic.getFont().deriveFont(Font.ITALIC, 18f));
|
|
italic.setColor(new Color(0.31f, 0.51f, 0.74f));
|
|
bold.setBounds(40, 140, 120, 50);
|
|
bold.setText("Fett");
|
|
bold.setFont(bold.getFont().deriveFont(Font.BOLD, 24f));
|
|
pink.setBounds(20, 20, 300, 200);
|
|
pink.setColor(new Color(1f, 0.79f, 0.79f));
|
|
grey.setBounds(400, 20, 100, 50);
|
|
for (JDocuElement each : new JDocuElement[] { italic, bold, pink, grey }) saved.add(GUIDocuItem.createDocuItem(each));
|
|
});
|
|
List<Object> savedItems = new ArrayList<>();
|
|
for (GUIDocuItem each : saved) savedItems.add(item(each));
|
|
output.put("saved", savedItems);
|
|
if (!SzenarioVerwaltung.getInstance().speichern(args[1], new ArrayList<>(), new ArrayList<>(), saved)) throw new IllegalStateException("not saved");
|
|
List<GUIDocuItem> loaded = new ArrayList<>();
|
|
SzenarioVerwaltung.getInstance().laden(args[1], new ArrayList<>(), new ArrayList<>(), loaded);
|
|
List<Object> loadedItems = new ArrayList<>();
|
|
for (GUIDocuItem each : loaded) loadedItems.add(item(each));
|
|
output.put("loaded", loadedItems);
|
|
|
|
try (FileOutputStream out = new FileOutputStream(args[0])) {
|
|
out.write((FlsOracle.Json.write(output, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
System.out.println("documentation measured");
|
|
}
|
|
}
|