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.MoneyWiseXAnalysisPortfolioBucket;
26  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisPortfolioBucket.MoneyWiseXAnalysisPortfolioBucketList;
27  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter;
28  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter.MoneyWiseXAnalysisPortfolioCashFilter;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
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   * Portfolio Analysis Selection.
45   */
46  public class MoneyWiseXPortfolioAnalysisSelect
47          implements MoneyWiseXAnalysisFilterSelection, OceanusEventProvider<PrometheusDataEvent> {
48      /**
49       * Text for Portfolio Label.
50       */
51      private static final String NLS_PORTFOLIO = MoneyWiseBasicDataType.PORTFOLIO.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 portfolio button.
65       */
66      private final TethysUIScrollButtonManager<MoneyWiseXAnalysisPortfolioBucket> thePortButton;
67  
68      /**
69       * Portfolio menu.
70       */
71      private final TethysUIScrollMenu<MoneyWiseXAnalysisPortfolioBucket> thePortfolioMenu;
72  
73      /**
74       * The active portfolio bucket list.
75       */
76      private MoneyWiseXAnalysisPortfolioBucketList thePortfolios;
77  
78      /**
79       * The state.
80       */
81      private MoneyWisePortfolioState theState;
82  
83      /**
84       * The savePoint.
85       */
86      private MoneyWisePortfolioState theSavePoint;
87  
88      /**
89       * Constructor.
90       *
91       * @param pFactory the GUI factory
92       */
93      protected MoneyWiseXPortfolioAnalysisSelect(final TethysUIFactory<?> pFactory) {
94          /* Create the portfolio button */
95          thePortButton = pFactory.buttonFactory().newScrollButton(MoneyWiseXAnalysisPortfolioBucket.class);
96  
97          /* Create Event Manager */
98          theEventManager = new OceanusEventManager<>();
99  
100         /* Create the labels */
101         final TethysUILabel myPortLabel = pFactory.controlFactory().newLabel(NLS_PORTFOLIO + TethysUIConstant.STR_COLON);
102 
103         /* Define the layout */
104         thePanel = pFactory.paneFactory().newHBoxPane();
105         thePanel.addSpacer();
106         thePanel.addNode(myPortLabel);
107         thePanel.addNode(thePortButton);
108 
109         /* Create initial state */
110         theState = new MoneyWisePortfolioState();
111         theState.applyState();
112 
113         /* Access the menus */
114         thePortfolioMenu = thePortButton.getMenu();
115 
116         /* Create the listeners */
117         final OceanusEventRegistrar<TethysUIEvent> myRegistrar = thePortButton.getEventRegistrar();
118         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewPortfolio());
119         thePortButton.setMenuConfigurator(e -> buildPortfolioMenu());
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 MoneyWiseXAnalysisPortfolioCashFilter getFilter() {
134         return theState.getFilter();
135     }
136 
137     @Override
138     public boolean isAvailable() {
139         return thePortfolios != null
140                 && !thePortfolios.isEmpty();
141     }
142 
143     /**
144      * Create SavePoint.
145      */
146     public void createSavePoint() {
147         /* Create the savePoint */
148         theSavePoint = new MoneyWisePortfolioState(theState);
149     }
150 
151     /**
152      * Restore SavePoint.
153      */
154     public void restoreSavePoint() {
155         /* Restore the savePoint */
156         theState = new MoneyWisePortfolioState(theSavePoint);
157 
158         /* Apply the state */
159         theState.applyState();
160     }
161 
162     @Override
163     public void setEnabled(final boolean bEnabled) {
164         /* Determine whether there are any portfolios to select */
165         final boolean portAvailable = bEnabled && isAvailable();
166 
167         /* Pass call on to buttons */
168         thePortButton.setEnabled(portAvailable);
169     }
170 
171     @Override
172     public void setVisible(final boolean pVisible) {
173         thePanel.setVisible(pVisible);
174     }
175 
176     /**
177      * Set analysis.
178      *
179      * @param pAnalysis the analysis.
180      */
181     public void setAnalysis(final MoneyWiseXAnalysis pAnalysis) {
182         /* Access buckets */
183         thePortfolios = pAnalysis.getPortfolios();
184 
185         /* Obtain the current portfolio */
186         MoneyWiseXAnalysisPortfolioBucket myPortfolio = theState.getPortfolio();
187 
188         /* Switch to versions from the analysis */
189         myPortfolio = myPortfolio != null
190                 ? thePortfolios.getMatchingPortfolio(myPortfolio.getPortfolio())
191                 : thePortfolios.getDefaultPortfolio();
192 
193         /* Set the portfolio */
194         theState.setThePortfolio(myPortfolio);
195         theState.setDateRange(pAnalysis.getDateRange());
196         theState.applyState();
197     }
198 
199     @Override
200     public void setFilter(final MoneyWiseXAnalysisFilter<?, ?> pFilter) {
201         /* If this is the correct filter type */
202         if (pFilter instanceof MoneyWiseXAnalysisPortfolioCashFilter myFilter) {
203             /* Obtain the filter bucket */
204             MoneyWiseXAnalysisPortfolioBucket myPortfolio = myFilter.getPortfolioBucket();
205 
206             /* Look for the equivalent bucket */
207             myPortfolio = thePortfolios.getMatchingPortfolio(myPortfolio.getPortfolio());
208 
209             /* Set the portfolio */
210             theState.setThePortfolio(myPortfolio);
211             theState.setDateRange(myFilter.getDateRange());
212             theState.applyState();
213         }
214     }
215 
216     /**
217      * Handle new Portfolio.
218      */
219     private void handleNewPortfolio() {
220         /* Select the new portfolio */
221         if (theState.setPortfolio(thePortButton.getValue())) {
222             theState.applyState();
223             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
224         }
225     }
226 
227     /**
228      * Build Portfolio menu.
229      */
230     private void buildPortfolioMenu() {
231         /* Reset the popUp menu */
232         thePortfolioMenu.removeAllItems();
233 
234         /* Record active item */
235         TethysUIScrollItem<MoneyWiseXAnalysisPortfolioBucket> myActive = null;
236         final MoneyWiseXAnalysisPortfolioBucket myCurr = theState.getPortfolio();
237 
238         /* Loop through the available portfolio values */
239         final Iterator<MoneyWiseXAnalysisPortfolioBucket> myIterator = thePortfolios.iterator();
240         while (myIterator.hasNext()) {
241             final MoneyWiseXAnalysisPortfolioBucket myBucket = myIterator.next();
242 
243             /* Create a new MenuItem and add it to the popUp */
244             final TethysUIScrollItem<MoneyWiseXAnalysisPortfolioBucket> myItem = thePortfolioMenu.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 MoneyWisePortfolioState {
263         /**
264          * The active Portfolio.
265          */
266         private MoneyWiseXAnalysisPortfolioBucket thePortfolio;
267 
268         /**
269          * The dateRange.
270          */
271         private OceanusDateRange theDateRange;
272 
273         /**
274          * The active filter.
275          */
276         private MoneyWiseXAnalysisPortfolioCashFilter theFilter;
277 
278         /**
279          * Constructor.
280          */
281         private MoneyWisePortfolioState() {
282         }
283 
284         /**
285          * Constructor.
286          *
287          * @param pState state to copy from
288          */
289         private MoneyWisePortfolioState(final MoneyWisePortfolioState pState) {
290             /* Initialise state */
291             thePortfolio = pState.getPortfolio();
292             theDateRange = pState.getDateRange();
293             theFilter = pState.getFilter();
294         }
295 
296         /**
297          * Obtain the Portfolio.
298          *
299          * @return the portfolio
300          */
301         private MoneyWiseXAnalysisPortfolioBucket getPortfolio() {
302             return thePortfolio;
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 MoneyWiseXAnalysisPortfolioCashFilter getFilter() {
320             return theFilter;
321         }
322 
323         /**
324          * Set new Portfolio.
325          *
326          * @param pPortfolio the Portfolio
327          * @return true/false did a change occur
328          */
329         private boolean setPortfolio(final MoneyWiseXAnalysisPortfolioBucket pPortfolio) {
330             /* Adjust the selected portfolio */
331             if (!MetisDataDifference.isEqual(pPortfolio, thePortfolio)) {
332                 setThePortfolio(pPortfolio);
333                 return true;
334             }
335             return false;
336         }
337 
338         /**
339          * Set the Portfolio.
340          *
341          * @param pPortfolio the Portfolio
342          */
343         private void setThePortfolio(final MoneyWiseXAnalysisPortfolioBucket pPortfolio) {
344             /* Set the selected portfolio */
345             thePortfolio = pPortfolio;
346             if (thePortfolio != null) {
347                 theFilter = new MoneyWiseXAnalysisPortfolioCashFilter(thePortfolio);
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             thePortButton.setValue(thePortfolio);
374         }
375     }
376 }