!7 sclass Msg { S author, text; long created = now(); } concept ItemPage { S globalID = aGlobalID(); S title, imageID; long created = now(), occurred; L comments = listInConcept(this); } static JTextPane textPane; static JTextField tfComment; static ItemPage page; p-subst { setConsoleInputFontSize(20); centerConsoleInput(); centerBottomConsole(); db(); bot("Show Item Page."); focusConsole(); } static bool showItemPage(S _word) { final new ItemPage p; fS word = trim(_word); cset(p, title := word); showPage(p); true; } svoid showPage(final ItemPage p) { swing { page = p; fS shorter = deUserSaid(p.title); JFrame f = getFrame(textPane); fS text = p.title + "\n\n"; JTextPane oldTextPane = textPane; textPane = jcenteredtextpane(text, style_bold(style_fontSize(24))); if (oldTextPane != null) { replaceAWTComponent(oldTextPane, textPane); frameToFront(f); } else { showFrame(shorter, textPane); addToFrame(textPane, withLabel("Add Comment:", centerAndEast(tfComment = jtextfield(), jbutton("OK", f addComment)))); onEnter(tfComment, f addComment); } textPane.setEditable(false); focusConsole(); if (p.imageID == null) thread { BufferedImage img = quickVisualize(shorter); if (p.imageID != null) ret; cset(p, imageID := "quickvis/" + urlencode(quickVisualize_preprocess(shorter)) + "/" + md5OfBufferedImage(img)); showPage(p); } else { BufferedImage img = quickVisualize(shorter); addImageToTextPane(textPane, img); // sync OK, uses swing {} } for (Msg c : p.comments) appendToTextPane(textPane, "\n\n" + c.author + ": " + c.text, style_normal()); centerTextPane(textPane); } } answer { if "quickrun *" { fS prog = $1; thread { _run($1); print("[done]"); } ret "OK"; } if (showItemPage(s)) ret "OK"; } svoid addComment { S text = getTextTrim(tfComment); if (empty(text)) ret; page.comments.add(nuWithValues(Msg, author := 'User, +text)); showPage(page); } // called by child processes svoid addProgramComment(S programID, ItemPage page, S text) { page.comments.add(nuWithValues(Msg, author := programID, +text)); showPage(page); }