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.profile.OceanusProfile;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
22  import io.github.tonywasher.joceanus.metis.ui.MetisAction;
23  import io.github.tonywasher.joceanus.metis.ui.MetisErrorPanel;
24  import io.github.tonywasher.joceanus.metis.ui.MetisIcon;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataSet;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseRegion;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseRegion.MoneyWiseRegionList;
29  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
30  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
31  import io.github.tonywasher.joceanus.moneywise.ui.base.MoneyWiseBaseTable;
32  import io.github.tonywasher.joceanus.moneywise.ui.dialog.MoneyWiseRegionDialog;
33  import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
35  import io.github.tonywasher.joceanus.prometheus.views.PrometheusDataEvent;
36  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
37  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButton;
38  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControl.TethysUIIconMapSet;
39  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
40  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBoxPaneManager;
41  import io.github.tonywasher.joceanus.tethys.api.table.TethysUITableManager;
42  
43  /**
44   * MoneyWise Region Table.
45   */
46  public class MoneyWiseRegionTable
47          extends MoneyWiseBaseTable<MoneyWiseRegion> {
48      /**
49       * The filter panel.
50       */
51      private final TethysUIBoxPaneManager theFilterPanel;
52  
53      /**
54       * The Region dialog.
55       */
56      private final MoneyWiseRegionDialog theActiveRegion;
57  
58      /**
59       * The edit list.
60       */
61      private MoneyWiseRegionList theRegions;
62  
63      /**
64       * Constructor.
65       *
66       * @param pView    the view
67       * @param pEditSet the editSet
68       * @param pError   the error panel
69       */
70      MoneyWiseRegionTable(final MoneyWiseView pView,
71                           final PrometheusEditSet pEditSet,
72                           final MetisErrorPanel pError) {
73          /* Store parameters */
74          super(pView, pEditSet, pError, MoneyWiseBasicDataType.REGION);
75  
76          /* Access the GUI factory */
77          final TethysUIFactory<?> myGuiFactory = pView.getGuiFactory();
78          final TethysUITableManager<MetisDataFieldId, MoneyWiseRegion> myTable = getTable();
79  
80          /* Create new button */
81          final TethysUIButton myNewButton = myGuiFactory.buttonFactory().newButton();
82          MetisIcon.configureNewIconButton(myNewButton);
83  
84          /* Create a filter panel */
85          theFilterPanel = myGuiFactory.paneFactory().newHBoxPane();
86          theFilterPanel.addSpacer();
87          theFilterPanel.addNode(myNewButton);
88  
89          /* Create a region panel */
90          theActiveRegion = new MoneyWiseRegionDialog(myGuiFactory, pEditSet, this);
91          declareItemPanel(theActiveRegion);
92  
93          /* Set table configuration */
94          myTable.setDisabled(MoneyWiseRegion::isDisabled)
95                  .setComparator(MoneyWiseRegion::compareTo);
96  
97          /* Create the name column */
98          myTable.declareStringColumn(PrometheusDataResource.DATAITEM_FIELD_NAME)
99                  .setValidator(this::isValidName)
100                 .setCellValueFactory(MoneyWiseRegion::getName)
101                 .setEditable(true)
102                 .setColumnWidth(WIDTH_NAME)
103                 .setOnCommit((r, v) -> updateField(MoneyWiseRegion::setName, r, v));
104 
105         /* Create the description column */
106         myTable.declareStringColumn(PrometheusDataResource.DATAITEM_FIELD_DESC)
107                 .setValidator(this::isValidDesc)
108                 .setCellValueFactory(MoneyWiseRegion::getDesc)
109                 .setEditable(true)
110                 .setColumnWidth(WIDTH_DESC)
111                 .setOnCommit((r, v) -> updateField(MoneyWiseRegion::setDescription, r, v));
112 
113         /* Create the Active column */
114         final TethysUIIconMapSet<MetisAction> myActionMapSet = MetisIcon.configureStatusIconButton(pView.getGuiFactory());
115         myTable.declareIconColumn(PrometheusDataResource.DATAITEM_TOUCH, MetisAction.class)
116                 .setIconMapSet(r -> myActionMapSet)
117                 .setCellValueFactory(r -> r.isActive() ? MetisAction.ACTIVE : MetisAction.DELETE)
118                 .setName(MoneyWiseUIResource.STATICDATA_ACTIVE.getValue())
119                 .setEditable(true)
120                 .setCellEditable(r -> !r.isActive())
121                 .setColumnWidth(WIDTH_ICON)
122                 .setOnCommit((r, v) -> updateField(this::deleteRow, r, v));
123 
124         /* Add listeners */
125         myNewButton.getEventRegistrar().addEventListener(e -> addNewItem());
126         theActiveRegion.getEventRegistrar().addEventListener(PrometheusDataEvent.ADJUSTVISIBILITY, e -> handlePanelState());
127     }
128 
129     @Override
130     protected boolean isItemEditing() {
131         return theActiveRegion.isEditing();
132     }
133 
134     /**
135      * Obtain the filter panel.
136      *
137      * @return the filter panel
138      */
139     protected TethysUIBoxPaneManager getFilterPanel() {
140         return theFilterPanel;
141     }
142 
143     @Override
144     protected void refreshData() throws OceanusException {
145         /* Obtain the active profile */
146         OceanusProfile myTask = getView().getActiveTask();
147         myTask = myTask.startTask("Regions");
148 
149         /* Access list */
150         final MoneyWiseDataSet myData = getView().getData();
151         final MoneyWiseRegionList myBase = myData.getRegions();
152         theRegions = myBase.deriveEditList(getEditSet());
153         getTable().setItems(theRegions.getUnderlyingList());
154 
155         /* Notify panel of refresh */
156         theActiveRegion.refreshData();
157         restoreSelected();
158 
159         /* Complete the task */
160         myTask.end();
161     }
162 
163     @Override
164     public void cancelEditing() {
165         super.cancelEditing();
166         theActiveRegion.setEditable(false);
167     }
168 
169     /**
170      * Select region.
171      *
172      * @param pRegion the region to select
173      */
174     void selectRegion(final MoneyWiseRegion pRegion) {
175         /* Select the row and ensure that it is visible */
176         getTable().selectRow(pRegion);
177     }
178 
179     @Override
180     protected void handleRewind() {
181         /* Only action if we are not editing */
182         if (!theActiveRegion.isEditing()) {
183             /* Handle the reWind */
184             setEnabled(true);
185             super.handleRewind();
186         }
187 
188         /* Adjust for changes */
189         notifyChanges();
190     }
191 
192     /**
193      * Handle panel state.
194      */
195     private void handlePanelState() {
196         /* Only action if we are not editing */
197         if (!theActiveRegion.isEditing()) {
198             /* handle the edit transition */
199             setEnabled(true);
200             final MoneyWiseRegion myRegion = theActiveRegion.getSelectedItem();
201             updateTableData();
202             if (myRegion != null) {
203                 getTable().selectRow(myRegion);
204             } else {
205                 restoreSelected();
206             }
207         } else {
208             getTable().cancelEditing();
209         }
210 
211         /* Note changes */
212         notifyChanges();
213     }
214 
215     /**
216      * New item.
217      */
218     private void addNewItem() {
219         /* Protect against Exceptions */
220         try {
221             /* Make sure that we have finished editing */
222             cancelEditing();
223 
224             /* Create a new profile */
225             final OceanusProfile myTask = getView().getNewProfile("addNewItem");
226 
227             /* Create the new region */
228             myTask.startTask("buildItem");
229             final MoneyWiseRegion myRegion = theRegions.addNewItem();
230             myRegion.setDefaults();
231 
232             /* Set as new and adjust map */
233             myTask.startTask("incrementVersion");
234             myRegion.setNewVersion();
235             myRegion.adjustMapForItem();
236             getEditSet().incrementVersion();
237 
238             /* Validate the new item */
239             myTask.startTask("validate");
240             myRegion.validate();
241 
242             /* update panel */
243             myTask.startTask("setItem");
244             theActiveRegion.setNewItem(myRegion);
245 
246             /* Lock the table */
247             setTableEnabled(false);
248             myTask.end();
249 
250             /* Handle Exceptions */
251         } catch (OceanusException e) {
252             /* Build the error */
253             final OceanusException myError = new MoneyWiseDataException("Failed to create new region", e);
254 
255             /* Show the error */
256             setError(myError);
257         }
258     }
259 }