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.atlas.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.atlas.data.analysis.buckets.MoneyWiseXAnalysis;
25  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisBucketResource;
26  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisTaxBasisAccountBucket;
27  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisTaxBasisBucket;
28  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisTaxBasisBucket.MoneyWiseXAnalysisTaxBasisBucketList;
29  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter;
30  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter.MoneyWiseXAnalysisTaxBasisFilter;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
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 MoneyWiseXTaxBasisAnalysisSelect
51          implements MoneyWiseXAnalysisFilterSelection, 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 = MoneyWiseXAnalysisBucketResource.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<MoneyWiseXAnalysisTaxBasisBucket> theBasisButton;
81  
82      /**
83       * The account button.
84       */
85      private final TethysUIScrollButtonManager<MoneyWiseXAnalysisTaxBasisAccountBucket> theAccountButton;
86  
87      /**
88       * Tax menu.
89       */
90      private final TethysUIScrollMenu<MoneyWiseXAnalysisTaxBasisBucket> theTaxMenu;
91  
92      /**
93       * Account menu.
94       */
95      private final TethysUIScrollMenu<MoneyWiseXAnalysisTaxBasisAccountBucket> theAccountMenu;
96  
97      /**
98       * The active tax basis bucket list.
99       */
100     private MoneyWiseXAnalysisTaxBasisBucketList 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 MoneyWiseXTaxBasisAnalysisSelect(final TethysUIFactory<?> pFactory) {
118         /* Create the buttons */
119         final TethysUIButtonFactory<?> myButtons = pFactory.buttonFactory();
120         theBasisButton = myButtons.newScrollButton(MoneyWiseXAnalysisTaxBasisBucket.class);
121         theAccountButton = myButtons.newScrollButton(MoneyWiseXAnalysisTaxBasisAccountBucket.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 MoneyWiseXAnalysisTaxBasisFilter 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 MoneyWiseXAnalysis pAnalysis) {
214         /* Access buckets */
215         theTaxBases = pAnalysis.getTaxBasis();
216 
217         /* Obtain the current basis */
218         MoneyWiseXAnalysisTaxBasisBucket 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 MoneyWiseXAnalysisFilter<?, ?> pFilter) {
233         /* If this is the correct filter type */
234         if (pFilter instanceof MoneyWiseXAnalysisTaxBasisFilter myFilter) {
235             /* Obtain the filter bucket */
236             MoneyWiseXAnalysisTaxBasisBucket myTaxBasis = myFilter.getBucket();
237 
238             /* Obtain equivalent bucket */
239             myTaxBasis = theTaxBases.getMatchingBasis(myTaxBasis);
240 
241             /* Set the taxBasis */
242             theState.setTheTaxBasis(myTaxBasis);
243             theState.setDateRange(myFilter.getDateRange());
244             theState.applyState();
245         }
246     }
247 
248     /**
249      * Handle new Basis.
250      */
251     private void handleNewBasis() {
252         /* Select the new taxBasis */
253         if (theState.setTaxBasis(theBasisButton.getValue())) {
254             theState.applyState();
255             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
256         }
257     }
258 
259     /**
260      * Handle new Account.
261      */
262     private void handleNewAccount() {
263         /* Select the new account */
264         if (theState.setTaxBasis(theAccountButton.getValue())) {
265             theState.applyState();
266             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
267         }
268     }
269 
270     /**
271      * Build Basis menu.
272      */
273     private void buildBasisMenu() {
274         /* Reset the popUp menu */
275         theTaxMenu.removeAllItems();
276 
277         /* Record active item */
278         TethysUIScrollItem<MoneyWiseXAnalysisTaxBasisBucket> myActive = null;
279         final MoneyWiseXAnalysisTaxBasisBucket myCurr = theState.getTaxBasis();
280 
281         /* Loop through the available basis values */
282         final Iterator<MoneyWiseXAnalysisTaxBasisBucket> myIterator = theTaxBases.iterator();
283         while (myIterator.hasNext()) {
284             final MoneyWiseXAnalysisTaxBasisBucket myBucket = myIterator.next();
285 
286             /* Create a new MenuItem and add it to the popUp */
287             final TethysUIScrollItem<MoneyWiseXAnalysisTaxBasisBucket> myItem = theTaxMenu.addItem(myBucket);
288 
289             /* If this is the active bucket */
290             if (myBucket.equals(myCurr)) {
291                 /* Record it */
292                 myActive = myItem;
293             }
294         }
295 
296         /* Ensure active item is visible */
297         if (myActive != null) {
298             myActive.scrollToItem();
299         }
300     }
301 
302     /**
303      * Build Account menu.
304      */
305     private void buildAccountMenu() {
306         /* Reset the popUp menu */
307         theAccountMenu.removeAllItems();
308 
309         /* Record active item */
310         final MoneyWiseXAnalysisTaxBasisBucket myBasis = theState.getTaxBasis();
311         final MoneyWiseXAnalysisTaxBasisAccountBucket myCurr = theState.getAccount();
312 
313         /* Add the all item menu */
314         TethysUIScrollItem<MoneyWiseXAnalysisTaxBasisAccountBucket> myActive = theAccountMenu.addItem(null, NLS_ALL);
315 
316         /* Loop through the available account values */
317         final Iterator<MoneyWiseXAnalysisTaxBasisAccountBucket> myIterator = myBasis.accountIterator();
318         while (myIterator.hasNext()) {
319             final MoneyWiseXAnalysisTaxBasisAccountBucket myBucket = myIterator.next();
320 
321             /* Create a new MenuItem and add it to the popUp */
322             final TethysUIScrollItem<MoneyWiseXAnalysisTaxBasisAccountBucket> myItem = theAccountMenu.addItem(myBucket, myBucket.getSimpleName());
323 
324             /* If this is the active bucket */
325             if (myBucket.equals(myCurr)) {
326                 /* Record it */
327                 myActive = myItem;
328             }
329         }
330 
331         /* Ensure active item is visible */
332         if (myActive != null) {
333             myActive.scrollToItem();
334         }
335     }
336 
337     /**
338      * SavePoint values.
339      */
340     private final class MoneyWiseTaxBasisState {
341         /**
342          * The active TaxBasisBucket.
343          */
344         private MoneyWiseXAnalysisTaxBasisBucket theBasis;
345 
346         /**
347          * The account TaxBasisBucket.
348          */
349         private MoneyWiseXAnalysisTaxBasisAccountBucket theAccount;
350 
351         /**
352          * The dateRange.
353          */
354         private OceanusDateRange theDateRange;
355 
356         /**
357          * The active filter.
358          */
359         private MoneyWiseXAnalysisTaxBasisFilter theFilter;
360 
361         /**
362          * Constructor.
363          */
364         private MoneyWiseTaxBasisState() {
365         }
366 
367         /**
368          * Constructor.
369          *
370          * @param pState state to copy from
371          */
372         private MoneyWiseTaxBasisState(final MoneyWiseTaxBasisState pState) {
373             /* Initialise state */
374             theBasis = pState.getTaxBasis();
375             theAccount = pState.getAccount();
376             theDateRange = pState.getDateRange();
377             theFilter = pState.getFilter();
378         }
379 
380         /**
381          * Obtain the TaxBasis Bucket.
382          *
383          * @return the Basis
384          */
385         private MoneyWiseXAnalysisTaxBasisBucket getTaxBasis() {
386             return theBasis;
387         }
388 
389         /**
390          * Obtain the Account Bucket.
391          *
392          * @return the Account
393          */
394         private MoneyWiseXAnalysisTaxBasisAccountBucket getAccount() {
395             return theAccount;
396         }
397 
398         /**
399          * Obtain the dateRange.
400          *
401          * @return the dateRange
402          */
403         private OceanusDateRange getDateRange() {
404             return theDateRange;
405         }
406 
407         /**
408          * Obtain the Filter.
409          *
410          * @return the Filter
411          */
412         private MoneyWiseXAnalysisTaxBasisFilter getFilter() {
413             return theFilter;
414         }
415 
416         /**
417          * Set new TaxBasis.
418          *
419          * @param pTaxBasis the TaxBasis
420          * @return true/false did a change occur
421          */
422         private boolean setTaxBasis(final MoneyWiseXAnalysisTaxBasisBucket pTaxBasis) {
423             /* Adjust the selected taxBasis */
424             if (!MetisDataDifference.isEqual(pTaxBasis, theBasis)) {
425                 setTheTaxBasis(pTaxBasis);
426                 return true;
427             }
428             return false;
429         }
430 
431         /**
432          * Set the TaxBasis.
433          *
434          * @param pTaxBasis the TaxBasis
435          */
436         private void setTheTaxBasis(final MoneyWiseXAnalysisTaxBasisBucket pTaxBasis) {
437             /* Adjust the selected taxBasis */
438             if (pTaxBasis instanceof MoneyWiseXAnalysisTaxBasisAccountBucket myBucket) {
439                 theAccount = myBucket;
440                 theBasis = theAccount.getParent();
441                 theFilter = new MoneyWiseXAnalysisTaxBasisFilter(theAccount);
442                 theFilter.setDateRange(theDateRange);
443             } else {
444                 theAccount = null;
445                 theBasis = pTaxBasis;
446                 if (theBasis != null) {
447                     theFilter = new MoneyWiseXAnalysisTaxBasisFilter(theBasis);
448                     theFilter.setDateRange(theDateRange);
449                 } else {
450                     theFilter = null;
451                 }
452             }
453         }
454 
455         /**
456          * Set the dateRange.
457          *
458          * @param pRange the dateRange
459          */
460         private void setDateRange(final OceanusDateRange pRange) {
461             /* Store the dateRange */
462             theDateRange = pRange;
463             if (theFilter != null) {
464                 theFilter.setDateRange(theDateRange);
465             }
466         }
467 
468         /**
469          * Apply the State.
470          */
471         private void applyState() {
472             /* Adjust the lock-down */
473             setEnabled(true);
474             theBasisButton.setValue(theBasis);
475             if (theAccount == null) {
476                 theAccountButton.setValue(null, NLS_ALL);
477             } else {
478                 theAccountButton.setValue(theAccount, theAccount.getSimpleName());
479             }
480             theAccountButton.setEnabled((theBasis != null) && theBasis.hasAccounts());
481         }
482     }
483 }