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.ui.controls;
18  
19  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
20  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
21  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
22  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
23  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar.OceanusEventProvider;
24  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
25  import io.github.tonywasher.joceanus.metis.ui.MetisIcon;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataSet;
27  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
28  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
29  import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
30  import io.github.tonywasher.joceanus.prometheus.views.PrometheusDataEvent;
31  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIArrowIconId;
32  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIComponent;
33  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
34  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButton;
35  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButtonFactory;
36  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIDateButtonManager;
37  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControlFactory;
38  import io.github.tonywasher.joceanus.tethys.api.control.TethysUILabel;
39  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
40  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBoxPaneManager;
41  
42  /**
43   * SpotRates selection panel.
44   */
45  public class MoneyWiseSpotRatesSelect
46          implements OceanusEventProvider<PrometheusDataEvent>, TethysUIComponent {
47      /**
48       * Text for Currency Prompt.
49       */
50      private static final String NLS_CURRENCY = MoneyWiseUIResource.SPOTRATE_PROMPT_CURR.getValue();
51  
52      /**
53       * Text for Date Label.
54       */
55      private static final String NLS_DATE = MoneyWiseUIResource.SPOTEVENT_DATE.getValue();
56  
57      /**
58       * Text for Title.
59       */
60      private static final String NLS_TITLE = MoneyWiseUIResource.SPOTRATE_TITLE.getValue();
61  
62      /**
63       * Text for Next toolTip.
64       */
65      private static final String NLS_NEXTTIP = MoneyWiseUIResource.SPOTRATE_NEXT.getValue();
66  
67      /**
68       * Text for Previous toolTip.
69       */
70      private static final String NLS_PREVTIP = MoneyWiseUIResource.SPOTRATE_PREV.getValue();
71  
72      /**
73       * The Event Manager.
74       */
75      private final OceanusEventManager<PrometheusDataEvent> theEventManager;
76  
77      /**
78       * The panel.
79       */
80      private final TethysUIBoxPaneManager thePanel;
81  
82      /**
83       * The data view.
84       */
85      private final MoneyWiseView theView;
86  
87      /**
88       * The currency label.
89       */
90      private final TethysUILabel theCurrLabel;
91  
92      /**
93       * The date button.
94       */
95      private final TethysUIDateButtonManager theDateButton;
96  
97      /**
98       * The next button.
99       */
100     private final TethysUIButton theNext;
101 
102     /**
103      * The previous button.
104      */
105     private final TethysUIButton thePrev;
106 
107     /**
108      * The download button.
109      */
110     private final TethysUIButton theDownloadButton;
111 
112     /**
113      * The current state.
114      */
115     private MoneyWiseSpotRatesState theState;
116 
117     /**
118      * The saved state.
119      */
120     private MoneyWiseSpotRatesState theSavePoint;
121 
122     /**
123      * Constructor.
124      *
125      * @param pFactory the GUI factory
126      * @param pView    the data view
127      */
128     public MoneyWiseSpotRatesSelect(final TethysUIFactory<?> pFactory,
129                                     final MoneyWiseView pView) {
130         /* Store table and view details */
131         theView = pView;
132 
133         /* Create Event Manager */
134         theEventManager = new OceanusEventManager<>();
135 
136         /* Create Labels */
137         final TethysUIControlFactory myControls = pFactory.controlFactory();
138         final TethysUILabel myCurr = myControls.newLabel(NLS_CURRENCY);
139         final TethysUILabel myDate = myControls.newLabel(NLS_DATE);
140 
141         /* Create the DateButton */
142         final TethysUIButtonFactory<?> myButtons = pFactory.buttonFactory();
143         theDateButton = myButtons.newDateButton();
144 
145         /* Create the Download Button */
146         theDownloadButton = myButtons.newButton();
147         MetisIcon.configureDownloadIconButton(theDownloadButton);
148 
149         /* Create the Currency indication */
150         theCurrLabel = myControls.newLabel();
151 
152         /* Create the Buttons */
153         theNext = myButtons.newButton();
154         theNext.setIcon(TethysUIArrowIconId.RIGHT);
155         theNext.setToolTip(NLS_NEXTTIP);
156         thePrev = myButtons.newButton();
157         thePrev.setIcon(TethysUIArrowIconId.LEFT);
158         thePrev.setToolTip(NLS_PREVTIP);
159 
160         /* Create initial state */
161         theState = new MoneyWiseSpotRatesState();
162 
163         /* Create the panel */
164         thePanel = pFactory.paneFactory().newHBoxPane();
165         thePanel.setBorderTitle(NLS_TITLE);
166 
167         /* Define the layout */
168         thePanel.addNode(myCurr);
169         thePanel.addNode(theCurrLabel);
170         thePanel.addSpacer();
171         thePanel.addNode(myDate);
172         thePanel.addNode(thePrev);
173         thePanel.addNode(theDateButton);
174         thePanel.addNode(theNext);
175         thePanel.addSpacer();
176         thePanel.addNode(theDownloadButton);
177 
178         /* Initialise the data from the view */
179         refreshData();
180 
181         /* Apply the current state */
182         theState.applyState();
183 
184         /* Add the listeners */
185         theDateButton.getEventRegistrar().addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewDate());
186         theDownloadButton.getEventRegistrar().addEventListener(TethysUIEvent.PRESSED, e -> theEventManager.fireEvent(PrometheusDataEvent.DOWNLOAD));
187         theNext.getEventRegistrar().addEventListener(e -> {
188             theState.setNext();
189             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
190         });
191         thePrev.getEventRegistrar().addEventListener(e -> {
192             theState.setPrev();
193             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
194         });
195     }
196 
197     @Override
198     public TethysUIComponent getUnderlying() {
199         return thePanel;
200     }
201 
202     @Override
203     public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
204         return theEventManager.getEventRegistrar();
205     }
206 
207     /**
208      * Get the selected date.
209      *
210      * @return the date
211      */
212     public OceanusDate getDate() {
213         return theState.getDate();
214     }
215 
216     /**
217      * Refresh data.
218      */
219     public final void refreshData() {
220         /* Access the data */
221         final OceanusDateRange myRange = theView.getRange();
222 
223         /* Set the range for the Date Button */
224         setRange(myRange);
225 
226         /* Set the currency name */
227         final MoneyWiseDataSet myData = theView.getData();
228         final MoneyWiseCurrency myDefault = myData.getReportingCurrency();
229         theCurrLabel.setText(myDefault != null
230                 ? myDefault.getDesc() + " (" + myDefault.getName() + ")"
231                 : null);
232     }
233 
234     /**
235      * Set the range for the date box.
236      *
237      * @param pRange the Range to set
238      */
239     private void setRange(final OceanusDateRange pRange) {
240         final OceanusDate myStart = (pRange == null)
241                 ? null
242                 : pRange.getStart();
243         final OceanusDate myEnd = (pRange == null)
244                 ? null
245                 : pRange.getEnd();
246 
247         /* Set up range */
248         theDateButton.setEarliestDate(myStart);
249         theDateButton.setLatestDate(myEnd);
250     }
251 
252     @Override
253     public void setEnabled(final boolean bEnabled) {
254         theNext.setEnabled(bEnabled && (theState.getNextDate() != null));
255         thePrev.setEnabled(bEnabled && (theState.getPrevDate() != null));
256         theDateButton.setEnabled(bEnabled);
257         theDownloadButton.setEnabled(bEnabled);
258     }
259 
260     @Override
261     public void setVisible(final boolean pVisible) {
262         thePanel.setVisible(pVisible);
263     }
264 
265     /**
266      * Create SavePoint.
267      */
268     public void createSavePoint() {
269         /* Create the savePoint */
270         theSavePoint = new MoneyWiseSpotRatesState(theState);
271     }
272 
273     /**
274      * Restore SavePoint.
275      */
276     public void restoreSavePoint() {
277         /* Restore the savePoint */
278         theState = new MoneyWiseSpotRatesState(theSavePoint);
279 
280         /* Apply the state */
281         theState.applyState();
282     }
283 
284     /**
285      * Set Adjacent dates.
286      *
287      * @param pPrev the previous Date
288      * @param pNext the next Date
289      */
290     public void setAdjacent(final OceanusDate pPrev,
291                             final OceanusDate pNext) {
292         /* Record the dates */
293         theState.setAdjacent(pPrev, pNext);
294     }
295 
296     /**
297      * Handle new Date.
298      */
299     private void handleNewDate() {
300         /* Select the new date */
301         if (theState.setDate(theDateButton)) {
302             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
303         }
304     }
305 
306     /**
307      * SavePoint values.
308      */
309     private final class MoneyWiseSpotRatesState {
310         /**
311          * Selected date.
312          */
313         private OceanusDate theDate;
314 
315         /**
316          * Next date.
317          */
318         private OceanusDate theNextDate;
319 
320         /**
321          * Previous date.
322          */
323         private OceanusDate thePrevDate;
324 
325         /**
326          * Constructor.
327          */
328         private MoneyWiseSpotRatesState() {
329             theDate = new OceanusDate();
330         }
331 
332         /**
333          * Constructor.
334          *
335          * @param pState state to copy from
336          */
337         private MoneyWiseSpotRatesState(final MoneyWiseSpotRatesState pState) {
338             theDate = new OceanusDate(pState.getDate());
339             if (pState.getNextDate() != null) {
340                 theNextDate = new OceanusDate(pState.getNextDate());
341             }
342             if (pState.getPrevDate() != null) {
343                 thePrevDate = new OceanusDate(pState.getPrevDate());
344             }
345         }
346 
347         /**
348          * Get the selected date.
349          *
350          * @return the date
351          */
352         private OceanusDate getDate() {
353             return theDate;
354         }
355 
356         /**
357          * Get the next date.
358          *
359          * @return the date
360          */
361         private OceanusDate getNextDate() {
362             return theNextDate;
363         }
364 
365         /**
366          * Get the previous date.
367          *
368          * @return the date
369          */
370         private OceanusDate getPrevDate() {
371             return thePrevDate;
372         }
373 
374         /**
375          * Set new Date.
376          *
377          * @param pButton the Button with the new date
378          * @return true/false did a change occur
379          */
380         private boolean setDate(final TethysUIDateButtonManager pButton) {
381             /* Adjust the date and build the new range */
382             final OceanusDate myDate = new OceanusDate(pButton.getSelectedDate());
383             if (!MetisDataDifference.isEqual(myDate, theDate)) {
384                 theDate = myDate;
385                 return true;
386             }
387             return false;
388         }
389 
390         /**
391          * Set Next Date.
392          */
393         private void setNext() {
394             /* Copy date */
395             theDate = new OceanusDate(theNextDate);
396             applyState();
397         }
398 
399         /**
400          * Set Previous Date.
401          */
402         private void setPrev() {
403             /* Copy date */
404             theDate = new OceanusDate(thePrevDate);
405             applyState();
406         }
407 
408         /**
409          * Set Adjacent dates.
410          *
411          * @param pPrev the previous Date
412          * @param pNext the next Date
413          */
414         private void setAdjacent(final OceanusDate pPrev,
415                                  final OceanusDate pNext) {
416             /* Record the dates */
417             thePrevDate = pPrev;
418             theNextDate = pNext;
419 
420             /* Adjust values */
421             setEnabled(true);
422         }
423 
424         /**
425          * Apply the State.
426          */
427         private void applyState() {
428             /* Adjust the lock-down */
429             setEnabled(true);
430             theDateButton.setSelectedDate(theDate);
431 
432             /* Determine whether we are todays date */
433             final boolean isToday = MetisDataDifference.isEqual(theDate, new OceanusDate());
434             theDownloadButton.setVisible(isToday);
435         }
436     }
437 }