abstract sclass DynObjectTable extends DynModule {
new L data;
transient JTable table;
transient F1 itemToMap;
transient VF1 defaultAction;
transient bool debug, fieldsInOrder = true, withSearcher;
transient TableSearcher searcher;
transient L onListChanged;
transient Set hideFields;
start {
itemToMap = func(A a) -> Map {
a instanceof S ? litorderedmap("" := (S) a)
: humanizeKeys(fieldsInOrder ? objectToMap_inOrder_withoutFields(a, hideFields) : objectToMap(a)) };
onChange(r updateTable);
}
void addCountToName {
onListChanged = addDyn_sync(onListChanged, r addCountToNameNow);
addCountToNameNow();
}
void addCountToNameNow() enter {
setModuleName(programTitle() + " (" + count() + ")");
}
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);
});
if (withSearcher)
ret (searcher = tableWithSearcher2(table)).panel;
ret table;
}
void unvisualize() { super.unvisualize(); searcher = null; }
void onDoubleClick(A line) { callF(defaultAction, line); }
void updateTable() enter {
if (table != null) swing {
Point scrollPosition = enclosingViewPosition(table);
if (debug) print("Scroll position: " + scrollPosition);
dataToTable_uneditable(table, map(itemToMap, data));
setEnclosingViewPosition(table, scrollPosition);
if (searcher != null) searcher.rowIndices = null;
if (debug) print("dataToTable done, alerting " + n2(onListChanged, "listener"));
}
pcallFAll(onListChanged);
}
/*TODO void itemChanged(int row, A entry) {
if (getRow(row) != entry) {
fireDataChanged();
warn("Item index mismatch, recreating table");
}
rows.add(dataToTable_makeRow(x, cols));
}*/
void dontPersist() { _persistenceInfo = mapPlus(_persistenceInfo, data := false); }
void clear() { syncClear(data); fireDataChanged(); }
void add(A a) { syncAdd(data, a); fireDataChanged(); }
void add(int idx, A a) { syncAdd(data, idx, a); fireDataChanged(); }
void addAll(Collection l) { if (empty(l)) ret; syncAddAll(data, l); fireDataChanged(); }
void addAndScrollDown(A a) { add(a); scrollTableDownNow(table); }
void remove(A a) { syncRemove(data, a); fireDataChanged(); }
void removeAll(L a) { syncRemoveAll(data, a); fireDataChanged(); }
void setList(Collection data) { setData(data); }
void removeSelected() { removeAll(allSelected()); }
void setData(Collection data) {
setData(data, false);
}
void setData(Collection data, bool force) {
swingIf(table != null, r {
//int selection = selectedIndex();
int[] selection = selectedTableRows_array(table);
if (isFalse(mapGet(_persistenceInfo, 'data))) {
if (force || neq(DynObjectTable.this.data, data)) {
DynObjectTable.this.data = cloneList(data);
updateTable();
}
} else {
setField(data := cloneList(data));
if (force) _change();
}
//selectRow(table, selection);
selectTableRows(table, selection);
});
}
int count() { ret syncL(data); }
void setData_force(Collection data) {
setData(data, true);
}
// tries to keep selection
void fireDataChanged() {
setData_force(data);
}
int rowFromSearcher(int i) {
ret searcher == null || searcher.rowIndices == null ? i : or(get(searcher.rowIndices, i), -1);
}
A selected() { ret syncGet(data, rowFromSearcher(selectedTableRowInModel(table))); }
L allSelected() { ret syncListGetMulti(data, selectedIndices()); }
int selectedIndex() { ret selectedTableRow(table); }
L selectedIndices() { ret map(i -> rowFromSearcher(i), selectedTableRowsInModel(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; }
void hideFields(S... fields) {
if (hideFields == null) hideFields = new Set;
_addAll(hideFields, fields);
}
A getRow(int row) { ret get(data, row); }
// API
L getData() { ret data; } // data is usually immutable
L data() { ret getData(); }
L list() { ret getData(); }
L getList() { ret getData(); }
L clonedList() { ret cloneList(data); }
}