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