sclass JConceptsTable { Class conceptClass; Concepts concepts; JTable table; // options L dropFields; IF1 postProcess; Runnable afterUpdate; bool latestFirst; IF1> sorter; int idWidth = 50; int updateInterval = 1000; *() {} *(Class *conceptClass) {} *(Concepts *concepts, Class *conceptClass) {} swappable MapSO itemToMap(A a) { ret mapValues renderForTable_noStruct(allConceptFieldsAsMap(a)); } S defaultTitle() { ret plural(shortClassName(conceptClass)); } void showAsFrame(S title default defaultTitle()) { makeTable(); showFrame(title, table); } void makeTable { if (table != null) ret; if (concepts == null) concepts = db_mainConcepts(); table = sexyTable(); awtOnConceptChanges(table, updateInterval, r { new L data; Cl l = list(concepts, conceptClass); l = postProcess(sorter, l); for (A c : l) addIfNotNull(data, itemToMap(c)); if (latestFirst) reverseInPlace(data); data = (L) postProcess(postProcess, data); dataToTable_uneditable(data, table); pcallF(afterUpdate); }); } JComponent visualize() { makeTable(); ret table; } }