Uses 3874K of libraries. Click here for Pure Java version (10162L/76K/261K).
1 | // The Runner! |
2 | |
3 | !7 |
4 | |
5 | static JFrame frame; |
6 | static JList list; |
7 | static JTextField tfCmd; |
8 | static JLabel status; |
9 | static JButton btnReload, btnRun, btnClear; |
10 | static S submittedInput; |
11 | static JCheckBox cbPrograms; |
12 | static TrayIcon trayIcon; |
13 | static volatile boolean searching; |
14 | static long lastSearch; // time of last search |
15 | |
16 | static JTable lastRunTable; |
17 | static ReliableSingleThread thread_lastRun; |
18 | |
19 | static S menuSnippet = "#1000880"; |
20 | static S menuScript; |
21 | |
22 | static int searchDelay = 100; |
23 | static int maxResults = 100; |
24 | static int autoResearchInterval = 30000; // 30 secs |
25 | static boolean useFastNohup = true; // use pre-spun VMs if available |
26 | static int topTenLookBack = 100; // look at last 100 program runs |
27 | |
28 | static L<S> actionHistory = synchroList(); |
29 | |
30 | !include #1000839 // PopupMenuHelper |
31 | |
32 | p-awt { |
33 | becomeBotVMIfFirst(); |
34 | //mistAqua(); |
35 | //magellan(); |
36 | //gemini(); |
37 | //emeraldDusk(); |
38 | //mistSilver(); |
39 | //substanceLAF("Raven"); |
40 | //substanceLAF("OfficeSilver2007"); |
41 | //substanceLAF("OfficeBlue2007"); |
42 | //substanceLAF("OfficeBlack2007"); |
43 | substanceLAF("Sahara"); |
44 | |
45 | try { |
46 | frame = showFrame(); |
47 | } catch (HeadlessException e) { |
48 | System.out.println("We're headless..."); |
49 | // TODO: Something useful. |
50 | System.exit(0); |
51 | } |
52 | |
53 | updateTitle(); |
54 | makeAndroid3("JavaX Starter."); |
55 | |
56 | setFrameIconLater(frame, "#1003596"); |
57 | |
58 | // Show the rays |
59 | disposeWindowOnClick(showAnimation("#1003828", 3.5)); |
60 | |
61 | list = new JList; |
62 | |
63 | new PopupMenuHelper { |
64 | void fillMenu() { |
65 | try { |
66 | if (menuScript == null) |
67 | menuScript = loadSnippet(menuSnippet); |
68 | |
69 | JMenuItem mi; |
70 | int idx = list.locationToIndex(point); |
71 | final String item = cast list.getModel().getElementAt(idx); |
72 | list.setSelectedIndex(idx); |
73 | |
74 | L<S> tok = javaTok(menuScript); |
75 | for (int i = 1; i+4 < tok.size(); i += 2) |
76 | if (tok.get(i+2).equals("=")) { |
77 | final S snip = unquote(tok.get(i+4)); |
78 | S text = unquote(tok.get(i)); |
79 | mi = new JMenuItem(text); |
80 | mi.addActionListener(actionListener { |
81 | runCustom(snip, item); |
82 | }); |
83 | menu.add(mi); |
84 | } |
85 | } catch (Throwable e) { |
86 | popup(e); |
87 | } |
88 | } |
89 | }.install(list); |
90 | |
91 | // install double click listener on list |
92 | onDoubleClick(list, voidfunc(S item) { |
93 | if (nempty(item)) |
94 | runCustom("", item); |
95 | }); |
96 | |
97 | // install enter key listener on list |
98 | |
99 | onEnter(list, f run); |
100 | |
101 | ActionListener go = actionListener { |
102 | tfCmd.selectAll(); |
103 | search(true); |
104 | }; |
105 | |
106 | btnReload = new JButton(isWindows() ? "Reload" : "\u27F3"); |
107 | btnReload.setToolTipText("Search again (if our " + autoResearchInterval/1000 + "s update interval is not enough for you)"); |
108 | btnReload.addActionListener(go); |
109 | |
110 | btnClear = new JButton("X"); |
111 | btnClear.setToolTipText("Show latest"); |
112 | btnClear.addActionListener(actionListener { tfCmd.setText(""); }); |
113 | |
114 | tfCmd = new JTextField; |
115 | |
116 | cbPrograms = new JCheckBox("Programs", true); |
117 | cbPrograms.setToolTipText("Show only runnable programs (not random text snippets)"); |
118 | cbPrograms.addActionListener(go); |
119 | |
120 | JPanel controls = jflow(btnClear, cbPrograms, btnReload); |
121 | |
122 | JPanel north = centerAndEast( |
123 | withLabel("Search term:", tfCmd), |
124 | controls); |
125 | |
126 | btnRun = jbutton("Run", r { main.run() }); |
127 | listDependButton(list, btnRun); |
128 | |
129 | status = new JLabel(" "); |
130 | JPanel searchPanel = northCenterAndSouth(north, list, |
131 | centerAndEast(status, btnRun)); |
132 | |
133 | tfCmd.addActionListener(go); |
134 | |
135 | frame.addWindowListener(new WindowAdapter() { |
136 | public void windowOpened(WindowEvent e) { |
137 | tfCmd.requestFocus(); |
138 | } |
139 | |
140 | public void windowClosing(WindowEvent e) { |
141 | frame.setVisible(false); |
142 | } |
143 | |
144 | public void windowActivated(WindowEvent e) { |
145 | search(false); |
146 | } |
147 | }); |
148 | |
149 | installTimer(tfCmd, new Runnable() { |
150 | String lastContents; |
151 | boolean autoSearchOn = true; |
152 | |
153 | public void run() { |
154 | updateTitle(); |
155 | String text = getInput(); |
156 | if (text.equals(lastContents)) { |
157 | if ( |
158 | isFocusedWindow(frame) && now() > lastSearch + autoResearchInterval |
159 | |
160 | || (!text.equals(submittedInput) && autoSearchOn && !searching)) |
161 | search(false); |
162 | } else |
163 | lastContents = text; |
164 | } |
165 | }, searchDelay); |
166 | |
167 | lastRunTable = sexyTable(); |
168 | onDoubleClickOrEnter(lastRunTable, voidfunc(int row) { |
169 | Map map = getTableLineAsMap(lastRunTable, row); |
170 | S id = getString(map, "Program ID"); |
171 | S args = getString(map, "Arguments"); |
172 | runCustom("", id + " " + args); |
173 | }); |
174 | |
175 | thread_lastRun = new ReliableSingleThread(f updateLastRun); |
176 | thread_lastRun.go(); |
177 | |
178 | JTable injectionsTable = jInjectionsTable(); |
179 | |
180 | frame.add(jRightTabs("Search", searchPanel, "Last Run Programs", tableWithSearcher(lastRunTable), "Running", injectionsTable)); |
181 | frame.setBounds(100, 100, 500, 400); |
182 | frame.setVisible(true); |
183 | frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); |
184 | hideFrameOnMinimize(frame); |
185 | |
186 | addMenu(frame, "Starter", |
187 | "Show Talk Program [Eleutheria]", r { talkProgram() }, |
188 | "Your Computer ID: " + computerID(), r {}, |
189 | "Update JavaX", r { nohupJavax(#1001639) }, |
190 | "Log in", r { nohupJavax(#1000896) }); |
191 | |
192 | trayIcon = installTrayIcon("JavaX!", "#1003596", popupItems()); |
193 | |
194 | thread "Updating Menu every 10 minutes" { |
195 | sleepMinutes(10); |
196 | while (licensed()) { |
197 | pcall { |
198 | print("Updating menu."); |
199 | updateMenu(); |
200 | } |
201 | sleepMinutes(10); |
202 | } |
203 | } |
204 | |
205 | hideConsole(); |
206 | |
207 | search(false); |
208 | } |
209 | |
210 | svoid updateTitle { |
211 | S title = "JavaX Starter v3"; |
212 | if (isOfflineMode()) title += " [OFFLINE MODE]"; |
213 | setFrameTitle(frame, title); |
214 | } |
215 | |
216 | svoid updateMenu { |
217 | updateTitle(); |
218 | trayIcon.setPopupMenu(makePopupMenu(dropFirst(popupItems()))); |
219 | } |
220 | |
221 | static O[] popupItems() { |
222 | new L topTenItems; |
223 | pcall { |
224 | L<S> calls = programTopTenWithArgs(topTenLookBack).getTopTen(); |
225 | new HashSet<S> ids; |
226 | for (S s : calls) |
227 | ids.add(onlyUntilSpace(s)); |
228 | Map<S, S> titles = getSnippetTitles(asList(ids)); |
229 | |
230 | for (final S call : calls) { |
231 | S id = onlyUntilSpace(call); |
232 | topTenItems.add(menuItem(id + " [" + lookupSnippetID(titles, id) + "]" + (eq(id, call) ? "" : " " + trim(dropPrefix(id, call))), |
233 | r { runProgram(call); })); |
234 | } |
235 | } |
236 | |
237 | ret flattenArray( |
238 | r { bringUpFrame(); }, // on left click |
239 | toObjectArray(topTenItems), |
240 | "***", |
241 | menuItem("Show Runner", r { bringUpFrame(); }), |
242 | menuItem("Show Console", r { showConsole(); }), |
243 | menuItem("Restart Runner", r { restart(); }), |
244 | menuItem("Show Talk Program [Eleutheria]", r { talkProgram(); }), |
245 | //menuItem("Hide Console", r { hideConsole(); }), |
246 | isOfflineMode() |
247 | ? menuItem("Switch to online mode", r { goOnlineMode(); updateMenu(); }) |
248 | : menuItem("Switch to offline mode", r { goOfflineMode(); updateMenu(); }), |
249 | menuItem("Exit", r { System.exit(0); })); |
250 | } |
251 | |
252 | static S getInput() { |
253 | ret tfCmd.getText().trim(); |
254 | } |
255 | |
256 | static void search(String cmd, final boolean requestFocus) ctex { |
257 | searching = true; |
258 | try { |
259 | status("Searching " + quote(cmd) + "..."); |
260 | if (empty(cmd)) cmd = "_"; |
261 | if (cbPrograms.isSelected()) |
262 | cmd += " type:runnable"; |
263 | S page = loadPage("http://tinybrain.de:8080/tb/search.php?q=" + urlencode(cmd) + "&limit=" + maxResults + "&sort=modified&quick=1" + standardCredentials()); |
264 | Matcher m = Pattern.compile(">(#\\d+)</a> - (.*?)<br>").matcher(page); |
265 | |
266 | final new DefaultListModel model; |
267 | while (m.find()) { |
268 | String title = m.group(2); |
269 | title = join(dropAllTags(htmlcoarsetok(title))); |
270 | model.addElement(htmldecode(m.group(1) + " - " + title)); |
271 | } |
272 | |
273 | awt { |
274 | list.setModel(model); |
275 | status("Found " + model.size() + (model.size() == maxResults ? "+" : "") + (cbPrograms.isSelected() ? " runnable(s)." : " snippet(s).")); |
276 | if (requestFocus) |
277 | tfCmd.requestFocus(); |
278 | } |
279 | } finally { |
280 | searching = false; |
281 | } |
282 | } |
283 | |
284 | static void status(final S s) { |
285 | awt { status.setText(s); } |
286 | } |
287 | |
288 | static void runProgram(final S cmd) { |
289 | print("Running " + cmd); |
290 | S msg = format3("*: Running *", now(), cmd); |
291 | actionHistory.add(msg); |
292 | logQuoted("run.log", msg); |
293 | awtLater(1000, r { thread_lastRun.go() }); |
294 | |
295 | thread { // new thread so we can see progress messages, e.g. for loading the JavaX jar |
296 | if (useFastNohup) |
297 | fastNohupJavax(cmd); |
298 | else |
299 | nohupJavax(cmd); |
300 | } |
301 | } |
302 | |
303 | static void runHotwired(final S worker, final long id) { |
304 | print("Hotwiring " + worker + " on " + id); |
305 | S msg = format3("*: Hotwiring * on *", now(), worker, id); |
306 | actionHistory.add(msg); |
307 | logQuoted("run.log", msg); |
308 | |
309 | thread { |
310 | _run(worker, new S[] {str(id)}); // TODO: cache code? |
311 | } |
312 | } |
313 | |
314 | static void runCustom(S worker, S item) { |
315 | if (item == null) ret; |
316 | int i = item.indexOf(' '); |
317 | if (i >= 0) item = item.substring(0, i); |
318 | long id = parseSnippetID(item); |
319 | print("runCustom: " + id + " [" + worker + "]"); |
320 | if (empty(worker)) |
321 | runProgram(str(id)); |
322 | else |
323 | runHotwired(worker, id); |
324 | } |
325 | |
326 | static void runWithArguments(S item) { |
327 | // TODO: run a dialog for that |
328 | } |
329 | |
330 | static void search(final boolean requestFocus) { |
331 | submittedInput = getInput(); |
332 | lastSearch = now(); |
333 | final String cmd = submittedInput; |
334 | actionHistory.add(format3("*: Searching *", now(), cmd)); |
335 | thread { |
336 | search(cmd, requestFocus); |
337 | } |
338 | } |
339 | |
340 | answer { |
341 | if "very quick java *" |
342 | ret format("ok *", structure(callCalc(veryQuickJava(m.unq(0))))); |
343 | } |
344 | |
345 | static void run() { |
346 | S item = cast list.getModel().getElementAt(list.getSelectedIndex()); |
347 | runCustom("", item); |
348 | } |
349 | |
350 | static void bringUpFrame() { |
351 | makeFrameVisible(frame); |
352 | } |
353 | |
354 | svoid updateLastRun { |
355 | print("Updating last run list..."); |
356 | new L<Map> l; |
357 | for (S s : uniquifyList(reversedList(scanRunLog(programID())))) { |
358 | S progID = s; |
359 | int i = s.indexOf(' '); |
360 | if (i >= 0) { |
361 | progID = substring(s, 0, i); |
362 | s = trim(substring(s, i+1)); |
363 | } else |
364 | s = ""; // no arguments |
365 | //S title = getSnippetTitle_cached(progID); |
366 | l.add(litorderedmap("Program ID" := fsI(progID), |
367 | "Title" := "?", "Arguments" := s)); |
368 | } |
369 | addProgramTitles(l); |
370 | dataToTable_uneditable(l, lastRunTable); |
371 | } |
372 | |
373 | svoid addProgramTitles(L<Map> l) { |
374 | new HashSet<S> needed; |
375 | for (Map m : l) { |
376 | if (eq(m.get("Title"), "?")) { |
377 | S id = getString(m, "Program ID"); |
378 | S title = getSnippetTitle_cached_probe(id); |
379 | if (title != null) |
380 | m.put("Title", title); |
381 | else |
382 | needed.add(id); |
383 | } |
384 | } |
385 | print("Need " + n(needed, "snippet titles") + ": " + struct(needed)); |
386 | if (empty(needed)) ret; |
387 | getSnippetTitles_verbose = true; |
388 | SS titles = getSnippetTitles(needed); |
389 | print("Done!"); |
390 | for (Map m : l) { |
391 | S id = getString(m, "Program ID"); |
392 | if (eq(m.get("Title"), "?") && titles.containsKey(id)) { |
393 | S title = titles.get(id); |
394 | getSnippetTitle_cached_put(id, title); |
395 | m.put("Title", title); |
396 | } |
397 | } |
398 | } |
Began life as a copy of #1000825
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1006316 |
Snippet name: | JavaX Starter - Runnables search (dev.) |
Eternal ID of this version: | #1006316/3 |
Text MD5: | 5fbfa53ef208716c1b42144dcd4716e6 |
Transpilation MD5: | d2b0f3952ae127d7e0a06af716a2abe2 |
Author: | stefan |
Category: | javax |
Type: | JavaX source code |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2017-03-12 13:30:30 |
Source code size: | 11285 bytes / 398 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 610 / 709 |
Version history: | 2 change(s) |
Referenced in: | [show references] |