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.dialog;
18  
19  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
20  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetBase;
21  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
22  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
23  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee.MoneyWisePayeeList;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio.MoneyWisePortfolioList;
27  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
28  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAssetCategory;
29  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
30  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency.MoneyWiseCurrencyList;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePortfolioType;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePortfolioType.MoneyWisePortfolioTypeList;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
34  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseIcon;
35  import io.github.tonywasher.joceanus.moneywise.ui.base.MoneyWiseUIAssetTable;
36  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
37  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
38  import io.github.tonywasher.joceanus.prometheus.ui.fieldset.PrometheusFieldSet;
39  import io.github.tonywasher.joceanus.prometheus.ui.fieldset.PrometheusFieldSetEvent;
40  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
41  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControl.TethysUIIconMapSet;
42  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
43  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUICharArrayEditField;
44  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUICharArrayTextAreaField;
45  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIIconButtonField;
46  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIScrollButtonField;
47  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIStringEditField;
48  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIFieldFactory;
49  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollItem;
50  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
51  
52  import java.util.Iterator;
53  import java.util.Map;
54  
55  /**
56   * Panel to display/edit/create a Portfolio.
57   */
58  public class MoneyWiseUIPortfolioDialog
59          extends MoneyWiseUIAssetDialog<MoneyWisePortfolio> {
60      /**
61       * The fieldSet.
62       */
63      private final PrometheusFieldSet<MoneyWisePortfolio> theFieldSet;
64  
65      /**
66       * The Closed State.
67       */
68      private Boolean theClosedState = Boolean.FALSE;
69  
70      /**
71       * Constructor.
72       *
73       * @param pFactory the GUI factory
74       * @param pEditSet the edit set
75       * @param pOwner   the owning table
76       */
77      public MoneyWiseUIPortfolioDialog(final TethysUIFactory<?> pFactory,
78                                        final PrometheusEditSet pEditSet,
79                                        final MoneyWiseUIAssetTable<MoneyWisePortfolio> pOwner) {
80          /* Initialise the panel */
81          super(pFactory, pEditSet, pOwner);
82  
83          /* Access the fieldSet */
84          theFieldSet = getFieldSet();
85          theFieldSet.setReporter(pOwner::showValidateError);
86  
87          /* Build the main panel */
88          buildMainPanel(pFactory);
89  
90          /* Build the account panel */
91          buildAccountPanel(pFactory);
92  
93          /* Build the web panel */
94          buildWebPanel(pFactory);
95  
96          /* Build the notes panel */
97          buildNotesPanel(pFactory);
98      }
99  
100     /**
101      * Build Main subPanel.
102      *
103      * @param pFactory the GUI factory
104      */
105     private void buildMainPanel(final TethysUIFactory<?> pFactory) {
106         /* Create the text fields */
107         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
108         final TethysUIStringEditField myName = myFields.newStringField();
109         final TethysUIStringEditField myDesc = myFields.newStringField();
110 
111         /* Create the buttons */
112         final TethysUIScrollButtonField<MoneyWiseAssetCategory> myTypeButton = myFields.newScrollField(MoneyWiseAssetCategory.class);
113         final TethysUIScrollButtonField<MoneyWisePayee> myParentButton = myFields.newScrollField(MoneyWisePayee.class);
114         final TethysUIScrollButtonField<MoneyWiseCurrency> myCurrencyButton = myFields.newScrollField(MoneyWiseCurrency.class);
115         final TethysUIIconButtonField<Boolean> myClosedButton = myFields.newIconField(Boolean.class);
116 
117         /* Assign the fields to the panel */
118         theFieldSet.addField(PrometheusDataResource.DATAITEM_FIELD_NAME, myName, MoneyWisePortfolio::getName);
119         theFieldSet.addField(PrometheusDataResource.DATAITEM_FIELD_DESC, myDesc, MoneyWisePortfolio::getDesc);
120         theFieldSet.addField(MoneyWiseBasicResource.CATEGORY_NAME, myTypeButton, MoneyWisePortfolio::getCategory);
121         theFieldSet.addField(MoneyWiseBasicResource.ASSET_PARENT, myParentButton, MoneyWisePortfolio::getParent);
122         theFieldSet.addField(MoneyWiseStaticDataType.CURRENCY, myCurrencyButton, MoneyWisePortfolio::getAssetCurrency);
123         theFieldSet.addField(MoneyWiseBasicResource.ASSET_CLOSED, myClosedButton, MoneyWisePortfolio::isClosed);
124 
125         /* Configure the menuBuilders */
126         myTypeButton.setMenuConfigurator(c -> buildTypeMenu(c, getItem()));
127         myParentButton.setMenuConfigurator(c -> buildParentMenu(c, getItem()));
128         myCurrencyButton.setMenuConfigurator(c -> buildCurrencyMenu(c, getItem()));
129         final Map<Boolean, TethysUIIconMapSet<Boolean>> myMapSets = MoneyWiseIcon.configureLockedIconButton(pFactory);
130         myClosedButton.setIconMapSet(() -> myMapSets.get(theClosedState));
131 
132         /* Configure validation checks */
133         myName.setValidator(this::isValidName);
134         myDesc.setValidator(this::isValidDesc);
135     }
136 
137     /**
138      * Build extras subPanel.
139      *
140      * @param pFactory the GUI factory
141      */
142     private void buildAccountPanel(final TethysUIFactory<?> pFactory) {
143         /* Create a new panel */
144         theFieldSet.newPanel(TAB_ACCOUNT);
145 
146         /* Allocate fields */
147         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
148         final TethysUICharArrayEditField mySortCode = myFields.newCharArrayField();
149         final TethysUICharArrayEditField myAccount = myFields.newCharArrayField();
150         final TethysUICharArrayEditField myReference = myFields.newCharArrayField();
151 
152         /* Assign the fields to the panel */
153         theFieldSet.addField(MoneyWiseAccountInfoClass.SORTCODE, mySortCode, MoneyWisePortfolio::getSortCode);
154         theFieldSet.addField(MoneyWiseAccountInfoClass.ACCOUNT, myAccount, MoneyWisePortfolio::getAccount);
155         theFieldSet.addField(MoneyWiseAccountInfoClass.REFERENCE, myReference, MoneyWisePortfolio::getReference);
156 
157         /* Configure validation checks */
158         mySortCode.setValidator(this::isValidSortCode);
159         myAccount.setValidator(this::isValidAccount);
160         myReference.setValidator(this::isValidReference);
161     }
162 
163     /**
164      * Build extras subPanel.
165      *
166      * @param pFactory the GUI factory
167      */
168     private void buildWebPanel(final TethysUIFactory<?> pFactory) {
169         /* Create a new panel */
170         theFieldSet.newPanel(TAB_WEB);
171 
172         /* Allocate fields */
173         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
174         final TethysUICharArrayEditField myWebSite = myFields.newCharArrayField();
175         final TethysUICharArrayEditField myCustNo = myFields.newCharArrayField();
176         final TethysUICharArrayEditField myUserId = myFields.newCharArrayField();
177         final TethysUICharArrayEditField myPassWord = myFields.newCharArrayField();
178 
179         /* Assign the fields to the panel */
180         theFieldSet.addField(MoneyWiseAccountInfoClass.WEBSITE, myWebSite, MoneyWisePortfolio::getWebSite);
181         theFieldSet.addField(MoneyWiseAccountInfoClass.CUSTOMERNO, myCustNo, MoneyWisePortfolio::getCustNo);
182         theFieldSet.addField(MoneyWiseAccountInfoClass.USERID, myUserId, MoneyWisePortfolio::getUserId);
183         theFieldSet.addField(MoneyWiseAccountInfoClass.PASSWORD, myPassWord, MoneyWisePortfolio::getPassword);
184 
185         /* Configure validation checks */
186         myWebSite.setValidator(this::isValidWebSite);
187         myCustNo.setValidator(this::isValidCustNo);
188         myUserId.setValidator(this::isValidUserId);
189         myPassWord.setValidator(this::isValidPassword);
190     }
191 
192     /**
193      * Build Notes subPanel.
194      *
195      * @param pFactory the GUI factory
196      */
197     private void buildNotesPanel(final TethysUIFactory<?> pFactory) {
198         /* Allocate fields */
199         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
200         final TethysUICharArrayTextAreaField myNotes = myFields.newCharArrayAreaField();
201 
202         /* Assign the fields to the panel */
203         theFieldSet.newTextArea(TAB_NOTES, MoneyWiseAccountInfoClass.NOTES, myNotes, MoneyWisePortfolio::getNotes);
204 
205         /* Configure validation checks */
206         myNotes.setValidator(this::isValidNotes);
207     }
208 
209     @Override
210     public void refreshData() {
211         /* If we have an item */
212         final MoneyWisePortfolio myItem = getItem();
213         if (myItem != null) {
214             final MoneyWisePortfolioList myPortfolios = getDataList(MoneyWiseBasicDataType.PORTFOLIO, MoneyWisePortfolioList.class);
215             setItem(myPortfolios.findItemById(myItem.getIndexedId()));
216         }
217 
218         /* Make sure that the item is not editable */
219         setEditable(false);
220     }
221 
222     @Override
223     protected void adjustFields(final boolean isEditable) {
224         /* Access the item */
225         final MoneyWisePortfolio myPortfolio = getItem();
226         final boolean bIsClosed = myPortfolio.isClosed();
227         final boolean bIsActive = myPortfolio.isActive();
228         final boolean bIsRelevant = myPortfolio.isRelevant();
229         final boolean bIsChangeable = !bIsActive && isEditable;
230 
231         /* Determine whether the closed button should be visible */
232         final boolean bShowClosed = bIsClosed || (bIsActive && !bIsRelevant);
233         theFieldSet.setFieldVisible(MoneyWiseBasicResource.ASSET_CLOSED, bShowClosed);
234 
235         /* Determine the state of the closed button */
236         final boolean bEditClosed = bIsClosed || !bIsRelevant;
237         theFieldSet.setFieldEditable(MoneyWiseBasicResource.ASSET_CLOSED, isEditable && bEditClosed);
238         theClosedState = bEditClosed;
239 
240         /* Determine whether the description field should be visible */
241         final boolean bShowDesc = isEditable || myPortfolio.getDesc() != null;
242         theFieldSet.setFieldVisible(PrometheusDataResource.DATAITEM_FIELD_DESC, bShowDesc);
243 
244         /* Determine whether the account details should be visible */
245         final boolean bShowSortCode = isEditable || myPortfolio.getSortCode() != null;
246         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.SORTCODE, bShowSortCode);
247         final boolean bShowAccount = isEditable || myPortfolio.getAccount() != null;
248         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.ACCOUNT, bShowAccount);
249         final boolean bShowReference = isEditable || myPortfolio.getReference() != null;
250         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.REFERENCE, bShowReference);
251         final boolean bShowWebSite = isEditable || myPortfolio.getWebSite() != null;
252         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.WEBSITE, bShowWebSite);
253         final boolean bShowCustNo = isEditable || myPortfolio.getCustNo() != null;
254         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.CUSTOMERNO, bShowCustNo);
255         final boolean bShowUserId = isEditable || myPortfolio.getUserId() != null;
256         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.USERID, bShowUserId);
257         final boolean bShowPasswd = isEditable || myPortfolio.getPassword() != null;
258         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.PASSWORD, bShowPasswd);
259         final boolean bShowNotes = isEditable || myPortfolio.getNotes() != null;
260         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.NOTES, bShowNotes);
261 
262         /* Type, Parent and Currency status cannot be changed if the item is active */
263         theFieldSet.setFieldEditable(MoneyWiseBasicResource.CATEGORY_NAME, bIsChangeable);
264         theFieldSet.setFieldEditable(MoneyWiseStaticDataType.CURRENCY, bIsChangeable);
265 
266         /* Set editable value for parent */
267         theFieldSet.setFieldEditable(MoneyWiseBasicResource.ASSET_PARENT, bIsChangeable && !bIsClosed);
268     }
269 
270     @Override
271     protected void updateField(final PrometheusFieldSetEvent pUpdate) throws OceanusException {
272         /* Access the field */
273         final MetisDataFieldId myField = pUpdate.getFieldId();
274         final MoneyWisePortfolio myPortfolio = getItem();
275 
276         /* Process updates */
277         if (PrometheusDataResource.DATAITEM_FIELD_NAME.equals(myField)) {
278             /* Update the Name */
279             myPortfolio.setName(pUpdate.getValue(String.class));
280         } else if (PrometheusDataResource.DATAITEM_FIELD_DESC.equals(myField)) {
281             /* Update the Description */
282             myPortfolio.setDescription(pUpdate.getValue(String.class));
283         } else if (MoneyWiseBasicResource.CATEGORY_NAME.equals(myField)) {
284             /* Update the portfolioType */
285             myPortfolio.setCategory(pUpdate.getValue(MoneyWisePortfolioType.class));
286         } else if (MoneyWiseBasicResource.ASSET_PARENT.equals(myField)) {
287             /* Update the Parent */
288             myPortfolio.setParent(pUpdate.getValue(MoneyWisePayee.class));
289         } else if (MoneyWiseStaticDataType.CURRENCY.equals(myField)) {
290             /* Update the Currency */
291             myPortfolio.setAssetCurrency(pUpdate.getValue(MoneyWiseCurrency.class));
292         } else if (MoneyWiseBasicResource.ASSET_CLOSED.equals(myField)) {
293             /* Update the Closed indication */
294             myPortfolio.setClosed(pUpdate.getValue(Boolean.class));
295         } else if (MoneyWiseAccountInfoClass.SORTCODE.equals(myField)) {
296             /* Update the SortCode */
297             myPortfolio.setSortCode(pUpdate.getValue(char[].class));
298         } else if (MoneyWiseAccountInfoClass.ACCOUNT.equals(myField)) {
299             /* Update the Account */
300             myPortfolio.setAccount(pUpdate.getValue(char[].class));
301         } else if (MoneyWiseAccountInfoClass.REFERENCE.equals(myField)) {
302             /* Update the Reference */
303             myPortfolio.setReference(pUpdate.getValue(char[].class));
304         } else if (MoneyWiseAccountInfoClass.WEBSITE.equals(myField)) {
305             /* Update the WebSite */
306             myPortfolio.setWebSite(pUpdate.getValue(char[].class));
307         } else if (MoneyWiseAccountInfoClass.CUSTOMERNO.equals(myField)) {
308             /* Update the Customer# */
309             myPortfolio.setCustNo(pUpdate.getValue(char[].class));
310         } else if (MoneyWiseAccountInfoClass.USERID.equals(myField)) {
311             /* Update the UserId */
312             myPortfolio.setUserId(pUpdate.getValue(char[].class));
313         } else if (MoneyWiseAccountInfoClass.PASSWORD.equals(myField)) {
314             /* Update the Password */
315             myPortfolio.setPassword(pUpdate.getValue(char[].class));
316         } else if (MoneyWiseAccountInfoClass.NOTES.equals(myField)) {
317             /* Update the Notes */
318             myPortfolio.setNotes(pUpdate.getValue(char[].class));
319         }
320     }
321 
322     @Override
323     protected void declareGoToItems(final boolean pUpdates) {
324         final MoneyWisePortfolio myItem = getItem();
325         final MoneyWiseAssetBase myParent = myItem.getParent();
326         if (!pUpdates) {
327             final MoneyWisePortfolioType myType = myItem.getCategory();
328             declareGoToItem(myType);
329             final MoneyWiseCurrency myCurrency = myItem.getAssetCurrency();
330             declareGoToItem(myCurrency);
331         }
332         declareGoToItem(myParent);
333     }
334 
335     /**
336      * Build the portfolioType menu for an item.
337      *
338      * @param pMenu      the menu
339      * @param pPortfolio the portfolio to build for
340      */
341     public void buildTypeMenu(final TethysUIScrollMenu<MoneyWiseAssetCategory> pMenu,
342                               final MoneyWisePortfolio pPortfolio) {
343         /* Clear the menu */
344         pMenu.removeAllItems();
345 
346         /* Record active item */
347         final MoneyWisePortfolioType myCurr = pPortfolio.getCategory();
348         TethysUIScrollItem<MoneyWiseAssetCategory> myActive = null;
349 
350         /* Access PortfolioTypes */
351         final MoneyWisePortfolioTypeList myTypes = getDataList(MoneyWiseStaticDataType.PORTFOLIOTYPE, MoneyWisePortfolioTypeList.class);
352 
353         /* Loop through the Types */
354         final Iterator<MoneyWisePortfolioType> myIterator = myTypes.iterator();
355         while (myIterator.hasNext()) {
356             final MoneyWisePortfolioType myType = myIterator.next();
357 
358             /* Create a new action for the type */
359             final TethysUIScrollItem<MoneyWiseAssetCategory> myItem = pMenu.addItem(myType);
360 
361             /* If this is the active type */
362             if (myType.equals(myCurr)) {
363                 /* Record it */
364                 myActive = myItem;
365             }
366         }
367 
368         /* Ensure active item is visible */
369         if (myActive != null) {
370             myActive.scrollToItem();
371         }
372     }
373 
374     /**
375      * Build the parent menu for an item.
376      *
377      * @param pMenu      the menu
378      * @param pPortfolio the portfolio to build for
379      */
380     public void buildParentMenu(final TethysUIScrollMenu<MoneyWisePayee> pMenu,
381                                 final MoneyWisePortfolio pPortfolio) {
382         /* Clear the menu */
383         pMenu.removeAllItems();
384 
385         /* Record active item */
386         final MoneyWisePayee myCurr = pPortfolio.getParent();
387         TethysUIScrollItem<MoneyWisePayee> myActive = null;
388 
389         /* Access Payees */
390         final MoneyWisePayeeList myPayees = getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class);
391 
392         /* Loop through the Payees */
393         final Iterator<MoneyWisePayee> myIterator = myPayees.iterator();
394         while (myIterator.hasNext()) {
395             final MoneyWisePayee myPayee = myIterator.next();
396 
397             /* Ignore deleted/closed and ones that cannot own this portfolio */
398             boolean bIgnore = myPayee.isDeleted() || myPayee.isClosed();
399             bIgnore |= !myPayee.getCategoryClass().canParentPortfolio();
400             if (bIgnore) {
401                 continue;
402             }
403 
404             /* Create a new action for the payee */
405             final TethysUIScrollItem<MoneyWisePayee> myItem = pMenu.addItem(myPayee);
406 
407             /* If this is the active parent */
408             if (myPayee.equals(myCurr)) {
409                 /* Record it */
410                 myActive = myItem;
411             }
412         }
413 
414         /* Ensure active item is visible */
415         if (myActive != null) {
416             myActive.scrollToItem();
417         }
418     }
419 
420     /**
421      * Build the currency menu for an item.
422      *
423      * @param pMenu      the menu
424      * @param pPortfolio the portfolio to build for
425      */
426     public void buildCurrencyMenu(final TethysUIScrollMenu<MoneyWiseCurrency> pMenu,
427                                   final MoneyWisePortfolio pPortfolio) {
428         /* Clear the menu */
429         pMenu.removeAllItems();
430 
431         /* Record active item */
432         final MoneyWiseCurrency myCurr = pPortfolio.getAssetCurrency();
433         TethysUIScrollItem<MoneyWiseCurrency> myActive = null;
434 
435         /* Access Currencies */
436         final MoneyWiseCurrencyList myCurrencies = getDataList(MoneyWiseStaticDataType.CURRENCY, MoneyWiseCurrencyList.class);
437 
438         /* Loop through the AccountCurrencies */
439         final Iterator<MoneyWiseCurrency> myIterator = myCurrencies.iterator();
440         while (myIterator.hasNext()) {
441             final MoneyWiseCurrency myCurrency = myIterator.next();
442 
443             /* Ignore deleted or disabled */
444             final boolean bIgnore = myCurrency.isDeleted() || !myCurrency.getEnabled();
445             if (bIgnore) {
446                 continue;
447             }
448 
449             /* Create a new action for the currency */
450             final TethysUIScrollItem<MoneyWiseCurrency> myItem = pMenu.addItem(myCurrency);
451 
452             /* If this is the active currency */
453             if (myCurrency.equals(myCurr)) {
454                 /* Record it */
455                 myActive = myItem;
456             }
457         }
458 
459         /* Ensure active item is visible */
460         if (myActive != null) {
461             myActive.scrollToItem();
462         }
463     }
464 }