Libraryless. Click here for Pure Java version (25943L/171K).
sbool SimpleCRUD_searcher = true; sclass SimpleCRUD<A extends Concept> { Concepts concepts; Class<A> cc; JTable table; JPanel buttons, panel; O renderer; // optional, func(A) -> Map O sorter; // optional, func(Cl<Concept>) -> Cl<Concept> S hID = "ID"; Set<S> unshownFields; // not shown in table or form Set<S> excludeFieldsFromEditing; S modifiedField; // field to hold last-modified timestamp TableSearcher tableSearcher; Set<S> multiLineFields; // string fields that should be shown as text areas Set<S> dontDuplicateFields; bool latestFirst; int formFixer = 12; // stupid value to make submit button appear bool editOnDoubleClick = true; bool ensureIndexed; bool showValuesAsStruct; // BREAKING CHANGE - used to be true *(Class<A> cc) { this(db_mainConcepts(), cc); } *(Concepts *concepts, Class<A> *cc) {} SimpleCRUD<A> show(S frameTitle) { make(); showFrame(frameTitle, panel); this; } SimpleCRUD<A> show() { ret show(plural(shortClassName(cc))); } SimpleCRUD<A> showMaximized() { show(); maximizeFrame(panel); ret this; } JPanel makePanel() { ret make(); } JPanel make() { db(); framesBot(); ret make_dontStartBots(); } JPanel make_dontStartBots() { printVars("SimpleCRUD.make_dontStartBots", +concepts, +cc, count := countConcepts(cc)); if (ensureIndexed) indexConceptClass(concepts, cc); // next line not in swing part to allow passing arguments // from outside like showConceptsTable_afterUpdate temp tempSetTL(showConceptsTable_concepts, concepts); temp tempSetTL(showConceptsTable_latestFirst, latestFirst); temp tempSetTL(showConceptsTable_sorter, sorter); temp tempSetTL(showConceptsTable_dropFields, asList(unshownFields)); temp tempSetTL(dataToTable_useStruct, showValuesAsStruct); table = makeConceptsTable(cc, wrapRenderer(renderer)); swing { buttons = jRightAlignedLine( jbutton("Add...", r { newConcept() }), tableDependButton(table, jbutton("Edit", r { editConcept(selectedConcept()) })), tableDependButton(table, jbutton("Delete", r { final L<A> l = selectedConcepts(); thread "Delete concepts" { withDBLock(concepts, r { for (A c : l) c.delete() }); } })), tableDependButton(table, jbutton("Duplicate...", r { duplicateConcept(selectedConcept()) }))); if (SimpleCRUD_searcher) { tableSearcher = tableWithSearcher2(table, withMargin := true); panel = centerAndSouthWithMargin(tableSearcher.panel, withBottomMargin(buttons)); } else panel = centerAndSouthWithMargin(table, withBottomMargin(buttons)); O fEdit = voidfunc(int row) { editConcept(conceptForRow(row)) }; tablePopupMenuItem(table, "Edit...", fEdit); if (editOnDoubleClick) 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 { duplicateConcept(null); } void duplicateConcept(A oldConcept) { final A c = unlisted(cc); ccopyFieldsExcept(oldConcept, c, dontDuplicateFields); final Map<S, JComponent> map = makeComponents(c); Runnable r = r { concepts.register(c); saveData(c, map); }; temp tempSetMCOpt(formLayouter1_fixer2 := formFixer); showFormTitled2("New " + shortClassName(cc), arrayPlus(mapToObjectArray(map), r)); } void editConcept(final A c) { if (c == null) ret; final Map<S, JComponent> map = makeComponents(c); Runnable r = r { saveData(c, map) }; temp tempSetMCOpt(formLayouter1_fixer2 := formFixer); showFormTitled2("Edit " + shortClassName(cc) + " #" + c.id, arrayPlus(mapToObjectArray(map), r)); } A selected aka selectedConcept() { ret conceptForRow(selectedRow(table)); } A conceptForRow(int row) { ret (A) concepts.getConcept(toLong(getTableCell(table, row, 0))); } int indexOfConcept(final A c) { if (c == null) ret -1; ret swing(func -> int { int n = tableRowCount(table); for row to n: if (toLong(getTableCell(table, row, 0)) == c.id) ret row; ret -1; }); } L<A> selectedConcepts() { ret swing(() -> { int[] rows = table?.getSelectedRows(); new L<A> l; fOr (int row : rows) l.add(conceptForRow(row)); ret l; }); } Map<S, JComponent> makeComponents(A c) { Map<S, JComponent> 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 if (contains(multiLineFields, field) || containsNewLines(optCast S(value))) ret typeWriterTextArea((S) value); else if (isSubtype(type, Concept)) ret jcomboboxFromConcepts_str(concepts, type, (Concept) value); ifclass SecretValue else if (type == SecretValue.class) ret jpassword(strOrEmpty(getVar(value/SecretValue))); endif else try { ret autoComboBox(valueToString(value), new TreeSet<S>(map valueToString(collect(list(concepts, cc), field)))); } catch e { printException(e); ret jTextField(valueToString(value)); } } void saveComponent(A c, S field, JComponent comp) { comp = unwrap(comp); Class type = fieldType(c, field); ifclass SecretValue if (type == SecretValue.class) { S text = getTextTrim((JPasswordField) comp); cset(c, field, empty(text) ? null : SecretValue(text)); } else endif if (comp instanceof JTextComponent) cset(c, field, convertToField(trimIf(!comp instanceof JTextArea, getText((JTextComponent) comp)), cc, field)); else if (comp cast JComboBox) { S text = getTextTrim(comp); if (isSubtype(type, Concept)) cset(c, field, getConcept(concepts, parseFirstLong(text))); else cset(c, field, convertToField(text, cc, field)); } else if (comp instanceof JCheckBox) cset(c, field, isChecked((JCheckBox) comp)); ifclass ImageChooser else if (comp instanceof ImageChooser) cUpdatePNGFile(c, field, comp/ImageChooser.getImage(), false); endif } L<S> fields() { if (excludeFieldsFromEditing != null && modifiedField != null) excludeFieldsFromEditing.add(modifiedField); ret listWithoutSet([S field : conceptFieldsInOrder(cc) | fieldType(cc, field) != Concept.Ref.class], joinSets(excludeFieldsFromEditing, unshownFields)); } void excludeFieldsFromEditing(S... fields) { excludeFieldsFromEditing = setPlus(excludeFieldsFromEditing, fields); } // override the following two methods to customize edit window void makeComponents(A c, Map<S, JComponent> map) { for (S field : fields()) map.put(field, fieldComponent(c, field)); } void saveData(A c, Map<S, JComponent> components) { for (S field : keys(components)) saveComponent(c, field, components.get(field)); if (modifiedField != null) cset(c, modifiedField, now()); } JTable table() { ret table; } swappable S valueToString(O o) { ret showValuesAsStruct ? structureOrText_crud(o) : strOrNull(o); } } // end of SimpleCRUD
Ref<PNGFile> fields can be saved, but are not shown automatically
download show line numbers debug dex old transpilations
Travelled to 16 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1006540 |
Snippet name: | SimpleCRUD - create/read/update/delete for a concept class with simple fields [Swing] |
Eternal ID of this version: | #1006540/99 |
Text MD5: | 8b2fd8c89a872f145d98fef41bfaea1b |
Transpilation MD5: | a5d4304b3c919484906283274b0b3454 |
Author: | stefan |
Category: | javax / concepts / gui |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-09-12 04:28:18 |
Source code size: | 7766 bytes / 230 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 1064 / 2284 |
Version history: | 98 change(s) |
Referenced in: | #1019417 - dm_SimpleCRUD [dev.] - create/read/update/delete for a list in a dynamic module #1019715 - SimpleCRUD - older version #1030726 - SimpleCRUD_v2 - create/read/update/delete for a concept class with simple fields [Swing] #1034167 - Standard Classes + Interfaces (LIVE, continuation of #1003674) |