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.panel;
18  
19  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
21  import io.github.tonywasher.joceanus.oceanus.event.OceanusEvent;
22  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
23  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
24  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar.OceanusEventProvider;
25  import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
26  import io.github.tonywasher.joceanus.metis.report.MetisReportEvent;
27  import io.github.tonywasher.joceanus.metis.report.MetisReportHTMLBuilder;
28  import io.github.tonywasher.joceanus.metis.report.MetisReportManager;
29  import io.github.tonywasher.joceanus.metis.ui.MetisErrorPanel;
30  import io.github.tonywasher.joceanus.metis.viewer.MetisViewerEntry;
31  import io.github.tonywasher.joceanus.metis.viewer.MetisViewerManager;
32  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.analyse.MoneyWiseXAnalysisManager;
33  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysis;
34  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisSecurityBucket;
35  import io.github.tonywasher.joceanus.moneywise.atlas.reports.MoneyWiseXReportBuilder;
36  import io.github.tonywasher.joceanus.moneywise.atlas.reports.MoneyWiseXReportStyleSheet;
37  import io.github.tonywasher.joceanus.moneywise.atlas.reports.MoneyWiseXReportType;
38  import io.github.tonywasher.joceanus.moneywise.atlas.ui.controls.MoneyWiseXAnalysisSelect.MoneyWiseXStatementSelect;
39  import io.github.tonywasher.joceanus.moneywise.atlas.ui.controls.MoneyWiseXReportSelect;
40  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter;
41  import io.github.tonywasher.joceanus.moneywise.atlas.views.MoneyWiseXAnalysisFilter.MoneyWiseXAnalysisSecurityFilter;
42  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
43  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseGoToId;
44  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
45  import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
46  import io.github.tonywasher.joceanus.prometheus.ui.PrometheusGoToEvent;
47  import io.github.tonywasher.joceanus.prometheus.views.PrometheusDataEvent;
48  import io.github.tonywasher.joceanus.prometheus.views.PrometheusViewerEntryId;
49  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIComponent;
50  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
51  import io.github.tonywasher.joceanus.tethys.api.button.TethysUIDateRangeSelector;
52  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIHTMLManager;
53  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
54  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBorderPaneManager;
55  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIPaneFactory;
56  import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIScrollPaneManager;
57  import org.w3c.dom.Document;
58  
59  /**
60   * Report panel.
61   */
62  public class MoneyWiseXReportTab
63          implements OceanusEventProvider<PrometheusDataEvent>, TethysUIComponent {
64      /**
65       * Text for DataEntry Title.
66       */
67      private static final String NLS_DATAENTRY = MoneyWiseUIResource.REPORT_DATAENTRY.getValue();
68  
69      /**
70       * The Event Manager.
71       */
72      private final OceanusEventManager<PrometheusDataEvent> theEventManager;
73  
74      /**
75       * The Data View.
76       */
77      private final MoneyWiseView theView;
78  
79      /**
80       * The AnalysisManager.
81       */
82      private final MoneyWiseXAnalysisManager theAnalysisMgr;
83  
84      /**
85       * The Panel.
86       */
87      private final TethysUIBorderPaneManager thePanel;
88  
89      /**
90       * The HTML pane.
91       */
92      private final TethysUIHTMLManager theHTMLPane;
93  
94      /**
95       * The Report selection Panel.
96       */
97      private final MoneyWiseXReportSelect theSelect;
98  
99      /**
100      * The Spot Analysis Entry.
101      */
102     private final MetisViewerEntry theSpotEntry;
103 
104     /**
105      * The Error Panel.
106      */
107     private final MetisErrorPanel theError;
108 
109     /**
110      * The Report Manager.
111      */
112     private final MetisReportManager<MoneyWiseXAnalysisFilter<?, ?>> theManager;
113 
114     /**
115      * The ReportBuilder.
116      */
117     private final MoneyWiseXReportBuilder theBuilder;
118 
119     /**
120      * Constructor for Report Window.
121      *
122      * @param pView        the data view
123      * @param pAnalysisMgr the analysisManager
124      * @throws OceanusException on error
125      */
126     public MoneyWiseXReportTab(final MoneyWiseView pView,
127                                final MoneyWiseXAnalysisManager pAnalysisMgr) throws OceanusException {
128         /* Store the view */
129         theView = pView;
130         theAnalysisMgr = pAnalysisMgr;
131 
132         /* Access GUI Factory */
133         final TethysUIFactory<?> myFactory = pView.getGuiFactory();
134 
135         /* Create the event manager */
136         theEventManager = new OceanusEventManager<>();
137 
138         /* Create the Panel */
139         final TethysUIPaneFactory myPanes = myFactory.paneFactory();
140         thePanel = myPanes.newBorderPane();
141 
142         /* Create the top level debug entry for this view */
143         final MetisViewerManager myDataMgr = theView.getViewerManager();
144         final MetisViewerEntry mySection = theView.getViewerEntry(PrometheusViewerEntryId.VIEW);
145         final MetisViewerEntry myReport = myDataMgr.newEntry(mySection, NLS_DATAENTRY);
146         theSpotEntry = myDataMgr.newEntry(myReport, PrometheusViewerEntryId.ANALYSIS.toString());
147         theSpotEntry.setVisible(false);
148 
149         /* Create the HTML Pane */
150         theHTMLPane = myFactory.controlFactory().newHTMLManager();
151 
152         /* Create Report Manager */
153         theManager = new MetisReportManager<>(new MetisReportHTMLBuilder(pView.getDataFormatter()));
154 
155         /* Create the report builder */
156         theBuilder = new MoneyWiseXReportBuilder(theManager);
157 
158         /* Create the Report Selection panel */
159         theSelect = new MoneyWiseXReportSelect(myFactory);
160 
161         /* Create the error panel for this view */
162         theError = theView.getToolkit().getToolkit().newErrorPanel(myReport);
163 
164         /* Create a scroll pane */
165         final TethysUIScrollPaneManager myHTMLScroll = myPanes.newScrollPane();
166         myHTMLScroll.setContent(theHTMLPane);
167 
168         /* Create the header panel */
169         final TethysUIBorderPaneManager myHeader = myPanes.newBorderPane();
170         myHeader.setCentre(theSelect);
171         myHeader.setNorth(theError);
172 
173         /* Now define the panel */
174         thePanel.setNorth(myHeader);
175         thePanel.setCentre(myHTMLScroll);
176 
177         /* Load the CSS */
178         theHTMLPane.setCSSContent(MoneyWiseXReportStyleSheet.CSS_REPORT);
179 
180         /* Create listeners */
181         theView.getEventRegistrar().addEventListener(e -> refreshData());
182         theManager.getEventRegistrar().addEventListener(this::handleGoToRequest);
183         theError.getEventRegistrar().addEventListener(e -> handleErrorPane());
184         final OceanusEventRegistrar<PrometheusDataEvent> myRegistrar = theSelect.getEventRegistrar();
185         myRegistrar.addEventListener(PrometheusDataEvent.SELECTIONCHANGED, e -> handleReportRequest());
186         myRegistrar.addEventListener(PrometheusDataEvent.PRINT, e -> theHTMLPane.printIt());
187         myRegistrar.addEventListener(PrometheusDataEvent.SAVETOFILE, e -> theHTMLPane.saveToFile());
188         theHTMLPane.getEventRegistrar().addEventListener(TethysUIEvent.BUILDPAGE, e -> {
189             theManager.processReference(e.getDetails(String.class), theHTMLPane);
190             e.consume();
191         });
192     }
193 
194     @Override
195     public TethysUIComponent getUnderlying() {
196         return thePanel;
197     }
198 
199     @Override
200     public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
201         return theEventManager.getEventRegistrar();
202     }
203 
204     @Override
205     public void setEnabled(final boolean pEnabled) {
206         /* Pass on to important elements */
207         theSelect.setEnabled(pEnabled);
208         theError.setEnabled(pEnabled);
209         theHTMLPane.setEnabled(pEnabled);
210     }
211 
212     @Override
213     public void setVisible(final boolean pVisible) {
214         thePanel.setVisible(pVisible);
215     }
216 
217     /**
218      * Refresh views/controls after a load/update of underlying data.
219      */
220     private void refreshData() {
221         /* Obtain the active profile */
222         OceanusProfile myTask = theView.getActiveTask();
223         myTask = myTask.startTask("Reports");
224 
225         /* Protect against exceptions */
226         try {
227             /* Hide the instant debug since it is now invalid */
228             theSpotEntry.setVisible(false);
229 
230             /* Refresh the data */
231             theSelect.setRange(theView.getRange());
232             theSelect.setSecurities(theView.hasActiveSecurities());
233             buildReport();
234 
235             /* Create SavePoint */
236             theSelect.createSavePoint();
237         } catch (OceanusException e) {
238             /* Show the error */
239             theView.addError(e);
240 
241             /* Restore SavePoint */
242             theSelect.restoreSavePoint();
243         }
244 
245         /* Complete the task */
246         myTask.end();
247     }
248 
249     /**
250      * Build the report.
251      *
252      * @throws OceanusException on error
253      */
254     private void buildReport() throws OceanusException {
255         /* Access the values from the selection */
256         final MoneyWiseXReportType myReportType = theSelect.getReportType();
257         final OceanusDateRange myRange = theSelect.getDateRange();
258         final MoneyWiseXAnalysisSecurityBucket mySecurity = theSelect.getSecurity();
259 
260         /* set lockDown of selection */
261         theSelect.setEnabled(true);
262 
263         /* Skip if we have no analysis */
264         if (theAnalysisMgr.isIdle()) {
265             theHTMLPane.setHTMLContent("", "");
266             return;
267         }
268 
269         /* Access the appropriate analysis */
270         final MoneyWiseXAnalysis myAnalysis = myReportType.isPointInTime()
271                 ? theAnalysisMgr.getDatedAnalysis(myRange.getEnd())
272                 : theAnalysisMgr.getRangedAnalysis(myRange);
273 
274         /* Record analysis and build report */
275         theSelect.setAnalysis(myAnalysis);
276         final Document myDoc = theBuilder.createReport(myAnalysis, myReportType, mySecurity);
277 
278         /* Declare to debugger */
279         theSpotEntry.setObject(myAnalysis);
280         theSpotEntry.setVisible(true);
281 
282         /* Declare the document */
283         theManager.setDocument(myDoc);
284 
285         /* Create initial display version */
286         final String myText = theManager.formatXML();
287         theHTMLPane.setHTMLContent(myText, "");
288     }
289 
290     /**
291      * handleErrorPane.
292      */
293     private void handleErrorPane() {
294         /* Determine whether we have an error */
295         final boolean isError = theError.hasError();
296 
297         /* Hide selection panel on error */
298         theSelect.setVisible(!isError);
299 
300         /* Lock HTML area */
301         theHTMLPane.setEnabled(!isError);
302     }
303 
304     /**
305      * handleGoToRequest.
306      *
307      * @param pEvent the event
308      */
309     private void handleGoToRequest(final OceanusEvent<MetisReportEvent> pEvent) {
310         /* Access the filter */
311         final MoneyWiseXAnalysisFilter<?, ?> myFilter = pEvent.getDetails(MoneyWiseXAnalysisFilter.class);
312 
313         /* If we are currently showing Asset Gains */
314         if (MoneyWiseXReportType.ASSETGAINS.equals(theSelect.getReportType())) {
315             /* Select the capital gains report */
316             final MoneyWiseXAnalysisSecurityBucket myBucket = ((MoneyWiseXAnalysisSecurityFilter) myFilter).getBucket();
317             theSelect.setSecurity(myBucket);
318 
319             /* else we are selecting a statement */
320         } else {
321             /* Create the details of the report */
322             final TethysUIDateRangeSelector mySelect = theSelect.getDateRangeSelector();
323             final MoneyWiseXStatementSelect myStatement = new MoneyWiseXStatementSelect(mySelect, myFilter);
324 
325             /* Request the action */
326             theEventManager.fireEvent(PrometheusDataEvent.GOTOWINDOW, new PrometheusGoToEvent<>(MoneyWiseGoToId.STATEMENT, myStatement));
327         }
328     }
329 
330     /**
331      * handleReportRequest.
332      */
333     private void handleReportRequest() {
334         /* Protect against exceptions */
335         try {
336             /* build the report */
337             buildReport();
338 
339             /* Create SavePoint */
340             theSelect.createSavePoint();
341 
342             /* Catch Exceptions */
343         } catch (OceanusException e) {
344             /* Build the error */
345             final OceanusException myError = new MoneyWiseDataException("Failed to change selection", e);
346 
347             /* Show the error */
348             theError.addError(myError);
349             handleErrorPane();
350 
351             /* Restore SavePoint */
352             theSelect.restoreSavePoint();
353         }
354     }
355 }