sbool dm_SimpleCRUD_searcher = true;
sclass dm_SimpleCRUD {
DynModule module;
L theList;
Class cc;
JTable table;
JPanel buttons, panel;
O renderer; // optional, func(A) -> Map
S hID = "ID";
LS fields;
*(DynModule *module, L *theList, Class *cc) {}
JPanel make() {
// next line not in swing part to allow passing arguments
// from outside like showConceptsTable_afterUpdate
table = makeConceptsTable(cc, wrapRenderer(renderer));
swing {
panel = centerAndSouth(SimpleCRUD_searcher ? tableWithSearcher(table) : table, buttons = jRightAlignedLine(
jbutton("Add...", r { newConcept() }),
tableDependButton(table, jbutton("Edit", r {
editConcept(selectedConcept())
})),
tableDependButton(table, jbutton("Delete", r {
final L l = selectedConcepts();
withDBLock(r { for (A c : l) c.delete() });
}))));
O fEdit = voidfunc(int row) {
editConcept((A) getConcept(toLong(getTableCell(table, row, 0))))
};
tablePopupMenuItem(table, "Edit...", fEdit);
onDoubleClick(table, fEdit);
}
ret panel;
}
O wrapRenderer(fO renderer) {
ret renderer == null ? null : func(A a) {
putAll(litorderedmap(hID, str(a.id)), (Map) callF(renderer, a))
};
}
void newConcept {
final A c = nu(cc);
final Map map = makeComponents(c);
Runnable r = r {
saveData(c, map);
theList.add(c); module.change();
};
showFormTitled("New " + shortClassName(cc), arrayPlus(mapToObjectArray(map), r));
}
void editConcept(final A c) {
if (c == null) ret;
final Map map = makeComponents(c);
Runnable r = r { saveData(c, map); module.change(); };
showFormTitled("Edit " + shortClassName(cc) + " #" + c.id, arrayPlus(mapToObjectArray(map), r));
}
A selectedConcept() {
ret (A) getConcept(toLong(selectedTableCell(table, 0)));
}
L selectedConcepts() {
int[] rows = table.getSelectedRows();
new L l;
for (int row : rows)
l.add((A) getConcept(toLong(getTableCell(table, row, 0))));
ret l;
}
Map makeComponents(A c) {
Map map = litorderedmap();
makeComponents(c, map);
ret map;
}
JComponent fieldComponent(A c, S field) {
Class type = getFieldType(cc, field);
O value = getOpt(c, field);
//print("Field type: " + field + " => " + type);
if (type == bool.class)
ret jCenteredCheckBox(isTrue(value));
else try {
ret autoComboBox(structureOrText_crud(value), new TreeSet(map structureOrText_crud(collect(list(cc), field))));
} catch e {
printException(e);
ret jTextField(structureOrText_crud(value));
}
}
void saveComponent(A c, S field, JComponent comp) {
comp = unwrap(comp);
if (comp instanceof JTextComponent)
setOpt(c, field, convertToField(getTextTrim((JTextComponent) comp), cc, field));
else if (comp instanceof JComboBox)
setOpt(c, field, convertToField(getTextTrim((JComboBox) comp), cc, field));
else if (comp instanceof JCheckBox)
setOpt(c, field, isChecked((JCheckBox) comp));
/*ifclass ImageChooser
else if (comp instanceof ImageChooser)
cUpdatePNGFile(c, field, comp/ImageChooser.getImage(), false);
endif*/
}
L fields() {
if (fields != null) ret fields;
ret fieldsInOrder(cc);
}
// override the following two methods to customize edit window
void makeComponents(A c, Map map) {
for (S field : fields())
map.put(field, fieldComponent(c, field));
}
void saveData(A c, Map components) {
for (S field : keys(components))
saveComponent(c, field, components.get(field));
}
}