Libraryless. Click here for Pure Java version (21444L/150K).
1 | sbool SimpleCRUD_searcher = true; |
2 | |
3 | sclass SimpleCRUD_v2<A extends Concept> extends JConceptsTable<A> { |
4 | JPanel buttons, panel; |
5 | S hID = "ID"; // Column header for concept ID |
6 | Set<S> unshownFields; // not shown in table or form |
7 | Set<S> excludeFieldsFromEditing; |
8 | S modifiedField; // field to hold last-modified timestamp |
9 | TableSearcher tableSearcher; |
10 | Set<S> multiLineFields; // string fields that should be shown as text areas |
11 | Set<S> dontDuplicateFields; |
12 | int formFixer = 12; // stupid value to make submit button appear |
13 | bool showBackRefs; |
14 | int maxRefsToShow = 3; |
15 | |
16 | *(Class<A> conceptClass) { super(conceptClass); } |
17 | *(Concepts concepts, Class<A> conceptClass) { super(concepts, conceptClass); } |
18 | |
19 | SimpleCRUD_v2<A> show(S frameTitle) { |
20 | make(); |
21 | showFrame(frameTitle, panel); |
22 | this; |
23 | } |
24 | |
25 | SimpleCRUD_v2<A> show() { |
26 | ret show(plural(shortClassName(conceptClass))); |
27 | } |
28 | |
29 | SimpleCRUD_v2<A> showMaximized() { show(); maximizeFrame(panel); ret this; } |
30 | |
31 | JPanel makePanel() { ret make(); } |
32 | JPanel make() { |
33 | db(); |
34 | framesBot(); |
35 | ret make_dontStartBots(); |
36 | } |
37 | |
38 | swappable MapSO itemToMap_inner(A a) { |
39 | ret super.itemToMap_base(a); |
40 | } |
41 | |
42 | MapSO itemToMap_base(A a) { |
43 | MapSO map = itemToMap_inner(a); |
44 | if (map == null) null; |
45 | ret putAll(putAll(specialFieldsForItem(a), map), moreSpecialFieldsForItem(a)); |
46 | } |
47 | |
48 | // shown on the left (usually) |
49 | swappable MapSO specialFieldsForItem(A a) { |
50 | MapSO map = litorderedmap(hID, str(a.id)); |
51 | mapPut(map, "Java Class", javaClassDescForItem(a)); |
52 | ret map; |
53 | } |
54 | |
55 | // shown on the right (usually) |
56 | swappable MapSO moreSpecialFieldsForItem(A a) { |
57 | MapSO map = litorderedmap(); |
58 | if (showBackRefs) { |
59 | Cl<Concept> refs = allBackRefs(a); |
60 | if (nempty(refs)) { |
61 | refs = sortedByConceptID(refs); |
62 | int more = l(refs)-maxRefsToShow; |
63 | map.put("Referenced by", |
64 | joinWithComma(takeFirst(maxRefsToShow, refs)) |
65 | + (more > 0 ? ", " + more + " more" : "")); |
66 | } |
67 | } |
68 | ret map; |
69 | } |
70 | |
71 | S javaClassDescForItem(A a) { |
72 | S className = dynShortClassName(a); |
73 | if (neq(className, shortClassName(conceptClass))) { |
74 | S text = className; |
75 | S realClass = shortClassName(a); |
76 | if (neq(className, realClass)) |
77 | text += " as " + realClass; |
78 | ret text; |
79 | } |
80 | null; |
81 | } |
82 | |
83 | JPanel make_dontStartBots() { |
84 | dropFields = asList(unshownFields); |
85 | makeTable(); |
86 | swing { |
87 | buttons = jRightAlignedLine( |
88 | jbutton("Add...", r { newConcept() }), |
89 | tableDependButton(table, jbutton("Edit", r { |
90 | editConcept(selectedConcept()) |
91 | })), |
92 | tableDependButton(table, jbutton("Delete", r { |
93 | final L<A> l = selectedConcepts(); |
94 | withDBLock(concepts, r { for (A c : l) c.delete() }); |
95 | })), |
96 | tableDependButton(table, jbutton("Duplicate...", r { |
97 | duplicateConcept(selectedConcept()) |
98 | }))); |
99 | |
100 | if (SimpleCRUD_searcher) { |
101 | tableSearcher = tableWithSearcher2(table, withMargin := true); |
102 | panel = centerAndSouthWithMargin(tableSearcher.panel, withBottomMargin(buttons)); |
103 | } else |
104 | panel = centerAndSouthWithMargin(table, withBottomMargin(buttons)); |
105 | |
106 | O fEdit = voidfunc(int row) { |
107 | editConcept(getItem(row)) |
108 | }; |
109 | tablePopupMenuItem(table, "Edit...", fEdit); |
110 | onDoubleClick(table, fEdit); |
111 | tablePopupMenuFirst(table, (menu, row) -> { |
112 | Concept c = getItem(row); |
113 | if (c != null) |
114 | addMenuItem(menu, "Delete " + quote(shorten(str(c))), rThread { |
115 | deleteConcept(c); |
116 | }); |
117 | }); |
118 | } // end of swing |
119 | ret panel; |
120 | } |
121 | |
122 | void newConcept { |
123 | duplicateConcept(null); |
124 | } |
125 | |
126 | void duplicateConcept(A oldConcept) { |
127 | final A c = unlisted(conceptClass); |
128 | ccopyFieldsExcept(oldConcept, c, dontDuplicateFields); |
129 | final Map<S, JComponent> map = makeComponents(c); |
130 | Runnable r = r { |
131 | concepts.register(c); |
132 | saveData(c, map); |
133 | }; |
134 | temp tempSetMCOpt(formLayouter1_fixer2 := formFixer); |
135 | showFormTitled2("New " + shortClassName(conceptClass), arrayPlus(mapToObjectArray(map), r)); |
136 | } |
137 | |
138 | void editConcept(final A c) { |
139 | if (c == null) ret; |
140 | final Map<S, JComponent> map = makeComponents(c); |
141 | Runnable r = r { saveData(c, map) }; |
142 | temp tempSetMCOpt(formLayouter1_fixer2 := formFixer); |
143 | showFormTitled2("Edit " + shortClassName(conceptClass) + " #" + c.id, arrayPlus(mapToObjectArray(map), r)); |
144 | } |
145 | |
146 | A selectedConcept() { |
147 | ret (A) concepts.getConcept(toLong(selectedTableCell(table, 0))); |
148 | } |
149 | |
150 | A selected() { ret selectedConcept(); } |
151 | |
152 | A getItem(int row) { |
153 | ret (A) concepts.getConcept(toLong(getTableCell(table, row, 0))); |
154 | } |
155 | |
156 | int indexOfConcept(final A c) { |
157 | if (c == null) ret -1; |
158 | ret swing(func -> int { |
159 | int n = tableRowCount(table); |
160 | for row to n: |
161 | if (toLong(getTableCell(table, row, 0)) == c.id) |
162 | ret row; |
163 | ret -1; |
164 | }); |
165 | } |
166 | |
167 | L<A> selectedConcepts() { |
168 | int[] rows = table.getSelectedRows(); |
169 | new L<A> l; |
170 | for (int row : rows) |
171 | l.add(getItem(row)); |
172 | ret l; |
173 | } |
174 | |
175 | Map<S, JComponent> makeComponents(A c) { |
176 | Map<S, JComponent> map = litorderedmap(); |
177 | makeComponents(c, map); |
178 | ret map; |
179 | } |
180 | |
181 | JComponent fieldComponent(A c, S field) { |
182 | Class type = getFieldType(conceptClass, field); |
183 | O value = getOpt(c, field); |
184 | //print("Field type: " + field + " => " + type); |
185 | if (type == bool.class) |
186 | ret jCenteredCheckBox(isTrue(value)); |
187 | else if (contains(multiLineFields, field) || containsNewLines(optCast S(value))) |
188 | ret typeWriterTextArea((S) value); |
189 | else if (isSubtype(type, Concept)) |
190 | ret jcomboboxFromConcepts_str(concepts, type, (Concept) value); |
191 | ifclass SecretValue |
192 | else if (type == SecretValue.class) |
193 | ret jpassword(strOrEmpty(getVar(value/SecretValue))); |
194 | endif |
195 | else try { |
196 | ret autoComboBox(structureOrText_crud(value), new TreeSet<S>(map structureOrText_crud(collect(list(concepts, conceptClass), field)))); |
197 | } catch e { |
198 | printException(e); |
199 | ret jTextField(structureOrText_crud(value)); |
200 | } |
201 | } |
202 | |
203 | void saveComponent(A c, S field, JComponent comp) { |
204 | comp = unwrap(comp); |
205 | Class type = fieldType(c, field); |
206 | ifclass SecretValue |
207 | if (type == SecretValue.class) { |
208 | S text = getTextTrim((JPasswordField) comp); |
209 | cset(c, field, empty(text) ? null : SecretValue(text)); |
210 | } else |
211 | endif |
212 | if (comp instanceof JTextComponent) |
213 | cset(c, field, convertToField(trimIf(!comp instanceof JTextArea, getText((JTextComponent) comp)), conceptClass, field)); |
214 | else if (comp cast JComboBox) { |
215 | S text = getTextTrim(comp); |
216 | if (isSubtype(type, Concept)) |
217 | cset(c, field, getConcept(concepts, parseFirstLong(text))); |
218 | else |
219 | cset(c, field, convertToField(text, conceptClass, field)); |
220 | } else if (comp instanceof JCheckBox) |
221 | cset(c, field, isChecked((JCheckBox) comp)); |
222 | ifclass ImageChooser |
223 | else if (comp instanceof ImageChooser) |
224 | cUpdatePNGFile(c, field, comp/ImageChooser.getImage(), false); |
225 | endif |
226 | } |
227 | |
228 | L<S> fields() { |
229 | if (excludeFieldsFromEditing != null && modifiedField != null) excludeFieldsFromEditing.add(modifiedField); |
230 | ret listWithoutSet([S field : conceptFieldsInOrder(conceptClass) | fieldType(conceptClass, field) != Concept.Ref.class], |
231 | joinSets(excludeFieldsFromEditing, unshownFields)); |
232 | } |
233 | |
234 | void excludeFieldsFromEditing(S... fields) { |
235 | excludeFieldsFromEditing = setPlus(excludeFieldsFromEditing, fields); |
236 | } |
237 | |
238 | // override the following two methods to customize edit window |
239 | |
240 | void makeComponents(A c, Map<S, JComponent> map) { |
241 | for (S field : fields()) |
242 | map.put(field, fieldComponent(c, field)); |
243 | } |
244 | |
245 | void saveData(A c, Map<S, JComponent> components) { |
246 | for (S field : keys(components)) |
247 | saveComponent(c, field, components.get(field)); |
248 | if (modifiedField != null) cset(c, modifiedField, now()); |
249 | } |
250 | } |
Began life as a copy of #1030726
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt
No comments. add comment
Snippet ID: | #1030792 |
Snippet name: | SimpleCRUD_v2 [backup before dynamic fields] |
Eternal ID of this version: | #1030792/1 |
Text MD5: | 6d10e55d6b4076c1509ec1b5297f89c1 |
Transpilation MD5: | 98ca5325aa29889c8bc0862c10088ef8 |
Author: | stefan |
Category: | javax / concepts / gui |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-03-26 14:41:28 |
Source code size: | 8266 bytes / 250 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 152 / 217 |
Referenced in: | [show references] |