Libraryless. Click here for Pure Java version (30096L/193K).
1 | sclass JConceptsTable<A extends Concept> is Swingable {
|
2 | Class<? extends A> conceptClass; |
3 | Concepts concepts; |
4 | JTable table; |
5 | |
6 | // options |
7 | MapSO filters; // fields to filter by/add to new objects |
8 | S hID = "ID"; // Column header for concept ID |
9 | settable LS dropFields; |
10 | settable bool noSubclasses; |
11 | IF1<L> postProcess; |
12 | Runnable afterUpdate; |
13 | bool latestFirst; |
14 | IF1<Cl<A>> sorter = lambda1 defaultSort; |
15 | int idWidth = 50; |
16 | settable int updateInterval = 100; |
17 | int firstUpdateInterval = 100; |
18 | bool humanizeFieldNames = true; |
19 | Float tableFontSize; |
20 | Int tableRowHeight; |
21 | settable bool addCountToEnclosingTab; |
22 | settable bool useNewChangeHandler; |
23 | settable IVF1<A> defaultAction; |
24 | bool pauseUpdates; |
25 | int count; |
26 | |
27 | event selectionChanged; |
28 | event singleSelectionChanged; |
29 | |
30 | // internal |
31 | AWTOnConceptChanges changeHandler; |
32 | AWTOnConceptChangesByClass newChangeHandler; |
33 | bool updatingList; |
34 | settable A selectAfterUpdate; |
35 | A lastSelected; |
36 | |
37 | *() {}
|
38 | *(Class<? extends A> *conceptClass) {}
|
39 | *(Concepts *concepts, Class<? extends A> *conceptClass) {}
|
40 | |
41 | swappable MapSO itemToMap(A a) {
|
42 | MapSO map = specialFieldsForItem(a); |
43 | try {
|
44 | putAll(map, mapValues renderValue(itemToMap_inner2(a))); |
45 | } catch print e {
|
46 | map.put("Error", str(e));
|
47 | } |
48 | ret map; |
49 | } |
50 | |
51 | swappable O renderValue(O o) {
|
52 | ret renderForTable_noStruct(o); |
53 | } |
54 | |
55 | swappable MapSO itemToMap_inner2(A a) {
|
56 | ret allConceptFieldsAsMapExcept(a, dropFields); |
57 | } |
58 | |
59 | // shown on the left (usually) |
60 | swappable MapSO specialFieldsForItem(A a) {
|
61 | MapSO map = litorderedmap(hID, str(a.id)); |
62 | mapPut(map, "Java Class", javaClassDescForItem(a)); |
63 | ret map; |
64 | } |
65 | |
66 | S javaClassDescForItem(A a) {
|
67 | S className = dynShortClassName(a); |
68 | if (neq(className, shortClassName(conceptClass))) {
|
69 | S text = className; |
70 | S realClass = shortClassName(a); |
71 | if (neq(className, realClass)) |
72 | text += " as " + realClass; |
73 | ret text; |
74 | } |
75 | null; |
76 | } |
77 | |
78 | S defaultTitle() {
|
79 | ret plural(shortClassName(conceptClass)); |
80 | } |
81 | |
82 | void showAsFrame(S title default defaultTitle()) {
|
83 | makeTable(); |
84 | showFrame(title, table); |
85 | } |
86 | |
87 | void makeTable {
|
88 | if (table != null) ret; |
89 | if (concepts == null) concepts = db_mainConcepts(); |
90 | |
91 | table = sexyTable(); |
92 | if (tableFontSize != null) {
|
93 | setTableFontSizes(tableFontSize, table); |
94 | if (tableRowHeight == null) |
95 | tableRowHeight = iround(tableFontSize*1.5); |
96 | } |
97 | if (tableRowHeight != null) setRowHeight(table, tableRowHeight); |
98 | |
99 | if (useNewChangeHandler) {
|
100 | newChangeHandler = new AWTOnConceptChangesByClass(concepts, conceptClass, table, l0 _update) |
101 | .delay(updateInterval) |
102 | .firstDelay(firstUpdateInterval); |
103 | newChangeHandler.install(); |
104 | } else {
|
105 | changeHandler = new AWTOnConceptChanges(concepts, table, l0 _update) |
106 | .delay(updateInterval) |
107 | .firstDelay(firstUpdateInterval); |
108 | changeHandler.install(); |
109 | } |
110 | |
111 | onTableSelectionChanged(table, -> {
|
112 | if (updatingList) ret; |
113 | selectionChanged(); |
114 | }); |
115 | |
116 | onSelectionChanged(-> {
|
117 | var a = selected(); |
118 | if (a != lastSelected) {
|
119 | lastSelected = a; |
120 | singleSelectionChanged(); |
121 | } |
122 | }); |
123 | |
124 | onDoubleClickOrEnter(table, -> {
|
125 | A a = selected(); |
126 | if (a != null && defaultAction != null) |
127 | pcallF(defaultAction, a); |
128 | }); |
129 | } |
130 | |
131 | // e.g. to update enclosing tab when hidden |
132 | void update {
|
133 | swing { _update(); }
|
134 | } |
135 | |
136 | // run in Swing thread |
137 | void _update {
|
138 | if (table == null || pauseUpdates) ret; |
139 | set updatingList; |
140 | bool allRestored; |
141 | A selectAfterUpdate = selectAfterUpdate(); |
142 | |
143 | try {
|
144 | new L<Map> data; |
145 | |
146 | Set<Long> selection; |
147 | if (selectAfterUpdate != null) {
|
148 | selection = litset(selectAfterUpdate._conceptID()); |
149 | selectAfterUpdate(null); |
150 | } else |
151 | selection = toSet(selectedConceptIDs()); |
152 | |
153 | Cl<? extends A> l = conceptsWhere(concepts, conceptClass, mapToParams(filters)); |
154 | if (noSubclasses) l = filter(l, x -> x.getClass() == conceptClass); |
155 | l = postProcess(sorter, l); |
156 | for (A c : l) |
157 | addIfNotNull(data, itemToMap(c)); |
158 | if (latestFirst) reverseInPlace(data); |
159 | data = (L) postProcess(postProcess, data); |
160 | count = l(data); |
161 | dataToTable_uneditable(data, table); |
162 | if (humanizeFieldNames) |
163 | humanizeTableColumns(); |
164 | tableColumnMaxWidth(table, 0, idWidth); |
165 | |
166 | allRestored = restoreSelection(selection); |
167 | |
168 | if (addCountToEnclosingTab) |
169 | updateEnclosingTabTitle(); |
170 | } finally {
|
171 | updatingList = false; |
172 | } |
173 | |
174 | pcallF(afterUpdate); |
175 | |
176 | if (!allRestored || selectAfterUpdate != null) |
177 | selectionChanged(); |
178 | } |
179 | |
180 | void updateEnclosingTabTitle {
|
181 | updateEnclosingTabTitleWithCount(table, count); |
182 | } |
183 | |
184 | void humanizeTableColumns {
|
185 | int n = tableColumnCount(table); |
186 | for i to n: |
187 | setColumnName(table, i, humanizeFormLabel(getColumnName(table, i))); |
188 | }; |
189 | |
190 | visual table(); |
191 | |
192 | JTable table() {
|
193 | makeTable(); |
194 | ret table; |
195 | } |
196 | |
197 | A selectedConcept() {
|
198 | ret (A) concepts.getConcept(toLong(selectedTableCell(table, 0))); |
199 | } |
200 | |
201 | A selected() { ret selectedConcept(); }
|
202 | |
203 | long getItemID(int row) {
|
204 | ret toLong(getTableCell(table, row, 0)); |
205 | } |
206 | |
207 | L<A> getList() swing {
|
208 | ret countIteratorAsList(size(), row -> getItem(row)); |
209 | } |
210 | |
211 | A getItem(int row) {
|
212 | ret (A) concepts.getConcept(getItemID(row)); |
213 | } |
214 | |
215 | int size() { ret tableRowCount(table); }
|
216 | |
217 | int indexOfConcept(final A c) {
|
218 | if (c == null) ret -1; |
219 | ret swing(func -> int {
|
220 | int n = size(); |
221 | for row to n: |
222 | if (toLong(getTableCell(table, row, 0)) == c.id) |
223 | ret row; |
224 | ret -1; |
225 | }); |
226 | } |
227 | |
228 | L<A> selectedConcepts() {
|
229 | ret swing(-> {
|
230 | int[] rows = table.getSelectedRows(); |
231 | new L<A> l; |
232 | for (int row : rows) |
233 | l.add(getItem(row)); |
234 | ret l; |
235 | }); |
236 | } |
237 | |
238 | L<Long> selectedConceptIDs() {
|
239 | ret swing(-> {
|
240 | int[] rows = table.getSelectedRows(); |
241 | L<Long> l = emptyList(l(rows)); |
242 | for (int row : rows) |
243 | l.add(getItemID(row)); |
244 | ret l; |
245 | }); |
246 | } |
247 | |
248 | // returns true if all selected items still exist |
249 | bool restoreSelection(Set<Long> selection) {
|
250 | ret swing(-> {
|
251 | int n = size(); |
252 | new IntBuffer toSelect; |
253 | for row to n: |
254 | if (selection.contains(getItemID(row))) |
255 | toSelect.add(row); |
256 | selectTableRows(table, toSelect.toIntArray()); |
257 | ret toSelect.size() == selection.size(); |
258 | }); |
259 | } |
260 | |
261 | void setSelected(A a) {
|
262 | selectRow(table(), indexOfConcept(a)); |
263 | } |
264 | |
265 | Cl<A> defaultSort(Cl<A> l) {
|
266 | ret sortByConceptID(l); |
267 | } |
268 | |
269 | selfType addFilter(S field, O value) {
|
270 | filters = orderedMapPutOrCreate(filters, field, value); |
271 | this; |
272 | } |
273 | |
274 | void onSelectionChangedAndWhenShowing(Runnable r) {
|
275 | bindToComponent(table(), r); |
276 | onSelectionChanged(r); |
277 | } |
278 | |
279 | void onSelectionChangedAndNow(Runnable r) {
|
280 | if (r == null) ret; |
281 | onSelectionChanged(r); |
282 | r.run(); |
283 | } |
284 | |
285 | selfType updateInterval(double seconds) {
|
286 | ret updateInterval(toMS_int(seconds)); |
287 | } |
288 | |
289 | selfType pauseUpdates(bool b) {
|
290 | swing {
|
291 | if (pauseUpdates != b) {
|
292 | if (!(pauseUpdates = b)) |
293 | _update(); |
294 | } |
295 | } |
296 | this; |
297 | } |
298 | } |
Began life as a copy of #1006009
download show line numbers debug dex old transpilations
Travelled to 5 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt
No comments. add comment
| Snippet ID: | #1030725 |
| Snippet name: | JConceptsTable - new version of showConceptsTable |
| Eternal ID of this version: | #1030725/76 |
| Text MD5: | 0a61293494dec29dee23d130b6d6b4c8 |
| Transpilation MD5: | e4b404ad5e5c1dd7f30581e04988d005 |
| Author: | stefan |
| Category: | javax / gui / concepts |
| Type: | JavaX fragment (include) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2023-01-17 18:40:16 |
| Source code size: | 7632 bytes / 298 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 778 / 1433 |
| Version history: | 75 change(s) |
| Referenced in: | [show references] |