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.MoneyWiseXAnalysisPayeeBucket;
26  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisPayeeBucket.MoneyWiseXAnalysisPayeeBucketList;
27  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter;
28  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter.MoneyWiseXAnalysisPayeeFilter;
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   * Payee Analysis Selection.
45   */
46  public class MoneyWiseXPayeeAnalysisSelect
47          implements MoneyWiseXAnalysisFilterSelection, OceanusEventProvider<PrometheusDataEvent> {
48      /**
49       * Text for Payee Label.
50       */
51      private static final String NLS_PAYEE = MoneyWiseBasicDataType.PAYEE.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 select button.
65       */
66      private final TethysUIScrollButtonManager<MoneyWiseXAnalysisPayeeBucket> theButton;
67  
68      /**
69       * Payee menu.
70       */
71      private final TethysUIScrollMenu<MoneyWiseXAnalysisPayeeBucket> thePayeeMenu;
72  
73      /**
74       * The active payee bucket list.
75       */
76      private MoneyWiseXAnalysisPayeeBucketList thePayees;
77  
78      /**
79       * The state.
80       */
81      private MoneyWisePayeeState theState;
82  
83      /**
84       * The savePoint.
85       */
86      private MoneyWisePayeeState theSavePoint;
87  
88      /**
89       * Constructor.
90       *
91       * @param pFactory the GUI factory
92       */
93      protected MoneyWiseXPayeeAnalysisSelect(final TethysUIFactory<?> pFactory) {
94          /* Create the button */
95          theButton = pFactory.buttonFactory().newScrollButton(MoneyWiseXAnalysisPayeeBucket.class);
96  
97          /* Create Event Manager */
98          theEventManager = new OceanusEventManager<>();
99  
100         /* Create the label */
101         final TethysUILabel myLabel = pFactory.controlFactory().newLabel(NLS_PAYEE + TethysUIConstant.STR_COLON);
102 
103         /* Define the layout */
104         thePanel = pFactory.paneFactory().newHBoxPane();
105         thePanel.addSpacer();
106         thePanel.addNode(myLabel);
107         thePanel.addNode(theButton);
108 
109         /* Create initial state */
110         theState = new MoneyWisePayeeState();
111         theState.applyState();
112 
113         /* Access the menus */
114         thePayeeMenu = theButton.getMenu();
115 
116         /* Create the listeners */
117         final OceanusEventRegistrar<TethysUIEvent> myRegistrar = theButton.getEventRegistrar();
118         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewPayee());
119         theButton.setMenuConfigurator(e -> buildPayeeMenu());
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 MoneyWiseXAnalysisPayeeFilter getFilter() {
134         return theState.getFilter();
135     }
136 
137     @Override
138     public boolean isAvailable() {
139         return thePayees != null
140                 && !thePayees.isEmpty();
141     }
142 
143     /**
144      * Create SavePoint.
145      */
146     public void createSavePoint() {
147         /* Create the savePoint */
148         theSavePoint = new MoneyWisePayeeState(theState);
149     }
150 
151     /**
152      * Restore SavePoint.
153      */
154     public void restoreSavePoint() {
155         /* Restore the savePoint */
156         theState = new MoneyWisePayeeState(theSavePoint);
157 
158         /* Apply the state */
159         theState.applyState();
160     }
161 
162     @Override
163     public void setEnabled(final boolean bEnabled) {
164         /* Pass call on to button */
165         theButton.setEnabled(bEnabled && isAvailable());
166     }
167 
168     @Override
169     public void setVisible(final boolean pVisible) {
170         thePanel.setVisible(pVisible);
171     }
172 
173     /**
174      * Set analysis.
175      *
176      * @param pAnalysis the analysis.
177      */
178     public void setAnalysis(final MoneyWiseXAnalysis pAnalysis) {
179         /* Access buckets */
180         thePayees = pAnalysis.getPayees();
181 
182         /* Obtain the current payee */
183         MoneyWiseXAnalysisPayeeBucket myPayee = theState.getPayee();
184 
185         /* Switch to versions from the analysis */
186         myPayee = myPayee != null
187                 ? thePayees.getMatchingPayee(myPayee.getPayee())
188                 : thePayees.getDefaultPayee();
189 
190         /* Set the payee */
191         theState.setThePayee(myPayee);
192         theState.setDateRange(pAnalysis.getDateRange());
193         theState.applyState();
194     }
195 
196     @Override
197     public void setFilter(final MoneyWiseXAnalysisFilter<?, ?> pFilter) {
198         /* If this is the correct filter type */
199         if (pFilter instanceof MoneyWiseXAnalysisPayeeFilter myFilter) {
200             /* Obtain the filter bucket */
201             MoneyWiseXAnalysisPayeeBucket myPayee = myFilter.getBucket();
202 
203             /* Obtain equivalent bucket */
204             myPayee = thePayees.getMatchingPayee(myPayee.getPayee());
205 
206             /* Set the payee */
207             theState.setThePayee(myPayee);
208             theState.setDateRange(myFilter.getDateRange());
209             theState.applyState();
210         }
211     }
212 
213     /**
214      * Handle new Payee.
215      */
216     private void handleNewPayee() {
217         /* Select the new Payee */
218         if (theState.setPayee(theButton.getValue())) {
219             theState.applyState();
220             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
221         }
222     }
223 
224     /**
225      * Build Payee menu.
226      */
227     private void buildPayeeMenu() {
228         /* Reset the popUp menu */
229         thePayeeMenu.removeAllItems();
230 
231         /* Record active item */
232         TethysUIScrollItem<MoneyWiseXAnalysisPayeeBucket> myActive = null;
233         final MoneyWiseXAnalysisPayeeBucket myCurr = theState.getPayee();
234 
235         /* Loop through the available payee values */
236         final Iterator<MoneyWiseXAnalysisPayeeBucket> myIterator = thePayees.iterator();
237         while (myIterator.hasNext()) {
238             final MoneyWiseXAnalysisPayeeBucket myBucket = myIterator.next();
239 
240             /* Create a new MenuItem and add it to the popUp */
241             final TethysUIScrollItem<MoneyWiseXAnalysisPayeeBucket> myItem = thePayeeMenu.addItem(myBucket);
242 
243             /* If this is the active bucket */
244             if (myBucket.equals(myCurr)) {
245                 /* Record it */
246                 myActive = myItem;
247             }
248         }
249 
250         /* Ensure active item is visible */
251         if (myActive != null) {
252             myActive.scrollToItem();
253         }
254     }
255 
256     /**
257      * SavePoint values.
258      */
259     private final class MoneyWisePayeeState {
260         /**
261          * The active PayeeBucket.
262          */
263         private MoneyWiseXAnalysisPayeeBucket thePayee;
264 
265         /**
266          * The dateRange.
267          */
268         private OceanusDateRange theDateRange;
269 
270         /**
271          * The active filter.
272          */
273         private MoneyWiseXAnalysisPayeeFilter theFilter;
274 
275         /**
276          * Constructor.
277          */
278         private MoneyWisePayeeState() {
279         }
280 
281         /**
282          * Constructor.
283          *
284          * @param pState state to copy from
285          */
286         private MoneyWisePayeeState(final MoneyWisePayeeState pState) {
287             /* Initialise state */
288             thePayee = pState.getPayee();
289             theDateRange = pState.getDateRange();
290             theFilter = pState.getFilter();
291         }
292 
293         /**
294          * Obtain the Payee Bucket.
295          *
296          * @return the Payee
297          */
298         private MoneyWiseXAnalysisPayeeBucket getPayee() {
299             return thePayee;
300         }
301 
302         /**
303          * Obtain the dateRange.
304          *
305          * @return the dateRange
306          */
307         private OceanusDateRange getDateRange() {
308             return theDateRange;
309         }
310 
311         /**
312          * Obtain the Filter.
313          *
314          * @return the Filter
315          */
316         private MoneyWiseXAnalysisPayeeFilter getFilter() {
317             return theFilter;
318         }
319 
320         /**
321          * Set new Payee.
322          *
323          * @param pPayee the Payee
324          * @return true/false did a change occur
325          */
326         private boolean setPayee(final MoneyWiseXAnalysisPayeeBucket pPayee) {
327             /* Adjust the selected payee */
328             if (!MetisDataDifference.isEqual(pPayee, thePayee)) {
329                 setThePayee(pPayee);
330                 return true;
331             }
332             return false;
333         }
334 
335         /**
336          * Set the Payee.
337          *
338          * @param pPayee the Payee
339          */
340         private void setThePayee(final MoneyWiseXAnalysisPayeeBucket pPayee) {
341             /* Store the payee */
342             thePayee = pPayee;
343             if (thePayee != null) {
344                 theFilter = new MoneyWiseXAnalysisPayeeFilter(thePayee);
345                 theFilter.setDateRange(theDateRange);
346             } else {
347                 theFilter = null;
348             }
349         }
350 
351         /**
352          * Set the dateRange.
353          *
354          * @param pRange the dateRange
355          */
356         private void setDateRange(final OceanusDateRange pRange) {
357             /* Store the dateRange */
358             theDateRange = pRange;
359             if (theFilter != null) {
360                 theFilter.setDateRange(theDateRange);
361             }
362         }
363 
364         /**
365          * Apply the State.
366          */
367         private void applyState() {
368             /* Adjust the lock-down */
369             setEnabled(true);
370             theButton.setValue(thePayee);
371         }
372     }
373 }