1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.moneywise.ui.base;
18
19 import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
20 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
21 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataNamedItem;
22 import io.github.tonywasher.joceanus.metis.list.MetisListKey;
23 import io.github.tonywasher.joceanus.metis.ui.MetisAction;
24 import io.github.tonywasher.joceanus.metis.ui.MetisErrorPanel;
25 import io.github.tonywasher.joceanus.metis.ui.MetisIcon;
26 import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
27 import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseCategoryBase;
28 import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
29 import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
30 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
31 import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataItem;
32 import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
33 import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
34 import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButton;
35 import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButtonFactory;
36 import io.github.tonywasher.joceanus.tethys.api.button.TethysUIScrollButtonManager;
37 import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControl.TethysUIIconMapSet;
38 import io.github.tonywasher.joceanus.tethys.api.control.TethysUILabel;
39 import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
40 import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollItem;
41 import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
42 import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBoxPaneManager;
43 import io.github.tonywasher.joceanus.tethys.api.table.TethysUITableManager;
44
45 import java.util.List;
46 import java.util.Objects;
47
48
49
50
51
52
53
54 public abstract class MoneyWiseCategoryTable<T extends MoneyWiseCategoryBase, S extends PrometheusStaticDataItem>
55 extends MoneyWiseBaseTable<T> {
56
57
58
59 private static final String TITLE_FILTER = MoneyWiseUIResource.CATEGORY_PROMPT_FILTER.getValue();
60
61
62
63
64 private static final String FILTER_PARENTS = MoneyWiseUIResource.CATEGORY_FILTER_PARENT.getValue();
65
66
67
68
69 private final TethysUIBoxPaneManager theFilterPanel;
70
71
72
73
74 private final TethysUIScrollButtonManager<T> theSelectButton;
75
76
77
78
79 private T theParent;
80
81
82
83
84
85
86
87
88
89
90 protected MoneyWiseCategoryTable(final MoneyWiseView pView,
91 final PrometheusEditSet pEditSet,
92 final MetisErrorPanel pError,
93 final Class<T> pClazz,
94 final MetisListKey pDataType) {
95
96 super(pView, pEditSet, pError, pDataType);
97
98
99 final TethysUIFactory<?> myGuiFactory = pView.getGuiFactory();
100 final TethysUITableManager<MetisDataFieldId, T> myTable = getTable();
101
102
103 final TethysUIButtonFactory<?> myButtons = myGuiFactory.buttonFactory();
104 final TethysUIButton myNewButton = myButtons.newButton();
105 MetisIcon.configureNewIconButton(myNewButton);
106
107
108 final TethysUILabel myPrompt = myGuiFactory.controlFactory().newLabel(TITLE_FILTER);
109 theSelectButton = myButtons.newScrollButton(pClazz);
110 theSelectButton.setValue(null, FILTER_PARENTS);
111
112
113 theFilterPanel = myGuiFactory.paneFactory().newHBoxPane();
114 theFilterPanel.addSpacer();
115 theFilterPanel.addNode(myPrompt);
116 theFilterPanel.addNode(theSelectButton);
117 theFilterPanel.addSpacer();
118 theFilterPanel.addNode(myNewButton);
119
120
121 myTable.setDisabled(MoneyWiseCategoryBase::isDisabled)
122 .setComparator(MoneyWiseCategoryBase::compareTo);
123
124
125 myTable.declareStringColumn(MoneyWiseBasicResource.CATEGORY_SUBCAT)
126 .setValidator(this::isValidName)
127 .setCellValueFactory(this::getShortName)
128 .setEditable(true)
129 .setColumnWidth(WIDTH_NAME)
130 .setOnCommit((r, v) -> updateField(MoneyWiseCategoryBase::setSubCategoryName, r, v));
131
132
133 myTable.declareStringColumn(PrometheusDataResource.DATAITEM_FIELD_NAME)
134 .setCellValueFactory(MoneyWiseCategoryBase::getName)
135 .setEditable(false)
136 .setColumnWidth(WIDTH_NAME);
137
138
139 addCategoryTypeColumn();
140
141
142 myTable.declareStringColumn(PrometheusDataResource.DATAITEM_FIELD_DESC)
143 .setValidator(this::isValidDesc)
144 .setCellValueFactory(MoneyWiseCategoryBase::getDesc)
145 .setEditable(true)
146 .setColumnWidth(WIDTH_NAME)
147 .setOnCommit((r, v) -> updateField(MoneyWiseCategoryBase::setDescription, r, v));
148
149
150 final TethysUIIconMapSet<MetisAction> myActionMapSet = MetisIcon.configureStatusIconButton(myGuiFactory);
151 myTable.declareIconColumn(PrometheusDataResource.DATAITEM_TOUCH, MetisAction.class)
152 .setIconMapSet(r -> myActionMapSet)
153 .setCellValueFactory(r -> r.isActive() ? MetisAction.ACTIVE : MetisAction.DELETE)
154 .setName(MoneyWiseUIResource.STATICDATA_ACTIVE.getValue())
155 .setEditable(true)
156 .setCellEditable(r -> !r.isActive())
157 .setColumnWidth(WIDTH_ICON)
158 .setOnCommit((r, v) -> updateField(this::deleteRow, r, v));
159
160
161 myNewButton.getEventRegistrar().addEventListener(e -> addNewItem());
162 theSelectButton.getEventRegistrar().addEventListener(TethysUIEvent.NEWVALUE, e -> handleParentSelection());
163 theSelectButton.setMenuConfigurator(e -> buildSelectMenu());
164 }
165
166
167
168
169 protected abstract void addCategoryTypeColumn();
170
171
172
173
174
175
176 public TethysUIBoxPaneManager getFilterPanel() {
177 return theFilterPanel;
178 }
179
180
181
182
183
184
185
186 protected String getShortName(final T pCategory) {
187 final String myName = pCategory.getSubCategory();
188 return myName == null ? pCategory.getName() : myName;
189 }
190
191
192
193
194
195
196 protected T getParent() {
197 return theParent;
198 }
199
200
201
202
203
204
205 protected void updateParent(final T pParent) {
206 theParent = pParent;
207 theSelectButton.setValue(theParent);
208 }
209
210
211
212
213
214
215 protected void selectParent(final T pParent) {
216
217 if (!MetisDataDifference.isEqual(pParent, theParent)) {
218
219 theParent = pParent;
220
221
222 if (pParent == null) {
223 theSelectButton.setValue(null, FILTER_PARENTS);
224 } else {
225 theSelectButton.setValue(pParent);
226 }
227
228
229 updateTableData();
230 }
231 }
232
233
234
235
236 private void handleParentSelection() {
237 selectParent(theSelectButton.getValue());
238 }
239
240
241
242
243
244
245
246 protected abstract void buildCategoryTypeMenu(T pCategory,
247 TethysUIScrollMenu<S> pMenu);
248
249
250
251
252
253
254 protected abstract List<T> getCategories();
255
256
257
258
259
260
261
262 protected abstract boolean isChildCategory(S pCategoryType);
263
264
265
266
267 private void buildSelectMenu() {
268
269 final TethysUIScrollMenu<T> myCategoryMenu = theSelectButton.getMenu();
270 myCategoryMenu.removeAllItems();
271
272
273 final List<T> myCategories = getCategories();
274 if (myCategories == null) {
275 return;
276 }
277
278
279 TethysUIScrollItem<T> myActive = null;
280
281
282 TethysUIScrollItem<T> myItem = myCategoryMenu.addItem(null, FILTER_PARENTS);
283
284
285 if (theParent == null) {
286
287 myActive = myItem;
288 }
289
290
291 for (T myCurr : myCategories) {
292 @SuppressWarnings("unchecked") final S myType = (S) myCurr.getCategoryType();
293
294
295 if (myCurr.isDeleted() || isChildCategory(myType)) {
296 continue;
297 }
298
299
300 myItem = myCategoryMenu.addItem(myCurr);
301
302
303 if (myCurr.equals(theParent)) {
304
305 myActive = myItem;
306 }
307 }
308
309
310 if (myActive != null) {
311 myActive.scrollToItem();
312 }
313 }
314
315
316
317
318 protected abstract void addNewItem();
319
320 @Override
321 protected String getInvalidNameChars() {
322 return ":";
323 }
324
325 @Override
326 protected boolean isDuplicateName(final String pNewName,
327 final T pRow,
328 final MetisDataNamedItem pCheck) {
329
330 final MoneyWiseCategoryBase myCheck = (MoneyWiseCategoryBase) pCheck;
331 return Objects.equals(myCheck.getParentCategory(), pRow.getParentCategory())
332 && pNewName.equals(myCheck.getSubCategory());
333 }
334 }