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.MoneyWiseAnalysisPortfolioBucket;
27  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysisPortfolioBucket.MoneyWiseAnalysisPortfolioBucketList;
28  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter;
29  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter.MoneyWiseAnalysisPortfolioCashFilter;
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 MoneyWisePortfolioAnalysisSelect
47          implements MoneyWiseAnalysisFilterSelection, 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<MoneyWiseAnalysisPortfolioBucket> thePortButton;
67  
68      /**
69       * Portfolio menu.
70       */
71      private final TethysUIScrollMenu<MoneyWiseAnalysisPortfolioBucket> thePortfolioMenu;
72  
73      /**
74       * The active portfolio bucket list.
75       */
76      private MoneyWiseAnalysisPortfolioBucketList 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 MoneyWisePortfolioAnalysisSelect(final TethysUIFactory<?> pFactory) {
94          /* Create the portfolio button */
95          thePortButton = pFactory.buttonFactory().newScrollButton(MoneyWiseAnalysisPortfolioBucket.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 MoneyWiseAnalysisPortfolioCashFilter 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 MoneyWiseAnalysis pAnalysis) {
182         /* Access buckets */
183         thePortfolios = pAnalysis.getPortfolios();
184 
185         /* Obtain the current portfolio */
186         MoneyWiseAnalysisPortfolioBucket 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 MoneyWiseAnalysisFilter<?, ?> pFilter) {
201         /* If this is the correct filter type */
202         if (pFilter instanceof MoneyWiseAnalysisPortfolioCashFilter) {
203             /* Access filter */
204             final MoneyWiseAnalysisPortfolioCashFilter myFilter = (MoneyWiseAnalysisPortfolioCashFilter) pFilter;
205 
206             /* Obtain the filter bucket */
207             MoneyWiseAnalysisPortfolioBucket myPortfolio = myFilter.getPortfolioBucket();
208 
209             /* Look for the equivalent bucket */
210             myPortfolio = thePortfolios.getMatchingPortfolio(myPortfolio.getPortfolio());
211 
212             /* Set the portfolio */
213             theState.setThePortfolio(myPortfolio);
214             theState.setDateRange(myFilter.getDateRange());
215             theState.applyState();
216         }
217     }
218 
219     /**
220      * Handle new Portfolio.
221      */
222     private void handleNewPortfolio() {
223         /* Select the new portfolio */
224         if (theState.setPortfolio(thePortButton.getValue())) {
225             theState.applyState();
226             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
227         }
228     }
229 
230     /**
231      * Build Portfolio menu.
232      */
233     private void buildPortfolioMenu() {
234         /* Reset the popUp menu */
235         thePortfolioMenu.removeAllItems();
236 
237         /* Record active item */
238         TethysUIScrollItem<MoneyWiseAnalysisPortfolioBucket> myActive = null;
239         final MoneyWiseAnalysisPortfolioBucket myCurr = theState.getPortfolio();
240 
241         /* Loop through the available portfolio values */
242         final Iterator<MoneyWiseAnalysisPortfolioBucket> myIterator = thePortfolios.iterator();
243         while (myIterator.hasNext()) {
244             final MoneyWiseAnalysisPortfolioBucket myBucket = myIterator.next();
245 
246             /* Create a new MenuItem and add it to the popUp */
247             final TethysUIScrollItem<MoneyWiseAnalysisPortfolioBucket> myItem = thePortfolioMenu.addItem(myBucket);
248 
249             /* If this is the active bucket */
250             if (myBucket.equals(myCurr)) {
251                 /* Record it */
252                 myActive = myItem;
253             }
254         }
255 
256         /* Ensure active item is visible */
257         if (myActive != null) {
258             myActive.scrollToItem();
259         }
260     }
261 
262     /**
263      * SavePoint values.
264      */
265     private final class MoneyWisePortfolioState {
266         /**
267          * The active Portfolio.
268          */
269         private MoneyWiseAnalysisPortfolioBucket thePortfolio;
270 
271         /**
272          * The dateRange.
273          */
274         private OceanusDateRange theDateRange;
275 
276         /**
277          * The active filter.
278          */
279         private MoneyWiseAnalysisPortfolioCashFilter theFilter;
280 
281         /**
282          * Constructor.
283          */
284         private MoneyWisePortfolioState() {
285         }
286 
287         /**
288          * Constructor.
289          *
290          * @param pState state to copy from
291          */
292         private MoneyWisePortfolioState(final MoneyWisePortfolioState pState) {
293             /* Initialise state */
294             thePortfolio = pState.getPortfolio();
295             theDateRange = pState.getDateRange();
296             theFilter = pState.getFilter();
297         }
298 
299         /**
300          * Obtain the Portfolio.
301          *
302          * @return the portfolio
303          */
304         private MoneyWiseAnalysisPortfolioBucket getPortfolio() {
305             return thePortfolio;
306         }
307 
308         /**
309          * Obtain the dateRange.
310          *
311          * @return the dateRange
312          */
313         private OceanusDateRange getDateRange() {
314             return theDateRange;
315         }
316 
317         /**
318          * Obtain the Filter.
319          *
320          * @return the filter
321          */
322         private MoneyWiseAnalysisPortfolioCashFilter getFilter() {
323             return theFilter;
324         }
325 
326         /**
327          * Set new Portfolio.
328          *
329          * @param pPortfolio the Portfolio
330          * @return true/false did a change occur
331          */
332         private boolean setPortfolio(final MoneyWiseAnalysisPortfolioBucket pPortfolio) {
333             /* Adjust the selected portfolio */
334             if (!MetisDataDifference.isEqual(pPortfolio, thePortfolio)) {
335                 setThePortfolio(pPortfolio);
336                 return true;
337             }
338             return false;
339         }
340 
341         /**
342          * Set the Portfolio.
343          *
344          * @param pPortfolio the Portfolio
345          */
346         private void setThePortfolio(final MoneyWiseAnalysisPortfolioBucket pPortfolio) {
347             /* Set the selected portfolio */
348             thePortfolio = pPortfolio;
349             if (thePortfolio != null) {
350                 theFilter = new MoneyWiseAnalysisPortfolioCashFilter(thePortfolio);
351                 theFilter.setDateRange(theDateRange);
352             } else {
353                 theFilter = null;
354             }
355         }
356 
357         /**
358          * Set the dateRange.
359          *
360          * @param pRange the dateRange
361          */
362         private void setDateRange(final OceanusDateRange pRange) {
363             /* Store the dateRange */
364             theDateRange = pRange;
365             if (theFilter != null) {
366                 theFilter.setDateRange(theDateRange);
367             }
368         }
369 
370         /**
371          * Apply the State.
372          */
373         private void applyState() {
374             /* Adjust the lock-down */
375             setEnabled(true);
376             thePortButton.setValue(thePortfolio);
377         }
378     }
379 }