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.statics.MoneyWiseStaticDataType;
25  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysis;
26  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisDataResource;
27  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisTaxBasisAccountBucket;
28  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisTaxBasisBucket;
29  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisTaxBasisBucket.MoneyWiseAnalysisTaxBasisBucketList;
30  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter;
31  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisTaxBasisFilter;
32  import io.github.tonywasher.joceanus.prometheus.views.PrometheusDataEvent;
33  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIComponent;
34  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIConstant;
35  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
36  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButtonFactory;
37  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIScrollButtonManager;
38  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControlFactory;
39  import io.github.tonywasher.joceanus.tethys.api.control.TethysUILabel;
40  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
41  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollItem;
42  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
43  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBoxPaneManager;
44  
45  import java.util.Iterator;
46  
47  /**
48   * TaxBasisAnalysis Selection.
49   */
50  public class MoneyWiseTaxBasisAnalysisSelect
51          implements MoneyWiseAnalysisFilterSelection, OceanusEventProvider<PrometheusDataEvent> {
52      /**
53       * Text for TaxBasis Label.
54       */
55      private static final String NLS_BASIS = MoneyWiseStaticDataType.TAXBASIS.getItemName();
56  
57      /**
58       * Text for Account Label.
59       */
60      private static final String NLS_ACCOUNT = MoneyWiseAnalysisDataResource.BUCKET_ACCOUNT.getValue();
61  
62      /**
63       * Text for All Item.
64       */
65      private static final String NLS_ALL = "All";
66  
67      /**
68       * The Event Manager.
69       */
70      private final OceanusEventManager<PrometheusDataEvent> theEventManager;
71  
72      /**
73       * The panel.
74       */
75      private final TethysUIBoxPaneManager thePanel;
76  
77      /**
78       * The basis button.
79       */
80      private final TethysUIScrollButtonManager<MoneyWiseAnalysisTaxBasisBucket> theBasisButton;
81  
82      /**
83       * The account button.
84       */
85      private final TethysUIScrollButtonManager<MoneyWiseAnalysisTaxBasisAccountBucket> theAccountButton;
86  
87      /**
88       * Tax menu.
89       */
90      private final TethysUIScrollMenu<MoneyWiseAnalysisTaxBasisBucket> theTaxMenu;
91  
92      /**
93       * Account menu.
94       */
95      private final TethysUIScrollMenu<MoneyWiseAnalysisTaxBasisAccountBucket> theAccountMenu;
96  
97      /**
98       * The active tax basis bucket list.
99       */
100     private MoneyWiseAnalysisTaxBasisBucketList theTaxBases;
101 
102     /**
103      * The state.
104      */
105     private MoneyWiseTaxBasisState theState;
106 
107     /**
108      * The savePoint.
109      */
110     private MoneyWiseTaxBasisState theSavePoint;
111 
112     /**
113      * Constructor.
114      *
115      * @param pFactory the GUI factory
116      */
117     protected MoneyWiseTaxBasisAnalysisSelect(final TethysUIFactory<?> pFactory) {
118         /* Create the buttons */
119         final TethysUIButtonFactory<?> myButtons = pFactory.buttonFactory();
120         theBasisButton = myButtons.newScrollButton(MoneyWiseAnalysisTaxBasisBucket.class);
121         theAccountButton = myButtons.newScrollButton(MoneyWiseAnalysisTaxBasisAccountBucket.class);
122 
123         /* Create Event Manager */
124         theEventManager = new OceanusEventManager<>();
125 
126         /* Create the labels */
127         final TethysUIControlFactory myControls = pFactory.controlFactory();
128         final TethysUILabel myBasisLabel = myControls.newLabel(NLS_BASIS + TethysUIConstant.STR_COLON);
129         final TethysUILabel myAccountLabel = myControls.newLabel(NLS_ACCOUNT + TethysUIConstant.STR_COLON);
130 
131         /* Define the layout */
132         thePanel = pFactory.paneFactory().newHBoxPane();
133         thePanel.addSpacer();
134         thePanel.addNode(myBasisLabel);
135         thePanel.addNode(theBasisButton);
136         thePanel.addStrut();
137         thePanel.addNode(myAccountLabel);
138         thePanel.addNode(theAccountButton);
139 
140         /* Create initial state */
141         theState = new MoneyWiseTaxBasisState();
142         theState.applyState();
143 
144         /* Access the menus */
145         theTaxMenu = theBasisButton.getMenu();
146         theAccountMenu = theAccountButton.getMenu();
147 
148         /* Create the listener */
149         OceanusEventRegistrar<TethysUIEvent> myRegistrar = theBasisButton.getEventRegistrar();
150         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewBasis());
151         theBasisButton.setMenuConfigurator(e -> buildBasisMenu());
152         myRegistrar = theAccountButton.getEventRegistrar();
153         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewAccount());
154         theAccountButton.setMenuConfigurator(e -> buildAccountMenu());
155     }
156 
157     @Override
158     public TethysUIComponent getUnderlying() {
159         return thePanel;
160     }
161 
162     @Override
163     public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
164         return theEventManager.getEventRegistrar();
165     }
166 
167     @Override
168     public MoneyWiseAnalysisTaxBasisFilter getFilter() {
169         return theState.getFilter();
170     }
171 
172     @Override
173     public boolean isAvailable() {
174         return theTaxBases != null
175                 && !theTaxBases.isEmpty();
176     }
177 
178     /**
179      * Create SavePoint.
180      */
181     public void createSavePoint() {
182         /* Create the savePoint */
183         theSavePoint = new MoneyWiseTaxBasisState(theState);
184     }
185 
186     /**
187      * Restore SavePoint.
188      */
189     public void restoreSavePoint() {
190         /* Restore the savePoint */
191         theState = new MoneyWiseTaxBasisState(theSavePoint);
192 
193         /* Apply the state */
194         theState.applyState();
195     }
196 
197     @Override
198     public void setEnabled(final boolean bEnabled) {
199         /* Pass call on to basis button */
200         theBasisButton.setEnabled(bEnabled && isAvailable());
201     }
202 
203     @Override
204     public void setVisible(final boolean pVisible) {
205         thePanel.setVisible(pVisible);
206     }
207 
208     /**
209      * Set analysis.
210      *
211      * @param pAnalysis the analysis.
212      */
213     public void setAnalysis(final MoneyWiseAnalysis pAnalysis) {
214         /* Access buckets */
215         theTaxBases = pAnalysis.getTaxBasis();
216 
217         /* Obtain the current basis */
218         MoneyWiseAnalysisTaxBasisBucket myBasis = theState.getTaxBasis();
219 
220         /* Switch to versions from the analysis */
221         myBasis = myBasis != null
222                 ? theTaxBases.getMatchingBasis(myBasis)
223                 : theTaxBases.getDefaultBasis();
224 
225         /* Set the basis */
226         theState.setTheTaxBasis(myBasis);
227         theState.setDateRange(pAnalysis.getDateRange());
228         theState.applyState();
229     }
230 
231     @Override
232     public void setFilter(final MoneyWiseAnalysisFilter<?, ?> pFilter) {
233         /* If this is the correct filter type */
234         if (pFilter instanceof MoneyWiseAnalysisTaxBasisFilter) {
235             /* Access filter */
236             final MoneyWiseAnalysisTaxBasisFilter myFilter = (MoneyWiseAnalysisTaxBasisFilter) pFilter;
237 
238             /* Obtain the filter bucket */
239             MoneyWiseAnalysisTaxBasisBucket myTaxBasis = myFilter.getBucket();
240 
241             /* Obtain equivalent bucket */
242             myTaxBasis = theTaxBases.getMatchingBasis(myTaxBasis);
243 
244             /* Set the taxBasis */
245             theState.setTheTaxBasis(myTaxBasis);
246             theState.setDateRange(myFilter.getDateRange());
247             theState.applyState();
248         }
249     }
250 
251     /**
252      * Handle new Basis.
253      */
254     private void handleNewBasis() {
255         /* Select the new taxBasis */
256         if (theState.setTaxBasis(theBasisButton.getValue())) {
257             theState.applyState();
258             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
259         }
260     }
261 
262     /**
263      * Handle new Account.
264      */
265     private void handleNewAccount() {
266         /* Select the new account */
267         if (theState.setTaxBasis(theAccountButton.getValue())) {
268             theState.applyState();
269             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
270         }
271     }
272 
273     /**
274      * Build Basis menu.
275      */
276     private void buildBasisMenu() {
277         /* Reset the popUp menu */
278         theTaxMenu.removeAllItems();
279 
280         /* Record active item */
281         TethysUIScrollItem<MoneyWiseAnalysisTaxBasisBucket> myActive = null;
282         final MoneyWiseAnalysisTaxBasisBucket myCurr = theState.getTaxBasis();
283 
284         /* Loop through the available basis values */
285         final Iterator<MoneyWiseAnalysisTaxBasisBucket> myIterator = theTaxBases.iterator();
286         while (myIterator.hasNext()) {
287             final MoneyWiseAnalysisTaxBasisBucket myBucket = myIterator.next();
288 
289             /* Create a new MenuItem and add it to the popUp */
290             final TethysUIScrollItem<MoneyWiseAnalysisTaxBasisBucket> myItem = theTaxMenu.addItem(myBucket);
291 
292             /* If this is the active bucket */
293             if (myBucket.equals(myCurr)) {
294                 /* Record it */
295                 myActive = myItem;
296             }
297         }
298 
299         /* Ensure active item is visible */
300         if (myActive != null) {
301             myActive.scrollToItem();
302         }
303     }
304 
305     /**
306      * Build Account menu.
307      */
308     private void buildAccountMenu() {
309         /* Reset the popUp menu */
310         theAccountMenu.removeAllItems();
311 
312         /* Record active item */
313         final MoneyWiseAnalysisTaxBasisBucket myBasis = theState.getTaxBasis();
314         final MoneyWiseAnalysisTaxBasisAccountBucket myCurr = theState.getAccount();
315 
316         /* Add the all item menu */
317         TethysUIScrollItem<MoneyWiseAnalysisTaxBasisAccountBucket> myActive = theAccountMenu.addItem(null, NLS_ALL);
318 
319         /* Loop through the available account values */
320         final Iterator<MoneyWiseAnalysisTaxBasisAccountBucket> myIterator = myBasis.accountIterator();
321         while (myIterator.hasNext()) {
322             final MoneyWiseAnalysisTaxBasisAccountBucket myBucket = myIterator.next();
323 
324             /* Create a new MenuItem and add it to the popUp */
325             final TethysUIScrollItem<MoneyWiseAnalysisTaxBasisAccountBucket> myItem = theAccountMenu.addItem(myBucket, myBucket.getSimpleName());
326 
327             /* If this is the active bucket */
328             if (myBucket.equals(myCurr)) {
329                 /* Record it */
330                 myActive = myItem;
331             }
332         }
333 
334         /* Ensure active item is visible */
335         if (myActive != null) {
336             myActive.scrollToItem();
337         }
338     }
339 
340     /**
341      * SavePoint values.
342      */
343     private final class MoneyWiseTaxBasisState {
344         /**
345          * The active TaxBasisBucket.
346          */
347         private MoneyWiseAnalysisTaxBasisBucket theBasis;
348 
349         /**
350          * The account TaxBasisBucket.
351          */
352         private MoneyWiseAnalysisTaxBasisAccountBucket theAccount;
353 
354         /**
355          * The dateRange.
356          */
357         private OceanusDateRange theDateRange;
358 
359         /**
360          * The active filter.
361          */
362         private MoneyWiseAnalysisTaxBasisFilter theFilter;
363 
364         /**
365          * Constructor.
366          */
367         private MoneyWiseTaxBasisState() {
368         }
369 
370         /**
371          * Constructor.
372          *
373          * @param pState state to copy from
374          */
375         private MoneyWiseTaxBasisState(final MoneyWiseTaxBasisState pState) {
376             /* Initialise state */
377             theBasis = pState.getTaxBasis();
378             theAccount = pState.getAccount();
379             theDateRange = pState.getDateRange();
380             theFilter = pState.getFilter();
381         }
382 
383         /**
384          * Obtain the TaxBasis Bucket.
385          *
386          * @return the Basis
387          */
388         private MoneyWiseAnalysisTaxBasisBucket getTaxBasis() {
389             return theBasis;
390         }
391 
392         /**
393          * Obtain the Account Bucket.
394          *
395          * @return the Account
396          */
397         private MoneyWiseAnalysisTaxBasisAccountBucket getAccount() {
398             return theAccount;
399         }
400 
401         /**
402          * Obtain the dateRange.
403          *
404          * @return the dateRange
405          */
406         private OceanusDateRange getDateRange() {
407             return theDateRange;
408         }
409 
410         /**
411          * Obtain the Filter.
412          *
413          * @return the Filter
414          */
415         private MoneyWiseAnalysisTaxBasisFilter getFilter() {
416             return theFilter;
417         }
418 
419         /**
420          * Set new TaxBasis.
421          *
422          * @param pTaxBasis the TaxBasis
423          * @return true/false did a change occur
424          */
425         private boolean setTaxBasis(final MoneyWiseAnalysisTaxBasisBucket pTaxBasis) {
426             /* Adjust the selected taxBasis */
427             if (!MetisDataDifference.isEqual(pTaxBasis, theBasis)) {
428                 setTheTaxBasis(pTaxBasis);
429                 return true;
430             }
431             return false;
432         }
433 
434         /**
435          * Set the TaxBasis.
436          *
437          * @param pTaxBasis the TaxBasis
438          */
439         private void setTheTaxBasis(final MoneyWiseAnalysisTaxBasisBucket pTaxBasis) {
440             /* Adjust the selected taxBasis */
441             if (pTaxBasis instanceof MoneyWiseAnalysisTaxBasisAccountBucket) {
442                 theAccount = (MoneyWiseAnalysisTaxBasisAccountBucket) pTaxBasis;
443                 theBasis = theAccount.getParent();
444                 theFilter = new MoneyWiseAnalysisTaxBasisFilter(theAccount);
445                 theFilter.setDateRange(theDateRange);
446             } else {
447                 theAccount = null;
448                 theBasis = pTaxBasis;
449                 if (theBasis != null) {
450                     theFilter = new MoneyWiseAnalysisTaxBasisFilter(theBasis);
451                     theFilter.setDateRange(theDateRange);
452                 } else {
453                     theFilter = null;
454                 }
455             }
456         }
457 
458         /**
459          * Set the dateRange.
460          *
461          * @param pRange the dateRange
462          */
463         private void setDateRange(final OceanusDateRange pRange) {
464             /* Store the dateRange */
465             theDateRange = pRange;
466             if (theFilter != null) {
467                 theFilter.setDateRange(theDateRange);
468             }
469         }
470 
471         /**
472          * Apply the State.
473          */
474         private void applyState() {
475             /* Adjust the lock-down */
476             setEnabled(true);
477             theBasisButton.setValue(theBasis);
478             if (theAccount == null) {
479                 theAccountButton.setValue(null, NLS_ALL);
480             } else {
481                 theAccountButton.setValue(theAccount, theAccount.getSimpleName());
482             }
483             theAccountButton.setEnabled((theBasis != null) && theBasis.hasAccounts());
484         }
485     }
486 }