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.date.OceanusDateResource;
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.atlas.data.analysis.analyse.MoneyWiseXAnalysisManager;
27  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.base.MoneyWiseXAnalysisAttribute;
28  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysis;
29  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisType;
30  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter;
31  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter.MoneyWiseXAnalysisAllFilter;
32  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseAnalysisColumnSet;
33  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
34  import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
35  import io.github.tonywasher.joceanus.prometheus.views.PrometheusDataEvent;
36  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIArrowIconId;
37  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIComponent;
38  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
39  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButton;
40  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIButtonFactory;
41  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIDateRangeSelector;
42  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIScrollButtonManager;
43  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControlFactory;
44  import io.github.tonywasher.joceanus.tethys.api.control.TethysUILabel;
45  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
46  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
47  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBoxPaneManager;
48  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUICardPaneManager;
49  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIPaneFactory;
50  
51  import java.util.EnumMap;
52  import java.util.Map;
53  import java.util.Map.Entry;
54  
55  /**
56   * Selection panel for Analysis Statement.
57   */
58  public class MoneyWiseXAnalysisSelect
59          implements OceanusEventProvider<PrometheusDataEvent>, TethysUIComponent {
60      /**
61       * Text for DateRange Label.
62       */
63      private static final String NLS_RANGE = MoneyWiseUIResource.ANALYSIS_PROMPT_RANGE.getValue();
64  
65      /**
66       * Text for Filter Label.
67       */
68      private static final String NLS_FILTER = MoneyWiseUIResource.ANALYSIS_PROMPT_FILTER.getValue();
69  
70      /**
71       * Text for FilterType Label.
72       */
73      private static final String NLS_FILTERTYPE = MoneyWiseUIResource.ANALYSIS_PROMPT_FILTERTYPE.getValue();
74  
75      /**
76       * Text for ColumnSet Label.
77       */
78      private static final String NLS_COLUMNS = MoneyWiseUIResource.ANALYSIS_PROMPT_COLUMNSET.getValue();
79  
80      /**
81       * Text for BucketType Label.
82       */
83      private static final String NLS_BUCKET = MoneyWiseUIResource.ANALYSIS_PROMPT_BUCKET.getValue();
84  
85      /**
86       * Text for Title.
87       */
88      private static final String NLS_TITLE = MoneyWiseUIResource.ANALYSIS_TITLE.getValue();
89  
90      /**
91       * Text for NoBucket.
92       */
93      private static final String NLS_NONE = MoneyWiseUIResource.ANALYSIS_BUCKET_NONE.getValue();
94  
95      /**
96       * Text for Title.
97       */
98      private static final String NLS_FILTERTITLE = MoneyWiseUIResource.ANALYSIS_FILTER_TITLE.getValue();
99  
100     /**
101      * Text for Box Title.
102      */
103     private static final String NLS_RANGETITLE = OceanusDateResource.TITLE_BOX.getValue();
104 
105     /**
106      * The Event Manager.
107      */
108     private final OceanusEventManager<PrometheusDataEvent> theEventManager;
109 
110     /**
111      * View.
112      */
113     private final MoneyWiseView theView;
114 
115     /**
116      * Panel.
117      */
118     private final TethysUIBoxPaneManager thePanel;
119 
120     /**
121      * Range Button.
122      */
123     private final TethysUIButton theRangeButton;
124 
125     /**
126      * Filter Button.
127      */
128     private final TethysUIButton theFilterButton;
129 
130     /**
131      * Filter Type Button.
132      */
133     private final TethysUIScrollButtonManager<MoneyWiseXAnalysisType> theFilterTypeButton;
134 
135     /**
136      * Bucket Type Button.
137      */
138     private final TethysUIScrollButtonManager<MoneyWiseXAnalysisAttribute> theBucketButton;
139 
140     /**
141      * ColumnSet Button.
142      */
143     private final TethysUIScrollButtonManager<MoneyWiseAnalysisColumnSet> theColumnButton;
144 
145     /**
146      * The bucket label.
147      */
148     private final TethysUILabel theBucketLabel;
149 
150     /**
151      * The column label.
152      */
153     private final TethysUILabel theColumnLabel;
154 
155     /**
156      * The filter detail panel.
157      */
158     private final TethysUIBoxPaneManager theFilterDetail;
159 
160     /**
161      * DateRange Select Panel.
162      */
163     private final TethysUIDateRangeSelector theRangeSelect;
164 
165     /**
166      * Filter Select Panel.
167      */
168     private final TethysUIBoxPaneManager theFilterSelect;
169 
170     /**
171      * Deposit Select Panel.
172      */
173     private final MoneyWiseXDepositAnalysisSelect theDepositSelect;
174 
175     /**
176      * Cash Select Panel.
177      */
178     private final MoneyWiseXCashAnalysisSelect theCashSelect;
179 
180     /**
181      * Loan Select Panel.
182      */
183     private final MoneyWiseXLoanAnalysisSelect theLoanSelect;
184 
185     /**
186      * Security Select Panel.
187      */
188     private final MoneyWiseXSecurityAnalysisSelect theSecuritySelect;
189 
190     /**
191      * Portfolio Select Panel.
192      */
193     private final MoneyWiseXPortfolioAnalysisSelect thePortfolioSelect;
194 
195     /**
196      * Payee Select Panel.
197      */
198     private final MoneyWiseXPayeeAnalysisSelect thePayeeSelect;
199 
200     /**
201      * TransCategory Select Panel.
202      */
203     private final MoneyWiseXTransCategoryAnalysisSelect theCategorySelect;
204 
205     /**
206      * TaxBasis Select Panel.
207      */
208     private final MoneyWiseXTaxBasisAnalysisSelect theTaxBasisSelect;
209 
210     /**
211      * TransactionTag Select Panel.
212      */
213     private final MoneyWiseXTransTagSelect theTagSelect;
214 
215     /**
216      * All Select Panel.
217      */
218     private final MoneyWiseXAllSelect theAllSelect;
219 
220     /**
221      * The card panel.
222      */
223     private final TethysUICardPaneManager<MoneyWiseXAnalysisFilterSelection> theCardPanel;
224 
225     /**
226      * The analysis manager.
227      */
228     private final MoneyWiseXAnalysisManager theAnalysisMgr;
229 
230     /**
231      * Select panel map.
232      */
233     private final Map<MoneyWiseXAnalysisType, MoneyWiseXAnalysisFilterSelection> theMap;
234 
235     /**
236      * AnalysisType menu.
237      */
238     private final TethysUIScrollMenu<MoneyWiseXAnalysisType> theTypeMenu;
239 
240     /**
241      * Bucket menu.
242      */
243     private final TethysUIScrollMenu<MoneyWiseXAnalysisAttribute> theBucketMenu;
244 
245     /**
246      * Column menu.
247      */
248     private final TethysUIScrollMenu<MoneyWiseAnalysisColumnSet> theColumnMenu;
249 
250     /**
251      * Analysis.
252      */
253     private MoneyWiseXAnalysis theAnalysis;
254 
255     /**
256      * Analysis State.
257      */
258     private MoneyWiseAnalysisState theState;
259 
260     /**
261      * The savePoint.
262      */
263     private MoneyWiseAnalysisState theSavePoint;
264 
265     /**
266      * Is the control refreshing?
267      */
268     private boolean isRefreshing;
269 
270     /**
271      * Is the range visible?
272      */
273     private boolean isRangeVisible;
274 
275     /**
276      * Is the filter visible?
277      */
278     private boolean isFilterVisible;
279 
280     /**
281      * Constructor.
282      *
283      * @param pFactory     the GUI factory
284      * @param pView        the view
285      * @param pAnalysisMgr the analysis manager
286      * @param pNewButton   the new button
287      */
288     public MoneyWiseXAnalysisSelect(final TethysUIFactory<?> pFactory,
289                                     final MoneyWiseView pView,
290                                     final MoneyWiseXAnalysisManager pAnalysisMgr,
291                                     final TethysUIButton pNewButton) {
292         /* Access the analysis manager */
293         theView = pView;
294         theAnalysisMgr = pAnalysisMgr;
295 
296         /* Create Event Manager */
297         theEventManager = new OceanusEventManager<>();
298 
299         /* Create the range button */
300         final TethysUIButtonFactory<?> myButtons = pFactory.buttonFactory();
301         theRangeButton = myButtons.newButton();
302         theRangeButton.setIcon(TethysUIArrowIconId.DOWN);
303         theRangeButton.setTextAndIcon();
304 
305         /* Create the filter button */
306         theFilterButton = myButtons.newButton();
307         theFilterButton.setIcon(TethysUIArrowIconId.DOWN);
308         theFilterButton.setTextAndIcon();
309 
310         /* Create the filter type button */
311         theFilterTypeButton = myButtons.newScrollButton(MoneyWiseXAnalysisType.class);
312 
313         /* Create the columnSet button */
314         final TethysUIControlFactory myControls = pFactory.controlFactory();
315         theColumnLabel = myControls.newLabel(NLS_COLUMNS);
316         theColumnButton = myButtons.newScrollButton(MoneyWiseAnalysisColumnSet.class);
317 
318         /* Create the bucket button */
319         theBucketLabel = myControls.newLabel(NLS_BUCKET);
320         theBucketButton = myButtons.newScrollButton(MoneyWiseXAnalysisAttribute.class);
321 
322         /* Create the Range Select panel */
323         theRangeSelect = myButtons.newDateRangeSelector();
324         theRangeSelect.setBorderTitle(NLS_RANGETITLE);
325 
326         /* Create the panel map */
327         theMap = new EnumMap<>(MoneyWiseXAnalysisType.class);
328 
329         /* Create the filter selection panels */
330         theDepositSelect = new MoneyWiseXDepositAnalysisSelect(pFactory);
331         theCashSelect = new MoneyWiseXCashAnalysisSelect(pFactory);
332         theLoanSelect = new MoneyWiseXLoanAnalysisSelect(pFactory);
333         theSecuritySelect = new MoneyWiseXSecurityAnalysisSelect(pFactory);
334         thePortfolioSelect = new MoneyWiseXPortfolioAnalysisSelect(pFactory);
335         thePayeeSelect = new MoneyWiseXPayeeAnalysisSelect(pFactory);
336         theCategorySelect = new MoneyWiseXTransCategoryAnalysisSelect(pFactory);
337         theTaxBasisSelect = new MoneyWiseXTaxBasisAnalysisSelect(pFactory);
338         theTagSelect = new MoneyWiseXTransTagSelect(pFactory);
339         theAllSelect = new MoneyWiseXAllSelect(pFactory);
340 
341         /* Create the card panel */
342         final TethysUIPaneFactory myPanes = pFactory.paneFactory();
343         theCardPanel = myPanes.newCardPane();
344 
345         /* Create the filter detail panel */
346         theFilterDetail = buildFilterDetail(pFactory);
347 
348         /* Create the filter selection panel */
349         theFilterSelect = buildFilterSelect(pFactory);
350 
351         /* Create the control panel */
352         final TethysUIBoxPaneManager myPanel = buildControlPanel(pFactory, pNewButton);
353 
354         /* Create the panel */
355         thePanel = myPanes.newVBoxPane();
356         thePanel.addNode(myPanel);
357         thePanel.addNode(theRangeSelect);
358         thePanel.addNode(theFilterSelect);
359 
360         /* Initially hide the select boxes */
361         theRangeSelect.setVisible(false);
362         theFilterSelect.setVisible(false);
363 
364         /* Create initial state */
365         theState = new MoneyWiseAnalysisState();
366         theState.showColumns(true);
367         final MoneyWiseXStatementSelect mySelect = new MoneyWiseXStatementSelect(theRangeSelect, new MoneyWiseXAnalysisAllFilter());
368         selectStatement(mySelect);
369 
370         /* Access the menus */
371         theTypeMenu = theFilterTypeButton.getMenu();
372         theBucketMenu = theBucketButton.getMenu();
373         theColumnMenu = theColumnButton.getMenu();
374 
375         /* Create the listeners */
376         OceanusEventRegistrar<TethysUIEvent> myRegistrar = theFilterTypeButton.getEventRegistrar();
377         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleFilterType());
378         theFilterTypeButton.setMenuConfigurator(e -> buildAnalysisTypeMenu());
379         myRegistrar = theBucketButton.getEventRegistrar();
380         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewBucket());
381         theBucketButton.setMenuConfigurator(e -> buildBucketMenu());
382         myRegistrar = theColumnButton.getEventRegistrar();
383         myRegistrar.addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewColumns());
384         theColumnButton.setMenuConfigurator(e -> buildColumnsMenu());
385 
386         /* Handle Analysis Manager */
387         theAnalysisMgr.getEventRegistrar().addEventListener(e -> refreshData());
388 
389         /* Handle buttons */
390         theRangeButton.getEventRegistrar().addEventListener(e -> setRangeVisibility(!isRangeVisible));
391         theFilterButton.getEventRegistrar().addEventListener(e -> setFilterVisibility(!isFilterVisible));
392         theRangeSelect.getEventRegistrar().addEventListener(TethysUIEvent.NEWVALUE, e -> handleNewRange());
393 
394         /* handle sub-selections */
395         theDepositSelect.getEventRegistrar().addEventListener(e -> buildDepositFilter());
396         theCashSelect.getEventRegistrar().addEventListener(e -> buildCashFilter());
397         theLoanSelect.getEventRegistrar().addEventListener(e -> buildLoanFilter());
398         theSecuritySelect.getEventRegistrar().addEventListener(e -> buildSecurityFilter());
399         thePortfolioSelect.getEventRegistrar().addEventListener(e -> buildPortfolioFilter());
400         thePayeeSelect.getEventRegistrar().addEventListener(e -> buildPayeeFilter());
401         theCategorySelect.getEventRegistrar().addEventListener(e -> buildCategoryFilter());
402         theTaxBasisSelect.getEventRegistrar().addEventListener(e -> buildTaxBasisFilter());
403         theTagSelect.getEventRegistrar().addEventListener(e -> buildTagFilter());
404     }
405 
406     @Override
407     public TethysUIComponent getUnderlying() {
408         return thePanel;
409     }
410 
411     @Override
412     public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
413         return theEventManager.getEventRegistrar();
414     }
415 
416     /**
417      * Obtain the DateDayRange.
418      *
419      * @return the range.
420      */
421     public OceanusDateRange getRange() {
422         return theState.getRange();
423     }
424 
425     /**
426      * Obtain the analysis.
427      *
428      * @return the range.
429      */
430     public MoneyWiseXAnalysis getAnalysis() {
431         return theAnalysis;
432     }
433 
434     /**
435      * Obtain the Filter.
436      *
437      * @return the filter.
438      */
439     public MoneyWiseXAnalysisFilter<?, ?> getFilter() {
440         return theState.getFilter();
441     }
442 
443     /**
444      * Obtain the ColumnSet.
445      *
446      * @return the columnSet.
447      */
448     public MoneyWiseAnalysisColumnSet getColumns() {
449         return theState.getColumns();
450     }
451 
452     /**
453      * Are we showing columns?
454      *
455      * @return true/false.
456      */
457     public boolean showColumns() {
458         return theState.showColumns();
459     }
460 
461     /**
462      * Create control panel.
463      *
464      * @param pFactory   the GUI factory
465      * @param pNewButton the new button
466      * @return the panel
467      */
468     private TethysUIBoxPaneManager buildControlPanel(final TethysUIFactory<?> pFactory,
469                                                      final TethysUIButton pNewButton) {
470         /* Create the control panel */
471         final TethysUIBoxPaneManager myPanel = pFactory.paneFactory().newHBoxPane();
472 
473         /* Create the labels */
474         final TethysUILabel myRangeLabel = pFactory.controlFactory().newLabel(NLS_RANGE);
475 
476         /* Create save button */
477         final TethysUIButton mySave = pFactory.buttonFactory().newButton();
478         MetisIcon.configureSaveIconButton(mySave);
479 
480         /* Create the panel */
481         myPanel.setBorderTitle(NLS_TITLE);
482         myPanel.addNode(myRangeLabel);
483         myPanel.addNode(theRangeButton);
484         myPanel.addSpacer();
485         myPanel.addNode(theFilterDetail);
486         myPanel.addSpacer();
487         myPanel.addNode(mySave);
488         myPanel.addNode(pNewButton);
489 
490         /* Pass through the save event */
491         final OceanusEventRegistrar<TethysUIEvent> myRegistrar = mySave.getEventRegistrar();
492         myRegistrar.addEventListener(e -> theEventManager.fireEvent(PrometheusDataEvent.SAVETOFILE));
493 
494         /* Return the panel */
495         return myPanel;
496     }
497 
498     /**
499      * Create filter detail panel.
500      *
501      * @param pFactory the GUI factory
502      * @return the panel
503      */
504     private TethysUIBoxPaneManager buildFilterDetail(final TethysUIFactory<?> pFactory) {
505         /* Create the control panel */
506         final TethysUIBoxPaneManager myPanel = pFactory.paneFactory().newHBoxPane();
507 
508         /* Create the labels */
509         final TethysUILabel myFilterLabel = pFactory.controlFactory().newLabel(NLS_FILTER);
510 
511         /* Create the panel */
512         myPanel.addNode(myFilterLabel);
513         myPanel.addNode(theFilterButton);
514         myPanel.addSpacer();
515         myPanel.addNode(theBucketLabel);
516         myPanel.addNode(theColumnLabel);
517         myPanel.addNode(theBucketButton);
518         myPanel.addNode(theColumnButton);
519 
520         /* Return the panel */
521         return myPanel;
522     }
523 
524     /**
525      * Create filter select panel.
526      *
527      * @param pFactory the GUI factory
528      * @return the panel
529      */
530     private TethysUIBoxPaneManager buildFilterSelect(final TethysUIFactory<?> pFactory) {
531         /* Create the filter panel */
532         final TethysUIBoxPaneManager myPanel = pFactory.paneFactory().newHBoxPane();
533 
534         /* Create the labels */
535         final TethysUILabel myTypeLabel = pFactory.controlFactory().newLabel(NLS_FILTERTYPE);
536 
537         /* Add to the card panels */
538         theCardPanel.addCard(MoneyWiseXAnalysisType.DEPOSIT.name(), theDepositSelect);
539         theCardPanel.addCard(MoneyWiseXAnalysisType.CASH.name(), theCashSelect);
540         theCardPanel.addCard(MoneyWiseXAnalysisType.LOAN.name(), theLoanSelect);
541         theCardPanel.addCard(MoneyWiseXAnalysisType.SECURITY.name(), theSecuritySelect);
542         theCardPanel.addCard(MoneyWiseXAnalysisType.PORTFOLIO.name(), thePortfolioSelect);
543         theCardPanel.addCard(MoneyWiseXAnalysisType.PAYEE.name(), thePayeeSelect);
544         theCardPanel.addCard(MoneyWiseXAnalysisType.CATEGORY.name(), theCategorySelect);
545         theCardPanel.addCard(MoneyWiseXAnalysisType.TAXBASIS.name(), theTaxBasisSelect);
546         theCardPanel.addCard(MoneyWiseXAnalysisType.TRANSTAG.name(), theTagSelect);
547         theCardPanel.addCard(MoneyWiseXAnalysisType.ALL.name(), theAllSelect);
548 
549         /* Build the map */
550         theMap.put(MoneyWiseXAnalysisType.DEPOSIT, theDepositSelect);
551         theMap.put(MoneyWiseXAnalysisType.CASH, theCashSelect);
552         theMap.put(MoneyWiseXAnalysisType.LOAN, theLoanSelect);
553         theMap.put(MoneyWiseXAnalysisType.SECURITY, theSecuritySelect);
554         theMap.put(MoneyWiseXAnalysisType.PORTFOLIO, thePortfolioSelect);
555         theMap.put(MoneyWiseXAnalysisType.PAYEE, thePayeeSelect);
556         theMap.put(MoneyWiseXAnalysisType.TAXBASIS, theTaxBasisSelect);
557         theMap.put(MoneyWiseXAnalysisType.TRANSTAG, theTagSelect);
558         theMap.put(MoneyWiseXAnalysisType.ALL, theAllSelect);
559 
560         /* Create the panel */
561         myPanel.setBorderTitle(NLS_FILTERTITLE);
562         myPanel.addNode(myTypeLabel);
563         myPanel.addNode(theFilterTypeButton);
564         myPanel.addSpacer();
565         myPanel.addNode(theCardPanel);
566 
567         /* Return the panel */
568         return myPanel;
569     }
570 
571     /**
572      * Select Statement.
573      *
574      * @param pSelect the selection
575      */
576     public void selectStatement(final MoneyWiseXStatementSelect pSelect) {
577         /* Set refreshing flag */
578         isRefreshing = true;
579 
580         /* Update the range */
581         final TethysUIDateRangeSelector mySelect = pSelect.getRangeSelect();
582         if (mySelect != null) {
583             theRangeSelect.setSelection(mySelect);
584             theRangeSelect.lockPeriod(false);
585             theState.setRange(mySelect);
586 
587             /* Update the analysis */
588             theAnalysis = theAnalysisMgr.getRangedAnalysis(mySelect.getRange());
589             setAnalysis();
590         }
591 
592         /* Access the filter and the selection panel */
593         final MoneyWiseXAnalysisFilter<?, ?> myFilter = pSelect.getFilter();
594         final MoneyWiseXAnalysisType myType = myFilter.getAnalysisType();
595         final MoneyWiseXAnalysisFilterSelection myPanel = theMap.get(myType);
596 
597         /* Move correct card to front and update it */
598         theCardPanel.selectCard(myType.name());
599         myPanel.setFilter(myFilter);
600 
601         /* Determine the state */
602         theState.determineState(myPanel);
603 
604         /* Clear refreshing flag */
605         isRefreshing = false;
606     }
607 
608     /**
609      * Refresh data.
610      */
611     private void refreshData() {
612         /* Update the range selection */
613         final OceanusDateRange myRange = theView.getRange();
614         theRangeSelect.setOverallRange(myRange);
615 
616         /* Refresh the analysisView */
617         theAnalysis = theAnalysisMgr.getRangedAnalysis(getRange());
618 
619         /* Update the filter selection */
620         checkType();
621     }
622 
623     /**
624      * Declare analysis.
625      */
626     private void setAnalysis() {
627         /* Only update if we have an analysis */
628         if (theAnalysis != null) {
629             /* Update filters */
630             theDepositSelect.setAnalysis(theAnalysis);
631             theCashSelect.setAnalysis(theAnalysis);
632             theLoanSelect.setAnalysis(theAnalysis);
633             theSecuritySelect.setAnalysis(theAnalysis);
634             thePortfolioSelect.setAnalysis(theAnalysis);
635             theCategorySelect.setAnalysis(theAnalysis);
636             thePayeeSelect.setAnalysis(theAnalysis);
637             theTaxBasisSelect.setAnalysis(theAnalysis);
638             theTagSelect.setAnalysis(theAnalysis);
639             theAllSelect.setAnalysis(theAnalysis);
640 
641             /* Update the filter */
642             updateFilter();
643         }
644     }
645 
646     /**
647      * Update the filter.
648      */
649     private void updateFilter() {
650         /* Access the active panel */
651         final MoneyWiseXAnalysisType myType = theState.getType();
652         final MoneyWiseXAnalysisFilterSelection myPanel = theMap.get(myType);
653 
654         /* Update filters */
655         if (myPanel != null) {
656             final MoneyWiseXAnalysisFilter<?, ?> myFilter = myPanel.getFilter();
657             myFilter.setCurrentAttribute(theState.getBucket());
658             theState.setFilter(myFilter);
659         }
660 
661         /* Notify updated filter */
662         theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
663     }
664 
665     /**
666      * Create SavePoint.
667      */
668     protected void createSavePoint() {
669         /* Create the savePoint */
670         theSavePoint = new MoneyWiseAnalysisState(theState);
671     }
672 
673     /**
674      * Restore SavePoint.
675      */
676     protected void restoreSavePoint() {
677         /* Restore the savePoint */
678         theState = new MoneyWiseAnalysisState(theSavePoint);
679 
680         /* Apply the state */
681         theState.applyState();
682     }
683 
684     @Override
685     public void setEnabled(final boolean bEnabled) {
686         /* If there are filters available */
687         if (isAvailable()) {
688             /* Enabled disable range selection */
689             theRangeButton.setEnabled(bEnabled);
690 
691             /* Enable filter detail */
692             theFilterDetail.setVisible(true);
693             theFilterButton.setEnabled(bEnabled);
694             theColumnButton.setEnabled(bEnabled);
695             theBucketButton.setEnabled(bEnabled);
696 
697             /* If we are disabling */
698             if (!bEnabled) {
699                 /* Hide panels */
700                 setRangeVisibility(false);
701                 setFilterVisibility(false);
702             }
703 
704             /* else no filters available */
705         } else {
706             /* Enabled disable range selection */
707             theRangeButton.setEnabled(false);
708 
709             /* Hide panels */
710             setRangeVisibility(false);
711             setFilterVisibility(false);
712             theFilterDetail.setVisible(false);
713             theRangeSelect.setEnabled(bEnabled);
714         }
715     }
716 
717     @Override
718     public void setVisible(final boolean pVisible) {
719         thePanel.setVisible(pVisible);
720     }
721 
722     /**
723      * Is there any filter available?
724      *
725      * @return true/false
726      */
727     private boolean isAvailable() {
728         /* Loop through the panels */
729         for (MoneyWiseXAnalysisFilterSelection myEntry : theMap.values()) {
730             /* If the filter is possible */
731             if (myEntry.isAvailable()) {
732                 /* Filter available */
733                 return true;
734             }
735         }
736 
737         /* No available filters */
738         return false;
739     }
740 
741     /**
742      * Check analysis type.
743      */
744     private void checkType() {
745         /* If the type is not appropriate */
746         MoneyWiseXAnalysisType myType = theState.getType();
747 
748         /* If the type is selected */
749         if (myType != null) {
750             /* Check that the filter is appropriate */
751             final MoneyWiseXAnalysisFilterSelection myPanel = theMap.get(myType);
752             if (myPanel.isAvailable()) {
753                 /* We are OK */
754                 final MoneyWiseXAnalysisFilter<?, ?> myFilter = myPanel.getFilter();
755                 theState.setFilter(myFilter);
756                 return;
757             }
758         }
759 
760         /* Loop through the panels */
761         for (Entry<MoneyWiseXAnalysisType, MoneyWiseXAnalysisFilterSelection> myEntry : theMap.entrySet()) {
762             /* If the filter is possible */
763             final MoneyWiseXAnalysisFilterSelection myPanel = myEntry.getValue();
764             if (myPanel.isAvailable()) {
765                 /* Access Analysis type */
766                 myType = myEntry.getKey();
767 
768                 /* Move correct card to front */
769                 theCardPanel.selectCard(myType.name());
770 
771                 /* Obtain the relevant filter */
772                 final MoneyWiseXAnalysisFilter<?, ?> myFilter = myPanel.getFilter();
773                 final MoneyWiseXAnalysisAttribute myDefault = myType.getDefaultValue();
774                 if (myFilter != null) {
775                     myFilter.setCurrentAttribute(myDefault);
776                 }
777 
778                 /* Set new bucket type and apply state */
779                 theState.setAnalysisType(myType);
780                 theState.setFilter(myFilter);
781                 theState.setBucket(myDefault);
782                 theState.applyState();
783 
784                 /* Filter available */
785                 return;
786             }
787         }
788 
789         /* No available filters */
790         theState.setFilter(null);
791         theState.setAnalysisType(null);
792         theState.setBucket(null);
793     }
794 
795     /**
796      * Build AnalysisType menu.
797      */
798     private void buildAnalysisTypeMenu() {
799         /* Reset the popUp menu */
800         theTypeMenu.removeAllItems();
801 
802         /* Loop through the panels */
803         for (Entry<MoneyWiseXAnalysisType, MoneyWiseXAnalysisFilterSelection> myEntry : theMap.entrySet()) {
804             /* If the filter is possible */
805             if (myEntry.getValue().isAvailable()) {
806                 /* Create a new MenuItem and add it to the popUp */
807                 theTypeMenu.addItem(myEntry.getKey());
808             }
809         }
810     }
811 
812     /**
813      * Build Bucket menu.
814      */
815     private void buildBucketMenu() {
816         /* Reset the popUp menu */
817         theBucketMenu.removeAllItems();
818 
819         /* Loop through the buckets */
820         final MoneyWiseXAnalysisFilter<?, ?> myFilter = theState.getFilter();
821         for (MoneyWiseXAnalysisAttribute myAttr : theState.getType().getValues()) {
822             /* If the value is a counter */
823             if (!myAttr.isPreserved()
824                     && myFilter.isRelevantCounter(myAttr)) {
825                 /* Create a new MenuItem and add it to the popUp */
826                 theBucketMenu.addItem(myAttr);
827             }
828         }
829 
830         /* Add the entry for null bucket */
831         theBucketMenu.addNullItem(NLS_NONE);
832     }
833 
834     /**
835      * Build Columns menu.
836      */
837     private void buildColumnsMenu() {
838         /* Reset the popUp menu */
839         theColumnMenu.removeAllItems();
840 
841         /* Determine whether we have balances */
842         final boolean hasBalances = theState.getType().hasBalances();
843 
844         /* Loop through the sets */
845         for (MoneyWiseAnalysisColumnSet mySet : MoneyWiseAnalysisColumnSet.values()) {
846             /* if we have balances or this is not the balance set */
847             if (hasBalances
848                     || !mySet.isBalance()) {
849                 /* Add the item */
850                 theColumnMenu.addItem(mySet);
851             }
852         }
853     }
854 
855     /**
856      * Build Deposit Filter.
857      */
858     private void buildDepositFilter() {
859         applyFilter(theDepositSelect.getFilter());
860     }
861 
862     /**
863      * Build Cash Filter.
864      */
865     private void buildCashFilter() {
866         applyFilter(theCashSelect.getFilter());
867     }
868 
869     /**
870      * Build Loan Filter.
871      */
872     private void buildLoanFilter() {
873         applyFilter(theLoanSelect.getFilter());
874     }
875 
876     /**
877      * Build Security Filter.
878      */
879     private void buildSecurityFilter() {
880         applyFilter(theSecuritySelect.getFilter());
881     }
882 
883     /**
884      * Build Portfolio Filter.
885      */
886     private void buildPortfolioFilter() {
887         applyFilter(thePortfolioSelect.getFilter());
888     }
889 
890     /**
891      * Build Payee Filter.
892      */
893     private void buildPayeeFilter() {
894         applyFilter(thePayeeSelect.getFilter());
895     }
896 
897     /**
898      * Build Category Filter.
899      */
900     private void buildCategoryFilter() {
901         applyFilter(theCategorySelect.getFilter());
902     }
903 
904     /**
905      * Build TaxBasis Filter.
906      */
907     private void buildTaxBasisFilter() {
908         applyFilter(theTaxBasisSelect.getFilter());
909     }
910 
911     /**
912      * Build Tag Filter.
913      */
914     private void buildTagFilter() {
915         applyFilter(theTagSelect.getFilter());
916     }
917 
918     /**
919      * Apply Filter.
920      *
921      * @param pFilter the filter
922      */
923     private void applyFilter(final MoneyWiseXAnalysisFilter<?, ?> pFilter) {
924         /* Ignore if we are refreshing */
925         if (!isRefreshing) {
926             final MoneyWiseXAnalysisAttribute myBucket = theState.getBucket();
927             if (pFilter.isRelevantCounter(myBucket)) {
928                 pFilter.setCurrentAttribute(theState.getBucket());
929             } else {
930                 theState.setBucket(pFilter.getCurrentAttribute());
931             }
932             theState.setFilter(pFilter);
933             theState.applyState();
934             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
935         }
936     }
937 
938     /**
939      * Handle New Range.
940      */
941     private void handleNewRange() {
942         /* Ignore if we are refreshing */
943         if (isRefreshing) {
944             return;
945         }
946 
947         /* If we have a change to the range */
948         if (theState.setRange(theRangeSelect)) {
949             /* Note that we are refreshing */
950             isRefreshing = true;
951 
952             /* Obtain new analysis */
953             theAnalysis = theAnalysisMgr.getRangedAnalysis(getRange());
954             setAnalysis();
955 
956             /* Validate state and apply */
957             checkType();
958             theState.applyState();
959 
960             /* Remove refreshing flag and notify listeners */
961             isRefreshing = false;
962             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
963         }
964     }
965 
966     /**
967      * Set RangeSelect visibility.
968      *
969      * @param pVisible the visibility setting
970      */
971     private void setRangeVisibility(final boolean pVisible) {
972         theRangeButton.setIcon(pVisible
973                 ? TethysUIArrowIconId.UP
974                 : TethysUIArrowIconId.DOWN);
975         theRangeSelect.setVisible(pVisible);
976         isRangeVisible = pVisible;
977     }
978 
979     /**
980      * Set FilterSelect visibility.
981      *
982      * @param pVisible the visibility setting
983      */
984     private void setFilterVisibility(final boolean pVisible) {
985         theFilterButton.setIcon(pVisible
986                 ? TethysUIArrowIconId.UP
987                 : TethysUIArrowIconId.DOWN);
988         theFilterSelect.setVisible(pVisible);
989         isFilterVisible = pVisible;
990     }
991 
992     /**
993      * Handle New Bucket.
994      */
995     private void handleNewBucket() {
996         /* Ignore if we are refreshing */
997         if (isRefreshing) {
998             return;
999         }
1000 
1001         final MoneyWiseXAnalysisAttribute myBucket = theBucketButton.getValue();
1002         if (theState.setBucket(myBucket)) {
1003             final MoneyWiseXAnalysisFilter<?, ?> myFilter = theState.getFilter();
1004             if (myBucket != null) {
1005                 myFilter.setCurrentAttribute(myBucket);
1006             }
1007             theState.applyState();
1008             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
1009         }
1010     }
1011 
1012     /**
1013      * Handle New Columns.
1014      */
1015     private void handleNewColumns() {
1016         /* Ignore if we are refreshing */
1017         if (isRefreshing) {
1018             return;
1019         }
1020 
1021         /* Record the columns */
1022         final MoneyWiseAnalysisColumnSet mySet = theColumnButton.getValue();
1023         if (theState.setColumns(mySet)) {
1024             theState.applyState();
1025             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
1026         }
1027     }
1028 
1029     /**
1030      * Handle FilterType.
1031      */
1032     private void handleFilterType() {
1033         /* Ignore if we are refreshing */
1034         if (isRefreshing) {
1035             return;
1036         }
1037 
1038         /* If the type has changed */
1039         final MoneyWiseXAnalysisType myType = theFilterTypeButton.getValue();
1040         if (theState.setAnalysisType(myType)) {
1041             /* Determine whether we are showing balances */
1042             final boolean showingBalances = !theState.showColumns();
1043             if (showingBalances && !myType.hasBalances()) {
1044                 /* Move to columns if we have no balances */
1045                 theState.showColumns(true);
1046             }
1047 
1048             /* Move correct card to front */
1049             theCardPanel.selectCard(myType.name());
1050 
1051             /* Obtain the relevant filter */
1052             final MoneyWiseXAnalysisFilterSelection myPanel = theMap.get(myType);
1053             final MoneyWiseXAnalysisFilter<?, ?> myFilter = myPanel.getFilter();
1054             myFilter.setCurrentAttribute(myType.getDefaultValue());
1055 
1056             /* Set new bucket type and apply state */
1057             theState.setFilter(myFilter);
1058             theState.setBucket(myFilter.getCurrentAttribute());
1059             theState.applyState();
1060             theEventManager.fireEvent(PrometheusDataEvent.SELECTIONCHANGED);
1061         }
1062     }
1063 
1064     /**
1065      * SavePoint values.
1066      */
1067     private final class MoneyWiseAnalysisState {
1068         /**
1069          * The Range.
1070          */
1071         private OceanusDateRange theRange;
1072 
1073         /**
1074          * The AnalysisType.
1075          */
1076         private MoneyWiseXAnalysisType theType;
1077 
1078         /**
1079          * The BucketAttribute.
1080          */
1081         private MoneyWiseXAnalysisAttribute theBucket;
1082 
1083         /**
1084          * The ColumnSet.
1085          */
1086         private MoneyWiseAnalysisColumnSet theColumns;
1087 
1088         /**
1089          * The filter.
1090          */
1091         private MoneyWiseXAnalysisFilter<?, ?> theFilter;
1092 
1093         /**
1094          * Are we showing Columns?
1095          */
1096         private boolean showColumns;
1097 
1098         /**
1099          * Constructor.
1100          */
1101         private MoneyWiseAnalysisState() {
1102             theRange = null;
1103             theFilter = null;
1104             theType = null;
1105             theBucket = null;
1106             theColumns = MoneyWiseAnalysisColumnSet.STANDARD;
1107             showColumns = true;
1108         }
1109 
1110         /**
1111          * Constructor.
1112          *
1113          * @param pState state to copy from
1114          */
1115         private MoneyWiseAnalysisState(final MoneyWiseAnalysisState pState) {
1116             theRange = pState.getRange();
1117             theFilter = pState.getFilter();
1118             theType = pState.getType();
1119             theBucket = pState.getBucket();
1120             theColumns = pState.getColumns();
1121             showColumns = pState.showColumns();
1122         }
1123 
1124         /**
1125          * Obtain the DateDayRange.
1126          *
1127          * @return the range.
1128          */
1129         private OceanusDateRange getRange() {
1130             return theRange;
1131         }
1132 
1133         /**
1134          * Obtain the AnalysisType.
1135          *
1136          * @return the analysis type.
1137          */
1138         private MoneyWiseXAnalysisType getType() {
1139             return theType;
1140         }
1141 
1142         /**
1143          * Obtain the BucketType.
1144          *
1145          * @return the bucket type.
1146          */
1147         private MoneyWiseXAnalysisAttribute getBucket() {
1148             return theBucket;
1149         }
1150 
1151         /**
1152          * Obtain the Columns.
1153          *
1154          * @return the columns.
1155          */
1156         private MoneyWiseAnalysisColumnSet getColumns() {
1157             return theColumns;
1158         }
1159 
1160         /**
1161          * Obtain the Filter.
1162          *
1163          * @return the filter.
1164          */
1165         private MoneyWiseXAnalysisFilter<?, ?> getFilter() {
1166             return theFilter;
1167         }
1168 
1169         /**
1170          * Are we showing columns?
1171          *
1172          * @return true/false.
1173          */
1174         private boolean showColumns() {
1175             return showColumns;
1176         }
1177 
1178         /**
1179          * Determine selection from panels.
1180          *
1181          * @param pFilter selection panel
1182          */
1183         private void determineState(final MoneyWiseXAnalysisFilterSelection pFilter) {
1184             /* Update the selection panels */
1185             theRange = theRangeSelect.getRange();
1186             theFilter = pFilter.getFilter();
1187             theType = theFilter.getAnalysisType();
1188             theBucket = theFilter.getCurrentAttribute();
1189             showColumns = theBucket == null;
1190             applyState();
1191         }
1192 
1193         /**
1194          * Set new Range from select panel.
1195          *
1196          * @param pSelect the selection panel
1197          * @return true/false did a change occur
1198          */
1199         private boolean setRange(final TethysUIDateRangeSelector pSelect) {
1200             /* Adjust the selected account */
1201             final OceanusDateRange myRange = pSelect.getRange();
1202             if (!MetisDataDifference.isEqual(myRange, theRange)) {
1203                 theRange = myRange;
1204                 return true;
1205             }
1206             return false;
1207         }
1208 
1209         /**
1210          * Set new analysis type.
1211          *
1212          * @param pType the analysis type
1213          * @return true/false did a change occur
1214          */
1215         private boolean setAnalysisType(final MoneyWiseXAnalysisType pType) {
1216             if (!MetisDataDifference.isEqual(pType, theType)) {
1217                 theType = pType;
1218                 return true;
1219             }
1220             return false;
1221         }
1222 
1223         /**
1224          * Set new bucket type.
1225          *
1226          * @param pBucket the bucket type
1227          * @return true/false did a change occur
1228          */
1229         private boolean setBucket(final MoneyWiseXAnalysisAttribute pBucket) {
1230             if (!MetisDataDifference.isEqual(pBucket, theBucket)) {
1231                 /* If this is the null bucket */
1232                 if (pBucket == null) {
1233                     showColumns = true;
1234                 } else {
1235                     theBucket = pBucket;
1236                 }
1237                 return true;
1238             }
1239             return false;
1240         }
1241 
1242         /**
1243          * Set new column set.
1244          *
1245          * @param pColumnSet the column set
1246          * @return true/false did a change occur
1247          */
1248         private boolean setColumns(final MoneyWiseAnalysisColumnSet pColumnSet) {
1249             if (!MetisDataDifference.isEqual(pColumnSet, theColumns)) {
1250                 /* If this is the balance bucket */
1251                 if (pColumnSet.equals(MoneyWiseAnalysisColumnSet.BALANCE)) {
1252                     showColumns = false;
1253                 } else {
1254                     theColumns = pColumnSet;
1255                 }
1256                 return true;
1257             }
1258             return false;
1259         }
1260 
1261         /**
1262          * Set filter.
1263          *
1264          * @param pFilter the filter
1265          */
1266         private void setFilter(final MoneyWiseXAnalysisFilter<?, ?> pFilter) {
1267             theFilter = pFilter;
1268         }
1269 
1270         /**
1271          * Apply the State.
1272          */
1273         private void applyState() {
1274             /* Adjust the lock-down */
1275             setEnabled(true);
1276             theRangeButton.setText(theRange.toString());
1277             theFilterButton.setText((theFilter == null)
1278                     ? null
1279                     : theFilter.getName());
1280             theFilterTypeButton.setValue(theType);
1281             theBucketButton.setValue(theBucket);
1282             theColumnButton.setValue(theColumns);
1283             showColumns(showColumns);
1284         }
1285 
1286         /**
1287          * Show Columns.
1288          *
1289          * @param pShow true/false
1290          */
1291         private void showColumns(final boolean pShow) {
1292             /* Show columns */
1293             theColumnLabel.setVisible(pShow);
1294             theColumnButton.setVisible(pShow);
1295 
1296             /* Hide buckets */
1297             theBucketLabel.setVisible(!pShow);
1298             theBucketButton.setVisible(!pShow);
1299 
1300             /* Record details */
1301             showColumns = pShow;
1302         }
1303     }
1304 
1305     /**
1306      * The Statement Select class.
1307      */
1308     public static final class MoneyWiseXStatementSelect {
1309         /**
1310          * The Range Selection.
1311          */
1312         private final TethysUIDateRangeSelector theRangeSelect;
1313 
1314         /**
1315          * The AnalysisFilter.
1316          */
1317         private final MoneyWiseXAnalysisFilter<?, ?> theFilter;
1318 
1319         /**
1320          * Constructor.
1321          *
1322          * @param pRangeSelect the range selection
1323          * @param pFilter      the analysis filter
1324          */
1325         public MoneyWiseXStatementSelect(final TethysUIDateRangeSelector pRangeSelect,
1326                                          final MoneyWiseXAnalysisFilter<?, ?> pFilter) {
1327             /* Store parameters */
1328             theRangeSelect = pRangeSelect;
1329             theFilter = pFilter;
1330         }
1331 
1332         /**
1333          * Obtain the RangeSelection.
1334          *
1335          * @return the filter
1336          */
1337         public TethysUIDateRangeSelector getRangeSelect() {
1338             return theRangeSelect;
1339         }
1340 
1341         /**
1342          * Obtain the Filter.
1343          *
1344          * @return the filter
1345          */
1346         public MoneyWiseXAnalysisFilter<?, ?> getFilter() {
1347             return theFilter;
1348         }
1349     }
1350 }