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.metis.field.MetisFieldRequired;
21  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetBase;
22  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
23  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee.MoneyWisePayeeList;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseRegion;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseRegion.MoneyWiseRegionList;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity.MoneyWiseSecurityList;
30  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAssetCategory;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency.MoneyWiseCurrencyList;
34  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityClass;
35  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityType;
36  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityType.MoneyWiseSecurityTypeList;
37  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
38  import io.github.tonywasher.joceanus.moneywise.data.validate.MoneyWiseValidateSecurity;
39  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseIcon;
40  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
41  import io.github.tonywasher.joceanus.moneywise.ui.base.MoneyWiseUIAssetTable;
42  import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
43  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
44  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
45  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
46  import io.github.tonywasher.joceanus.prometheus.ui.fieldset.PrometheusFieldSet;
47  import io.github.tonywasher.joceanus.prometheus.ui.fieldset.PrometheusFieldSetEvent;
48  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
49  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControl.TethysUIIconMapSet;
50  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
51  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUICharArrayTextAreaField;
52  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIIconButtonField;
53  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIPriceEditField;
54  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIScrollButtonField;
55  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIStringEditField;
56  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIFieldFactory;
57  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollItem;
58  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
59  
60  import java.util.Iterator;
61  import java.util.Map;
62  
63  /**
64   * Panel to display/edit/create a Security.
65   */
66  public class MoneyWiseUISecurityDialog
67          extends MoneyWiseUIAssetDialog<MoneyWiseSecurity> {
68      /**
69       * Prices Tab Title.
70       */
71      private static final String TAB_PRICES = MoneyWiseUIResource.SECURITYPANEL_TAB_PRICES.getValue();
72  
73      /**
74       * The fieldSet.
75       */
76      private final PrometheusFieldSet<MoneyWiseSecurity> theFieldSet;
77  
78      /**
79       * SecurityPrice Table.
80       */
81      private final MoneyWiseUISecurityPriceTable thePrices;
82  
83      /**
84       * The Closed State.
85       */
86      private Boolean theClosedState = Boolean.FALSE;
87  
88      /**
89       * Constructor.
90       *
91       * @param pFactory the GUI factory
92       * @param pView    the data view
93       * @param pEditSet the edit set
94       * @param pOwner   the owning table
95       */
96      public MoneyWiseUISecurityDialog(final TethysUIFactory<?> pFactory,
97                                       final MoneyWiseView pView,
98                                       final PrometheusEditSet pEditSet,
99                                       final MoneyWiseUIAssetTable<MoneyWiseSecurity> pOwner) {
100         /* Initialise the panel */
101         super(pFactory, pEditSet, pOwner);
102 
103         /* Access the fieldSet */
104         theFieldSet = getFieldSet();
105         theFieldSet.setReporter(pOwner::showValidateError);
106 
107         /* Build the main panel */
108         buildMainPanel(pFactory);
109 
110         /* Build the details panel */
111         buildDetailsPanel(pFactory);
112 
113         /* Build the notes panel */
114         buildNotesPanel(pFactory);
115 
116         /* Create the SecurityPrices table */
117         thePrices = new MoneyWiseUISecurityPriceTable(pView, getEditSet(), pOwner.getErrorPanel());
118         theFieldSet.newTable(TAB_PRICES, thePrices);
119 
120         /* Create the listener */
121         thePrices.getEventRegistrar().addEventListener(e -> {
122             updateActions();
123             fireStateChanged();
124         });
125     }
126 
127     /**
128      * Build Main subPanel.
129      *
130      * @param pFactory the GUI factory
131      */
132     private void buildMainPanel(final TethysUIFactory<?> pFactory) {
133         /* Create the text fields */
134         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
135         final TethysUIStringEditField myName = myFields.newStringField();
136         final TethysUIStringEditField myDesc = myFields.newStringField();
137 
138         /* Create the buttons */
139         final TethysUIScrollButtonField<MoneyWiseAssetCategory> myTypeButton = myFields.newScrollField(MoneyWiseAssetCategory.class);
140         final TethysUIScrollButtonField<MoneyWisePayee> myParentButton = myFields.newScrollField(MoneyWisePayee.class);
141         final TethysUIScrollButtonField<MoneyWiseCurrency> myCurrencyButton = myFields.newScrollField(MoneyWiseCurrency.class);
142         final TethysUIIconButtonField<Boolean> myClosedButton = myFields.newIconField(Boolean.class);
143 
144         /* Assign the fields to the panel */
145         theFieldSet.addField(PrometheusDataResource.DATAITEM_FIELD_NAME, myName, MoneyWiseSecurity::getName);
146         theFieldSet.addField(PrometheusDataResource.DATAITEM_FIELD_DESC, myDesc, MoneyWiseSecurity::getDesc);
147         theFieldSet.addField(MoneyWiseBasicResource.CATEGORY_NAME, myTypeButton, MoneyWiseSecurity::getCategory);
148         theFieldSet.addField(MoneyWiseBasicResource.ASSET_PARENT, myParentButton, MoneyWiseSecurity::getParent);
149         theFieldSet.addField(MoneyWiseStaticDataType.CURRENCY, myCurrencyButton, MoneyWiseSecurity::getAssetCurrency);
150         theFieldSet.addField(MoneyWiseBasicResource.ASSET_CLOSED, myClosedButton, MoneyWiseSecurity::isClosed);
151 
152         /* Configure the menuBuilders */
153         myTypeButton.setMenuConfigurator(c -> buildSecTypeMenu(c, getItem()));
154         myParentButton.setMenuConfigurator(c -> buildParentMenu(c, getItem()));
155         myCurrencyButton.setMenuConfigurator(c -> buildCurrencyMenu(c, getItem()));
156         final Map<Boolean, TethysUIIconMapSet<Boolean>> myMapSets = MoneyWiseIcon.configureLockedIconButton(pFactory);
157         myClosedButton.setIconMapSet(() -> myMapSets.get(theClosedState));
158 
159         /* Configure validation checks */
160         myName.setValidator(this::isValidName);
161         myDesc.setValidator(this::isValidDesc);
162     }
163 
164     /**
165      * Build details subPanel.
166      *
167      * @param pFactory the GUI factory
168      */
169     private void buildDetailsPanel(final TethysUIFactory<?> pFactory) {
170         /* Create a new panel */
171         theFieldSet.newPanel(TAB_DETAILS);
172 
173         /* Allocate fields */
174         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
175         final TethysUIStringEditField mySymbol = myFields.newStringField();
176         final TethysUIPriceEditField myPrice = myFields.newPriceField();
177 
178         /* Create the buttons */
179         final TethysUIScrollButtonField<MoneyWiseRegion> myRegionButton = myFields.newScrollField(MoneyWiseRegion.class);
180         final TethysUIScrollButtonField<MoneyWiseSecurity> myStockButton = myFields.newScrollField(MoneyWiseSecurity.class);
181 
182         /* Assign the fields to the panel */
183         theFieldSet.addField(MoneyWiseAccountInfoClass.SYMBOL, mySymbol, MoneyWiseSecurity::getSymbol);
184         theFieldSet.addField(MoneyWiseAccountInfoClass.REGION, myRegionButton, MoneyWiseSecurity::getRegion);
185         theFieldSet.addField(MoneyWiseAccountInfoClass.UNDERLYINGSTOCK, myStockButton, MoneyWiseSecurity::getUnderlyingStock);
186         theFieldSet.addField(MoneyWiseAccountInfoClass.OPTIONPRICE, myPrice, MoneyWiseSecurity::getOptionPrice);
187 
188         /* Configure the menuBuilders */
189         myRegionButton.setMenuConfigurator(c -> buildRegionMenu(c, getItem()));
190         myStockButton.setMenuConfigurator(c -> buildStockMenu(c, getItem()));
191         myPrice.setDeemedCurrency(() -> getItem().getCurrency());
192 
193         /* Configure validation checks */
194         mySymbol.setValidator(this::isValidSymbol);
195     }
196 
197     /**
198      * Build Notes subPanel.
199      *
200      * @param pFactory the GUI factory
201      */
202     private void buildNotesPanel(final TethysUIFactory<?> pFactory) {
203         /* Allocate fields */
204         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
205         final TethysUICharArrayTextAreaField myNotes = myFields.newCharArrayAreaField();
206 
207         /* Assign the fields to the panel */
208         theFieldSet.newTextArea(TAB_NOTES, MoneyWiseAccountInfoClass.NOTES, myNotes, MoneyWiseSecurity::getNotes);
209 
210         /* Configure validation checks */
211         myNotes.setValidator(this::isValidNotes);
212     }
213 
214     @Override
215     public void refreshData() {
216         /* If we have an item */
217         final MoneyWiseSecurity myItem = getItem();
218         if (myItem != null) {
219             final MoneyWiseSecurityList mySecurities = getDataList(MoneyWiseBasicDataType.SECURITY, MoneyWiseSecurityList.class);
220             setItem(mySecurities.findItemById(myItem.getIndexedId()));
221         }
222 
223         /* Refresh the prices */
224         thePrices.refreshData();
225 
226         /* Make sure that the item is not editable */
227         setEditable(false);
228     }
229 
230     @Override
231     protected void adjustFields(final boolean isEditable) {
232         /* Access the item */
233         final MoneyWiseSecurity mySecurity = getItem();
234         final boolean bIsClosed = mySecurity.isClosed();
235         final boolean bIsActive = mySecurity.isActive();
236         final boolean bIsRelevant = mySecurity.isRelevant();
237 
238         /* Determine whether the closed button should be visible */
239         final boolean bShowClosed = bIsClosed || (bIsActive && !bIsRelevant);
240         theFieldSet.setFieldVisible(MoneyWiseBasicResource.ASSET_CLOSED, bShowClosed);
241 
242         /* Determine the state of the closed button */
243         final boolean bEditClosed = bIsClosed
244                 ? !mySecurity.getParent().isClosed()
245                 : !bIsRelevant;
246         theFieldSet.setFieldEditable(MoneyWiseBasicResource.ASSET_CLOSED, isEditable && bEditClosed);
247         theClosedState = bEditClosed;
248 
249         /* Determine whether the description field should be visible */
250         final boolean bShowDesc = isEditable || mySecurity.getDesc() != null;
251         theFieldSet.setFieldVisible(PrometheusDataResource.DATAITEM_FIELD_DESC, bShowDesc);
252 
253         /* Determine whether the account details should be visible */
254         final boolean bShowNotes = isEditable || mySecurity.getNotes() != null;
255         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.NOTES, bShowNotes);
256 
257         /* Determine whether the symbol field should be visible */
258         boolean bEditField = isEditable && isEditableField(mySecurity, MoneyWiseAccountInfoClass.SYMBOL);
259         boolean bShowField = bEditField || mySecurity.getSymbol() != null;
260         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.SYMBOL, bShowField);
261         theFieldSet.setFieldEditable(MoneyWiseAccountInfoClass.SYMBOL, bEditField);
262 
263         /* Determine whether the region field should be visible */
264         bEditField = isEditable && isEditableField(mySecurity, MoneyWiseAccountInfoClass.REGION);
265         bShowField = bEditField || mySecurity.getRegion() != null;
266         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.REGION, bShowField);
267         theFieldSet.setFieldEditable(MoneyWiseAccountInfoClass.REGION, bEditField);
268 
269         /* Determine whether the stock field should be visible */
270         bEditField = isEditable && isEditableField(mySecurity, MoneyWiseAccountInfoClass.UNDERLYINGSTOCK);
271         bShowField = bEditField || mySecurity.getRegion() != null;
272         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.UNDERLYINGSTOCK, bShowField);
273         theFieldSet.setFieldEditable(MoneyWiseAccountInfoClass.UNDERLYINGSTOCK, bEditField);
274 
275         /* Determine whether the price field should be visible */
276         bEditField = isEditable && isEditableField(mySecurity, MoneyWiseAccountInfoClass.OPTIONPRICE);
277         bShowField = bEditField || mySecurity.getRegion() != null;
278         theFieldSet.setFieldVisible(MoneyWiseAccountInfoClass.OPTIONPRICE, bShowField);
279         theFieldSet.setFieldEditable(MoneyWiseAccountInfoClass.OPTIONPRICE, bEditField);
280 
281         /* Security type and currency cannot be changed if the item is active */
282         theFieldSet.setFieldEditable(MoneyWiseBasicResource.CATEGORY_NAME, isEditable && !bIsActive);
283         theFieldSet.setFieldEditable(MoneyWiseStaticDataType.CURRENCY, isEditable && !bIsActive);
284 
285         /* Set editable value for parent */
286         theFieldSet.setFieldEditable(MoneyWiseBasicResource.ASSET_PARENT, isEditable && !bIsClosed);
287     }
288 
289     /**
290      * Is the field editable?
291      *
292      * @param pSecurity the security
293      * @param pField    the field class
294      * @return true/false
295      */
296     public static boolean isEditableField(final MoneyWiseSecurity pSecurity,
297                                           final MoneyWiseAccountInfoClass pField) {
298         /* Check whether the field is available */
299         final MoneyWiseValidateSecurity myValidator = (MoneyWiseValidateSecurity) pSecurity.getList().getValidator();
300         final MetisFieldRequired isRequired = myValidator.isClassRequired(pField);
301         return !isRequired.equals(MetisFieldRequired.NOTALLOWED);
302     }
303 
304     @Override
305     protected void updateField(final PrometheusFieldSetEvent pUpdate) throws OceanusException {
306         /* Access the field */
307         final MetisDataFieldId myField = pUpdate.getFieldId();
308         final MoneyWiseSecurity mySecurity = getItem();
309 
310         /* Process updates */
311         if (PrometheusDataResource.DATAITEM_FIELD_NAME.equals(myField)) {
312             /* Update the Name */
313             mySecurity.setName(pUpdate.getValue(String.class));
314         } else if (PrometheusDataResource.DATAITEM_FIELD_DESC.equals(myField)) {
315             /* Update the Description */
316             mySecurity.setDescription(pUpdate.getValue(String.class));
317         } else if (MoneyWiseBasicResource.CATEGORY_NAME.equals(myField)) {
318             /* Update the Security Type */
319             mySecurity.setCategory(pUpdate.getValue(MoneyWiseSecurityType.class));
320             mySecurity.autoCorrect();
321         } else if (MoneyWiseBasicResource.ASSET_PARENT.equals(myField)) {
322             /* Update the Parent */
323             mySecurity.setParent(pUpdate.getValue(MoneyWisePayee.class));
324         } else if (MoneyWiseStaticDataType.CURRENCY.equals(myField)) {
325             /* Update the Currency */
326             mySecurity.setAssetCurrency(pUpdate.getValue(MoneyWiseCurrency.class));
327         } else if (MoneyWiseBasicResource.ASSET_CLOSED.equals(myField)) {
328             /* Update the Closed indication */
329             mySecurity.setClosed(pUpdate.getValue(Boolean.class));
330         } else if (MoneyWiseAccountInfoClass.SYMBOL.equals(myField)) {
331             /* Update the Symbol */
332             mySecurity.setSymbol(pUpdate.getValue(String.class));
333         } else if (MoneyWiseAccountInfoClass.REGION.equals(myField)) {
334             /* Update the Region */
335             mySecurity.setRegion(pUpdate.getValue(MoneyWiseRegion.class));
336         } else if (MoneyWiseAccountInfoClass.UNDERLYINGSTOCK.equals(myField)) {
337             /* Update the Underlying Stock */
338             mySecurity.setUnderlyingStock(pUpdate.getValue(MoneyWiseSecurity.class));
339         } else if (MoneyWiseAccountInfoClass.OPTIONPRICE.equals(myField)) {
340             /* Update the OptionPrice */
341             mySecurity.setOptionPrice(pUpdate.getValue(OceanusPrice.class));
342         } else if (MoneyWiseAccountInfoClass.NOTES.equals(myField)) {
343             /* Update the Notes */
344             mySecurity.setNotes(pUpdate.getValue(char[].class));
345         }
346     }
347 
348     @Override
349     protected void declareGoToItems(final boolean pUpdates) {
350         final MoneyWiseSecurity myItem = getItem();
351         final MoneyWiseAssetBase myParent = myItem.getParent();
352         if (!pUpdates) {
353             final MoneyWiseSecurityType myType = myItem.getCategory();
354             final MoneyWiseCurrency myCurrency = myItem.getAssetCurrency();
355             final MoneyWiseRegion myRegion = myItem.getRegion();
356             declareGoToItem(myType);
357             declareGoToItem(myRegion);
358             declareGoToItem(myCurrency);
359         }
360         declareGoToItem(myParent);
361     }
362 
363     /**
364      * Add a new price for a new security.
365      *
366      * @param pSecurity the security
367      * @throws OceanusException on error
368      */
369     public void addNewPrice(final MoneyWiseSecurity pSecurity) throws OceanusException {
370         /* Create the new price */
371         thePrices.addNewPrice(pSecurity);
372     }
373 
374     @Override
375     public void setEditable(final boolean isEditable) {
376         /* Update the prices */
377         thePrices.setEditable(isEditable);
378 
379         /* Pass call onwards */
380         super.setEditable(isEditable);
381     }
382 
383     @Override
384     protected void refreshAfterUpdate() {
385         /* Pass call onwards */
386         super.refreshAfterUpdate();
387 
388         /* Refresh the prices */
389         thePrices.refreshAfterUpdate();
390     }
391 
392     /**
393      * Build the securityType menu for an item.
394      *
395      * @param pMenu     the menu
396      * @param pSecurity the security to build for
397      */
398     public void buildSecTypeMenu(final TethysUIScrollMenu<MoneyWiseAssetCategory> pMenu,
399                                  final MoneyWiseSecurity pSecurity) {
400         /* Clear the menu */
401         pMenu.removeAllItems();
402 
403         /* Record active item */
404         final MoneyWiseSecurityType myCurr = pSecurity.getCategory();
405         TethysUIScrollItem<MoneyWiseAssetCategory> myActive = null;
406 
407         /* Access SecurityTypes */
408         final MoneyWiseSecurityTypeList myTypes = getDataList(MoneyWiseStaticDataType.SECURITYTYPE, MoneyWiseSecurityTypeList.class);
409 
410         /* Loop through the SecurityTypes */
411         final Iterator<MoneyWiseSecurityType> myIterator = myTypes.iterator();
412         while (myIterator.hasNext()) {
413             final MoneyWiseSecurityType myType = myIterator.next();
414 
415             /* Ignore deleted or disabled */
416             final boolean bIgnore = myType.isDeleted() || !myType.getEnabled();
417             if (bIgnore) {
418                 continue;
419             }
420 
421             /* Create a new action for the secType */
422             final TethysUIScrollItem<MoneyWiseAssetCategory> myItem = pMenu.addItem(myType);
423 
424             /* If this is the active secType */
425             if (myType.equals(myCurr)) {
426                 /* Record it */
427                 myActive = myItem;
428             }
429         }
430 
431         /* Ensure active item is visible */
432         if (myActive != null) {
433             myActive.scrollToItem();
434         }
435     }
436 
437     /**
438      * Build the parent menu for an item.
439      *
440      * @param pMenu     the menu
441      * @param pSecurity the security to build for
442      */
443     public void buildParentMenu(final TethysUIScrollMenu<MoneyWisePayee> pMenu,
444                                 final MoneyWiseSecurity pSecurity) {
445         /* Clear the menu */
446         pMenu.removeAllItems();
447 
448         /* Record active item */
449         final MoneyWiseSecurityClass myType = pSecurity.getCategoryClass();
450         final MoneyWisePayee myCurr = pSecurity.getParent();
451         TethysUIScrollItem<MoneyWisePayee> myActive = null;
452 
453         /* Access Payees */
454         final MoneyWisePayeeList myPayees = getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class);
455 
456         /* Loop through the Payees */
457         final Iterator<MoneyWisePayee> myIterator = myPayees.iterator();
458         while (myIterator.hasNext()) {
459             final MoneyWisePayee myPayee = myIterator.next();
460 
461             /* Ignore deleted or non-owner */
462             boolean bIgnore = myPayee.isDeleted() || !myPayee.getCategoryClass().canParentSecurity(myType);
463             bIgnore |= myPayee.isClosed();
464             if (bIgnore) {
465                 continue;
466             }
467 
468             /* Create a new action for the payee */
469             final TethysUIScrollItem<MoneyWisePayee> myItem = pMenu.addItem(myPayee);
470 
471             /* If this is the active parent */
472             if (myPayee.equals(myCurr)) {
473                 /* Record it */
474                 myActive = myItem;
475             }
476         }
477 
478         /* Ensure active item is visible */
479         if (myActive != null) {
480             myActive.scrollToItem();
481         }
482     }
483 
484     /**
485      * Build the region menu for an item.
486      *
487      * @param pMenu     the menu
488      * @param pSecurity the security to build for
489      */
490     public void buildRegionMenu(final TethysUIScrollMenu<MoneyWiseRegion> pMenu,
491                                 final MoneyWiseSecurity pSecurity) {
492         /* Clear the menu */
493         pMenu.removeAllItems();
494 
495         /* Record active item */
496         final MoneyWiseRegion myCurr = pSecurity.getRegion();
497         TethysUIScrollItem<MoneyWiseRegion> myActive = null;
498 
499         /* Access regions */
500         final MoneyWiseRegionList myRegions = getDataList(MoneyWiseBasicDataType.REGION, MoneyWiseRegionList.class);
501 
502         /* Loop through the Regions */
503         final Iterator<MoneyWiseRegion> myIterator = myRegions.iterator();
504         while (myIterator.hasNext()) {
505             final MoneyWiseRegion myRegion = myIterator.next();
506 
507             /* Ignore deleted */
508             final boolean bIgnore = myRegion.isDeleted();
509             if (bIgnore) {
510                 continue;
511             }
512 
513             /* Create a new action for the region */
514             final TethysUIScrollItem<MoneyWiseRegion> myItem = pMenu.addItem(myRegion);
515 
516             /* If this is the active region */
517             if (myRegion.equals(myCurr)) {
518                 /* Record it */
519                 myActive = myItem;
520             }
521         }
522 
523         /* Ensure active item is visible */
524         if (myActive != null) {
525             myActive.scrollToItem();
526         }
527     }
528 
529     /**
530      * Build the stock menu for an item.
531      *
532      * @param pMenu     the menu
533      * @param pSecurity the security to build for
534      */
535     public void buildStockMenu(final TethysUIScrollMenu<MoneyWiseSecurity> pMenu,
536                                final MoneyWiseSecurity pSecurity) {
537         /* Clear the menu */
538         pMenu.removeAllItems();
539 
540         /* Record active item */
541         final MoneyWiseSecurity myCurr = pSecurity.getUnderlyingStock();
542         TethysUIScrollItem<MoneyWiseSecurity> myActive = null;
543 
544         /* Access securities */
545         final MoneyWiseSecurityList mySecurities = getDataList(MoneyWiseBasicDataType.SECURITY, MoneyWiseSecurityList.class);
546 
547         /* Loop through the Securities */
548         final Iterator<MoneyWiseSecurity> myIterator = mySecurities.iterator();
549         while (myIterator.hasNext()) {
550             final MoneyWiseSecurity mySecurity = myIterator.next();
551 
552             /* Ignore deleted and non share */
553             boolean bIgnore = mySecurity.isDeleted();
554             bIgnore |= !mySecurity.getCategoryClass().isShares();
555             if (bIgnore) {
556                 continue;
557             }
558 
559             /* Create a new action for the region */
560             final TethysUIScrollItem<MoneyWiseSecurity> myItem = pMenu.addItem(mySecurity);
561 
562             /* If this is the active stock */
563             if (mySecurity.equals(myCurr)) {
564                 /* Record it */
565                 myActive = myItem;
566             }
567         }
568 
569         /* Ensure active item is visible */
570         if (myActive != null) {
571             myActive.scrollToItem();
572         }
573     }
574 
575     /**
576      * Build the currency menu for an item.
577      *
578      * @param pMenu     the menu
579      * @param pSecurity the security to build for
580      */
581     public void buildCurrencyMenu(final TethysUIScrollMenu<MoneyWiseCurrency> pMenu,
582                                   final MoneyWiseSecurity pSecurity) {
583         /* Clear the menu */
584         pMenu.removeAllItems();
585 
586         /* Record active item */
587         final MoneyWiseCurrency myCurr = pSecurity.getAssetCurrency();
588         TethysUIScrollItem<MoneyWiseCurrency> myActive = null;
589 
590         /* Access Currencies */
591         final MoneyWiseCurrencyList myCurrencies = getDataList(MoneyWiseStaticDataType.CURRENCY, MoneyWiseCurrencyList.class);
592 
593         /* Loop through the AccountCurrencies */
594         final Iterator<MoneyWiseCurrency> myIterator = myCurrencies.iterator();
595         while (myIterator.hasNext()) {
596             final MoneyWiseCurrency myCurrency = myIterator.next();
597 
598             /* Ignore deleted or disabled */
599             final boolean bIgnore = myCurrency.isDeleted() || !myCurrency.getEnabled();
600             if (bIgnore) {
601                 continue;
602             }
603 
604             /* Create a new action for the currency */
605             final TethysUIScrollItem<MoneyWiseCurrency> myItem = pMenu.addItem(myCurrency);
606 
607             /* If this is the active currency */
608             if (myCurrency.equals(myCurr)) {
609                 /* Record it */
610                 myActive = myItem;
611             }
612         }
613 
614         /* Ensure active item is visible */
615         if (myActive != null) {
616             myActive.scrollToItem();
617         }
618     }
619 }