abstract sclass DynObjectTable extends DynModule {
new L data;
transient JTable table;
transient F1 itemToMap;
transient VF1 defaultAction;
transient bool debug;
start {
itemToMap = func(A a) -> Map {
a instanceof S ? litorderedmap("" := (S) a)
: humanizeKeys(objectToMap(a)) };
onChange(r updateTable);
}
JComponent visualize() {
table = dataToTable_uneditable(sexyTable(), map(itemToMap, data));
onDoubleClickOrEnter(table, voidfunc(int row) {
temp enter();
A a = _get(data, row);
if (a != null) onDoubleClick(a);
});
ret table;
}
void unvisualize() { table = null; }
void onDoubleClick(A line) { callF(defaultAction, line); }
void updateTable() {
temp enter();
if (table != null) {
dataToTable_uneditable(table, map(itemToMap, data));
if (debug) print("dataToTable done");
}
}
void dontPersist() { _persistenceInfo = mapPlus(_persistenceInfo, data := false); }
void clear() { syncClear(data); change(); }
void add(A a) { syncAdd(data, a); change(); }
void addAndScrollDown(A a) { add(a); scrollTableDownNow(table); }
void setData(Collection data) {
if (isFalse(mapGet(_persistenceInfo, 'data))) {
if (neq(this.data, data)) {
this.data = cloneList(data);
updateTable();
}
} else
setField(data := cloneList(data));
}
void setData_force(Collection data) {
this.data = null;
setData(data);
}
A selected() { ret syncGet(data, selectedTableRowInModel(table)); }
bool selectItem(A a) { int i = indexOf(data, a); selectRow(table, i); ret i >= 0; } // true if item exists
void doubleClickItem(A a) { if (selectItem(a)) onDoubleClick(a); }
// r : Runnable or VF1
// run only in visualize()!
void popupMenuItem(S text, O r) {
tablePopupMenuItemsThreaded(table, text, _convertRunnable(r));
}
void popupMenuItem_top(S text, O r) {
tablePopupMenuItemsThreaded_top(table, text, _convertRunnable(r));
}
// row index => element
O _convertRunnable(fO r) {
if (r == null || r instanceof Runnable) ret r;
ret voidfunc(int idx) { callF(r, syncGet(data, idx)) };
}
JTable table() { ret table; }
// API
L getData() { ret data; } // data is usually immutable
}