Libraryless. Click here for Pure Java version (18564L/137K).
1 | abstract sclass DynObjectTable<A> extends DynModule { |
2 | new L<A> data; |
3 | |
4 | transient JTable table; |
5 | transient F1<A, Map> itemToMap; |
6 | transient VF1<A> defaultAction; |
7 | transient bool debug, fieldsInOrder = true, withSearcher; |
8 | transient TableSearcher searcher; |
9 | transient L onListChanged; |
10 | transient Set<S> hideFields; |
11 | transient bool useStruct = false; // possible breaking change for older modules |
12 | |
13 | start { |
14 | itemToMap = func(A a) -> Map { |
15 | if (a instanceof S) ret litorderedmap("" := (S) a); |
16 | Map map = humanizeKeys(fieldsInOrder ? objectToMap_inOrder_withoutFields(a, hideFields) : objectToMap(a)); |
17 | if (!useStruct) map = mapValues strOrEmpty(map); |
18 | ret map; |
19 | }; |
20 | onChange(r updateTable); |
21 | } |
22 | |
23 | void onListChanged(Runnable r) { |
24 | if (r == null) ret; |
25 | onListChanged = addDyn_sync(onListChanged, r); |
26 | } |
27 | |
28 | void onListChangedAndNow(Runnable r) { |
29 | if (r == null) ret; |
30 | onListChanged(r); |
31 | r.run(); |
32 | } |
33 | |
34 | void addCountToName { |
35 | onListChangedAndNow(r addCountToNameNow); |
36 | } |
37 | |
38 | void addCountToNameNow() enter { |
39 | setModuleName(programTitle() + " (" + count() + ")"); |
40 | } |
41 | |
42 | visualize { |
43 | L<Map> l = map(itemToMap, data); |
44 | table = dataToTable_uneditable(sexyTable(), l); |
45 | onDoubleClickOrEnter(table, voidfunc(int row) { |
46 | temp enter(); |
47 | A a = _get(data, row); |
48 | if (a != null) onDoubleClick(a); |
49 | }); |
50 | if (withSearcher) |
51 | ret (searcher = tableWithSearcher2(table)).panel; |
52 | ret table; |
53 | } |
54 | |
55 | void unvisualize() { super.unvisualize(); searcher = null; } |
56 | |
57 | void onDoubleClick(A line) { callF(defaultAction, line); } |
58 | |
59 | void updateTable() enter { |
60 | if (table != null) swing { |
61 | Point scrollPosition = enclosingViewPosition(table); |
62 | if (debug) print("Scroll position: " + scrollPosition); |
63 | dataToTable_uneditable(table, map(itemToMap, data)); |
64 | setEnclosingViewPosition(table, scrollPosition); |
65 | if (searcher != null) searcher.rowIndices = null; |
66 | if (debug) print("dataToTable done, alerting " + n2(onListChanged, "listener")); |
67 | } |
68 | pcallFAll(onListChanged); |
69 | } |
70 | |
71 | /*TODO void itemChanged(int row, A entry) { |
72 | if (getRow(row) != entry) { |
73 | fireDataChanged(); |
74 | warn("Item index mismatch, recreating table"); |
75 | } |
76 | rows.add(dataToTable_makeRow(x, cols)); |
77 | }*/ |
78 | |
79 | void dontPersist() { _persistenceInfo = mapPlus(_persistenceInfo, data := false); } |
80 | |
81 | void clear() { syncClear(data); fireDataChanged(); } |
82 | void add(A a) { syncAdd(data, a); fireDataChanged(); } |
83 | A addAndReturn(A a) { add(a); ret a; } |
84 | void add(int idx, A a) { syncAdd(data, idx, a); fireDataChanged(); } |
85 | void addAll(Collection<A> l) { if (empty(l)) ret; syncAddAll(data, l); fireDataChanged(); } |
86 | void addAndScrollDown(A a) { add(a); scrollDown(); } |
87 | void remove(A a) { syncRemove(data, a); fireDataChanged(); } |
88 | void removeAll(L<A> a) { syncRemoveAll(data, a); fireDataChanged(); } |
89 | void setList(Iterable<A> data) { setData(data); } |
90 | void removeSelected() { removeAll(allSelected()); } |
91 | |
92 | // rare legacy binary compatibility workaround |
93 | void setData(Collection<A> data) { setData((Iterable) data); } |
94 | |
95 | void setData(Iterable<A> data) { |
96 | setData(data, false); |
97 | } |
98 | |
99 | void setData(Iterable<A> data, bool force) { |
100 | // ATTN: new logic. test if it works in all cases |
101 | swing { |
102 | //int selection = selectedIndex(); |
103 | int[] selection = selectedTableRows_array(table); |
104 | L<A> cloned = cloneList(data); |
105 | if (setField(data := cloned) || force) { |
106 | updateTable(); |
107 | dm_vmBus_send listChanged(module(), cloned); |
108 | } |
109 | if (force) change(); |
110 | //selectRow(table, selection); |
111 | selectTableRows(table, selection); |
112 | } |
113 | } |
114 | int count() { ret syncL(data); } |
115 | |
116 | void setData_force(Collection<A> data) { |
117 | setData(data, true); |
118 | } |
119 | |
120 | // tries to keep selection |
121 | void fireDataChanged() { |
122 | setData_force(data); |
123 | } |
124 | |
125 | int rowFromSearcher(int i) { |
126 | ret searcher == null || searcher.rowIndices == null ? i : or(get(searcher.rowIndices, i), -1); |
127 | } |
128 | |
129 | A selected() { ret syncGet(data, rowFromSearcher(selectedTableRowInModel(table))); } |
130 | L<A> allSelected() { ret syncListGetMulti(data, selectedIndices()); } |
131 | int selectedIndex() { ret selectedTableRow(table); } |
132 | L<Int> selectedIndices() { ret map(i -> rowFromSearcher(i), selectedTableRowsInModel(table)); } |
133 | bool selectItem(A a) { int i = indexOf(data, a); selectRow(table, i); ret i >= 0; } // true if item exists |
134 | void doubleClickItem(A a) { if (selectItem(a)) onDoubleClick(a); } |
135 | |
136 | // r : Runnable or VF1<A> |
137 | // run only in visualize()! |
138 | void popupMenuItem(S text, O r) { |
139 | tablePopupMenuItemsThreaded(table, text, _convertRunnable(r)); |
140 | } |
141 | |
142 | void popupMenuItem_top(S text, O r) { |
143 | tablePopupMenuItemsThreaded_top(table, text, _convertRunnable(r)); |
144 | } |
145 | |
146 | // row index => element |
147 | O _convertRunnable(fO r) { |
148 | if (r == null || r instanceof Runnable) ret r; |
149 | ret voidfunc(int idx) { callF(r, syncGet(data, idx)) }; |
150 | } |
151 | |
152 | JTable table() { ret table; } |
153 | |
154 | void hideFields(S... fields) { |
155 | if (hideFields == null) hideFields = new Set; |
156 | _addAll(hideFields, fields); |
157 | } |
158 | |
159 | A getRow(int row) { ret get(data, row); } |
160 | |
161 | void scrollDown { scrollTableDownNow(table); } |
162 | |
163 | // API |
164 | |
165 | L<A> getData() { ret data; } // data is usually immutable |
166 | L<A> data() { ret getData(); } |
167 | L<A> list() { ret getData(); } |
168 | L<A> getList() { ret getData(); } |
169 | |
170 | L<A> clonedList() { ret cloneList(data); } |
171 | |
172 | // log list (and whole module) contents somewhere |
173 | File quickBackup() { |
174 | File f = programFile("backup-" + ymd_minus_hms_minus_millis() + ".gz"); |
175 | saveGZStructToFile(f, module()); |
176 | printFileInfo(f); |
177 | ret f; |
178 | } |
179 | } |
Began life as a copy of #1016065
download show line numbers debug dex old transpilations
Travelled to 17 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mowyntqkapby, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1016978 |
Snippet name: | DynObjectTable |
Eternal ID of this version: | #1016978/103 |
Text MD5: | d8131ca27ae01e29848f4e709418605d |
Transpilation MD5: | c27c69b550539575ccd06bd16aaa64ea |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2020-02-21 13:32:58 |
Source code size: | 5878 bytes / 179 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 890 / 4050 |
Version history: | 102 change(s) |
Referenced in: | [show references] |