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.lethe.ui.controls;
18  
19  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
20  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
21  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
22  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar.OceanusEventProvider;
23  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
25  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysis;
26  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisPayeeBucket;
27  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisPayeeBucket.MoneyWiseAnalysisPayeeBucketList;
28  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter;
29  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisPayeeFilter;
30  import io.github.tonywasher.joceanus.prometheus.views.PrometheusDataEvent;
31  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIComponent;
32  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIConstant;
33  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
34  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIScrollButtonManager;
35  import io.github.tonywasher.joceanus.tethys.api.control.TethysUILabel;
36  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
37  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollItem;
38  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
39  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBoxPaneManager;
40  
41  import java.util.Iterator;
42  
43  /**
44   * Payee Analysis Selection.
45   */
46  public class MoneyWisePayeeAnalysisSelect
47          implements MoneyWiseAnalysisFilterSelection, OceanusEventProvider<PrometheusDataEvent> {
48      /**
49       * Text for Payee Label.
50       */
51      private static final String NLS_PAYEE = MoneyWiseBasicDataType.PAYEE.getItemName();
52  
53      /**
54       * The Event Manager.
55       */
56      private final OceanusEventManager<PrometheusDataEvent> theEventManager;
57  
58      /**
59       * The panel.
60       */
61      private final TethysUIBoxPaneManager thePanel;
62  
63      /**
64       * The select button.
65       */
66      private final TethysUIScrollButtonManager<MoneyWiseAnalysisPayeeBucket> theButton;
67  
68      /**
69       * Payee menu.
70       */
71      private final TethysUIScrollMenu<MoneyWiseAnalysisPayeeBucket> thePayeeMenu;
72  
73      /**
74       * The active payee bucket list.
75       */
76      private MoneyWiseAnalysisPayeeBucketList thePayees;
77  
78      /**
79       * The state.
80       */
81      private MoneyWisePayeeState theState;
82  
83      /**
84       * The savePoint.
85       */
86      private MoneyWisePayeeState theSavePoint;
87  
88      /**
89       * Constructor.
90       *
91       * @param pFactory the GUI factory
92       */
93      protected MoneyWisePayeeAnalysisSelect(final TethysUIFactory<?> pFactory) {
94          /* Create the button */
95          theButton = pFactory.buttonFactory().newScrollButton(MoneyWiseAnalysisPayeeBucket.class);
96  
97          /* Create Event Manager */
98          theEventManager = new OceanusEventManager<>();
99  
100         /* Create the label */
101         final TethysUILabel myLabel = pFactory.controlFactory().newLabel(NLS_PAYEE + TethysUIConstant.STR_COLON);
102 
103         /* Define the layout */
104         thePanel = pFactory.paneFactory().newHBoxPane();
105         thePanel.addSpacer();
106         thePanel.addNode(myLabel);
107         thePanel.addNode(theButton);
108 
109         /* Create initial state */
110         theState = new MoneyWisePayeeState();
111         theState.applyState();
112 
113         /* Access the menus */
114         thePayeeMenu = theButton.getMenu();
115 
116         /* Create the listeners */
117         final OceanusEventRegistrar<TethysUIEvent> myRegistrar = theButton.getEventRegistrar();
118         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewPayee());
119         theButton.setMenuConfigurator(e -> buildPayeeMenu());
120     }
121 
122     @Override
123     public TethysUIComponent getUnderlying() {
124         return thePanel;
125     }
126 
127     @Override
128     public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
129         return theEventManager.getEventRegistrar();
130     }
131 
132     @Override
133     public MoneyWiseAnalysisPayeeFilter getFilter() {
134         return theState.getFilter();
135     }
136 
137     @Override
138     public boolean isAvailable() {
139         return thePayees != null
140                 && !thePayees.isEmpty();
141     }
142 
143     /**
144      * Create SavePoint.
145      */
146     public void createSavePoint() {
147         /* Create the savePoint */
148         theSavePoint = new MoneyWisePayeeState(theState);
149     }
150 
151     /**
152      * Restore SavePoint.
153      */
154     public void restoreSavePoint() {
155         /* Restore the savePoint */
156         theState = new MoneyWisePayeeState(theSavePoint);
157 
158         /* Apply the state */
159         theState.applyState();
160     }
161 
162     @Override
163     public void setEnabled(final boolean bEnabled) {
164         /* Pass call on to button */
165         theButton.setEnabled(bEnabled && isAvailable());
166     }
167 
168     @Override
169     public void setVisible(final boolean pVisible) {
170         thePanel.setVisible(pVisible);
171     }
172 
173     /**
174      * Set analysis.
175      *
176      * @param pAnalysis the analysis.
177      */
178     public void setAnalysis(final MoneyWiseAnalysis pAnalysis) {
179         /* Access buckets */
180         thePayees = pAnalysis.getPayees();
181 
182         /* Obtain the current payee */
183         MoneyWiseAnalysisPayeeBucket myPayee = theState.getPayee();
184 
185         /* Switch to versions from the analysis */
186         myPayee = myPayee != null
187                 ? thePayees.getMatchingPayee(myPayee.getPayee())
188                 : thePayees.getDefaultPayee();
189 
190         /* Set the payee */
191         theState.setThePayee(myPayee);
192         theState.setDateRange(pAnalysis.getDateRange());
193         theState.applyState();
194     }
195 
196     @Override
197     public void setFilter(final MoneyWiseAnalysisFilter<?, ?> pFilter) {
198         /* If this is the correct filter type */
199         if (pFilter instanceof MoneyWiseAnalysisPayeeFilter) {
200             /* Access filter */
201             final MoneyWiseAnalysisPayeeFilter myFilter = (MoneyWiseAnalysisPayeeFilter) pFilter;
202 
203             /* Obtain the filter bucket */
204             MoneyWiseAnalysisPayeeBucket myPayee = myFilter.getBucket();
205 
206             /* Obtain equivalent bucket */
207             myPayee = thePayees.getMatchingPayee(myPayee.getPayee());
208 
209             /* Set the payee */
210             theState.setThePayee(myPayee);
211             theState.setDateRange(myFilter.getDateRange());
212             theState.applyState();
213         }
214     }
215 
216     /**
217      * Handle new Payee.
218      */
219     private void handleNewPayee() {
220         /* Select the new Payee */
221         if (theState.setPayee(theButton.getValue())) {
222             theState.applyState();
223             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
224         }
225     }
226 
227     /**
228      * Build Payee menu.
229      */
230     private void buildPayeeMenu() {
231         /* Reset the popUp menu */
232         thePayeeMenu.removeAllItems();
233 
234         /* Record active item */
235         TethysUIScrollItem<MoneyWiseAnalysisPayeeBucket> myActive = null;
236         final MoneyWiseAnalysisPayeeBucket myCurr = theState.getPayee();
237 
238         /* Loop through the available payee values */
239         final Iterator<MoneyWiseAnalysisPayeeBucket> myIterator = thePayees.iterator();
240         while (myIterator.hasNext()) {
241             final MoneyWiseAnalysisPayeeBucket myBucket = myIterator.next();
242 
243             /* Create a new MenuItem and add it to the popUp */
244             final TethysUIScrollItem<MoneyWiseAnalysisPayeeBucket> myItem = thePayeeMenu.addItem(myBucket);
245 
246             /* If this is the active bucket */
247             if (myBucket.equals(myCurr)) {
248                 /* Record it */
249                 myActive = myItem;
250             }
251         }
252 
253         /* Ensure active item is visible */
254         if (myActive != null) {
255             myActive.scrollToItem();
256         }
257     }
258 
259     /**
260      * SavePoint values.
261      */
262     private final class MoneyWisePayeeState {
263         /**
264          * The active PayeeBucket.
265          */
266         private MoneyWiseAnalysisPayeeBucket thePayee;
267 
268         /**
269          * The dateRange.
270          */
271         private OceanusDateRange theDateRange;
272 
273         /**
274          * The active filter.
275          */
276         private MoneyWiseAnalysisPayeeFilter theFilter;
277 
278         /**
279          * Constructor.
280          */
281         private MoneyWisePayeeState() {
282         }
283 
284         /**
285          * Constructor.
286          *
287          * @param pState state to copy from
288          */
289         private MoneyWisePayeeState(final MoneyWisePayeeState pState) {
290             /* Initialise state */
291             thePayee = pState.getPayee();
292             theDateRange = pState.getDateRange();
293             theFilter = pState.getFilter();
294         }
295 
296         /**
297          * Obtain the Payee Bucket.
298          *
299          * @return the Payee
300          */
301         private MoneyWiseAnalysisPayeeBucket getPayee() {
302             return thePayee;
303         }
304 
305         /**
306          * Obtain the dateRange.
307          *
308          * @return the dateRange
309          */
310         private OceanusDateRange getDateRange() {
311             return theDateRange;
312         }
313 
314         /**
315          * Obtain the Filter.
316          *
317          * @return the Filter
318          */
319         private MoneyWiseAnalysisPayeeFilter getFilter() {
320             return theFilter;
321         }
322 
323         /**
324          * Set new Payee.
325          *
326          * @param pPayee the Payee
327          * @return true/false did a change occur
328          */
329         private boolean setPayee(final MoneyWiseAnalysisPayeeBucket pPayee) {
330             /* Adjust the selected payee */
331             if (!MetisDataDifference.isEqual(pPayee, thePayee)) {
332                 setThePayee(pPayee);
333                 return true;
334             }
335             return false;
336         }
337 
338         /**
339          * Set the Payee.
340          *
341          * @param pPayee the Payee
342          */
343         private void setThePayee(final MoneyWiseAnalysisPayeeBucket pPayee) {
344             /* Store the payee */
345             thePayee = pPayee;
346             if (thePayee != null) {
347                 theFilter = new MoneyWiseAnalysisPayeeFilter(thePayee);
348                 theFilter.setDateRange(theDateRange);
349             } else {
350                 theFilter = null;
351             }
352         }
353 
354         /**
355          * Set the dateRange.
356          *
357          * @param pRange the dateRange
358          */
359         private void setDateRange(final OceanusDateRange pRange) {
360             /* Store the dateRange */
361             theDateRange = pRange;
362             if (theFilter != null) {
363                 theFilter.setDateRange(theDateRange);
364             }
365         }
366 
367         /**
368          * Apply the State.
369          */
370         private void applyState() {
371             /* Adjust the lock-down */
372             setEnabled(true);
373             theButton.setValue(thePayee);
374         }
375     }
376 }