View Javadoc
1   /*
2    * MoneyWise: Finance Application
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.moneywise.ui.panel;
18  
19  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
21  import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
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.MoneyWiseDataSet;
27  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
28  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
29  import io.github.tonywasher.joceanus.moneywise.ui.base.MoneyWiseBaseTable;
30  import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList.PrometheusListStyle;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataClass;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataItem;
35  import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataItem.PrometheusStaticList;
36  import io.github.tonywasher.joceanus.prometheus.ui.PrometheusIcon;
37  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
38  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
39  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIGenericWrapper;
40  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIScrollButtonManager;
41  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControl.TethysUIIconMapSet;
42  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
43  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
44  import io.github.tonywasher.joceanus.tethys.api.table.TethysUITableColumn;
45  import io.github.tonywasher.joceanus.tethys.api.table.TethysUITableManager;
46  
47  /**
48   * MoneyWise Static Table.
49   *
50   * @param <L> the list type
51   * @param <T> the data type
52   */
53  public class MoneyWiseStaticTable<L extends PrometheusStaticList<T>, T extends PrometheusStaticDataItem>
54          extends MoneyWiseBaseTable<T> {
55      /**
56       * Class column width.
57       */
58      private static final int WIDTH_CLASS = 90;
59  
60      /**
61       * The list class.
62       */
63      private final Class<L> theClass;
64  
65      /**
66       * The enabled column.
67       */
68      private final TethysUITableColumn<Boolean, MetisDataFieldId, T> theEnabledColumn;
69  
70      /**
71       * The new button.
72       */
73      private final TethysUIScrollButtonManager<TethysUIGenericWrapper> theNewButton;
74  
75      /**
76       * The edit list.
77       */
78      private L theStatic;
79  
80      /**
81       * show disabled.
82       */
83      private boolean showAll;
84  
85      /**
86       * Constructor.
87       *
88       * @param pView      the view
89       * @param pEditSet   the editSet
90       * @param pError     the error panel
91       * @param pDataType  the dataType
92       * @param pListClass the listClass
93       */
94      MoneyWiseStaticTable(final MoneyWiseView pView,
95                           final PrometheusEditSet pEditSet,
96                           final MetisErrorPanel pError,
97                           final MoneyWiseStaticDataType pDataType,
98                           final Class<L> pListClass) {
99          /* Store parameters */
100         super(pView, pEditSet, pError, pDataType);
101         theClass = pListClass;
102 
103         /* Access the gui factory */
104         final TethysUIFactory<?> myGuiFactory = pView.getGuiFactory();
105         final TethysUITableManager<MetisDataFieldId, T> myTable = getTable();
106 
107         /* Create new button */
108         theNewButton = myGuiFactory.buttonFactory().newScrollButton(TethysUIGenericWrapper.class);
109         MetisIcon.configureNewScrollButton(theNewButton);
110 
111         /* Set table configuration */
112         myTable.setDisabled(PrometheusStaticDataItem::isDisabled)
113                 .setComparator(PrometheusStaticDataItem::compareTo);
114 
115         /* Create the class column */
116         myTable.declareStringColumn(PrometheusDataResource.STATICDATA_CLASS)
117                 .setCellValueFactory(r -> r.getStaticClass().toString())
118                 .setEditable(false)
119                 .setColumnWidth(WIDTH_CLASS);
120 
121         /* Create the name column */
122         myTable.declareStringColumn(PrometheusDataResource.DATAITEM_FIELD_NAME)
123                 .setValidator(this::isValidName)
124                 .setCellValueFactory(PrometheusStaticDataItem::getName)
125                 .setEditable(true)
126                 .setColumnWidth(WIDTH_NAME)
127                 .setOnCommit((r, v) -> updateField(PrometheusStaticDataItem::setName, r, v));
128 
129         /* Create the description column */
130         myTable.declareStringColumn(PrometheusDataResource.DATAITEM_FIELD_DESC)
131                 .setValidator(this::isValidDesc)
132                 .setCellValueFactory(PrometheusStaticDataItem::getDesc)
133                 .setEditable(true)
134                 .setColumnWidth(WIDTH_DESC)
135                 .setOnCommit((r, v) -> updateField(PrometheusStaticDataItem::setDescription, r, v));
136 
137         /* Create the enabled column */
138         final TethysUIIconMapSet<Boolean> myEnabledMapSet = PrometheusIcon.configureEnabledIconButton(myGuiFactory);
139         theEnabledColumn = myTable.declareIconColumn(PrometheusDataResource.STATICDATA_ENABLED, Boolean.class)
140                 .setIconMapSet(r -> myEnabledMapSet)
141                 .setCellValueFactory(PrometheusStaticDataItem::getEnabled)
142                 .setVisible(false)
143                 .setEditable(true)
144                 .setCellEditable(r -> !r.isActive())
145                 .setColumnWidth(WIDTH_ICON)
146                 .setOnCommit((r, v) -> updateField(PrometheusStaticDataItem::setEnabled, r, v));
147 
148         /* Create the Active column */
149         final TethysUIIconMapSet<MetisAction> myActionMapSet = MetisIcon.configureStatusIconButton(myGuiFactory);
150         myTable.declareIconColumn(PrometheusDataResource.DATAITEM_TOUCH, MetisAction.class)
151                 .setIconMapSet(r -> myActionMapSet)
152                 .setCellValueFactory(r -> r.isActive() ? MetisAction.ACTIVE : MetisAction.DELETE)
153                 .setName(MoneyWiseUIResource.STATICDATA_ACTIVE.getValue())
154                 .setEditable(true)
155                 .setCellEditable(r -> !r.isActive())
156                 .setColumnWidth(WIDTH_ICON)
157                 .setOnCommit((r, v) -> updateField(this::deleteRow, r, v));
158 
159         /* Add listeners */
160         final OceanusEventRegistrar<TethysUIEvent> myRegistrar = theNewButton.getEventRegistrar();
161         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewClass());
162         theNewButton.setMenuConfigurator(e -> buildNewMenu());
163         setShowAll(false);
164     }
165 
166     /**
167      * Obtain the new button.
168      *
169      * @return the new Button
170      */
171     TethysUIScrollButtonManager<TethysUIGenericWrapper> getNewButton() {
172         return theNewButton;
173     }
174 
175     @Override
176     protected void refreshData() throws OceanusException {
177         final MoneyWiseDataSet myData = getView().getData();
178         final PrometheusStaticList<T> myStatic = myData.getDataList(theClass);
179         theStatic = theClass.cast(myStatic.deriveList(PrometheusListStyle.EDIT));
180         theStatic.mapData();
181         getTable().setItems(theStatic.getUnderlyingList());
182         getEditEntry().setDataList(theStatic);
183         restoreSelected();
184     }
185 
186     /**
187      * handle new static class.
188      */
189     private void handleNewClass() {
190         /* Create a new profile */
191         final OceanusProfile myTask = getView().getNewProfile("addNewClass");
192 
193         /* Access the new class */
194         cancelEditing();
195         final PrometheusStaticDataClass myClass = (PrometheusStaticDataClass) theNewButton.getValue().getData();
196 
197         /* Protect the action */
198         try {
199             /* Look to find a deleted value */
200             myTask.startTask("addToList");
201             T myValue = theStatic.findItemByClass(myClass);
202 
203             /* If we found a deleted value */
204             if (myValue != null) {
205                 /* reinstate it */
206                 myValue.setDeleted(false);
207 
208                 /* else we have no existing value */
209             } else {
210                 /* Create the new value */
211                 myValue = theStatic.addNewItem(myClass);
212                 myValue.setNewVersion();
213                 myValue.adjustMapForItem();
214             }
215 
216             /* Update the table */
217             myTask.startTask("incrementVersion");
218             getEditSet().incrementVersion();
219             updateTableData();
220             selectItem(myValue);
221             notifyChanges();
222 
223             /* Handle exceptions */
224         } catch (OceanusException e) {
225             setError(e);
226         }
227 
228         /* End the task */
229         myTask.end();
230     }
231 
232     /**
233      * Build the menu of available new items.
234      */
235     private void buildNewMenu() {
236         /* Reset the menu popUp */
237         final TethysUIScrollMenu<TethysUIGenericWrapper> myMenu = theNewButton.getMenu();
238         myMenu.removeAllItems();
239 
240         /* Loop through the missing classes */
241         for (PrometheusStaticDataClass myValue : theStatic.getMissingClasses()) {
242             /* Create a new MenuItem and add it to the popUp */
243             myMenu.addItem(new TethysUIGenericWrapper(myValue));
244         }
245     }
246 
247     /**
248      * Select static data.
249      *
250      * @param pStatic the static data
251      */
252     @SuppressWarnings("unchecked")
253     void selectStatic(final PrometheusStaticDataItem pStatic) {
254         getTable().selectRow((T) pStatic);
255     }
256 
257     /**
258      * Is the static table full?
259      *
260      * @return true/false
261      */
262     boolean isFull() {
263         return theStatic == null
264                 || theStatic.isFull();
265     }
266 
267     /**
268      * adjust showALL.
269      *
270      * @param pShow show disabled entries
271      */
272     void setShowAll(final boolean pShow) {
273         showAll = pShow;
274         cancelEditing();
275         getTable().setFilter(this::isFiltered);
276         theEnabledColumn.setVisible(showAll);
277         restoreSelected();
278     }
279 
280     @Override
281     protected boolean isFiltered(final T pRow) {
282         return super.isFiltered(pRow) && (pRow.getEnabled() || showAll);
283     }
284 }